#include "QFramework/TQXSecParser.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQUtils.h"

// #define _DEBUG_

#include "QFramework/TQLibrary.h"

ClassImp(TQXSecParser)

////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQXSecParser:
//
// The TQXSecParser is capable of reading crosssection information from a text file.
// Multiple input formattings are supported, the functionality relies on TQTable.
//
// The first row of the text file is interpreted as column labels.
// The first column will be taken as sample name.
//
// The other colum labels are expected to match the following patterns unless
// specified differently by setting the corresponding tags:
//
// column content    | default pattern | tag name
// --------------------------------------------------------
// cross section     | *xsec*          | xSecColName
// filter efficiency | *filt*eff*      | xFilterEffColName
// kFactor           | *k*fac*         | kFactorColName
// process info      | *proc*          | processInfoColName
// generator info    | *gen*           | generatorInfoColName
// simulation info   | *sim*           | simulationInfoColName
//
// For the column tag name xyz, the case sensitivity of the pattern
// can be controlled by setting the boolean tag "xyzCaseSensitive" on
// the TQXSecParser instance at hand, where the default is 'false' in
// all cases.
//
// If the cross section column title contains any of the following
// strings, this will affect the way the cross sections are
// implemented:
//  'mb': cross section interpreted in mb
//  'µb': cross section interpreted in µb
//  'nb': cross section interpreted in nb
//  'pb': cross section interpreted in pb (default)
//  'fb': cross section interpreted in fb
//  'ab': cross section interpreted in ab
//
// This information is used to construct a TQSampleFolder hierarchy.
//
// Columns not matching any of these patterns are ignored. However,
// the mapping of sample identifiers to paths in the sample folder
// hierarchy can explicitly be read in from a column of arbirtrary
// title (e.g. 'path') using the function
// TQXSecParser::readMappingFromColumn('path'). Alternatively, the
// mapping can be read in from an external file that contains lines of
// the type 'sampleID /path/to/this/sample'.
//
// Similarly, samples can be enabled or disabled based on a numeric
// priority column of arbitrary title (e.g. 'priority') by using the
// functions
// [enable|disable]SamplesWithPriority[Less|Greater]Than('priority',N),
// where N is the threshold of choice.
//
// It is also possible to add chunks of nTuples from a given path in
// the file system, regardless of their appearance in the cross
// section file, using the function
// TQXSecParser::addAllSamplesFromPath(...).
//
////////////////////////////////////////////////////////////////////////////////////////////////

TQXSecParser::TQXSecParser(TQSampleFolder* sf, const TString& xsecfilename) :
TQTable(xsecfilename),
  fSampleFolder(sf),
  fPathVariants(new TObjArray())
{
  // constructor receiving a sample folder and reading a tab-separated file
  this->setTagString("readFormatPrior","verbatim");
  this->setTagString(".xsecfilename",xsecfilename);
  this->setTagBool("adjustColWidth",true);
  this->readTSVfile(xsecfilename);
  this->fPathVariants->SetOwner(true);
}

TQXSecParser::TQXSecParser(const TString& xsecfilename) :
  TQTable(xsecfilename),
  fSampleFolder(NULL),
  fPathVariants(new TObjArray())
{
  // constructor reading a tab-separated file
  this->setTagString("readFormatPrior","verbatim");
  this->setTagString(".xsecfilename",xsecfilename);
  this->setTagBool("adjustColWidth",true);
  this->readTSVfile(xsecfilename);
  this->fPathVariants->SetOwner(true);
}

TQXSecParser::TQXSecParser(TQTable& tab) :
  TQTable(tab),
  fSampleFolder(NULL),
  fPathVariants(new TObjArray())
{
  // copy constructor based on TQTable
  this->setTagString("readFormatPrior","verbatim");
  this->setTagBool("adjustColWidth",true);
  this->cloneSettingsFrom(dynamic_cast<TQXSecParser*>(&tab));
}


TQXSecParser::TQXSecParser(TQTable* tab) :
  TQTable(tab),
  fSampleFolder(NULL),
  fPathVariants(new TObjArray())
{
  // copy constructor based on TQTable (pointer variant)
  this->setTagBool("adjustColWidth",true);
  this->cloneSettingsFrom(dynamic_cast<TQXSecParser*>(tab));
}

void TQXSecParser::cloneSettingsFrom(TQXSecParser* parser){
  // internal cloning helper
  if(!parser) return;
  this->fPathVariants->SetOwner(true);
  this->fPathVariants->Clear();
  this->importTags(parser);
  this->fSampleFolder = parser->fSampleFolder;
  this->fKeysToExport = parser->fKeysToExport;
  TQIterator itr(parser->fPathVariants);
  while(itr.hasNext()){
    this->fPathVariants->Add(itr.readNext()->Clone());
  }
}

TQXSecParser::TQXSecParser(TQXSecParser* parser) :
  TQTable(parser),
  fPathVariants(new TObjArray())
{
  // copy constructor based on TQTable (pointer variant)
  this->fPathVariants->SetOwner(true);
  this->cloneSettingsFrom(parser);
}

TQXSecParser::TQXSecParser(TQXSecParser& parser) :
  TQTable(parser),
  fPathVariants(new TObjArray())
{
  // copy constructor based on TQTable
  this->fPathVariants->SetOwner(true);
  this->cloneSettingsFrom(&parser);
}


TQXSecParser::TQXSecParser(TQSampleFolder* sf) :
  TQTable("TQXSecParser"),
  fSampleFolder(sf),
  fPathVariants(new TObjArray())
{
  // constructor reading a tab-separated file
  this->fPathVariants->SetOwner(true);
  this->setTagBool("adjustColWidth",true);
}

TQXSecParser::TQXSecParser() :
  TQTable("TQXSecParser"),
  fSampleFolder(NULL),
  fPathVariants(new TObjArray())
{
  // default constructor
  this->setTagBool("adjustColWidth",true);
  this->fPathVariants->SetOwner(true);
}

TQXSecParser::~TQXSecParser(){
  // default destructor
  delete this->fPathVariants;
}

void TQXSecParser::addPathVariant(const TString& replacements){
  // add a path variant to the list
  TQNamedTaggable* variant = new TQNamedTaggable("variant");
  variant->importTags(replacements);
  this->fPathVariants->Add(variant);
}

void TQXSecParser::addPathVariant(const TString& key, const TString& value){
  // add a path variant to the list
  TQNamedTaggable* variant = new TQNamedTaggable(value);
  variant->setTagString(key,value);
  this->fPathVariants->Add(variant);
}

void TQXSecParser::printPathVariants(){
  // print all registered path variants
  std::cout << TQStringUtils::makeBoldWhite(this->GetName()) << " - known path variants:" << std::endl;
  TQTaggableIterator itr(this->fPathVariants);
  while(itr.hasNext()){
    TQNamedTaggable* variant = itr.readNext();
    std::cout << "\t" << variant->exportTagsAsString() << std::endl;
  }
}

void TQXSecParser::clearPathVariants(){
  // clear known path variants
  this->fPathVariants->Clear();
}

TQSampleFolder* TQXSecParser::getSampleFolder(){
  // get the sample folder associated to this parser
  return this->fSampleFolder;
}

void TQXSecParser::setSampleFolder(TQSampleFolder* sf){
  // set the sample folder associated to this parser
  this->fSampleFolder = sf;
}

int TQXSecParser::readMapping(const TString& fname, bool print){
  // add mapping from an external TSV-formatted file
  TQTable tmp;
  if(!tmp.readTSVfile(fname)) return false;
  if(print) tmp.printPlain();
  int retval = this->readMapping(tmp);
  if(retval > 0) this->setTagBool(".hasMapping",true);
  return retval;
}

int TQXSecParser::writeMappingToColumn(const TString& colname){
  // copy paths to the given column
  // creates a column with this name if necessary
  this->shrink();
  int colidx = this->findColumn(colname);
  if(colidx < 0){
    this->setAutoExpand(true);
    colidx = this->ncols;
    if(!this->setEntry(0,colidx,colname)){
      ERRORclass("unable to allocate '%s' column!",colname.Data());
      return -1;
    }
    if(colidx != this->findColumn(colname)){
      ERRORclass("unable to find '%s' column!",colname.Data());
      return -1;
    }
  }
  this->setColAlign(colidx,"l");
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    TQTaggable* entry = this->getEntryInternal(i,0);
    if(!entry) continue;
    TString path = entry->getTagStringDefault("path","");
    if(path.IsNull()) continue;
    this->setEntry(i,colidx,path);
    count++;
  }
  this->shrink();
  return count;
}

