Description of the cmsRun Python Configuration Syntax

Complete: 4

Goals of this page

This page describes how to use the Python language to create configuration files.

For an introductory discussion of configuration files, see the WorkBook page WorkBookConfigFileIntro.

Translation Utilities (how to change old config files to PYTHON files)

To get used to the python configuration syntax, please have a look at e.g. the slides of the July 2008 python tutorial.

As most of the old configuration files have been deleted from the release, the last coherent version (i.e. CMSSW_2_1_0_pre6) is only accessible via AFS at CERN. To make these files known to the translation utilities you have to set (not needed for pre9 and following versions):


The following scripts will help you to translate your configuration files into python. The scripts,, and can be found in the FWCore/ParameterSet/python directory. For now, we recommend copying these scripts to your CMSSW src/ area and working from there.

python <your cfg, cff, or cfi>

Dumps to the screen a translation of your configuration file. Any dependent cffs or cfis which need to be translated will be translated and put in the appropriate directory.

python <subsystem/package/dir/your cfg, cff, or cfi>

Similar, but puts the output file in the appropriate python/ subdirectory of your package. This script catches exceptions, so if you get an error, try again with to see what went wrong.

This script needs to be run from the CMSSW release src/ area.

python <your cfg, cff, or cfi>

This second-pass script finds the comments in your old file, and tries to translate them over to the python file. It sometimes gets confused when there's more than one variable of the same name, or when the comments appear inside vectors. When that happens, it just dumps the comments in the top of the python file.

edmTestCfgTranslation <your cfg>

This script will do the translation of your full cfg, create dumps of the ParameterSet that results from both the cfg and python versions, and checks the two versions for differences. Any differences are likely due to differences in some underlying cfi or cff, and need to be investigated. Another possibility is that a (python) 'replace' on a member of a 'block' is done after its usage. Then simply move the replacing line in front of its usage in python.

Finally, test if your new python file will compile:

python <subsystem/package/python/your py file>

The automatic translation has a few quirks. We can't maintain the order of statements in the original files, comments inside vectors can't be translated properly, and modules default to the type EDFilter.

The reason order isn't maintained is because the python system uses python dictionaries internally, and python dictionaries can't maintain order. Your new python file may require a bit of manual cleanup.

The translation tries to guess which type of module, EDProducer, EDFilter, or EDAnalyzer, to make, based on the name. If it's not obvious to the system, the default is EDFilter, because a few of the Path operators, '~' and '-', only accept EDFilters. If you're module is really an EDProducer or an EDAnalyzer, please fix the translated python file by hand.


A configuration document, written using the Python language, is used to configure the cmsRun executable. A Python configuration program specifies which modules, inputs, outputs and services are to be loaded during execution, how to configure these modules and services, and in what order to execute them. It is a file which can be self-contained, or can read in any number of external Python configuration fragments using Python's standard import statement. Here is an illustration of the structure of a configuration file:

# Import configurations
import FWCore.ParameterSet.Config as cms

# Import contents of a file
import Foo.Bar.somefile

#set up a process , for e.g. RECO in this case
process = cms.Process("RECO")