int TQXSecParser::readMappingFromColumn(const TString& colname){
  // copy paths from the given column
  int colidx = this->findColumn(colname);
  if(colidx < 0) return -1;
  this->setColAlign(colidx,"l");
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    TString path = this->getEntryVerbatim(i,colidx);
    if(path.IsNull()) continue;
    this->setProperty(i,0,"path",path);
    count++;
  }
  if(count > 0){
    this->setTagBool(".hasMapping",true);
  }
  return count;
}

int TQXSecParser::readMapping(TQTable& tmp){
  // add a mapping from an external table
  DEBUGclass("Enter function");
  int count = 0;
  if(tmp.getNcols() < 2){
    return -1;
  }
  int pathcol = tmp.findColumn("path");
  if(pathcol < 0) pathcol = 1;
  std::map<TString,TString> map = tmp.getMap(0,pathcol,"verbatim","verbatim",false);
  std::map<TString,TString>::iterator it;
  for(size_t i=1; i<this->nrows; i++){
    TQTaggable* thisEntry = this->getEntryInternal(i,0);
    if(!thisEntry) continue;
    TString thisKey;
    if(!thisEntry->getTagString("content.verbatim",thisKey)) continue;
    it = map.find(thisKey);
    if(it==map.end()) continue;
    TString path(it->second);
    thisEntry->setTagString("path",path);
    count++;
  }
  return count;
}

int TQXSecParser::enableSamplesWithColumnStringMatch(const TString& colname, const TString& pattern, bool verbose){
  // enables all samples with string match in column
  int prioidx = this->findColumn(colname);
  if(prioidx < 0) return -1;
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    TString entry = this->getEntryPlain(i,prioidx);
    if(TQStringUtils::matches(entry,pattern)){
      if(verbose) INFOclass("enabling sample '%s', '%s' matches '%s'",this->getEntry(i,0).Data(),entry.Data(),pattern.Data());
      this->setProperty(i,0,"enabled",true);
      this->setProperty(i,0,"bold",true);
      count++;
    }
  }
  return count;
}

int TQXSecParser::disableSamplesWithColumnStringMatch(const TString& colname, const TString& pattern, bool verbose){
  // disables all samples with string match in column
  int prioidx = this->findColumn(colname);
  if(prioidx < 0) return -1;
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    TString entry = this->getEntryPlain(i,prioidx);
    if(TQStringUtils::matches(entry,pattern)){
      if(verbose) INFOclass("disabling sample '%s', '%s' matches '%s'",this->getEntry(i,0).Data(),entry.Data(),pattern.Data());
      this->setProperty(i,0,"enabled",false);
      this->setProperty(i,0,"bold",false);
      count++;
    }
  }
  return count;
}


int TQXSecParser::enableSamplesWithPriorityLessThan(const TString& colname, int val, bool verbose){
  // enables all samples with priority (given by colname) less than the given value
  int prioidx = this->findColumn(colname);
  if(prioidx < 0) return -1;
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    int p = this->getEntry(i,prioidx).Atoi();
    if(p < val){
      if(verbose) INFOclass("enabling sample '%s', priority=%d",this->getEntry(i,0).Data(),p);
      this->setProperty(i,0,"enabled",true);
      this->setProperty(i,0,"bold",true);
      count++;
    }
  }
  return count;
}

int TQXSecParser::disableSamplesWithPriorityLessThan(const TString& colname, int val, bool verbose){
  // disables all samples with priority (given by colname) less than the given value
  int prioidx = this->findColumn(colname);
  if(prioidx < 0) return -1;
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    int p = this->getEntry(i,prioidx).Atoi();
    if(p < val){
      if(verbose) INFOclass("disabling sample '%s', priority=%d",this->getEntry(i,0).Data(),p);
      this->setProperty(i,0,"enabled",false);
      this->setProperty(i,0,"bold",false);
      count++;
    }
  }
  return count;
}

int TQXSecParser::enableSamplesWithPriorityGreaterThan(const TString& colname, int val, bool verbose){
  // enables all samples with priority (given by colname) greater than the given value
  int prioidx = this->findColumn(colname);
  if(prioidx < 0) return -1;
  int count =0;
  for(size_t i=1; i<this->nrows; i++){
    int p = this->getEntry(i,prioidx).Atoi();
    if(p > val){
      if(verbose) INFOclass("enabling sample '%s', priority=%d",this->getEntry(i,0).Data(),p);
      this->setProperty(i,0,"enabled",true);
      this->setProperty(i,0,"bold",true);
      count++;
    }
  }
  return count;
}

int TQXSecParser::disableSamplesWithPriorityGreaterThan(const TString& colname, int val, bool verbose){
  // disables all samples with priority (given by colname) greater than the given value
  int prioidx = this->findColumn(colname);
  if(prioidx < 0) return -1;
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    int p = this->getEntry(i,prioidx).Atoi();
    if(p > val){
      if(verbose) INFOclass("disabling sample '%s', priority=%d",this->getEntry(i,0).Data(),p);
      this->setProperty(i,0,"enabled",false);
      this->setProperty(i,0,"bold",false);
      count++;
    }
  }
  return count;
}

int TQXSecParser::applyWhitelist(const TString& filename){
  // enables all listed samples
  std::vector<TString>* lines =  TQStringUtils::readFileLines(filename);
  if (!lines) {
    ERRORclass("Failed to read whitelist file '%s'. Does the file exist?",filename.Data());
    return 0;
  }
  int nActivated = this->applyWhitelist(lines);
  delete lines;
  return nActivated;
}

int TQXSecParser::applyWhitelist(std::vector<TString>* lines){
  // enables all listed samples (all non-listed ones will be disabled)
  // returns the number of enabled samples
  if(!lines) return false;
  this->disableAllSamples();
  int count = 0;
  std::vector<int> matchingRows;
  for(const auto& it:*lines){
    TString line(it);
    TString name;
    TQStringUtils::readUpTo(line,name," \t\n");
    TQStringUtils::removeLeading(line," \t\n");
    const bool replace = !line.IsNull();
    if(replace){
      line.ReplaceAll("$",name);
    }
    unsigned int nCurrentRows = this->nrows;
    bool foundMatch = false;
    for(size_t i=1; i<nCurrentRows; i++){
      if(TQStringUtils::equal(name,this->getEntry(i,0))){
        int rowIndex = -1;
        foundMatch = true;
        if(std::find(matchingRows.begin(), matchingRows.end(), i) != matchingRows.end()) {
          WARNclass("DSID '%s' already booked. Are you sure you also want to book DSID/samples with matching name '%s'?", name.Data(), line.Data());
          this->copyRow(i, nCurrentRows); //  duplicate row to the end of TQTable
          rowIndex = nCurrentRows;
        } else {
          rowIndex = i;
        }
        matchingRows.push_back(rowIndex);
        if(replace) this->setProperty(rowIndex,0,"matchingName",line);
        this->setProperty(rowIndex,0,"enabled",true);
        count++;
      }
    }
    if(!foundMatch) {
      WARNclass("Entry for DSID %s missing in xSec file. Skipping.", name.Data());
    }
  }
  for (auto i : matchingRows)
    this->setProperty(i,0,"bold",true); // will prevent from name matching with same entry in line above
  if (count==0) {
    WARNclass("No samples passed the whitelist selection!");
  }

  return count;
}

void TQXSecParser::selectFirstColumn(std::vector<TString>* lines){
  // remove all but the first column in a list of strings
  if(!lines) return;
  for(auto& line:*lines){
    TQStringUtils::removeLeading(line," \t");
    int pos = TQStringUtils::findFirstOf(line," \t\n");
    if(pos > 0 && pos < line.Length()){
      line.Remove(pos,line.Length()-pos);
    }
  }
}

int TQXSecParser::applyBlacklist(const TString& filename){
  // disables all listed samples
  std::vector<TString>* lines =  TQStringUtils::readFileLines(filename);
  TQXSecParser::selectFirstColumn(lines);
  return this->applyBlacklist(lines);
}

int TQXSecParser::applyBlacklist(std::vector<TString>* lines){
  // disables all listed samples
  if(!lines) return false;
  int count = this->enableAllSamples();
  for(size_t i=1; i<this->nrows; i++){
    TString name = this->getEntry(i,0);
    auto it = TQStringUtils::find(name,*lines);
    if(it != -1){
      this->setProperty(i,0,"enabled",false);
      this->setProperty(i,0,"bold",false);
      count--;
    }
  }
  return count;
}

int TQXSecParser::enableAllSamples(){
  // enables all listed samples
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    this->setProperty(i,0,"enabled",true);
    this->setProperty(i,0,"bold",true);
    count++;
  }
  return count;
}

int TQXSecParser::disableAllSamples(){
  // enables all listed samples
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    this->setProperty(i,0,"enabled",false);
    this->setProperty(i,0,"bold",false);
    count++;
  }
  return count;
}

//some information handling/ tag propagation
//fKeysToExport
void TQXSecParser::addTagKeyToExport(const TString& key) {
  // add the key (name) of a tag possibly set on the XSecParser to be
  // copied to TQSample instances created by this parser
  this->fKeysToExport.insert(key);
}

bool TQXSecParser::removeTagKeyToExport(const TString& key) {
  // remvoe the key (name) of a tag possibly set on the XSecParser to *not* be
  // copied to TQSample instances created by this parser (undoes a previous
  // addTagKeyToExport call with the same argument)
  return (bool)this->fKeysToExport.erase(key);
}

const std::set<TString>& TQXSecParser::getTagKeysToExport() const {
  // get the set of tag keys marked for being copied to newly created
  // TQSample instances
  return this->fKeysToExport;
}

void TQXSecParser::clearTagKeysToExport() {
  // reset the set of tag keys marked for being copied to newly created
  // TQSample instances
  this->fKeysToExport.clear();
}

int TQXSecParser::addAllEnabledSamples(){
  // add all mapped samples to the folder
  // an enabled sample is a mapped sample
  // that has the 'enabled' flag set
  return this->addAllSamples(true,true);
}

int TQXSecParser::addAllMappedSamples(){
  // add all mapped samples to the folder
  // a mapped sample is one that has a path assigned to it
  return this->addAllSamples(false,true);
}

int TQXSecParser::addAllListedSamples(){
  // add all listed samples to the folder
  return this->addAllSamples(false,false);
}


bool TQXSecParser::hasCompleteMapping(bool requireEnabled){
  // return true if all samples are mapped to a path
  // if requireEnabled=true, only enabled samples will be checked
  for(size_t i=1; i<this->nrows; i++){
    TQTaggable* entry = this->getEntryInternal(i,0);
    if(requireEnabled && !entry->getTagBoolDefault("enabled",false)) continue;
    if(!entry->hasTagString("path")) return false;
  }
  return true;
}

int TQXSecParser::addAllSamples(bool requireEnabled, bool requirePath){
  // add all samples to the folder
  DEBUGclass("entering function, requireEnabled=%d, requirePath=%d",(int)requireEnabled,(int)requirePath);
  if(!this->fSampleFolder) return -1;
  int retval = 0;
  if(this->fPathVariants->GetEntries() < 1){
    this->addPathVariant("");
  }
  int treeNameCol = this->findColumn("treename");
  int avgwCol = this->findColumn(this->getTagStringDefault("xAverageWeightColName","*average*weight*"),this->getTagBoolDefault("xAverageWeightColNameCaseSensitive",false));
  int sowCol = this->findColumn(this->getTagStringDefault("sumOfWeightsColName","*s*o*w*"),this->getTagBoolDefault("sumOfWeightsColNameCaseSensitive",false));
  int xSecCol = this->findColumn(this->getTagStringDefault("xSecColName","*xsec*"),this->getTagBoolDefault("xSecColNameCaseSensitive",false));
  int filterEffCol = this->findColumn(this->getTagStringDefault("xFilterEffColName","*filt*eff*"),this->getTagBoolDefault("xFilterEffColNameCaseSensitive",false));
  int kFactorCol = this->findColumn(this->getTagStringDefault("kFactorColName","*k*fac*"),this->getTagBoolDefault("kFactorColNameCaseSensitive",false));
  int procInfCol = this->findColumn(this->getTagStringDefault("processInfoColName","*proc*"),this->getTagBoolDefault("processInfoColNameCaseSensitive",false));
  int genInfCol = this->findColumn(this->getTagStringDefault("generatorInfoColName","*gen*"),this->getTagBoolDefault("generatorInfoColNameCaseSensitive",false));
  int simInfCol = this->findColumn(this->getTagStringDefault("simulationInfoColName","*sim*"),this->getTagBoolDefault("simulationInfoColNameCaseSensitive",false));
  TString unitstr = this->getEntryPlain(0,xSecCol);

  this->getTagString("xSectionUnit",unitstr);
  TQXSecParser::Unit unit = TQXSecParser::unit(unitstr);
  if (unit == TQXSecParser::Units::UNKNOWN || unit != unit) unit = TQXSecParser::Units::picobarn; //set default value if no valid value has been found. The check here actualy makes sense as UNKNOWN is currently defined as std::numeric_limits<double>::quiet_NaN(). We still keep the first part in case this gets changed (preventing a potential, very subtle bug...)
  DEBUGclass("using unit '%s', factor is '%f",unitstr.Data(),unit);

  if(!this->getTagBoolDefault(".hasMapping",false)){
    if(this->readMappingFromColumn("*path*") < 1){
      ERRORclass("refusing to add samples - no mapping specified, no adequate column found");
      return -1;
    }
  }
  TString treeName;
  for(size_t i=1; i<this->nrows; i++){
    DEBUGclass("investigating row %d...",(int)i);
    TQTaggable* entry = this->getEntryInternal(i,0);
    if(!entry){
      ERRORclass("encountered empty row at index %d - this should never have happened!",(int)i);
      continue;
    }
    TString samplenameorig;
    TString pathpattern = "uncategorized";
    if(!entry->getTagString("matchingName", samplenameorig) && !entry->getTagString("content.verbatim", samplenameorig)) continue; //if no whitelist has been applied, we use the regular content of the entry (i.e. the sample name)
    TString samplename = TQFolder::makeValidIdentifier(samplenameorig);
    if(requireEnabled && !entry->getTagBoolDefault("enabled",false)) continue;
    if(!entry->getTagString("path",pathpattern) && requirePath){
      WARNclass("Entry for DSID %s missing in mapping file. Skipping.", samplename.Data());
      continue;
    }
    pathpattern = this->replaceInTextRecursive(pathpattern);
    DEBUGclass("adding sample '%s'",samplename.Data());
    TQTaggableIterator itr(this->fPathVariants);
    while(itr.hasNext()){
      TQNamedTaggable* pathVariant = itr.readNext();
      int nReplaced = 0;
      int nFailed = 0;
      TString path = pathVariant ?
        pathVariant->replaceInText(pathpattern, nReplaced, nFailed, (TString) "") :
        pathpattern;
      DEBUGclass("path is '%s'",path.Data());
      TQSampleFolder* sf = this->fSampleFolder->getSampleFolder(path+"+");
      if(!sf){
        ERRORclass("cannot create sample folder at location '%s' - skipping sample '%s'",path.Data(),samplename.Data());
        continue;
      }
      if(sf->hasObject(samplename)){
        WARNclass("cowardly refusing to overwrite sample '%s' in folder '%s' - please check your cross section file for path conflicts!",samplename.Data(),path.Data());
        continue;
      }
      TQSample* s = new TQSample(samplename);
      if(!s){
        ERRORclass("unable to allocate sample with name '%s' - this should never have happened!",samplename.Data());
      }
      s->setTagString("name",samplename);
      s->setTagInteger("dsid",atof(samplename));
      s->setTagString(".xsp.sampleName",samplenameorig);
      for(size_t j=1; j<this->ncols; j++){
        TString key = TQFolder::makeValidIdentifier(this->getEntryPlain(0,j));
        TString value = this->getEntryPlain(i,j);
        if (!key.IsNull())
          {
            DEBUGclass("copying tag '%s'='%s'",key.Data(),value.Data());
            s->setTagString(key,value);
          }
      }
      //export dynamically configured tags to the newly created TQSample instance
      //(example use case: export campaign tag)
      // to use this you have to set the keys to export with
      // TQXSecParser::addTagKeyToExport(...)
      for (const TString& key : this->fKeysToExport) {
        this->exportTags(s, "", key);
      }
      double xSecScale;
      if(this->getTagDouble("xSecScale",xSecScale)){
        s->setTagDouble(".xsp.xSecScale",xSecScale);
      }
      if(xSecCol > 0){
        double xsec = this->getEntryDouble(i,xSecCol);
        s->setTagDouble(".xsp.xSection",TQXSecParser::convertUnit(xsec,unit,TQXSecParser::Units::picobarn));
      }
      if(filterEffCol > 0){
        double filtereff = this->getEntryDouble(i,filterEffCol);
        s->setTagDouble(".xsp.filterEfficiency",filtereff);
      }
      if(kFactorCol > 0){
        double kfactor = this->getEntryDouble(i,kFactorCol);
        s->setTagDouble(".xsp.kFactor",kfactor);
      }
      if(procInfCol > 0){
        TString processInfo = this->getEntryPlain(i,procInfCol);
        s->setTagString(".xsp.process",processInfo);
      }
      if(genInfCol > 0){
        TString generatorInfo = this->getEntryPlain(i,genInfCol);
        s->setTagString(".xsp.generator",generatorInfo);
      }
      if(simInfCol > 0){
        TString simulationInfo = this->getEntryPlain(i,simInfCol);
        s->setTagString(".xsp.simulation",simulationInfo);
      }
      if(treeNameCol > 0){
        s->setTagString(".xsp.treename",pathVariant->replaceInText(this->getEntryPlain(i,treeNameCol)));
      } else if(this->getTagString("treeName",treeName)){
        s->setTagString(".xsp.treename",pathVariant->replaceInText(treeName));
      }
      if(avgwCol > 0){
        TString sumOfWeightsInfo(this->getEntryPlain(i,avgwCol,false));
        if(!sumOfWeightsInfo.IsNull()){
          double sumOfWeightsPerEvent = this->getEntryDouble(i,avgwCol); //don't use the string representation as getEntryDouble has a more robust string->double conversion
          DEBUGclass("setting tag averageWeight=%f",sumOfWeightsPerEvent);
          s->setTagDouble(".xsp.averageWeight",sumOfWeightsPerEvent);
        }
      }
      if(sowCol > 0){
        TString sumOfWeightsInfo(this->getEntryPlain(i,sowCol,false));
        if(!sumOfWeightsInfo.IsNull()){
          double sumOfWeightsPerEvent = this->getEntryDouble(i,sowCol); //don't use the string representation as getEntryDouble has a more robust string->double conversion
          DEBUGclass("setting tag sumOfWeights=%f",sumOfWeightsPerEvent);
          s->setTagDouble(".xsp.sumOfWeights",sumOfWeightsPerEvent);
        }
      }

      DEBUGclass("treeName = %s", s->getTagStringDefault(".xsp.treename", "").Data());
      TString filepath;
      if(this->getTagString("fileNamePattern",filepath)){
        s->setTagString(".xsp.filepath",filepath);
      }
      DEBUGclass("adding sample");
      if(!sf->addObject(s)){
        ERRORclass("unable to add sample '%s' to folder '%s' - this should never have happened!",samplename.Data(),sf->GetName());
        delete s;
        continue;
      }
      retval++;
      DEBUGclass("done adding sample '%s' at path '%s'",samplename.Data(),sf->getPath().Data());
      if (nReplaced == 0){
        DEBUGclass("Skipping other path variants, because path doesn't depend on path variants.");
        break;
      }
      DEBUGclass("nReplaced = %d", nReplaced);
    }
  }
  return retval;
}

int TQXSecParser::addAllSamplesFromPath(const TString& filesystempath, const TString& folderpath, const TString& namefilter, const TString& pathfilter, const TString& tagstring){
  // search a file system path for all ntuples and add them to the sample folder
  TQFolder* f = TQFolder::copyDirectoryStructure(filesystempath);
  int retval = this->addAllSamplesFromFolder(f,folderpath,namefilter,pathfilter,tagstring);
  delete f;
  return retval;
}

int TQXSecParser::addAllSamplesFromList(const TString& inputfile, const TString& folderpath, const TString& tagstring){
  // add the contents of a text file as samples to a sample folder
  TQSampleFolder* sf =this->fSampleFolder->getSampleFolder(folderpath+"+");
  if(!sf){
    ERRORclass("cannot create sample folder at path '%s'",folderpath.Data());
    return -1;
  }
  TString treeName;
  bool hasTreeName = this->getTagString("treeName",treeName);
  std::vector<TString> lines;
  int retval = 0;
  if(!TQStringUtils::readFileLines(&lines,inputfile,1024,true)) return -1;
  for(auto line:lines){
    TString path = TQStringUtils::makeASCII(line);
    DEBUGclass("adding file %s",path.Data());
    const TString fname = TQFolder::getPathTail(path);
    TString name(fname);
    TQStringUtils::removeTrailing(name,".123456789");
    TQStringUtils::removeTrailingText(name,".root");
    TQSample* s = new TQSample(TQFolder::makeValidIdentifier(name));
    TString fileName = TQFolder::concatPaths(path,fname);
    s->setTagString(".xsp.filepath", fileName);
    if(hasTreeName){
      s->setTagString(".xsp.treename",treeName);
    }
    double fileSizeInMB = TQUtils::getFileSize(fileName)/1e6;
    if (fileSizeInMB>0.) {
      s->setTagDouble(".xsp.fileSize",fileSizeInMB);
    }
    // set trace ID (needed for merging)
    TString traceID = TQLibrary::getApplicationName();
    s->setTagBool(TString::Format(".%s.visited", traceID.Data()), true);
    s->setTagInteger(TString::Format(".%s.timestamp.machine",traceID.Data()),TQUtils::getCurrentTime());
    s->setTagString(TString::Format(".%s.timestamp.human",traceID.Data()),TQUtils::getTimeStamp());

    s->importTags(tagstring);
    sf->addObject(s);
    retval++;
  }
  return retval;
}


int TQXSecParser::addAllSamplesFromFolder(TQFolder* f, const TString& folderpath, const TString& namefilter, const TString& pathfilter, const TString& tagstring){
  // search a file system path for all ntuples and add them to the sample folder
  if(!f) return -1;
  TList* l = f->getObjectPaths(namefilter,pathfilter,TObjString::Class());
  TQStringIterator itr(l,true);
  int retval = 0;
  TString treeName;
  TQTaggable tags(tagstring);
#ifdef _DEBUG_
  DEBUGclass("adding all samples from folder '%s'",f->GetName());
  f->print("rdt");
#endif
  while(itr.hasNext()){
    TObjString* str = itr.readNext();
    if(!str) continue;
    TString path(str->GetName());
    path = TQStringUtils::makeASCII(path);
    const TString fname = TQFolder::getPathTail(path);
    TString name(fname);
    TQStringUtils::removeTrailingText(name,".root");
    TQSampleFolder* sf =this->fSampleFolder->getSampleFolder(folderpath+"+");
    if(!sf){
      ERRORclass("cannot create sample folder at path '%s', skipping",folderpath.Data());
      continue;
    }
    TQSample* s = new TQSample(TQFolder::makeValidIdentifier(name));
    TString filePath = TQFolder::concatPaths(path,fname);
    s->setTagString("name",name);
    s->setTagString(".xsp.filepath",filePath);
    if(this->getTagString("treeName",treeName)){
      s->setTagString(".xsp.treename",treeName);
    }
    double fileSizeInMB = TQUtils::getFileSize(filePath)/1e6;
    if (fileSizeInMB>0.) {
      s->setTagDouble(".xsp.fileSize",fileSizeInMB);
    }
    // set trace ID (needed for merging)
    TString traceID = TQLibrary::getApplicationName();
    s->setTagBool(TString::Format(".%s.visited", traceID.Data()), true);
    s->setTagInteger(TString::Format(".%s.timestamp.machine",traceID.Data()),TQUtils::getCurrentTime());
    s->setTagString(TString::Format(".%s.timestamp.human",traceID.Data()),TQUtils::getTimeStamp());

    s->importTags(tagstring);
    sf->addObject(s);
    retval++;
  }
  return retval;
}

bool TQXSecParser::isGood(){
  // return true if this reader was properly initialized and is good to go
  if(this->getNcols() < 2) return false;
  if(!this->fSampleFolder) return false;
  return true;
}

//__________________________________________________________________________________|___________


TQXSecParser::Unit TQXSecParser::unit(const TString& in) {
  // search a string for a cross section unit
  if(in.Contains("mb")) return TQXSecParser::Units::millibarn;
  if(in.Contains("µb")) return TQXSecParser::Units::microbarn;
  if(in.Contains("nb")) return TQXSecParser::Units::nanobarn;
  if(in.Contains("pb")) return TQXSecParser::Units::picobarn;
  if(in.Contains("fb")) return TQXSecParser::Units::femtobarn;
  if(in.Contains("ab")) return TQXSecParser::Units::attobarn;
  return TQXSecParser::Units::UNKNOWN;
}

//__________________________________________________________________________________|___________

TString TQXSecParser::unitName(TQXSecParser::Unit in){
  // convert a unit into a string
  if(in == TQXSecParser::Units::millibarn) return "mb";
  if(in == TQXSecParser::Units::microbarn) return "µb";
  if(in == TQXSecParser::Units::nanobarn ) return "nb";
  if(in == TQXSecParser::Units::picobarn ) return "pb";
  if(in == TQXSecParser::Units::femtobarn) return "fb";
  if(in == TQXSecParser::Units::attobarn ) return "ab";
  return "";
}

//__________________________________________________________________________________|___________

double TQXSecParser::convertUnit(double in, const TString& inUnit, const TString& outUnit) {
  // convert a cross section value from one unit to the other
  return TQXSecParser::convertUnit(in,TQXSecParser::unit(inUnit),TQXSecParser::unit(outUnit));
}

//__________________________________________________________________________________|___________

double TQXSecParser::convertUnit(double in, TQXSecParser::Unit inUnit, TQXSecParser::Unit outUnit) {
  // convert a cross section value from one unit to the other
  return in * inUnit / outUnit;
}

int TQXSecParser::readFilePatternFromColumn(const TString& colname){
  // copy paths from the given column
  int colidx = this->findColumn(colname);
  if(colidx < 0) return -1;
  this->setColAlign(colidx,"l");
  int count = 0;
  for(size_t i=1; i<this->nrows; i++){
    TString path = this->getEntryVerbatim(i,colidx);
    if(path.IsNull()) continue;

    TQTaggable* entry = this->getEntryInternal(i,0);
    if(entry && !entry->getTagBoolDefault("enabled",false)) continue; // avoid that the sample get's enabled if it wasn't before, e.g. because of low priority
    this->setProperty(i,0,"matchingName",path);
    this->setProperty(i,0,"enabled",true);
    this->setProperty(i,0,"bold",true);
    count++;
  }
  return count;
}
 TQXSecParser.cxx:1
 TQXSecParser.cxx:2
 TQXSecParser.cxx:3
 TQXSecParser.cxx:4
 TQXSecParser.cxx:5
 TQXSecParser.cxx:6
 TQXSecParser.cxx:7
 TQXSecParser.cxx:8
 TQXSecParser.cxx:9
 TQXSecParser.cxx:10
 TQXSecParser.cxx:11
 TQXSecParser.cxx:12
 TQXSecParser.cxx:13
 TQXSecParser.cxx:14
 TQXSecParser.cxx:15
 TQXSecParser.cxx:16
 TQXSecParser.cxx:17
 TQXSecParser.cxx:18
 TQXSecParser.cxx:19
 TQXSecParser.cxx:20
 TQXSecParser.cxx:21
 TQXSecParser.cxx:22
 TQXSecParser.cxx:23
 TQXSecParser.cxx:24
 TQXSecParser.cxx:25
 TQXSecParser.cxx:26
 TQXSecParser.cxx:27
 TQXSecParser.cxx:28
 TQXSecParser.cxx:29
 TQXSecParser.cxx:30
 TQXSecParser.cxx:31
 TQXSecParser.cxx:32
 TQXSecParser.cxx:33
 TQXSecParser.cxx:34
 TQXSecParser.cxx:35
 TQXSecParser.cxx:36
 TQXSecParser.cxx:37
 TQXSecParser.cxx:38
 TQXSecParser.cxx:39
 TQXSecParser.cxx:40
 TQXSecParser.cxx:41
 TQXSecParser.cxx:42
 TQXSecParser.cxx:43
 TQXSecParser.cxx:44
 TQXSecParser.cxx:45
 TQXSecParser.cxx:46
 TQXSecParser.cxx:47
 TQXSecParser.cxx:48
 TQXSecParser.cxx:49
 TQXSecParser.cxx:50
 TQXSecParser.cxx:51
 TQXSecParser.cxx:52
 TQXSecParser.cxx:53
 TQXSecParser.cxx:54
 TQXSecParser.cxx:55
 TQXSecParser.cxx:56
 TQXSecParser.cxx:57
 TQXSecParser.cxx:58
 TQXSecParser.cxx:59
 TQXSecParser.cxx:60
 TQXSecParser.cxx:61
 TQXSecParser.cxx:62
 TQXSecParser.cxx:63
 TQXSecParser.cxx:64
 TQXSecParser.cxx:65
 TQXSecParser.cxx:66
 TQXSecParser.cxx:67
 TQXSecParser.cxx:68
 TQXSecParser.cxx:69
 TQXSecParser.cxx:70
 TQXSecParser.cxx:71
 TQXSecParser.cxx:72
 TQXSecParser.cxx:73
 TQXSecParser.cxx:74
 TQXSecParser.cxx:75
 TQXSecParser.cxx:76
 TQXSecParser.cxx:77
 TQXSecParser.cxx:78
 TQXSecParser.cxx:79
 TQXSecParser.cxx:80
 TQXSecParser.cxx:81
 TQXSecParser.cxx:82
 TQXSecParser.cxx:83
 TQXSecParser.cxx:84
 TQXSecParser.cxx:85
 TQXSecParser.cxx:86
 TQXSecParser.cxx:87
 TQXSecParser.cxx:88
 TQXSecParser.cxx:89
 TQXSecParser.cxx:90
 TQXSecParser.cxx:91
 TQXSecParser.cxx:92
 TQXSecParser.cxx:93
 TQXSecParser.cxx:94
 TQXSecParser.cxx:95
 TQXSecParser.cxx:96
 TQXSecParser.cxx:97
 TQXSecParser.cxx:98
 TQXSecParser.cxx:99
 TQXSecParser.cxx:100
 TQXSecParser.cxx:101
 TQXSecParser.cxx:102
 TQXSecParser.cxx:103
 TQXSecParser.cxx:104
 TQXSecParser.cxx:105
 TQXSecParser.cxx:106
 TQXSecParser.cxx:107
 TQXSecParser.cxx:108
 TQXSecParser.cxx:109
 TQXSecParser.cxx:110
 TQXSecParser.cxx:111
 TQXSecParser.cxx:112
 TQXSecParser.cxx:113
 TQXSecParser.cxx:114
 TQXSecParser.cxx:115
 TQXSecParser.cxx:116
 TQXSecParser.cxx:117
 TQXSecParser.cxx:118
 TQXSecParser.cxx:119
 TQXSecParser.cxx:120
 TQXSecParser.cxx:121
 TQXSecParser.cxx:122
 TQXSecParser.cxx:123
 TQXSecParser.cxx:124
 TQXSecParser.cxx:125
 TQXSecParser.cxx:126
 TQXSecParser.cxx:127
 TQXSecParser.cxx:128
 TQXSecParser.cxx:129
 TQXSecParser.cxx:130
 TQXSecParser.cxx:131
 TQXSecParser.cxx:132
 TQXSecParser.cxx:133
 TQXSecParser.cxx:134
 TQXSecParser.cxx:135
 TQXSecParser.cxx:136
 TQXSecParser.cxx:137
 TQXSecParser.cxx:138
 TQXSecParser.cxx:139
 TQXSecParser.cxx:140
 TQXSecParser.cxx:141
 TQXSecParser.cxx:142
 TQXSecParser.cxx:143
 TQXSecParser.cxx:144
 TQXSecParser.cxx:145
 TQXSecParser.cxx:146
 TQXSecParser.cxx:147
 TQXSecParser.cxx:148
 TQXSecParser.cxx:149
 TQXSecParser.cxx:150
 TQXSecParser.cxx:151
 TQXSecParser.cxx:152
 TQXSecParser.cxx:153
 TQXSecParser.cxx:154
 TQXSecParser.cxx:155
 TQXSecParser.cxx:156
 TQXSecParser.cxx:157
 TQXSecParser.cxx:158
 TQXSecParser.cxx:159
 TQXSecParser.cxx:160
 TQXSecParser.cxx:161
 TQXSecParser.cxx:162
 TQXSecParser.cxx:163
 TQXSecParser.cxx:164
 TQXSecParser.cxx:165
 TQXSecParser.cxx:166
 TQXSecParser.cxx:167
 TQXSecParser.cxx:168
 TQXSecParser.cxx:169
 TQXSecParser.cxx:170
 TQXSecParser.cxx:171
 TQXSecParser.cxx:172
 TQXSecParser.cxx:173
 TQXSecParser.cxx:174
 TQXSecParser.cxx:175
 TQXSecParser.cxx:176
 TQXSecParser.cxx:177
 TQXSecParser.cxx:178
 TQXSecParser.cxx:179
 TQXSecParser.cxx:180
 TQXSecParser.cxx:181
 TQXSecParser.cxx:182
 TQXSecParser.cxx:183
 TQXSecParser.cxx:184
 TQXSecParser.cxx:185
 TQXSecParser.cxx:186
 TQXSecParser.cxx:187
 TQXSecParser.cxx:188
 TQXSecParser.cxx:189
 TQXSecParser.cxx:190
 TQXSecParser.cxx:191
 TQXSecParser.cxx:192
 TQXSecParser.cxx:193
 TQXSecParser.cxx:194
 TQXSecParser.cxx:195
 TQXSecParser.cxx:196
 TQXSecParser.cxx:197
 TQXSecParser.cxx:198
 TQXSecParser.cxx:199
 TQXSecParser.cxx:200
 TQXSecParser.cxx:201
 TQXSecParser.cxx:202
 TQXSecParser.cxx:203
 TQXSecParser.cxx:204
 TQXSecParser.cxx:205
 TQXSecParser.cxx:206
 TQXSecParser.cxx:207
 TQXSecParser.cxx:208
 TQXSecParser.cxx:209
 TQXSecParser.cxx:210
 TQXSecParser.cxx:211
 TQXSecParser.cxx:212
 TQXSecParser.cxx:213
 TQXSecParser.cxx:214
 TQXSecParser.cxx:215
 TQXSecParser.cxx:216
 TQXSecParser.cxx:217
 TQXSecParser.cxx:218
 TQXSecParser.cxx:219
 TQXSecParser.cxx:220
 TQXSecParser.cxx:221
 TQXSecParser.cxx:222
 TQXSecParser.cxx:223
 TQXSecParser.cxx:224
 TQXSecParser.cxx:225
 TQXSecParser.cxx:226
 TQXSecParser.cxx:227
 TQXSecParser.cxx:228
 TQXSecParser.cxx:229
 TQXSecParser.cxx:230
 TQXSecParser.cxx:231
 TQXSecParser.cxx:232
 TQXSecParser.cxx:233
 TQXSecParser.cxx:234
 TQXSecParser.cxx:235
 TQXSecParser.cxx:236
 TQXSecParser.cxx:237
 TQXSecParser.cxx:238
 TQXSecParser.cxx:239
 TQXSecParser.cxx:240
 TQXSecParser.cxx:241
 TQXSecParser.cxx:242
 TQXSecParser.cxx:243
 TQXSecParser.cxx:244
 TQXSecParser.cxx:245
 TQXSecParser.cxx:246
 TQXSecParser.cxx:247
 TQXSecParser.cxx:248
 TQXSecParser.cxx:249
 TQXSecParser.cxx:250
 TQXSecParser.cxx:251
 TQXSecParser.cxx:252
 TQXSecParser.cxx:253
 TQXSecParser.cxx:254
 TQXSecParser.cxx:255
 TQXSecParser.cxx:256
 TQXSecParser.cxx:257
 TQXSecParser.cxx:258
 TQXSecParser.cxx:259
 TQXSecParser.cxx:260
 TQXSecParser.cxx:261
 TQXSecParser.cxx:262
 TQXSecParser.cxx:263
 TQXSecParser.cxx:264
 TQXSecParser.cxx:265
 TQXSecParser.cxx:266
 TQXSecParser.cxx:267
 TQXSecParser.cxx:268
 TQXSecParser.cxx:269
 TQXSecParser.cxx:270
 TQXSecParser.cxx:271
 TQXSecParser.cxx:272
 TQXSecParser.cxx:273
 TQXSecParser.cxx:274
 TQXSecParser.cxx:275
 TQXSecParser.cxx:276
 TQXSecParser.cxx:277
 TQXSecParser.cxx:278
 TQXSecParser.cxx:279
 TQXSecParser.cxx:280
 TQXSecParser.cxx:281
 TQXSecParser.cxx:282
 TQXSecParser.cxx:283
 TQXSecParser.cxx:284
 TQXSecParser.cxx:285
 TQXSecParser.cxx:286
 TQXSecParser.cxx:287
 TQXSecParser.cxx:288
 TQXSecParser.cxx:289
 TQXSecParser.cxx:290
 TQXSecParser.cxx:291
 TQXSecParser.cxx:292
 TQXSecParser.cxx:293
 TQXSecParser.cxx:294
 TQXSecParser.cxx:295
 TQXSecParser.cxx:296
 TQXSecParser.cxx:297
 TQXSecParser.cxx:298
 TQXSecParser.cxx:299
 TQXSecParser.cxx:300
 TQXSecParser.cxx:301
 TQXSecParser.cxx:302
 TQXSecParser.cxx:303
 TQXSecParser.cxx:304
 TQXSecParser.cxx:305
 TQXSecParser.cxx:306
 TQXSecParser.cxx:307
 TQXSecParser.cxx:308
 TQXSecParser.cxx:309
 TQXSecParser.cxx:310
 TQXSecParser.cxx:311
 TQXSecParser.cxx:312
 TQXSecParser.cxx:313
 TQXSecParser.cxx:314
 TQXSecParser.cxx:315
 TQXSecParser.cxx:316
 TQXSecParser.cxx:317
 TQXSecParser.cxx:318
 TQXSecParser.cxx:319
 TQXSecParser.cxx:320
 TQXSecParser.cxx:321
 TQXSecParser.cxx:322
 TQXSecParser.cxx:323
 TQXSecParser.cxx:324
 TQXSecParser.cxx:325
 TQXSecParser.cxx:326
 TQXSecParser.cxx:327
 TQXSecParser.cxx:328
 TQXSecParser.cxx:329
 TQXSecParser.cxx:330
 TQXSecParser.cxx:331
 TQXSecParser.cxx:332
 TQXSecParser.cxx:333
 TQXSecParser.cxx:334
 TQXSecParser.cxx:335
 TQXSecParser.cxx:336
 TQXSecParser.cxx:337
 TQXSecParser.cxx:338
 TQXSecParser.cxx:339
 TQXSecParser.cxx:340
 TQXSecParser.cxx:341
 TQXSecParser.cxx:342
 TQXSecParser.cxx:343
 TQXSecParser.cxx:344
 TQXSecParser.cxx:345
 TQXSecParser.cxx:346
 TQXSecParser.cxx:347
 TQXSecParser.cxx:348
 TQXSecParser.cxx:349
 TQXSecParser.cxx:350
 TQXSecParser.cxx:351
 TQXSecParser.cxx:352
 TQXSecParser.cxx:353
 TQXSecParser.cxx:354
 TQXSecParser.cxx:355
 TQXSecParser.cxx:356
 TQXSecParser.cxx:357
 TQXSecParser.cxx:358
 TQXSecParser.cxx:359
 TQXSecParser.cxx:360
 TQXSecParser.cxx:361
 TQXSecParser.cxx:362
 TQXSecParser.cxx:363
 TQXSecParser.cxx:364
 TQXSecParser.cxx:365
 TQXSecParser.cxx:366
 TQXSecParser.cxx:367
 TQXSecParser.cxx:368
 TQXSecParser.cxx:369
 TQXSecParser.cxx:370
 TQXSecParser.cxx:371
 TQXSecParser.cxx:372
 TQXSecParser.cxx:373
 TQXSecParser.cxx:374
 TQXSecParser.cxx:375
 TQXSecParser.cxx:376
 TQXSecParser.cxx:377
 TQXSecParser.cxx:378
 TQXSecParser.cxx:379
 TQXSecParser.cxx:380
 TQXSecParser.cxx:381
 TQXSecParser.cxx:382
 TQXSecParser.cxx:383
 TQXSecParser.cxx:384
 TQXSecParser.cxx:385
 TQXSecParser.cxx:386
 TQXSecParser.cxx:387
 TQXSecParser.cxx:388
 TQXSecParser.cxx:389
 TQXSecParser.cxx:390
 TQXSecParser.cxx:391
 TQXSecParser.cxx:392
 TQXSecParser.cxx:393
 TQXSecParser.cxx:394
 TQXSecParser.cxx:395
 TQXSecParser.cxx:396
 TQXSecParser.cxx:397
 TQXSecParser.cxx:398
 TQXSecParser.cxx:399
 TQXSecParser.cxx:400
 TQXSecParser.cxx:401
 TQXSecParser.cxx:402
 TQXSecParser.cxx:403
 TQXSecParser.cxx:404
 TQXSecParser.cxx:405
 TQXSecParser.cxx:406
 TQXSecParser.cxx:407
 TQXSecParser.cxx:408
 TQXSecParser.cxx:409
 TQXSecParser.cxx:410
 TQXSecParser.cxx:411
 TQXSecParser.cxx:412
 TQXSecParser.cxx:413
 TQXSecParser.cxx:414
 TQXSecParser.cxx:415
 TQXSecParser.cxx:416
 TQXSecParser.cxx:417
 TQXSecParser.cxx:418
 TQXSecParser.cxx:419
 TQXSecParser.cxx:420
 TQXSecParser.cxx:421
 TQXSecParser.cxx:422
 TQXSecParser.cxx:423
 TQXSecParser.cxx:424
 TQXSecParser.cxx:425
 TQXSecParser.cxx:426
 TQXSecParser.cxx:427
 TQXSecParser.cxx:428
 TQXSecParser.cxx:429
 TQXSecParser.cxx:430
 TQXSecParser.cxx:431
 TQXSecParser.cxx:432
 TQXSecParser.cxx:433
 TQXSecParser.cxx:434
 TQXSecParser.cxx:435
 TQXSecParser.cxx:436
 TQXSecParser.cxx:437
 TQXSecParser.cxx:438
 TQXSecParser.cxx:439
 TQXSecParser.cxx:440
 TQXSecParser.cxx:441
 TQXSecParser.cxx:442
 TQXSecParser.cxx:443
 TQXSecParser.cxx:444
 TQXSecParser.cxx:445
 TQXSecParser.cxx:446
 TQXSecParser.cxx:447
 TQXSecParser.cxx:448
 TQXSecParser.cxx:449
 TQXSecParser.cxx:450
 TQXSecParser.cxx:451
 TQXSecParser.cxx:452
 TQXSecParser.cxx:453
 TQXSecParser.cxx:454
 TQXSecParser.cxx:455
 TQXSecParser.cxx:456
 TQXSecParser.cxx:457
 TQXSecParser.cxx:458
 TQXSecParser.cxx:459
 TQXSecParser.cxx:460
 TQXSecParser.cxx:461
 TQXSecParser.cxx:462
 TQXSecParser.cxx:463
 TQXSecParser.cxx:464
 TQXSecParser.cxx:465
 TQXSecParser.cxx:466
 TQXSecParser.cxx:467
 TQXSecParser.cxx:468
 TQXSecParser.cxx:469
 TQXSecParser.cxx:470
 TQXSecParser.cxx:471
 TQXSecParser.cxx:472
 TQXSecParser.cxx:473
 TQXSecParser.cxx:474
 TQXSecParser.cxx:475
 TQXSecParser.cxx:476
 TQXSecParser.cxx:477
 TQXSecParser.cxx:478
 TQXSecParser.cxx:479
 TQXSecParser.cxx:480
 TQXSecParser.cxx:481
 TQXSecParser.cxx:482
 TQXSecParser.cxx:483
 TQXSecParser.cxx:484
 TQXSecParser.cxx:485
 TQXSecParser.cxx:486
 TQXSecParser.cxx:487
 TQXSecParser.cxx:488
 TQXSecParser.cxx:489
 TQXSecParser.cxx:490
 TQXSecParser.cxx:491
 TQXSecParser.cxx:492
 TQXSecParser.cxx:493
 TQXSecParser.cxx:494
 TQXSecParser.cxx:495
 TQXSecParser.cxx:496
 TQXSecParser.cxx:497
 TQXSecParser.cxx:498
 TQXSecParser.cxx:499
 TQXSecParser.cxx:500
 TQXSecParser.cxx:501
 TQXSecParser.cxx:502
 TQXSecParser.cxx:503
 TQXSecParser.cxx:504
 TQXSecParser.cxx:505
 TQXSecParser.cxx:506
 TQXSecParser.cxx:507
 TQXSecParser.cxx:508
 TQXSecParser.cxx:509
 TQXSecParser.cxx:510
 TQXSecParser.cxx:511
 TQXSecParser.cxx:512
 TQXSecParser.cxx:513
 TQXSecParser.cxx:514
 TQXSecParser.cxx:515
 TQXSecParser.cxx:516
 TQXSecParser.cxx:517
 TQXSecParser.cxx:518
 TQXSecParser.cxx:519
 TQXSecParser.cxx:520
 TQXSecParser.cxx:521
 TQXSecParser.cxx:522
 TQXSecParser.cxx:523
 TQXSecParser.cxx:524
 TQXSecParser.cxx:525
 TQXSecParser.cxx:526
 TQXSecParser.cxx:527
 TQXSecParser.cxx:528
 TQXSecParser.cxx:529
 TQXSecParser.cxx:530
 TQXSecParser.cxx:531
 TQXSecParser.cxx:532
 TQXSecParser.cxx:533
 TQXSecParser.cxx:534
 TQXSecParser.cxx:535
 TQXSecParser.cxx:536
 TQXSecParser.cxx:537
 TQXSecParser.cxx:538
 TQXSecParser.cxx:539
 TQXSecParser.cxx:540
 TQXSecParser.cxx:541
 TQXSecParser.cxx:542
 TQXSecParser.cxx:543
 TQXSecParser.cxx:544
 TQXSecParser.cxx:545
 TQXSecParser.cxx:546
 TQXSecParser.cxx:547
 TQXSecParser.cxx:548
 TQXSecParser.cxx:549
 TQXSecParser.cxx:550
 TQXSecParser.cxx:551
 TQXSecParser.cxx:552
 TQXSecParser.cxx:553
 TQXSecParser.cxx:554
 TQXSecParser.cxx:555
 TQXSecParser.cxx:556
 TQXSecParser.cxx:557
 TQXSecParser.cxx:558
 TQXSecParser.cxx:559
 TQXSecParser.cxx:560
 TQXSecParser.cxx:561
 TQXSecParser.cxx:562
 TQXSecParser.cxx:563
 TQXSecParser.cxx:564
 TQXSecParser.cxx:565
 TQXSecParser.cxx:566
 TQXSecParser.cxx:567
 TQXSecParser.cxx:568
 TQXSecParser.cxx:569
 TQXSecParser.cxx:570
 TQXSecParser.cxx:571
 TQXSecParser.cxx:572
 TQXSecParser.cxx:573
 TQXSecParser.cxx:574
 TQXSecParser.cxx:575
 TQXSecParser.cxx:576
 TQXSecParser.cxx:577
 TQXSecParser.cxx:578
 TQXSecParser.cxx:579
 TQXSecParser.cxx:580
 TQXSecParser.cxx:581
 TQXSecParser.cxx:582
 TQXSecParser.cxx:583
 TQXSecParser.cxx:584
 TQXSecParser.cxx:585
 TQXSecParser.cxx:586
 TQXSecParser.cxx:587
 TQXSecParser.cxx:588
 TQXSecParser.cxx:589
 TQXSecParser.cxx:590
 TQXSecParser.cxx:591
 TQXSecParser.cxx:592
 TQXSecParser.cxx:593
 TQXSecParser.cxx:594
 TQXSecParser.cxx:595
 TQXSecParser.cxx:596
 TQXSecParser.cxx:597
 TQXSecParser.cxx:598
 TQXSecParser.cxx:599
 TQXSecParser.cxx:600
 TQXSecParser.cxx:601
 TQXSecParser.cxx:602
 TQXSecParser.cxx:603
 TQXSecParser.cxx:604
 TQXSecParser.cxx:605
 TQXSecParser.cxx:606
 TQXSecParser.cxx:607
 TQXSecParser.cxx:608
 TQXSecParser.cxx:609
 TQXSecParser.cxx:610
 TQXSecParser.cxx:611
 TQXSecParser.cxx:612
 TQXSecParser.cxx:613
 TQXSecParser.cxx:614
 TQXSecParser.cxx:615
 TQXSecParser.cxx:616
 TQXSecParser.cxx:617
 TQXSecParser.cxx:618
 TQXSecParser.cxx:619
 TQXSecParser.cxx:620
 TQXSecParser.cxx:621
 TQXSecParser.cxx:622
 TQXSecParser.cxx:623
 TQXSecParser.cxx:624
 TQXSecParser.cxx:625
 TQXSecParser.cxx:626
 TQXSecParser.cxx:627
 TQXSecParser.cxx:628
 TQXSecParser.cxx:629
 TQXSecParser.cxx:630
 TQXSecParser.cxx:631
 TQXSecParser.cxx:632
 TQXSecParser.cxx:633
 TQXSecParser.cxx:634
 TQXSecParser.cxx:635
 TQXSecParser.cxx:636
 TQXSecParser.cxx:637
 TQXSecParser.cxx:638
 TQXSecParser.cxx:639
 TQXSecParser.cxx:640
 TQXSecParser.cxx:641
 TQXSecParser.cxx:642
 TQXSecParser.cxx:643
 TQXSecParser.cxx:644
 TQXSecParser.cxx:645
 TQXSecParser.cxx:646
 TQXSecParser.cxx:647
 TQXSecParser.cxx:648
 TQXSecParser.cxx:649
 TQXSecParser.cxx:650
 TQXSecParser.cxx:651
 TQXSecParser.cxx:652
 TQXSecParser.cxx:653
 TQXSecParser.cxx:654
 TQXSecParser.cxx:655
 TQXSecParser.cxx:656
 TQXSecParser.cxx:657
 TQXSecParser.cxx:658
 TQXSecParser.cxx:659
 TQXSecParser.cxx:660
 TQXSecParser.cxx:661
 TQXSecParser.cxx:662
 TQXSecParser.cxx:663
 TQXSecParser.cxx:664
 TQXSecParser.cxx:665
 TQXSecParser.cxx:666
 TQXSecParser.cxx:667
 TQXSecParser.cxx:668
 TQXSecParser.cxx:669
 TQXSecParser.cxx:670
 TQXSecParser.cxx:671
 TQXSecParser.cxx:672
 TQXSecParser.cxx:673
 TQXSecParser.cxx:674
 TQXSecParser.cxx:675
 TQXSecParser.cxx:676
 TQXSecParser.cxx:677
 TQXSecParser.cxx:678
 TQXSecParser.cxx:679
 TQXSecParser.cxx:680
 TQXSecParser.cxx:681
 TQXSecParser.cxx:682
 TQXSecParser.cxx:683
 TQXSecParser.cxx:684
 TQXSecParser.cxx:685
 TQXSecParser.cxx:686
 TQXSecParser.cxx:687
 TQXSecParser.cxx:688
 TQXSecParser.cxx:689
 TQXSecParser.cxx:690
 TQXSecParser.cxx:691
 TQXSecParser.cxx:692
 TQXSecParser.cxx:693
 TQXSecParser.cxx:694
 TQXSecParser.cxx:695
 TQXSecParser.cxx:696
 TQXSecParser.cxx:697
 TQXSecParser.cxx:698
 TQXSecParser.cxx:699
 TQXSecParser.cxx:700
 TQXSecParser.cxx:701
 TQXSecParser.cxx:702
 TQXSecParser.cxx:703
 TQXSecParser.cxx:704
 TQXSecParser.cxx:705
 TQXSecParser.cxx:706
 TQXSecParser.cxx:707
 TQXSecParser.cxx:708
 TQXSecParser.cxx:709
 TQXSecParser.cxx:710
 TQXSecParser.cxx:711
 TQXSecParser.cxx:712
 TQXSecParser.cxx:713
 TQXSecParser.cxx:714
 TQXSecParser.cxx:715
 TQXSecParser.cxx:716
 TQXSecParser.cxx:717
 TQXSecParser.cxx:718
 TQXSecParser.cxx:719
 TQXSecParser.cxx:720
 TQXSecParser.cxx:721
 TQXSecParser.cxx:722
 TQXSecParser.cxx:723
 TQXSecParser.cxx:724
 TQXSecParser.cxx:725
 TQXSecParser.cxx:726
 TQXSecParser.cxx:727
 TQXSecParser.cxx:728
 TQXSecParser.cxx:729
 TQXSecParser.cxx:730
 TQXSecParser.cxx:731
 TQXSecParser.cxx:732
 TQXSecParser.cxx:733
 TQXSecParser.cxx:734
 TQXSecParser.cxx:735
 TQXSecParser.cxx:736
 TQXSecParser.cxx:737
 TQXSecParser.cxx:738
 TQXSecParser.cxx:739
 TQXSecParser.cxx:740
 TQXSecParser.cxx:741
 TQXSecParser.cxx:742
 TQXSecParser.cxx:743
 TQXSecParser.cxx:744
 TQXSecParser.cxx:745
 TQXSecParser.cxx:746
 TQXSecParser.cxx:747
 TQXSecParser.cxx:748
 TQXSecParser.cxx:749
 TQXSecParser.cxx:750
 TQXSecParser.cxx:751
 TQXSecParser.cxx:752
 TQXSecParser.cxx:753
 TQXSecParser.cxx:754
 TQXSecParser.cxx:755
 TQXSecParser.cxx:756
 TQXSecParser.cxx:757
 TQXSecParser.cxx:758
 TQXSecParser.cxx:759
 TQXSecParser.cxx:760
 TQXSecParser.cxx:761
 TQXSecParser.cxx:762
 TQXSecParser.cxx:763
 TQXSecParser.cxx:764
 TQXSecParser.cxx:765
 TQXSecParser.cxx:766
 TQXSecParser.cxx:767
 TQXSecParser.cxx:768
 TQXSecParser.cxx:769
 TQXSecParser.cxx:770
 TQXSecParser.cxx:771
 TQXSecParser.cxx:772
 TQXSecParser.cxx:773
 TQXSecParser.cxx:774
 TQXSecParser.cxx:775
 TQXSecParser.cxx:776
 TQXSecParser.cxx:777
 TQXSecParser.cxx:778
 TQXSecParser.cxx:779
 TQXSecParser.cxx:780
 TQXSecParser.cxx:781
 TQXSecParser.cxx:782
 TQXSecParser.cxx:783
 TQXSecParser.cxx:784
 TQXSecParser.cxx:785
 TQXSecParser.cxx:786
 TQXSecParser.cxx:787
 TQXSecParser.cxx:788
 TQXSecParser.cxx:789
 TQXSecParser.cxx:790
 TQXSecParser.cxx:791
 TQXSecParser.cxx:792
 TQXSecParser.cxx:793
 TQXSecParser.cxx:794
 TQXSecParser.cxx:795
 TQXSecParser.cxx:796
 TQXSecParser.cxx:797
 TQXSecParser.cxx:798
 TQXSecParser.cxx:799
 TQXSecParser.cxx:800
 TQXSecParser.cxx:801
 TQXSecParser.cxx:802
 TQXSecParser.cxx:803
 TQXSecParser.cxx:804
 TQXSecParser.cxx:805
 TQXSecParser.cxx:806
 TQXSecParser.cxx:807
 TQXSecParser.cxx:808
 TQXSecParser.cxx:809
 TQXSecParser.cxx:810
 TQXSecParser.cxx:811
 TQXSecParser.cxx:812
 TQXSecParser.cxx:813
 TQXSecParser.cxx:814
 TQXSecParser.cxx:815
 TQXSecParser.cxx:816
 TQXSecParser.cxx:817
 TQXSecParser.cxx:818
 TQXSecParser.cxx:819
 TQXSecParser.cxx:820
 TQXSecParser.cxx:821
 TQXSecParser.cxx:822
 TQXSecParser.cxx:823
 TQXSecParser.cxx:824
 TQXSecParser.cxx:825
 TQXSecParser.cxx:826
 TQXSecParser.cxx:827
 TQXSecParser.cxx:828
 TQXSecParser.cxx:829
 TQXSecParser.cxx:830
 TQXSecParser.cxx:831
 TQXSecParser.cxx:832
 TQXSecParser.cxx:833
 TQXSecParser.cxx:834
 TQXSecParser.cxx:835
 TQXSecParser.cxx:836
 TQXSecParser.cxx:837
 TQXSecParser.cxx:838
 TQXSecParser.cxx:839
 TQXSecParser.cxx:840
 TQXSecParser.cxx:841
 TQXSecParser.cxx:842
 TQXSecParser.cxx:843
 TQXSecParser.cxx:844
 TQXSecParser.cxx:845
 TQXSecParser.cxx:846
 TQXSecParser.cxx:847
 TQXSecParser.cxx:848
 TQXSecParser.cxx:849
 TQXSecParser.cxx:850
 TQXSecParser.cxx:851
 TQXSecParser.cxx:852
 TQXSecParser.cxx:853
 TQXSecParser.cxx:854
 TQXSecParser.cxx:855
 TQXSecParser.cxx:856
 TQXSecParser.cxx:857
 TQXSecParser.cxx:858
 TQXSecParser.cxx:859
 TQXSecParser.cxx:860
 TQXSecParser.cxx:861
 TQXSecParser.cxx:862
 TQXSecParser.cxx:863
 TQXSecParser.cxx:864
 TQXSecParser.cxx:865
 TQXSecParser.cxx:866
 TQXSecParser.cxx:867
 TQXSecParser.cxx:868
 TQXSecParser.cxx:869
 TQXSecParser.cxx:870
 TQXSecParser.cxx:871
 TQXSecParser.cxx:872
 TQXSecParser.cxx:873
 TQXSecParser.cxx:874
 TQXSecParser.cxx:875
 TQXSecParser.cxx:876
 TQXSecParser.cxx:877
 TQXSecParser.cxx:878
 TQXSecParser.cxx:879
 TQXSecParser.cxx:880
 TQXSecParser.cxx:881
 TQXSecParser.cxx:882
 TQXSecParser.cxx:883
 TQXSecParser.cxx:884
 TQXSecParser.cxx:885
 TQXSecParser.cxx:886
 TQXSecParser.cxx:887
 TQXSecParser.cxx:888
 TQXSecParser.cxx:889
 TQXSecParser.cxx:890
 TQXSecParser.cxx:891
 TQXSecParser.cxx:892
 TQXSecParser.cxx:893
 TQXSecParser.cxx:894
 TQXSecParser.cxx:895
 TQXSecParser.cxx:896
 TQXSecParser.cxx:897
 TQXSecParser.cxx:898
 TQXSecParser.cxx:899
 TQXSecParser.cxx:900
 TQXSecParser.cxx:901
 TQXSecParser.cxx:902
 TQXSecParser.cxx:903
 TQXSecParser.cxx:904
 TQXSecParser.cxx:905
 TQXSecParser.cxx:906