# this inputs the input files
process.source = cms.Source("PoolSource", 
        fileNames = cms.untracked.vstring("test.root")

process.tracker = cms.EDProducer("TrackFinderProducer")

# talk to output module
process.out = cms.OutputModule("PoolOutputModule",
      fileName = cms.untracked.string("test2.root")

#add the contents of Foo.Bar.somefile to the process

# define output path
process.p = cms.Path(process.tracker * process.out)

There must be exactly one cms.Process with the name process in a top level configuration file.

Python Quick Tips


Python has a few features that take some getting used to.

Python program flow is controlled by the indentation of the statements, so there's no need for 'endif' statements, or the curly braces from the old config language.

Objects in python are usually passed by reference. One difference between C++ and python is that when you assign an object to a variable using the '=' sign, python doesn't make a copy of the object. In general, assume that python shares references unless you explicitly make a copy, so when you modify an object, you modify it everywhere it's used.

Objects are built using constructor syntax. It's easy to forget the commas.

You can validate the syntax of your configuration using python

python <your file>

Python allows you to explore your configuration from the python command prompt

> python
>>> from Configuration.Examples.RecoExample_CMS.GlobalTag_cfg import process
>>> process.ecalRecHit
    EEuncalibRecHitCollection = cms.InputTag("ecalWeightUncalibRecHit","EcalUncalibRecHitsEE"),
    ChannelStatusToBeExcluded = cms.vint32(),
    EBuncalibRecHitCollection = cms.InputTag("ecalWeightUncalibRecHit","EcalUncalibRecHitsEB"),
    EBrechitCollection = cms.string('EcalRecHitsEB'),
    EErechitCollection = cms.string('EcalRecHitsEE')

Python and SCRAM

To make objects in your python files visible to other python files, they first need to be put in your package's python directory, or a subdirectory of python. Then, you need to run scramv1 build once in your python area, to initialize the symbolic links. Later, when you change your python file, you won't need to re-build.


A Python configuration program is structured as a hierarchy of objects, nested or adjacent with respect to each other. Each object specifies a recognizable component or feature of the cmsRun program (e.g., a module) and configures it via its parameter set. Each object is introduced by a class name that identifies the type of component it configures and gives the name of the component. The contents of the object (the parameter settings) are held by the object:

NAME1 = className("someC++Class",
parameter declarations

    NAME2 = className2( 
    parameter declarations for nested object

Comments may be added within a block's scope using "#" where the comment continues to the end of the line. It is clearest to define each parameter on a separate line in your configuration file, e.g.,:

VtxSmeared = cms.EDProducer("VertexGenerator",
    # Setting parameters:  <-- First comment
    type = cms.string ("IOMC/EventVertexGenerators/GaussianEventVertexGenerator"),
    MeanX = cms.double(0.),
    MeanY = cms.double(0.),
    MeanZ = cms.double(0.),
    # Second comment
    SigmaX = cms.double(0.015),
    SigmaY = cms.double(0.015),
    SigmaZ = cms.double(53.0)  # in mm (as in COBRA/OSCAR) <-- Third comment

Labelled vs Unlabelled Objects

A labelled object is an object which is assigned to an arbitrarily named python variable. The variable's name appears immediately before the '=' which preceeds the declaration of the object. The variable's name must be unique within a scope (e.g., all the attributes assigned to the process object's must be uniquely named). The component to which the object gets set is a C++ class:

variable_name =  keyword("component_name",
   ...  # parameter declarations

For example, here is a named EDProducer object:

VtxSmeared = cms.EDProducer("VertexGenerator",
      type = cms.string("IOMC/EventVertexGenerators/GaussianEventVertexGenerator"),
      MeanX = cms.double(0.),
      MeanY = cms.double(0.),
      MeanZ = cms.double(0.),
      SigmaX = cms.double(0.015),
      SigmaY = cms.double(0.015),
      SigmaZ = cms.double(53.0)  # in mm (as in COBRA/OSCAR)

This EDProducer declaration requests an instance of the component (a C++ class) called VertexGenerator, configures it via the parameter declarations, and assigns it the variable name VtxSmeared. This object can be referred to elsewhere in the configuration file by the variable VtxSmeared. One could request a second instance of the same class, configure it differently, and assign it to different variable.

An unlabelled object has a specific variable name to which it must be assigned and thus only one instance of the class will ultimately be assigned to the process object. In this example, a source object calls the class PoolSource:

source = cms.Source("PoolSource",
   ...  # parameter declarations

The Process Object

The top-level item of a configuration program is a Process object. Each configuration program must have a Process object assigned to a variable named process. [NOTE: the program may have other Process objects assigned to different variable names, but those Process objects will not be used to configure the job]. This process variable refers to a Process object which aggregates all the configuration information for the cmsRun executable. The Process object must be named by passing the name as the first argument to the Process class' constructor. This name gets carried along with the output data and is used as a branch name to distinguish between otherwise similar objects in a given event.

process = cms.Process("NAME")

Currently, a few names have been defined for process, but not the full set; users are encouraged to use these standard names where they apply:

Data coming from detector, through High Level Trigger (HLT)
Data coming from Prompt Reconstruction (PR) done at the T0s.
Post PR data
Generated/simulated data

For data that don't fit these categories, for the present time, you can make up your own name. Once an event is written to an output file, the name gets put in the list of processes that have touched the event; therefore the name should be as meaningful as possible to other users, and must be different from all the other process names that have touched the event. Eventually, the software may restrict the process name to being one of a recognized set.

Attribute Declarations for the Process Object

Inside the process object there must be at least one object assigned (for data input source), and there may be many. Each object points to a C++ class defined in CMSSW (see the CMSSW_7_4_15 Reference Manual home page). Your job is configured by your choice of classes to invoke, and by the configuration of each class through its object. (This may be done via "import" statements, instead of or in addition to object construction.) The following types of objects may be used, according to the stipulations given:

exactly one unlabelled Source object
Defines the data input source for the cmsRun executable; i.e., where the data comes from. It must be assigned to a variable named source.
zero or more labelled EDProducer, EDFilter, EDAnalyzer or OutputModule objects
The four types are collectively refered to as 'Module's. Module objects configure cmsRun. Each of the four type represents a specific C++ base class. The classes that go here would be subclasses of any of these base classes.
zero or more labelled EDAlias objects
Allows mapping of an EDProducer from its given label to one or more different module labels. Also allows multiple EDProducers to share the same label. This is useful for making multiple jobs with different configurations to appear to make the same Event products.
zero or more unlabelled Service object
Invoke services. They must be assigned to a variable name which matches their C++ class name.
zero or more labelled PSet objects
Define parameter sets.
zero or more labelled VPSet objects
Define vectors of parameter sets.
zero or more labelled SecSource objects
Define secondary data input source, used only with "mixing modules".
zero or more labelled or unlabelled ESSource objects
Grab information from an external input source, e.g., the calibration database, an xml file, etc. If unlabelled, then they must be assigned to a variable with a name which matches the C++ class name.
zero or more labelled or unlabelled ESProducer objects
Describe environmental quantities, e.g., ambient temperature, magnetic field, and so on. If unlabelled, then they must be assigned to a variable with a name which matches the C++ class name.
zero or more labelled Sequence definitions
Define ordered groups of modules, giving each group a name that may be used in other sequences, paths, or endpaths.
zero or more named Path definitions
Specify groups of modules to execute in the order given.
zero or more named EndPath definitions
Define groups of modules to run, in the order given, after all other named paths have been run.

CMSSW classes and modules

"Module" is a generic name for any of four types of "workers" (C++ base classes): EDProducer, EDFilter, EDAnalyzer and OutputModule. Any number of classes can be built from these base classes. A module object in a configuration program instantiates a class based on one of these base classes. The instantiation process is described in Modular Architecture.

To configure a job, you need to determine whether the functionality you need is already available in existing classes, or if you'll need to create any new ones. To examine the existing classes, look in the CMSSW Reference manual. For instance,

CMSSW Documentation
This is main page of the CMSSW Reference Manual. Choose "Class List" from menu bar at top.
CMSSW Class List
Here are the classes, structs, unions and interfaces with brief descriptions. Choose "edm::EDProducer".
edm::EDProducer Class Reference
provides an inheritance diagram for edm::EDProducer, i.e., lists all classes based on the base class EDProducer. Links on each class point to the package documentation. This page also tells which header file to use, provides short description, lists member functions, static attributes, provides constructor and destructor doc, member function doc, member data doc, and so on.

As another example, from the CMSSW Reference manual home page, choose "Calorimetry".

Calorimetry Packages
lists all packages related to calorimetry within the CMSSW repository. Links point to the package documentation. Choose "DataFormats/CMS.CaloTowers".
Package DataFormats/CMS.CaloTowers
gives short package description, lists public interface, collections (products) and status. Choose "CaloTowerDetId".
CaloTowerDetId Class Reference
tells which header file to use, provides short description, lists member functions, static attributes, provides constructor and destructor doc, member function doc, member data doc, and so on.

ALERT! Note that the reference manual is linked from the CMS Software page; click the "Reference Manual" link, and select the version. The reference manual is generated with Doxygen, which is a command line, open source documentation generator.)


Each C++ class that gets created from a Python object can be configured via its associated ParameterSet. For most of the types of objects the framework actually creates a ParameterSet object used to configure the related component of the executable. Each such object can contain any, or all, of the following types of named parameters, in any number or combination. NOTE: the examples assume one has done import ParameterSet.Config as cms so we can use the short name cms rather than the verbose name FWCore.ParameterSet.Config when refering to the Python objects.

Keyword C++ type Example
bool bool b = cms.bool(False)
int32 int i = cms.int32(-234)
uint32 unsigned i = cms.uint32(2112)
vint32 std::vector<int> v = cms.vint32( 1, -3, 5 )
vuint32 std::vector<unsigned> v =cms.vuint32( 0, 1, 0 )
int64 long long i = cms.int64(-234)
uint64 unsigned long long i = cms.uint64(2112)
vint64 std::vector<long long> v = cms.vint64( 1, -3, 5 )
vuint64 std::vector<unsigned long long> v =cms.vuint64( 0, 1, 0 )
string std::string s = cms.string("spaces are allowed")
s = cms.string('single quotes allowed')
vstring std::vector<std::string> v = cms.vstring( 'thing one', "thing two")
double double d = cms.double(-3.43e-34)
vdouble std::vector<double> v = cms.vdouble(1.2, 3, 4.5e-100, -inf)
FileInPath edm::FileInPath particleFile = cms.FileInPath("SimGeneral/HepPDTESSource/data/particle.tbl")
InputTag edm::InputTag inputTag = cms.InputTag("simrec","jets")
VInputTag std::vector<edm::InputTag> jetTags = cms.VInputTag( cms.InputTag("simrec","jets"), cms.InputTag("cone5CMS.CaloJets"))
ESInputTag edm::InputTag inputTag = cms.ESInputTag("hbconditions")
VESInputTag std::vector<edm::InputTag> inputTag = cms.VInputTag(cms.ESInputTag("hbconditions"))
EventID edm::EventID e = cms.EventID(1,1,1)
VEventID std::vector<edm::EventID> events = cms.VEventID(cms.EventID(1,1,1),cms.EventID(2,3,4))
EventRange edm::EventRange r = cms.EventRange(1,1,1,5,3,999) (0 corresponds to MAX)
r = cms.EventRange("1:1:1-5:3:999") ('min' and 'max' are allowed)
VEventRange std::vector<edm::EventRange> ranges = cms.VEventRange( cms.EventRange(1,1,1,5,0,0), cms.EventRange(8,1,1,9,1,10))
LuminosityBlockID edm::LuminosityBlockID l = cms.LuminosityBlockID(1,1)
VLuminosityBlockID std::vector<edm::LuminosityBlockID> lumis = cms.VLuminosityBlockID(cms.LuminosityBlockID(1,1),cms.LuminosityBlockID(2,3))
LuminosityBlockRange edm::LuminosityBlockRange r = cms.LuminosityBlockRange(1,1,5,0) (0 corresponds to MAX)
r = cms.LuminosityBlockRange("1:1-5:max") ('min' and 'max' are allowed)
VLuminosityBlockRange std::vector<edm::LuminosityBlockRanget> ranges = cms.VLuminosityBlockRange( cms.LuminosityBlockRange(1,1,5,0), cms.LuminosityBlockRange(8,1,9,1))
PSet edm::ParameterSet see below
VPSet std::vector<edm::ParameterSet> see below

Note that empty vectors are legal; e.g.,

    c = cms.vint32( )
creates an empty integer vector named "c".

The system keeps track of what parameters are used to create each data item in the Event. This can be used later to help understand how the data was made. However, sometimes a parameter will have no effect on the final objects created, e.g., the parameter just sets how much debugging information should be printed to the log. Such parameters are 'untracked'.

To see how parameters are defined, here is a sample :

import FWCore.ParameterSet.Config as cms
source = cms.Source("FlatRandomEGunSource",     
    # Here we define a parameter set (PSet) to be used by the source, 
    # and give it the name PGunParameters:
    PGunParameters =cms.PSet(
         # you can request more than one particle, e.g.:
         # PartID = cms.vint32(211,11)   # but we just request one this time:
         PartID = cms.vint32(211),
         MinEta = cms.double(-3.5),
         MaxEta =  cms.double(3.5),
         MinPhi = cms.double(-3.14159265358979323846), # in radians
         MaxPhi =  cms.double(3.14159265358979323846),
         MinE   =  cms.double(9.99),
         MaxE   = cms.double(10.01)
      Verbosity = cms.untracked.int32(0) # set to 1 (or greater)  for printouts

For modules with many parameters, it can be painful to have to write every single one of them in a job's configuration program. Instead, you may consult the module's "configuration fragment include" ( cfi) file which specifies the module's parameters and their default values. The cfi file is used as the default configuration; you only need to specify (replace) parameters in your configuration ( cfg) program whose values differ from the default values. The cfi files are located in the data directory of the package which contains the module. The name of the file should match the 'module label' assigned to the module from within the cfi file, and should end with the suffix

For example, in SimG4Core/Application/test/runP-WithPythiaAndQGSP.cfg, see the "include" statement, followed by a "replace" statement:

   from IOMC/GeneratorInterface/data/PythiaSourceMinBias_cfi import source
   source.pythiaVerbosity = True

This reads in the specified cfi file which starts with this contents:

import FWCore.ParameterSet.Config as cms
import IOMC.GeneratorInterface.pythiaDefault_cff as defaults

source = cms.ESSource("PythiaSource",  
  pythiaVerbosity = cms.untracked.bool(False)
This parameter gets replaced in the cfg file. Further along in the cfi file:
  • a parameter set (PSet) is defined whose parameters refer to the card file and the vstring parameters (discussed below)
  PythiaParameters = cms.PSet(
    # This is a vector of ParameterSet names to be read, in this order
    # The first two are in the include files below
    # The last one are simply my additional parameters
    parameterSets = cms.vstring(
  • two vstring parameters are defined (pythiaMinBias and myParameters)
    pythiaMinBias = cms.vstring(
      'MSEL=0         ! User defined processes',
      'MSUB(11)=1     ! Min bias process',
      'MSTJ(11)=3     ! Choice of the fragmentation function',
      'MSTJ(22)=2     ! Decay those unstable particles',
      'PARJ(71)=10 .  ! for which ctau  10 mm',
      'MSTP(2)=1      ! which order running alphaS',
      'MSTP(33)=0     ! no K factors in hard cross sections',
       ... (many more parameter definitions follow)
    myParameters = cms.vstring(
    #  'MRPY(1)= 123456789 ! Automatically random if -1')
  • add the contents of the pythiaDefault_cff file,

Using each type of Object

Input Source Objects

The data input source for the cmsRun executable is declared using exactly one unlabelled Source object. The Source must be assigned to the source attribute of a Process object. For generated data (see WorkBookGeneration) the choices are PythiaSource (to generate a collider-type event), FlatRandomEGunSource, PoolSource, and others. The instantiation of a "Source" object has this form:
source = cms.Source("SomeClass", 
     ... # parameter declarations and/or sub-blocks here
For example,
   source = cms.Source("FlatRandomEGunSource",
      PGunParameters = cms.PSet(            # a sub-block
         PartID = cms.vint32(211),         # parameters of the sub-block
         MinEta = cms.double(0.),
         MaxEta = cms.double(0.5),
         MinPhi = cms.double(0.),
         MaxPhi = cms.double(360.),
         MinE   = cms.double(9.99),
         MaxE   = cms.double(10.01)
      Verbosity = cms.untracked.int32(1)    # parameter of source block

Processing Component Objects

There are four types of dynamically loadable processing components (in addition to the source type which provides the event to be processed). These are known as "modules". As mentioned above,

  • "Module" is a generic name for 4 types of "workers" (C++ base classes): EDProducer, EDFilter, EDAnalyzer, and OutputModule.
  • Zero or more labelled module blocks can be present assigned to a Process object.
  • The classes that go here would be subclasses of any of the worker base classes.

The component types are:

Based on the EDProducer class; creates new data to be placed in the Event
Based on the EDFilter class; decides if processing should continue for an Event
Based on the EDAnalyzer class; studies properties of the Event
Stores the data from the Event

The label given to a module may be used elsewhere in the configuration, (e.g., in sequence, path and endpath specifications).

For example,:

process.filter = cms.EDFilter("PythiaFilter",
       moduleLabel = cms.untracked.string('source'),    
       MinMuonPt = cms.untracked.double(20.)
process.out = cms.OutputModule("PoolOutputModule", 
       fileName = cms.untracked.string("mcpool.root"),
       SelectEvents = cms.untracked.PSet( 
       SelectEvents = cms.vstring("p")
process.p = cms.Path( process.filter )
process.e = cms.EndPath(process.out)

Service Objects

A service is a facility that performs a well-defined task that is globally acessible and that does not affect physics results. Any number of unlabelled services can be attached to a Process object.

This example shows the form of the service object:

RandomNumberGeneratorService = cms.Service("RandomNumberGeneratorService",
      sourceSeed = cms.untracked.uint32(54321)

RandomNumberGeneratorService is the name of the C++ class of the service the program will use. The specific parameters required are determined by the class used.

Parameter Set (PSet) Objects

(See also Declaring configuration fragments for shared use, below.)

Any number of labelled parameter sets ("PSet") objects can be attached to the Process object. Parameter sets are used to define a list of parameters, most usefully, a list of parameters that are shared by multiple modules, i.e. can be used to configure multiple modules. The PSet concept allows a single point of maintenance for such a set of parameters.

The PSet object is of the form:

somename = cms.PSet(
   ... # parameter declarations here, e.g.,
   s = cms.string("thing zero"),
   v = cms.vstring( 'thing one', "thing two")


from import pythiaDefault_cff

PythiaParameters = cms.PSet(

    # This is a vector of ParameterSet names to be read, in this order
    parameterSets = cms.vstring(
      "pythiaDefault",  # This is the vstring listed in the "included" cff file
      "pythiaMinBias",  # This is the first vstring listed directly in this file
      "myParameters"    # This is another vstring listed directly in this file

    pythiaMinBias = cms.vstring(  
    # Notice this is 2nd in the "parameterSets" vstring.
      'MSEL=0         ! User defined processes',
      'MSUB(11)=1     ! Min bias process',
      'MSUB(12)=1     ! Min bias process',
   myParameters = cms.vstring(  
   # Notice this is 3rd in the "parameterSets" vstring.
   #  'MRPY(1)= 123456789 ! Automatically random if -1'
  ).extend(pythiaDefault_cff) # See contents below

and the cff file reads:
import FWCore.ParameterSet.Config as cms
pythiaDefault= cms.vstring(
# Notice this is 1st in the "parameterSets" vstring.
'PMAS(5,1)=4.8 ! b quark mass',
'PMAS(6,1)=172.3 ! t quark mass'
Any of the parameter declarations listed under Declaring Parameters, above, may appear in a PSet object, as may other PSet objects.

To import an external PSet into a module, put the PSet in the constructor of whatever you're constructing, after its name, but before any named variables:

myBlock = cms.PSet( a = cms.int32(1) )

myModule = cms.EDAnalyzer("MyModule",
  b = cms.int32(2)

Copies of the parameters from the PSet will be inserted into the module. These copies can then be modified, without affecting the original PSet.

Parameter Set Vector (VPSet) Objects

A parameter set vector, VPSet, is a vector (a list) of PSets. (This is not currently being used.) There may be any number of uniquely labelled vectors of parameter sets in the process object, and such a vector may be referred to, by name, from places where a ParameterSet is needed. There may be any number of vector entries. Each vector entry must be comma-separated from the next. Its format would look like:
MyParameters = cms.VPSet(       
The VPSet object is of the form:
somename = cms.VPSet(
    ... # parameter declarations for vector entry 0
  ) ,
    ... # parameter declarations for vector entry 1
  ) ,
  ) ,
    ... # parameter declarations for vector entry _n_

Note that it is also possible to use a VPSet which creates a std::vector<edm::ParameterSet> which is empty; this is done by:

somename = cms.VPSet()

EventRange, LuminosityBlockRange, VEventRange, VLuminosityBlockRange objects

These types are used to describe ranges of luminosity sections and events within runs. Both type follow the same syntax which is easiest to explain by looking at the text representation: cms.EventRange("1:1-5:6") which is the range begining with event (or lumi) number 1 of run 1 and continuing to event number 6 in run 5. You can also represent this as cms.EventRange(1, 1, 5, 6). The text form also takes a pair of wild-card like options, so cms.EventRange("1:min-5:max") represents the event number 1 of run 1 through the last event of run 5. This is represented as cms.EventRange(1, 1, 5, 0) as well (0 is invalid as a run, event, or lumi section, so we use it as a wildcard).

You can also supply vectors of range objects in a VEventRange or VLuminosityBlockRange objects that look like this: cms.VEventRange("1:2-3:4", "5:MIN-7:MAX").

The vector forms of these types are used to specify lumis or events to process or skip in the PoolInputSource configuration for CMSSW releases > 3_0_0.

In release 3_9_0 and later, an EventRange may optionally specify luminosity block numbers, in this representation: cms.EventRange("1:1:1-5:4:6"). If this form is used, events are ordered by run number, luminosity block number, and event number, in that order of significance. In contrast, if luminosity block numbers are not used, as in: cms.EventRange("1:1-5:6"), luminosity block numbers are ignored in determining the range, If given EventRange specifies a luminosity block number, it must specify it for both ends of the range. However, a given VEventRange may include both types of EventRange.

Secondary input source (secsource) objects

NOTE: This is a special feature, and is intended for use only by "mixing modules". Mixing, used in Monte Carlo generation and simulation, refers to adding a secondary source of events to the simulated hard scatter event. A mixing module is one that reads in both types of generated data and simulates the detector response accordingly.

Any number of uniquely labelled secondary data input source ( secsource) objects may be attached to the process object.

The object is of the form:

somename = cms.SecSource("SomeClass",
  ... # parameter declarations here

SomeClass is the name of the C++ class of the secondary input source the program will use. For example:

pu = cms.SecSource("PUSource",
         fileNames = cms.untracked.vstring("file:test/minbias.root")

Event Setup Source (ESSource) Objects

Any number of labelled or unlabelled EventSetup objects (ESSources) may be attached to the process block. An ES source grabs information from an external source, e.g., the calibration database, an xml file, etc. You can use an unlabelled ESSource unless you plan to include more than one instance of an ESSource.

The labelled object is of the form:

SomeClass = cms.ESSource("SomeClass",
  ... # parameter declarations here

The labelled object is of the form:

somename = cms.ESSource("SomeClass",
  ... # parameter declarations here

In both cases, SomeClass is the name of the C++ class of the ESSource the program will use.

Event Setup Producer (ESProducer) Objects

Event Setup producer describe environmental quantities, e.g., ambient temperature, magnetic field, and so on. Any number of uniquely labelled or unlabelled EventSetup producer objects (ESProducers) may be attached to a Process object. This is non-event data. You can use an unlabelled ESProducer unless you plan to include more than one instance of that same ESProducer.

The unlabelled object is of the form:

SomeClass = ESProducer("SomeClass",
  ... # parameter declarations here

The labelled object is of the form:

somename = ESProducer("SomeClass",
  ... # parameter declarations here

In both cases, SomeClass is the name of the C++ class of the ESProducer the program will use. The specific parameters required are determined by the specific class used.

Module sequences

Module sequences are used to define an ordered group of modules, giving the group a name that may be used in other sequences, paths, or endpaths in the configuration document. Any number of uniquely named sequence defintions may be attached to a Process object. Sequencing is a good organization tool if you have lots of modules to load, or if you want to easily switch in and out groups of modules from the execution path.

The sequence definition is of the form:

somename = cms.Sequence( ref1 + ref2 ... )
The entries in the definition (e.g., ref1 ref2 ...) must be variable of modules or sequences declared elsewhere in the configuration program. The plug ( +) or sequencing operator, specifies that the operand on the left is executed first, followed by the operand on the right, but they are not dependent on each other. See path syntax.

Here is an example taken from the WorkBookSimDigi topic:

trDigi = cms.Sequence( pixdigi + stripdigi )
calDigi = cms.Sequence( ecaldigi + hcaldigi )
muonDigi = cms.Sequence( muoncscdigi + muondtdigi  )
doDigi = cms.Sequence( trDigi + calDigi + muonDigi   )
p1 = cms.Path( VtxSmeared * SimG4Object * mix * doDigi )



EDAlias allows mapping of an EDProducer from its given label to one or more different module labels. Also allows multiple EDProducers to share the same label. This is useful for making multiple jobs with different configurations to appear to make the same Event products.

The label assigned to the the EDAlias is the new module label that can be used to lookup the data item. The EDAlias parameters accepted by an EDAlias are of the form

   <old module label> = cms.VPSet( cms.PSet( type = cms.string(<friendly class name>),
                                            [fromProductInstance = cms.string(<old product instance label>)],
                                            [toProductInstance = cms.string(<new product instance label>)] ))
  • <old module label> is the EDProducer's label from which the data originally derived.
  • <friendly class name> specifies exactly what class type is to be obtained from the original EDProducer. The name is not the C++ class name and is instead the name used when specifying what data should be stored in the OutputModule. This name also corresponds to the first part of the TBranch name. One can also find the friendly class names of collections available in a job by adding the EventContentAnalyzer to the job.
  • <old product instance label> specifies the product label used by the EDProducer when storing the data product. By default EDProducer's use an empty string. If fromProductInstance is not specified, the value of <old product instance label> defaults to '*' and therefore matches all data products of type <friendly class name> produced by the Producer with module label <old module label>.
  • <new product instance label> specifies a product label different from the one from the original one used by the EDProducer. If toProductInstance is not specified, <new product instance label> defaults to the value '*' which means the new label should match the old label.

Here is an example where we want to be able to get the data product Bars from module label otherbar but using the label bar

bar = cms.EDAlias( otherbar = cms.VPSet( cms.PSet(type=cms.string('Bars') ) ) )

Say the module otherbar makes two data products of different types Bars and BarExtras. Then if we want to be able to get both by the label bar

bar = cms.EDAlias( otherbar = cms.VPSet( cms.PSet(type=cms.string('Bars') ),
                                         cms.PSet(type=cms.string('BarExtras') ) ) )

If you want to make data coming from two different modules, foo and fee, appear to come from one module, bar, where foo makes data of type Foos and fee makes data of type Fees

bar = cms.EDAlias( foo = cms.VPSet( cms.PSet(type=cms.string('Foos') ) ),
                   fee = cms.VPSet( cms.PSet(type=cms.string('Fees') ) ) )

If you want to make data coming from two different modules, foo and fee, appear to come from one module, bar, where both modules create the same type, Bars. If both modules use the default product instance label then you will need to assign at least one of them to a different label.

bar = cms.EDAlias( foo = cms.VPSet( cms.PSet(type=cms.string('Bars') ) ),
                   fee = cms.VPSet( cms.PSet(type=cms.string('Bars'), 
                                             fromProductInstance = cms.string(''),
                                             toProductInstance = cms.string('refined') ) ) )

If you want to to data products, of type Fees and Foos coming from one module, bar, appear to come from two different modules then you can use two EDAlias both of which refer th to the same EDProducer.

foo = cms.EDAlias(bar = cms.VPSet( cms.PSet(type=cms.string('Foos'))))
fee = cms.EDALias(bar = cms.VPSet( cms.PSet(type=cms.string('Fees'))))


Processing and trigger path (path) statements

Processing and trigger paths are declared via Path objects. Any number of uniquely labelled Path defintions may be attached to a Process object.

The Path definition is of the form:

somename = cms.Path( ref1 OPERATOR ref2 ... )
The entries in the definition (e.g., ref1 ref2 ...) must be module labels or sequences declared elsewhere in the configuration program. OPERATOR is either + or *. In the old configuration language, the ! operator was used to invert the result of a module in the path. In the new python configuration, the equivalent operator is ~.

For example:

process.mypath = cms.Path (process.p1*process.p2*process.p3*process.p4*process.p5*process.p6*process.p7*process.p8*process.p9*process.p10)
You can also write this out as
process.mypath = cms.Path (process.p1+process.p2+process.p3+process.p4+process.p5+process.p6+process.p7+process.p8+process.p9+process.p10)
You can also write this as, in case of too many or too long paths (and one can replace * with +)
process.mypath = cms.Path (process.p1*

You can also write it as (again * can be replaced by +)

process.mypath = cms.Path(process.m1*process.m2*process.m3)
process.mypath *= process.m4*process.m5*process.m6
process.mypath *= process.m7*process.m8*process.m9*process.m10
A comment from experts about difference between '+' and '*' usage:
The only difference in behavior between the operators is that
when "*"  is used extra error checking is performed. This error
checking is not performed when "+" is used.  There is no other
difference.  It does not affect which modules run, other than
by throwing a configuration exception and letting none run.
The purpose of the operators is to allow error checking on paths.
If in one path a module is declared to depend on a specific set of modules,
then the module must depend on the same modules in the same order in
all other paths in that process. If not the error check will fail.

EndPath statements

An EndPath object is used to define an ordered group of modules which are to run after all other labelled Paths have been run. Any number of uniquely labelled EndPath defintions may be attached to a Process object. EndPaths are used e.g. for PoolOutputModules.

The EndPath definition is of the form:

somename = cms.EndPath( ref1 OPERATOR ref2 ... )
The entries in the definition (e.g., ref1 ref2 ...) must be the variable names of modules or sequences declared elsewhere in the configuration program.

Schedule statements

To define the final series of paths to be run, you can define a Schedule. If you don't define a Schedule, all paths and endpaths will be used, in an unspecified order.

To specify a schedule, use only Paths and EndPaths, separated by commas.

process.schedule = cms.Schedule(process.generation_step,process.out_step)

The import statement

The standard Python import statement is used to inject the objects from another file into the current file, therefore it can be used to include shared-use configuration fragments. The import statements may be "nested", meaning that a configuration document may import a fragment which itself imports another fragment. There is no limit (other than that caused by memory exhaustion) on the number of levels of inclusion allowed.

Use of import does not guarantee that the objects defined in the python configuration file will actually be used to configure the job. In order to be used to configure a job, the objects must be attached to the Process object which is referenced by the process variable. The attachment can either by done for each object individually by assigning them to attributes of process, e.g.,

import somemodule
process.somename = somemodule.somename
or the all variables of a python module can be attached to a process by using the extend() member function
import somemodule
When using 'extend' the variable names used in the imported module are assigned as the 'labels' for the process' attributes. Because the labelled assigned to a module comes from the process attribute's name assigned to the object and not from the original variable to which the object was assigned, the individual object assignment method allows one to 'relabel' a module to be different from the imported file
import somemodule
process.someothername = somemodule.somename

There are two framework scheduling modes. For the scheduled case, if the imported cf* file has module objects in it, you have to add those modules to a Path object which is assigned to process. For the unscheduled mode (documented here) the EDProducers will get invoked when an analyzer or filter requests data that it knows how to make.

There are several different syntaxes for the import statement depending on how you want wish to access the variables defined:

#must use full name to get to a variable
import Subsystem.package.filename
v = Subsystem.package.filename.variable

#must use short name to get to a variable
import Subsystem.package.filename as shortname
v = shortname.variable

#variable is added directly to this file
from Subsystem.package.filename import variable
p = variable

# Convenience method to insert every cms object in the module into a process
# In the following example, the module is declared in the file 
#     Configuration/StandardSequences/python/
# Please note that it is necessary to 
#   - change each "." by a "/", 
#   - add to the path the python subdirectory of the package
#   - add the .py termination


import FWCore.ParameterSet.Config as cms
process =cms.Process("TEST")

from IOMC.GeneratorInterface.PythiaSourceMinBias_cfi import source
source.maxEvents = 20
process.source = source

#will automatically assign the correct label to the service
process.add_( cms.Service("RandomNumberGeneratorService",
   #this sets the random number seed used by Pythia
   sourceSeed = cms.untracked.uint32(123456789)

process.out = cms.OutputModule("PoolOutputModule", 
   fileName = cms.untracked.string("mcpool.root"),

process.p = cms.Endpath(process.out)

An assignment statement can replaces the maxEvents value set in the included cfi file:
import FWCore.ParameterSet.Config as cms
source = cms.Source("PythiaSource", 
  maxEvents = cms.untracked.int32(0),
  pythiaVerbosity = cms.untracked.bool(False)
It is recommended that the author of each module create a sample configuration fragment (a cfi file), put into the package's python directory. Then, users are encouraged to include the module (and replace parameter values as needed), rather than configure each module from scratch in their config files.

Blocking imports

Occasionally, a or file may wish to declare itself "unimportable" except by certain files. As of CMSSW 3_1_2, this is possible by including the following statements at the start of the imported file:

import FWCore.ParameterSet.Config as cms

cms.checkImportPermission(allowedPatterns = ['Module','Module/Submodule'])

where the list can include any number of modules and/or submodules which are allowed to import the file. A user's top-level is allowed, by default, to import such a file. This behavior can be changed by setting the value of minLevel = 1 as another parameter to checkImportPermission()

Including Standard Module definitions

Configuration File Initializer files ( cfi files) are used to initialize modules with all of its default parameter settings. Each module is supposed to have one in its python directory, with the module label as its filename. This file is intended for use in end-users' cfg files; the user can then reset only the parameters that require non-default values. Cfi files may also be pulled into cff files, below. The file extension is

Configuration File Fragment files ( cff files) are like cfi files, but are not associated with modules one-for-one. They are used to contain (or pull in) pieces of a configuration which may be either larger than cfi files (e.g. contain multiple modules or multiple cfi files) or smaller than cfi files (e.g. contain just one or a few parameter specifications). These files may also be included in cfg files. The file extension is

For Component developers

Developers of modules should put standard configuration file fragments ( cff and cfi files) in a standard place, namely in the python subdirectory of the package:


Developers of ESSources and other components which have no module labels are asked to use the full class name as the cfi file name.

For example, the SimCalorimetry/HcalSimProducers package has a file named:

which contains:
import FWCore.ParameterSet.Config as cms

from SimCalorimetry.HcalSimProducers.hcalSimParameters_cfi import *
simHcalUnsuppressedDigis = cms.EDProducer("HcalDigiProducer",
    doNoise = cms.bool(True),
    doHPDNoise = cms.bool(False),
    doTimeSlew = cms.bool(True),
    hitsProducer = cms.string('g4SimHits')

where HcalDigiProducer is the class name. #CptUse

For Component Users

Users who wish to include the above module ( SimCalorimetry/HcalSimProducers/python/ can say in their cfg file:
from SimCalorimetry.HcalSimProducers.simHcalUnsuppressedDigis_cfi import simHcalUnsuppressedDigis

Users may user to include multiple copies of a module, but with slightly different parameters. This can be done using the 'clone' method.

For example, if the user wishes to find jets with a cone size of 0.6 instead of 0.5, he can say:

# defines a module named "midPointCone5CMS.CaloJets"
from  RecoJets.JetProducers.CaloJetMcone5_cfi import midPointCone5CMS.CaloJets

midPointCone6CMS.CaloJets = midPointCone5CMS.CaloJets.clone()
midPointCone6CMS.CaloJets.coneRadius = 0.6
# or simply:
# midPointCone6CMS.CaloJets = midPointCone5CMS.CaloJets.clone(coneRadius = 0.6)

This was discussed in The Include Statement, above.

Calling copy() is required since multiple Python variables are allowed to reference the same Python object.

midPointCone6CMS.CaloJets = midPointCone5CMS.CaloJets #BAD
midPointCone6CMS.CaloJets.coneRadius = 0.6
#now modPointCone5CalJets.coneRadius also equals 0.6!

Modifying Parameters

Now if the user wants to modify parameters imported from other files, one option is to check out the package where the cfi file lives, and edit it there. The framework will use the FileInPath mechanism to ensure that files from the user's local area are used instead of files from the release areas.

We also have a syntax to let users edit pre-existing configurations more easily. Users shouldn't need to explicitly re-specify types, or tracked/untracked. It is enough to just say something like:

from SimG4Core.Application.SimG4Object_cfi import SimG4Object
SimG4Object.UseMagneticField = False 

Replacement of more than one parameter is allowed.

Starting from the standard definition of FlatRandomEGunSource, the user might want to modify things:

from IOMC.ParticleGuns.FlatRandomEGunSource_cfi import source
source.PGunParameters.MinE = 5.0
source.PGunParameters.MaxE = 50.0
source.PGunParameters.PartID = ( 211, 11 )

Warning: If you wish to modify a vector and set it equal to a single-element array, then you must insert a comma after that element:

source.PGunParameters.PartID = ( 211, )

Starting from the standard definition of SimG4Object, the user may want to replace an entire ParameterSet:

from SimG4Core.Application.SimG4Object_cfi import SimG4Object
SimG4Object.SteppingAction = cms.PSet(
    KillBeamPipe = cms.bool(True)      # same as standard
    CriticalEnergyForVacuum = cms.double(1.0) #changed
    CriticalDensity = cms.double(1.0e-10)     # changed
    Verbosity = cms.untracked.int32(1)         # changed    

All vector style parameters behave like normal Python lists and therefor allow append, extend and other list manipulations.

The syntax is as follows:

a.painters.extend( ("Picasso", "da Vinci"))

Modifying Sequences and Paths

Sequences and paths have a "replace()" command, which lets you replace all occurences of a module or a sequence within a module or path with something else.

mySequence.replace(oldModule, newModule)
myPath.replace(oldSequence, newSequence)
myPath.replace(oldModule, newSequence)

If you wish to replace a module or a sequence in a process, and have the change propagated through to all sequences, paths, and endpaths which use that object, you should use

process.globalReplace("label", newObject)  # note the quotes!!

Passing Command Line Arguments Through cmsRun

Starting in CMSSW_3_0_0, you will be able to pass command-line arguments through to the Python system. For example, if you start your job via this command

> cmsRun -m grid myOpt myValue=True

Then, from anywhere in the Python configuration system, you could do:

import sys
print sys.argv

and see

['cmsRun', '-m', 'grid', '', 'myOpt', 'myValue=True']

Arguments beginning with '-' or '--' are handled by the C++ options parser in cmsRun, and other options which come after the Python file are used in Python.

Additionally, you can use FWCore.ParameterSet.VarParsing module to handle the parsing of the command line objects for you (see next section for documentation).

VarParsing Example

Here's a quick example of how to use the VarParsing Module

import FWCore.ParameterSet.VarParsing as VarParsing

# set up process
process = cms.Process("StarterKit")

# setup 'analysis'  options
options = VarParsing.VarParsing ('analysis')

# setup any defaults you want
options.outputFile = '/uscms/home/cplager/nobackup/outputFiles/try_3.root'
options.inputFiles= 'file1.root', 'file2.root'
options.maxEvents = -1 # -1 means all events

# get and parse the command line arguments

# Use the options

process.source = cms.Source ("PoolSource",
                             fileNames      = cms.untracked.vstring (options.inputFiles),
                             debugVerbosity = cms.untracked.uint32(200),
                             debugFlag      = cms.untracked.bool(True),

process.maxEvents = cms.untracked.PSet(
    input = cms.untracked.int32 (options.maxEvents)

# talk to output module
process.out = cms.OutputModule("PoolOutputModule",
                               verbose = cms.untracked.bool(False),
                               fileName = cms.untracked.string (options.outputFile)

Here's how I might call it:

unix> cmsRun print \
inputFiles=one.root inputFiles=two.root inputFiles_load=Zjets_2_2_3.list > & output&

where inputFiles=one.root inputFiles=two.root tells it to append one.root and two.root to the list of files to use as input. inputFiles_load=Zjets_2_2_3.list tells it to look at the file Zjets_2_2_3.list and append all files listed to the list of files to use as input as well. print tells it to print out the current values of all user access variables (very useful for log files) is a complete example configuration script.

VarParsing Documentation

The idea behind VarParsing package is simple: make it easy to set up variables that can be changed from the command line. When hooking up a variable, you need to tell the module certain information about the object:

  • name of object
  • default value of object
  • whether the object is a single number (VarParsing.VarParsing.multiplicity.singleton) or a list (VarParsing.VarParsing.multiplicity.list)
  • whether the object is a string (VarParsing.VarParsing.varType.string), integer (, or float (VarParsing.VarParsing.varType.float)
    • use integer for boolean flags (1 = True, 0 = False)
  • information string on object (shown when user types 'help' or 'print' from command line)

Note: Instead of typing VarParsing.VarParsing., you can simply type options. where options is the name of the VarParsing object you created.

Here's an example of hooking up an integer called someInt:

options.register ('someInt',
                  -1, # default value
                  VarParsing.VarParsing.multiplicity.singleton, # singleton or list
        ,          # string, int, or float
                  "Number of events to process (-1 for all)")

If when you create a VarParsing instance, you pass in the string 'analysis', you will get the following objects by default:

Analysis Options:

Option Purpose
maxEvents Number of events to process (singleton integer)
inputFiles List of files to process as input (list string)
secondaryFiles List of secondary files (if needed; list string)
outputFile Name of output file (singleton string)
secondaryOutput Name of secondary output (if needed; singleton string)

To set another default value, you would:

object.someInt = 4

If you have a list variable, you can load default values as follows:

options.someList = 'one.txt', 'two.txt'
options.someList = 'three.txt'
options.loadFromFile ('someList', 'nameOfFiles.list')

After this, options.someList will contain 'one.txt', 'one.txt', 'one.txt', and any files listed in 'nameOfFiles.list'.

Note that the format of 'nameOfFiles.list' text file is the same as the format that DBS will give to you. Comments (or lines you want to temporarily exclude) starting with the hash character (#) can be embedded in the text file and will be ignored.

Command Line Options

To assign a variable defined above from the command line, you simply use variable=value syntax.

If the variable (object) is a list, you have several options:

  • You can repeat variable=value many times to load different values into the list
  • You can type variable_clear to clear the variable list of all entries
  • You can type variable_load=nameOfFiles.list to load all files listed in nameOfFiles.list into the variable list

Finally there are two other commands you can put on the command line

  • print will print the current values of all of the settable variables
  • help will do the same as print, but also display possible commands and will then exit.

IMPORTANT: The configuration script MUST end with .py. If it does not, VarParsing will not know where to start looking at the commands and will assume that everything is for cmsRun.

VarParsing Tags

VarParsing has the ability to append tags to the name of the output file given the values of the command line options. This can be very useful, for example, when running different reconstruction algorithms so that 1) it is obvious which file goes with which options and 2) so you don't accidentally overwrite files you want to compare with each other.

object.setupTags (tag = 'someBool',
                  ifCond = 'someBool > 0')
object.setupTags (tag = 'someInt%d',
                  ifCond = 'someInt > 0',
                  tagArg = 'someInt')

The first case sets up a tag if the user variable someBool is greater than 0. The second case will setup a tag if someInt is greater than 0, and then it will embed the value into the tag ('%d').

An annotated example

Here we present an annotated sample configuration program that demonstrates many of the features found in a typical configuration program. The details of the file and the configuration objects are explained in the previous sections.

# Python is very picky about leading spaces on a line

# Comments (obviously!) are introduced by a sharp ('#'), and continue
# to the end of line.

# Eventually, the software may restrict the process name to being one
# of a recognized set (such as HLT, PROD, TEST, USER). This is not yet
# implemented.

#Bring in the configuration python objects
import FWCore.ParameterSet.Config as cms

process = cms.Process("TEST")
  # Each process block must assign a source
  # attribute. As the first argument of the constructor, one must specify the
  # name of the class to be instantiated. This name is the same name
  # that the plug-in was associated with, generally done in the
  # class's implementation file. This is usually the name of the
  # class, stripped of any namespace specification.

process.source = cms.Source("PoolSource",
    fileNames      = cms.untracked.vstring('file:no_real_file_here')

process.a = cms.EDProducer("AProducer",
    a = cms.int32(32),
    b = cms.vdouble( 1.1, 2.2 )
    c = cms.vstring( )            # empty vectors are accepted
    d = cms.vstring( 'boo', "yah" )

 # Configuration file fragments may be included by naming 
 # the file to be included...  
 # The 'import' statement below shows the syntax.

import SomeSubsystem.SomePackage.partial_configuration_cff as _partial
process.b = cms.EDProducer("BProducer",
    a = cms.untracked.int32(14),
    b = cms.string('sillyness ensues')
    c = cms.PSet(
      a = cms.string('nested')

process.y = cms.OutputModule("PoolOutputModule",
    fileName = cms.untracked.string('myfile_y.root')

process.z = cms.OutputModule("PoolOutputModule",
    fileName = cms.untracked.string('myfile_z.root')

process.s1 = cms.Sequence( process.a+process.b )
process.s2 =  cms.Sequence( process.b )
process.s3=  cms.Sequence( process.a )
# It is not an error for two sequences (here, s3 and s4) to be identical.
process.s4=  cms.Sequence( a )

process.p1 = cms.Path( (a+b)* c )
process.p2 = cms.Path( s1* (s3+s2) )
process.ep = cms.EndPath( y + z )

Review status

Reviewer/Editor and Date (copy from screen) Comments
-- ChrisDJones - 01 May 2007 translate config language page to python equivalent
-- JennyWilliams - 08 Aug 2007 moved page from workbook into SWGuide and put more basic introduction into the workbook
-- ChristopherJones - 19 Aug 2008 removed .data. from all import statements to match present day usage
-- CharlesPlager - 09 Jan 2009 Added information on and command line arguments to configuration scripts
-- WilliamTanenbaum - 27 Sep 2010 Allow specification of luminosity block numbers in EventID and EventRange
-- StefanoBelforte - 17 Sep 2014 fix reference to SWGuideEDMPathsAndTriggerBits to use CMSPublic twiki

%RESPONSIBLE% ChrisDJones, Liz Sexton-Kennedy
%REVIEW% Sudhir Malik- 24 January 2009

Edit | Attach | Watch | Print version | History: r1 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r1 - 2015-12-30 - eduardo
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2023 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback