ROOT logo

#if !defined(__CINT__) || defined(__MAKECINT__)
// ROOT includes
#include "TFile.h"
#include "TH1.h"
#include "TH2.h"
#include "TGraphAsymmErrors.h"
#include "TSystem.h"
#include "Riostream.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TROOT.h"
#include "TLegend.h"
#include "TMath.h"
#include "TObjArray.h"
#include "TList.h"
#include "TObjString.h"
#include "TString.h"
#include "TGrid.h"
#include "TArrayD.h"
#include "TArrayI.h"
#include "TMap.h"
#include "TGridResult.h"

#include "AliCDBManager.h"
#include "AliCDBEntry.h"
#include "AliCDBPath.h"
#include "AliCDBStorage.h"
#include "AliMUONTriggerEfficiencyCells.h"
#include "AliMUONTriggerChamberEfficiency.h"
#include "AliMUONTriggerUtilities.h"
#include "AliMUONDigitMaker.h"
#include "AliMUONVDigit.h"
#include "AliMUONDigitStoreV2R.h"
#include "AliMUONCalibrationData.h"
#include "AliAnalysisTriggerScalers.h"
#include "AliCounterCollection.h"
#include "AliTriggerConfiguration.h"
#endif

const Int_t kNch = 4;
const Double_t kZero = 1.e-7; // Avoid problems when comparing to 0.

//_____________________________________________________________________________
void SetMyStyle()
{
  /// Set graphic style
  gStyle->SetCanvasColor(10);
  gStyle->SetFrameFillColor(10);
  gStyle->SetStatColor(10);
  gStyle->SetFillColor(10);
  gStyle->SetTitleFillColor(10);
  
  gStyle->SetTitleXSize(0.03);
  gStyle->SetTitleXOffset(1.1);
  gStyle->SetTitleYSize(0.03);
  gStyle->SetTitleYOffset(1.9);
  
  gStyle->SetMarkerSize(0.7);
  gStyle->SetHistLineWidth(2);
  
  gStyle->SetPadLeftMargin(0.12);
  gStyle->SetPadRightMargin(0.04);
  gStyle->SetPadBottomMargin(0.08);
  gStyle->SetPadTopMargin(0.08);
  
  gROOT->ForceStyle();
}

//_____________________________________________________________________________
Bool_t IsRunNum ( TString stringToken )
{
  return ( stringToken.IsDigit() && stringToken.Length()>=6 && stringToken.Length()<=9 );
}


//_____________________________________________________________________________
void SetRunAxisRange ( TAxis* axis )
{
  /// Set axis range
  for ( Int_t ibin=1; ibin<=axis->GetNbins(); ibin++ ) {
    TString binLabel = axis->GetBinLabel(ibin);
    if ( ! binLabel.IsNull()) continue;
    axis->SetRange(1, ibin-1);
    return;
  }
}

//_____________________________________________________________________________
Int_t GetRunNumber(TString filePath)
{
  /// Get run number from file path
  TObjArray* array = filePath.Tokenize("/");
  array->SetOwner();
  TString auxString = "";
  Int_t runNum = -1;
  for ( Int_t ientry=0; ientry<array->GetEntries(); ientry++ ) {
    auxString = array->At(ientry)->GetName();
    if ( IsRunNum(auxString) ) {
      runNum = auxString.Atoi();
      break;
    }
  }
  delete array;
  
  if ( runNum < 0 ) {
    array = auxString.Tokenize("_");
    array->SetOwner();
    auxString = array->Last()->GetName();
    auxString.ReplaceAll(".root","");
    if ( IsRunNum(auxString) ) runNum = auxString.Atoi();
    delete array;
  }
  
  return runNum;
}

//_____________________________________________________________________________
Bool_t ChangeFilenames ( TObjArray &fileNameArray )
{
  /// Use custom output
  /// We used to perform the QA on the MTR chamber efficiency
  /// but since it is obtained form tracks matching with the tracker
  /// it is not that good for QA since we are dependent on the tracker status.
  /// In recent versions, the task also calculates the efficiency from all trigger tracks
  /// (including ghosts). Analyse this output instead.
  TString newBaseName = "trigChEff_ANY_Apt_allTrig.root";
  for ( Int_t ifile=0; ifile<fileNameArray.GetEntries(); ifile++ ) {
    TObjString* currObjString = static_cast<TObjString*>(fileNameArray.At(ifile));
    TString currFile = currObjString->GetString();
    TString baseName = gSystem->BaseName(currFile.Data());
    // In the old scripts, the run number is in the QA filename
    Int_t runNum = GetRunNumber(baseName);
    TString newFilename = "";
    if ( runNum < 0 ) {
      // New central script: the re-created trigger output is in the same directory
      newFilename = currFile;
      newFilename.ReplaceAll(baseName.Data(),newBaseName.Data());
    }
    else {
      // Old script. The re-creaated trigger output is in terminateRuns
      TString dirName = gSystem->DirName(currFile.Data());
      newFilename = Form("%s/terminateRuns/%i/%s",dirName.Data(),runNum,newBaseName.Data());
    }
    if ( gSystem->AccessPathName(newFilename.Data()) ) {
      printf("New output not found. Use the standard efficiency instead\n");
      return kFALSE;
    }
    else printf("Using re-built output in %s\n",newBaseName.Data());
    currObjString->SetString(newFilename);
  }
  return kTRUE;
}

//_____________________________________________________________________________
Double_t* GetProdErr(Double_t* effErr, Int_t exclude, Int_t nFactors = kNch)
{
  /// Error of product
  Double_t prod = 1.;
  Double_t relErr = 0., relProdErrSquare = 0.;
  for ( Int_t iprod=0; iprod<nFactors; iprod++ ) {
    if ( iprod == exclude ) continue;
    prod *= effErr[iprod];
    relErr = ( effErr[iprod] > kZero ) ? effErr[iprod+nFactors]/effErr[iprod] : 0.;
    relProdErrSquare += relErr*relErr;
    //printf("%f +- %f  ", effErr[iprod], effErr[iprod+nFactors]); // alBER TO CUT
  }
  Double_t* prodErr = new Double_t[2];
  prodErr[0] = prod;
  prodErr[1] = prod*TMath::Sqrt(relProdErrSquare);
  //printf("-> %f %f\n", prodErr[0], prodErr[1]); // REMEMBER TO CUT
  return prodErr;
}


//_____________________________________________________________________________
Double_t* GetConditionalEffErr(Double_t* effErr1, Double_t* effErr2, Double_t* effErrBoth, Int_t exclude = -1)
{
  /// Error on conditional efficiency
  Double_t* effErr = new Double_t[2*kNch];
  for ( Int_t ich=0; ich<kNch; ich++ ) {
    if ( ich == exclude ) {
      effErr[ich] = ( effErr1[ich] < 1. ) ? ( effErr2[ich] - effErrBoth[ich] ) / ( 1. - effErr1[ich] ) : 0.;
      effErr[ich+kNch] = 0;
      if ( effErr1[ich] < 1. ) {
        Double_t err2 = effErr2[ich+kNch] / ( 1. - effErr1[ich] );
        Double_t errBoth = effErrBoth[ich+kNch] / ( 1. - effErr1[ich] );
        Double_t err1 = effErr1[ich+kNch] * effErr[ich] / ( 1. - effErr1[ich] );
        effErr[ich+kNch] = TMath::Sqrt(err2*err2 + errBoth*errBoth + err1*err1);
      }
    }
    else {
      effErr[ich] = ( effErr1[ich] > kZero ) ? effErrBoth[ich]/effErr1[ich] : 0.;
      Double_t relErr1 = ( effErr1[ich] > kZero ) ? effErr1[ich+kNch]/effErr1[ich] : 0.;
      Double_t relErrBoth = ( effErrBoth[ich] > kZero ) ? effErrBoth[ich+kNch]/effErrBoth[ich] : 0.;
      effErr[ich+kNch] = effErr[ich] * TMath::Sqrt(relErr1*relErr1 + relErrBoth*relErrBoth);
    }
    //printf("%f  %f  %f -> %f\n", effErr1[ich], effErr2[ich], effErrBoth[ich], effErr[ich]); // REMEMBER TO CUT
  } // loop on chambers
  return effErr;
}


//_____________________________________________________________________________
Double_t* GetBinomial(Double_t* effErr1, Double_t* effErr2 = 0x0, Double_t* effErrBoth = 0x0)
{
  /// Binomial error
  Double_t effProd[4];
  Double_t defaultEffErr[2] = {1.,0.};
  Double_t* auxBinomial = 0x0;
  Double_t* currEffErr44 = 0x0;
  Double_t* effErrBinomial = new Double_t[2];
  effErrBinomial[0] = 0.;
  effErrBinomial[1] = 0.;
  
  for ( Int_t ich = -1; ich<kNch; ich++ ) {
    Double_t* currEffErr = GetProdErr(effErr1, ich);
    if ( ich >= 0 ) {
      currEffErr[0] = currEffErr[0] - currEffErr44[0];
      currEffErr[1] = TMath::Sqrt(currEffErr[1]*currEffErr[1] + currEffErr44[1]*currEffErr44[1]);
    }
    if ( effErr2 ) {
      Double_t* auxEffErr = GetConditionalEffErr(effErr1, effErr2, effErrBoth, ich);
      auxBinomial = GetBinomial(auxEffErr);
      delete auxEffErr;
    }
    for ( Int_t ival=0; ival<2; ival++ ) {
      effProd[2*ival] = currEffErr[ival];
      effProd[2*ival+1] = ( effErr2 ) ? auxBinomial[ival] : defaultEffErr[ival];
    }
    if ( ich < 0 ) currEffErr44 = currEffErr;
    else delete currEffErr;
    delete auxBinomial;
    
    Double_t* effErr = GetProdErr(effProd, -1, 2);
    //printf("%f * %f = %f\n", effProd[0], effProd[1], effErr[0]); // REMEMBER TO CUT
    effErrBinomial[0] += effErr[0];
    effErrBinomial[1] += effErr[1]*effErr[1];
    delete effErr;
  } // loop on chambers
  
  delete currEffErr44;
  
  effErrBinomial[1] = TMath::Sqrt(effErrBinomial[1]);
  
  return effErrBinomial;
}


//_____________________________________________________________________________
TH1* GetHisto(TString histoName, TFile* file, TList* histoList)
{
  /// Get histogram
  TH1* histo = 0x0;
  if ( histoList )
    histo = (TH1*)histoList->FindObject(histoName.Data());
  else
    histo = (TH1*)file->FindObjectAny(histoName.Data());
  
  return histo;
}

//_____________________________________________________________________________
Int_t GetEffIndex ( Int_t iel, Int_t icount, Int_t ich = -1 )
{
  /// Get efficienct histogram index
  if ( iel == 0 ) return icount;
  return 3 + 4*3*(iel-1) + 3*ich + icount;
}

//_____________________________________________________________________________
TList* GetOCDBList ( )
{
  /// Get list of CDB objetcs
  TString storageType = AliCDBManager::Instance()->GetDefaultStorage()->GetType();
  Bool_t isGrid = storageType.Contains("alien");
  TString baseFolder = AliCDBManager::Instance()->GetDefaultStorage()->GetBaseFolder();
  
  TList* outList = new TList();
  outList->SetOwner();
  TString dirName[3] = {"GlobalTriggerCrateConfig", "RegionalTriggerConfig", "LocalTriggerBoardMasks"};
  for ( Int_t idir=0; idir<3; idir++ ) {
    if ( isGrid ) {
      TGridResult *res = gGrid->Ls(Form("%s/MUON/Calib/%s", baseFolder.Data(), dirName[idir].Data()));
      if (!res) return 0x0;
      for ( Int_t ires=0; ires<res->GetEntries(); ires++ ) {
        TString currFile = static_cast<TMap*>(res->At(ires))->GetValue("name")->GetName();
        outList->Add(new TObjString(currFile));
      }
    }
    else {
      TString fileListStr = gSystem->GetFromPipe(Form("ls %s/MUON/Calib/%s", baseFolder.Data(), dirName[idir].Data()));
      TObjArray* fileList = fileListStr.Tokenize("\n");
      for ( Int_t ires=0; ires<fileList->GetEntries(); ires++ ) {
        TString currFile = fileList->At(ires)->GetName();
        outList->Add(new TObjString(currFile));
      }
      delete fileList;
    }
  }
  return outList;
}

//_____________________________________________________________________________
Bool_t IsOCDBChanged ( Int_t currRun, Int_t previousRun, TList* fileList )
{
  /// Check if the OCDB object is changed w.r.t. the previous run
  if ( ! fileList ) return kTRUE;
  for ( Int_t ifile=0; ifile<fileList->GetEntries(); ifile++ ) {
    TString filename = static_cast<TObjString*>(fileList->At(ifile))->GetString();
    filename.ReplaceAll("Run","");
    TObjArray* array = filename.Tokenize("_");
    Int_t firstRun = static_cast<TObjString*>(array->At(0))->GetString().Atoi();
    Int_t lastRun = static_cast<TObjString*>(array->At(1))->GetString().Atoi();
    delete array;
    Bool_t isCurrRunInside = ( currRun >= firstRun && currRun <= lastRun );
    Bool_t isPreviousRunInside = ( previousRun >= firstRun && previousRun <= lastRun );
    if ( isCurrRunInside != isPreviousRunInside ) return kTRUE;
  }
  return kFALSE;
}

//_____________________________________________________________________________
void TrigEffTrending(TObjArray runNumArray, TObjArray fileNameArray, TList& outCanList, TList& outList)
{
  /// Get the efficiency vs. run number
  TString elementName[3] = { "Chamber", "RPC", "Board" };
  TString countTypeName[4] = { "allTracks", "bendPlane", "nonBendPlane", "bothPlanes" };

  TString filename = "", effName = "", effTitle = "";

  SetMyStyle();
  Double_t effValues[3][2*kNch];
  const Int_t kNgraphs = kNch*3*2+3;
  TObjArray effList(kNgraphs);
  effList.SetOwner();
  const Int_t kNeffVsRun = kNgraphs+1;
  TObjArray effVsRunList(kNeffVsRun);
  
  effName = "totalEffEvolution";
  effTitle = "Multinomial probability of firing at least 3/4 chambers";
  TH1D* totalEff = new TH1D(effName.Data(), effTitle.Data(), 1, 0., 1.);
  effVsRunList.AddAt(totalEff, kNeffVsRun-1);

  TString runNumString = "";
  for ( Int_t irun=0; irun<runNumArray.GetEntries(); irun++ ) {
    effList.Clear();
    runNumString = runNumArray.At(irun)->GetName();

    // Search corresponding file (for sorting)
    for ( Int_t ifile=0; ifile<fileNameArray.GetEntries(); ifile++ ) {
      filename = fileNameArray.At(ifile)->GetName();
      if ( filename.Contains(runNumString.Data()) ) break;
    }

    if ( filename.Contains("alien://") && ! gGrid ) gGrid->Connect("alien://");
    
    //
    // First get the list of efficiency graphs
    //
    
    // Chamber efficiency
    TFile* file = TFile::Open(filename.Data());
    if ( ! file ) {
      printf("Warning: cannot find %s\n", filename.Data());
      continue;
    }
    
    TList* trigEffList = (TList*)file->FindObjectAny("triggerChamberEff");
    if ( ! trigEffList ) printf("Warning: histo list not found in %s. Check directly in file\n", filename.Data());
    if ( trigEffList->GetEntries() == 0 ) {
      printf("Warning: empty trigger list in file %s. Probably no MUON info there. Skip.\n", filename.Data());
      continue;
    }
    
    TH1* histoDen = 0x0;
    for ( Int_t icount=0; icount<AliMUONTriggerEfficiencyCells::kNcounts; icount++ ) {
      effName = countTypeName[icount] + "Count" + elementName[0];
      if ( icount == 0 ) {
        histoDen = GetHisto(effName, file, trigEffList);
        continue;
      }
      
      TH1* histoNum = GetHisto(effName, file, trigEffList);
      TGraphAsymmErrors* graph = new TGraphAsymmErrors(histoNum, histoDen,"e0");
      effName.ReplaceAll("Count","Eff");
      graph->SetName(effName.Data());
      effList.AddAt(graph, GetEffIndex(0, icount-1));
    }
    file->Close();
  
    if ( ! histoDen ) {
      printf("Error: cannot find histograms in file %s. Skip to next\n", filename.Data());
      continue;
    }
  
    // RPC/board efficiency
    AliMUONTriggerChamberEfficiency trigChEff(filename);
    for ( Int_t iel=1; iel<3; iel++ ) {
      for ( Int_t ich=0; ich<kNch; ich++ ) {
        for ( Int_t icount=0; icount<AliMUONTriggerEfficiencyCells::kNcounts-1; icount++ ) {
          TObject* obj = trigChEff.GetEffObject(2-iel, icount, ich);
          effList.AddAt(obj->Clone(Form("%s_cloned",obj->GetName())), GetEffIndex(iel, icount, ich));
        }
      }
    }
    
    // Fill efficiency vs run
    for ( Int_t iel=0; iel<3; iel++ ) {
      for ( Int_t ich=0; ich<kNch; ich++ ) {
        for ( Int_t icount=0; icount<AliMUONTriggerEfficiencyCells::kNcounts-1; icount++ ) {
          TGraphAsymmErrors* graph = static_cast<TGraphAsymmErrors*>(effList.At(GetEffIndex(iel, icount, ich)));
          Int_t nPoints = ( iel == 0 ) ? 1 : graph->GetN();
          for ( Int_t ipoint=0; ipoint<nPoints; ipoint++ ) {
            Int_t currPoint = ( iel == 0 ) ? ich : ipoint;
            Double_t xpt, ypt;
            graph->GetPoint(currPoint, xpt, ypt);
            effValues[icount][ich] = ypt;
            Int_t ihisto = GetEffIndex(iel,icount,ich);
            TH2* effHisto = static_cast<TH2*>(effVsRunList.At(ihisto));
            if ( ! effHisto ) {
              effName = Form("effEvolution%s%s", countTypeName[icount+1].Data(), elementName[iel].Data());
              effTitle = Form("Trigger chamber efficiency vs run");
              if ( iel>0 ) {
                effName += Form("Ch%i", 11+ich);
                effTitle += Form(" for chamber %i", 11+ich);
              }
              effHisto = new TH2D(effName.Data(), effTitle.Data(), 1, 0., 1., graph->GetN(), xpt-0.5, xpt-0.5+(Double_t)graph->GetN());
              effVsRunList.AddAt(effHisto, ihisto);
            }
            Int_t currBin = effHisto->Fill(runNumString.Data(), xpt, ypt);
            Double_t err = 0.5*(graph->GetErrorYlow(ipoint) + graph->GetErrorYhigh(ipoint));
            Int_t binx, biny, binz;
            effHisto->GetBinXYZ(currBin, binx, biny, binz);
            effHisto->SetBinError(binx, biny, err);
            effValues[icount][ich+kNch] = err;
          } // loop on points
        } // loop on counts
      } // loop on chambers
      if ( iel > 0 ) continue;
      Double_t* binomialEff = GetBinomial(effValues[0], effValues[1], effValues[2]);
      Int_t currBin = totalEff->Fill(runNumString, binomialEff[0]);
      // CAVEAT!!!!
      // Well, error calculation of the binomial efficiency is a mess...
      // Sometimes it happens that efficiency + error > 1.
      // In that case reduce the error.
      totalEff->SetBinError(currBin, TMath::Min(binomialEff[1], 1.-binomialEff[0]));
      delete binomialEff;
    } // loop on detection elements
  } // loop on runs
  
  // Set correct range (do not show last empty bins)
  for ( Int_t ihisto=0; ihisto<effVsRunList.GetEntries(); ihisto++ ) {
    TH1* histo = static_cast<TH1*>(effVsRunList.At(ihisto));
    if ( ! histo ) continue;
    SetRunAxisRange(histo->GetXaxis());
    outList.Add(histo);
    //histo->GetXaxis()->SetLabelSize(0.03);
  }

  TString canName = "totalEff";
  TCanvas* can = new TCanvas(canName.Data(), canName.Data(), 200, 10, 600, 600);
  TH1* totEff = (TH1*)effVsRunList.At(kNeffVsRun-1);
  totEff->GetYaxis()->SetRangeUser(0.9,1.05);
  totEff->GetYaxis()->SetTitle("Probability to satisfy trigger conditions (3/4)");
  totEff->SetStats(kFALSE);
  totEff->DrawCopy();
  outCanList.Add(can);

  Int_t color[3] = {kBlack, kRed, kBlue};
  Int_t markStyle[3] = {20, 24, 26};
  TLegend* leg = 0x0;

  for ( Int_t ich=0; ich<kNch; ich++ ) {
    canName = Form("trigEffCh%i", 11+ich);
    can = new TCanvas(canName.Data(), canName.Data(), 200, 10, 600, 600);
    can->SetGridy();
    leg = new TLegend(0.6, 0.2, 0.9, 0.4);
    leg->SetBorderSize(1);
    //can->Divide(2,2);
    TString drawOpt = "e";
    for(Int_t icount=0; icount<AliMUONTriggerEfficiencyCells::kNcounts-1; icount++) {
      //can->cd(icount+1);
      TH2* histo = static_cast<TH2*>(effVsRunList.At(GetEffIndex(0, icount)));
      if ( ! histo ) continue;
      TH1* chEff = histo->ProjectionX(Form("effEvolutionCh%i",11+ich), ich+1, ich+1);
      chEff->SetTitle(Form("%s for chamber %i", histo->GetTitle(), 11+ich));
      chEff->GetYaxis()->SetRangeUser(0.9,1.);
      chEff->SetStats(kFALSE);
      chEff->GetYaxis()->SetTitle("Trigger chamber efficiency");
      TH1* copyEff = chEff->DrawCopy(drawOpt.Data());
      copyEff->SetLineColor(color[icount]);
      copyEff->SetMarkerColor(color[icount]);
      copyEff->SetMarkerStyle(markStyle[icount]);
      leg->AddEntry(copyEff, countTypeName[icount+1].Data(), "lp");
      drawOpt = "esame";
    } // loop on counts
    leg->Draw("same");
    outCanList.Add(can);
  } // loop on chambers
  
  for ( Int_t iel=1; iel<3; iel++ ) {
    for ( Int_t ich=0; ich<kNch; ich++ ) {
      Int_t icount = AliMUONTriggerEfficiencyCells::kBothPlanesEff; // Just plot the efficiency for both
//      for ( Int_t icount=0; icount<AliMUONTriggerEfficiencyCells::kNcounts-1; icount++ ) {
        canName = Form("trigEff%sCh%i", elementName[iel].Data(), 11+ich);
        can = new TCanvas(canName.Data(), canName.Data(), 200, 10, 600, 600);
        can->SetRightMargin(0.14);
        TH2* histo = static_cast<TH2*>(effVsRunList.At(GetEffIndex(iel, icount,ich)));
        if ( ! histo ) continue;
        histo->SetStats(kFALSE);
        histo->GetYaxis()->SetTitle(elementName[iel].Data());
        histo->DrawCopy("COLZ");
//      } // loop on counts
      outCanList.Add(can);
    } // loop on chambers
  } // loop on detection element type
}

//_____________________________________________________________________________
void MaskTrending ( TObjArray runNumArray, TString defaultStorage, TList& outCanList, TList& outList )
{
  /// Get the masks vs. run number
  if ( defaultStorage.Contains("alien://") || defaultStorage.Contains("raw://") ) {
    if ( ! gGrid ) TGrid::Connect("alien://");
    if ( ! gGrid ) {
      printf("Error: Problem connetting to grid: nothing done");
      return;
    }
  }
  
  
  TObjArray maskedList(8);
  TObjArray auxList(8);
  auxList.SetOwner();
  TString histoName = "", histoTitle = "";
  for(Int_t icath=0; icath<2; icath++){
    TString cathName = ( icath==0 ) ? "bendPlane" : "nonBendPlane";
    for(Int_t ich=0; ich<kNch; ich++){
      histoName = Form("%sMaskCh%i", cathName.Data(), 11+ich);
      histoTitle = Form("Chamber %i - %s: fraction of masked channels", 11+ich, cathName.Data());
      TH2* histo = new TH2D(histoName.Data(), histoTitle.Data(),1,0.,1., 234, 0.5, 234. + 0.5);
      histo->GetYaxis()->SetTitle("Board Id");
      histo->SetOption("COLZ");
      Int_t imask = 2*ich + icath;
      maskedList.AddAt(histo, imask);
      auxList.AddAt(histo->Clone(Form("%s_aux",histoName.Data())), imask);
    } // loop on chambers
  } // loop on cathodes
  
  TArrayS xyPatternAll[2];
  for(Int_t icath=0; icath<2; icath++){
    xyPatternAll[icath].Set(kNch);
    xyPatternAll[icath].Reset(0xFFFF);
  }
  
  if ( ! AliCDBManager::Instance()->IsDefaultStorageSet() ) AliCDBManager::Instance()->SetDefaultStorage(defaultStorage.Data());
  TList* ocdbFileList = 0x0;
  Int_t previousRun = -1;
  AliMUONDigitMaker* digitMaker = 0x0;
  AliMUONDigitStoreV2R digitStore;
  
  AliMUONCalibrationData* calibData = 0x0;
  AliMUONTriggerUtilities* trigUtilities = 0x0;
  for ( Int_t irun=0; irun<runNumArray.GetEntries(); irun++ ) {
    TString runNumString = runNumArray.At(irun)->GetName();
    Int_t runNumber = runNumString.Atoi();
    
    if ( IsOCDBChanged(runNumber, previousRun, ocdbFileList) ) {
      AliCDBManager::Instance()->SetRun(runNumber);
      
      if ( ! digitMaker ) {
        digitMaker = new AliMUONDigitMaker(kFALSE);
        // Create a store with all digits in trigger
        for ( Int_t iboard=1; iboard<=234; iboard++ ) {
          digitMaker->TriggerDigits(iboard, xyPatternAll, digitStore, kFALSE);
        }
      }
      
      if ( ! ocdbFileList ) ocdbFileList = GetOCDBList();
  
      delete calibData;
      calibData = new AliMUONCalibrationData (runNumber);
      delete trigUtilities;
      trigUtilities = new AliMUONTriggerUtilities (calibData);
    }
    
    previousRun = runNumber;
    
    TIter next(digitStore.CreateIterator());
    AliMUONVDigit* dig = 0x0;
    while ( ( dig = static_cast<AliMUONVDigit*>(next()) ) ) {
      Int_t icath = dig->Cathode();
      Int_t detElemId = dig->DetElemId();
      Int_t ich = detElemId/100-11;
      Int_t iboard = dig->ManuId();
      Int_t imask = 2*ich + icath;
      static_cast<TH2*>(auxList.At(imask))->Fill(runNumString.Data(),iboard,1.);
      static_cast<TH2*>(maskedList.At(imask))->Fill(runNumString.Data(),iboard,(Double_t)trigUtilities->IsMasked(*dig));
    }
  } // loop on runs
  delete calibData;
  delete trigUtilities;
  delete digitMaker;

  TString canName = "";
  for ( Int_t imask=0; imask<maskedList.GetEntries(); imask++ ) {
    TH2* histo = static_cast<TH2*>(maskedList.At(imask));
    histo->Divide(static_cast<TH2*>(auxList.At(imask)));
    SetRunAxisRange(histo->GetXaxis());
    outList.Add(histo);
    
    canName = Form("%sCan", histo->GetName());
    TCanvas* can = new TCanvas(canName.Data(), canName.Data(), 200, 10, 600, 600);
    can->SetRightMargin(0.14);
    histo->SetStats(kFALSE);
    histo->DrawCopy("COLZ");
    outCanList.Add(can);
  }
}

//_____________________________________________________________________________
Bool_t CheckPattern ( TString trigName, TObjArray* keepArray, TObjArray* rejectArray )
{
  /// Check pattern
  for ( Int_t ipat=0; ipat<rejectArray->GetEntries(); ++ipat ) {
    if ( trigName.Contains(rejectArray->At(ipat)->GetName() ) ) return kFALSE;
  } // loop on reject pattern
  
  for ( Int_t ipat=0; ipat<keepArray->GetEntries(); ++ipat ) {
    if ( trigName.Contains(keepArray->At(ipat)->GetName() ) ) return kTRUE;
  } // loop on keep pattern
  
  return ( keepArray->GetEntries() == 0 ) ? kTRUE : kFALSE;
}

//_____________________________________________________________________________
TObjArray* BuildListOfTrigger ( const TObjArray* triggerArray, TString keepPattern = "", TString rejectPattern="OTHER,TRUE,PHI,ANY,EMC,-ACE-,-ABCE-,WU,MUP,SPI,SHM" )
{
  /// Build list of trigger classes
  TObjArray* selectedList = new TObjArray();
  selectedList->SetOwner();
  TObjArray* rejectArray = rejectPattern.Tokenize(",");
  TObjArray* keepArray = keepPattern.Tokenize(",");
  
  for ( Int_t iTrig = 0; iTrig < triggerArray->GetEntries(); iTrig++ ){
    TString currTrigName = ((TObjString*)triggerArray->At(iTrig))->GetName();
    if ( CheckPattern(currTrigName, keepArray, rejectArray) ) selectedList->AddLast(new TObjString(currTrigName.Data()));
  }

  delete rejectArray;
  delete keepArray;

  return selectedList;

}

//_____________________________________________________________________________
TString FindCorrespondingTrigger ( TString checkTrigger, TObjArray* triggerArray )
{
  /// Find trigger from pattern
  TString foundName = "";
  for ( Int_t iTrig = 0; iTrig < triggerArray->GetEntries(); iTrig++ ){
    TString currTrigName = ((TObjString*)triggerArray->At(iTrig))->GetName();
    TObjArray* array = currTrigName.Tokenize("-");
    TString collisionType = array->At(1)->GetName();
    delete array;
    collisionType.Append("-");
    collisionType.Prepend("-");
    if ( checkTrigger.Contains(collisionType.Data()) ) {
      foundName = currTrigName;
      break;
    }
  }

  return foundName;
}
  
//_____________________________________________________________________________
void ScalerTrending ( TObjArray runNumArray, TString mergedFileName, TString defaultStorage, TList& outCanList, TList& outList )
{
  /// Get the scalers vs. run number
  if ( defaultStorage.Contains("alien://") || defaultStorage.Contains("raw://") ) {
    if ( ! gGrid ) TGrid::Connect("alien://");
    if ( ! gGrid ) {
      printf("Error: Problem connetting to grid: nothing done");
      return;
    }
  }
  
  if ( ! AliCDBManager::Instance()->IsDefaultStorageSet() ) AliCDBManager::Instance()->SetDefaultStorage(defaultStorage.Data());

  //trigger count from ESDs
  TFile *file = TFile::Open(mergedFileName.Data());
  AliCounterCollection* ccol = (AliCounterCollection*)((TDirectoryFile*)file->FindObjectAny("MUON_QA"))->FindObjectAny("eventCounters");
  
  //Build the trigger list for trigger with muon only in readout and min. bias triggers
  TString triggerListName = ccol->GetKeyWords("trigger");
  
  TObjArray selectedTriggerArray, selectedL0TriggerArray;
  selectedTriggerArray.SetOwner();
  selectedL0TriggerArray.SetOwner();
  
  const Int_t nScaler = 3;
  TString sScaler[nScaler] = {"L0B","L2A","L0BRATE"};
  enum eScaler {kL0B = 0, kL2A=1, kL0BRATE=2};
  Float_t maxScaler[nScaler] = {1e8,1e7,1e6};
  TObjArray hFromQA;
  TObjArray hFromScalers; 
  TObjArray hOutput;
  
  
  TString sHistName, sHistNameFull, sTitleName;
  Int_t nRuns = runNumArray.GetEntries();

  //
  //Fill histos for Scalers and QA
  //
  //loop on run list
  for ( Int_t iRun = 0; iRun < runNumArray.GetEntries(); iRun++ ) {
    
    TString sRunNr = ((TObjString*)runNumArray.At(iRun))->GetString();
    Int_t runNr = sRunNr.Atoi();
    AliAnalysisTriggerScalers triggerScaler(runNr);
    AliTriggerConfiguration* tc = static_cast<AliTriggerConfiguration*>(triggerScaler.GetOCDBObject("GRP/CTP/Config",runNr));
    const TObjArray& trClasses = tc->GetClasses();
    
    Int_t ibin = iRun+1;
    
    for ( Int_t itype=0; itype<2; itype++ ) {
      TObjArray* currSelectedList = ( itype == 0 ) ? &selectedTriggerArray : &selectedL0TriggerArray;
      TString matchTrig = ( itype == 0 ) ? "" : "C0TVX";
      TObjArray* selectedTrigArrayForRun = BuildListOfTrigger(&trClasses, matchTrig);
      
      //loop on trigger list
      for ( Int_t iTrig = 0; iTrig < selectedTrigArrayForRun->GetEntries(); iTrig++ ) {
      
        TString currTrigName = selectedTrigArrayForRun->At(iTrig)->GetName();
        if ( itype == 0 && ! triggerListName.Contains(currTrigName.Data()) ) continue;
        if ( ! currSelectedList->FindObject(currTrigName.Data()) ) currSelectedList->Add(new TObjString(currTrigName));
        
        //loop on scaler list
        for ( Int_t iScaler = 0; iScaler < nScaler; iScaler++ ) {
        
          if ( itype == 1 && iScaler != kL0B ) continue;
          
          //from Scalers
          TGraph* graph = triggerScaler.PlotTrigger(currTrigName.Data(),sScaler[iScaler].Data());
        
          sHistName = Form("%s_%s",currTrigName.Data(),sScaler[iScaler].Data());
          sHistNameFull = Form("Scalers_%s",sHistName.Data());
          
          TH1* hist = (TH1*) hFromScalers.FindObject(sHistNameFull);
          if ( ! hist ) {
            hist = new TH1D(sHistNameFull,sHistName,nRuns,1.,1.+(Double_t)nRuns);
            hist->SetDirectory(0);
            hist->SetMinimum(1);
            hist->SetMaximum(maxScaler[0]);
            hFromScalers.AddLast(hist);
            hOutput.AddLast(hist);
            if ( iScaler == kL2A ) {
              sHistNameFull = "QA_" + sHistName;
              hFromQA.AddLast(hist->Clone(sHistNameFull.Data()));
            }
          }
          Double_t *tab = (Double_t*) graph->GetY();
          if ( tab ) hist->SetBinContent(ibin,tab[0]);
          hist->GetXaxis()->SetBinLabel(ibin,sRunNr.Data());
          delete graph;
          
          //from QA
          if ( iScaler != kL2A ) continue;
          TH1* histCounters = static_cast<TH1*>(ccol->Get("run",Form("run:%s/trigger:%s",sRunNr.Data(),currTrigName.Data())));
          sHistNameFull = sHistNameFull = "QA_" + sHistName;
          hist = (TH1*) hFromQA.FindObject(sHistNameFull);
          if ( histCounters ) hist->SetBinContent(ibin,histCounters->GetSumOfWeights());
          hist->GetXaxis()->SetBinLabel(ibin,sRunNr.Data());
          delete histCounters;
        }//end loop on scaler list
      }//end loop on trigger list
    } // end loop on type
  }//end loop on run list
  
  
  if ( selectedTriggerArray.GetEntries() == 0 ) {
    printf("No trigger selected from trigger list %s\n",triggerListName.Data());
    return;
  }
  printf("Nr of triggers selected %i\n",selectedTriggerArray.GetEntries());
  
  printf("Nr of T0 triggers selected %i\n",selectedL0TriggerArray.GetEntries());
  
  //Set options for QA and Scalers histos

  for ( Int_t itype=0; itype<2; itype++ ) {
    TObjArray* currList = ( itype == 0 ) ? &hFromScalers : &hFromQA;
    for ( Int_t ihisto=0; ihisto<currList->GetEntriesFast(); ihisto++ ) {
      TH1* histo = static_cast<TH1*> ( currList->At(ihisto) );
      if (!histo) continue;
      // Write run number to each bin
      for ( Int_t iRun = 0; iRun < runNumArray.GetEntries(); iRun++ ) {
        TString sRunNr = ((TObjString*)runNumArray.At(iRun))->GetString();
        Int_t ibin = iRun+1;
        TString binLabel = histo->GetXaxis()->GetBinLabel(ibin);
        if ( ! binLabel.IsNull() ) continue;
        histo->GetXaxis()->SetBinLabel(ibin,sRunNr.Data());
      }
      histo->SetStats(kFALSE);
    }
  }

  
  //Loop on histos from scalers and QA and create resulting histos from scalers
  const Int_t nHisto = 3;
  TString sHisto[nHisto] = {"L0BoverL0BC0TVX","L2AoverL0B","L2AQAoverSCALERS"};
  TString sTitleHisto[nHisto] = {"L0B trigger / L0BC0TVX","L2A / L0B","L2A from QA / L2A from SCALERS"};
  //  TString sHisto[nHisto] = {"L2AoverL0B","L2AQAoverSCALERS"};
  
  //loop on trigger list
  for ( Int_t iTrig = 0; iTrig < selectedTriggerArray.GetEntries(); iTrig++ ) {

    sHistNameFull = Form("Scalers_%s_L0B",((TObjString*) selectedTriggerArray.At(iTrig))->GetName());
    TH1* histo1 = static_cast<TH1*> ( hFromScalers.FindObject(sHistNameFull) );
    if (!histo1) continue;
    
    
    //C0TVX
    TString sTrig = ( (TObjString*) selectedTriggerArray.At(iTrig) )->GetName();
    TString sL0Trig = FindCorrespondingTrigger(sTrig, &selectedL0TriggerArray);

    sHistNameFull = Form("Scalers_%s_L0B",sL0Trig.Data());

    TH1* histo0 = static_cast<TH1*> ( hFromScalers.FindObject(sHistNameFull) );
    if ( histo0 ) {
      sHistNameFull = Form("%s_%s",sHisto[0].Data(),((TObjString*) selectedTriggerArray.At(iTrig))->GetName());
      TH1* histo10 = (TH1*) histo1->Clone(sHistNameFull);
      histo10->SetTitle(sTitleHisto[0].Data());
      histo10->Sumw2();
      histo10->Divide(histo0);
      histo10->SetMaximum(10);
      histo10->SetMinimum(1e-5);
      //outList.Add(histo10);
      hOutput.AddLast(histo10);
      //outList.Add(histo0);
      //outList.Add(histo1);
    }

    //DEADTIME    
    sHistNameFull = Form("Scalers_%s_L2A",((TObjString*) selectedTriggerArray.At(iTrig))->GetName());
    TH1* histo2 = static_cast<TH1*> ( hFromScalers.FindObject(sHistNameFull) );
    if (!histo2) continue;
    
    sHistNameFull = Form("%s_%s",sHisto[1].Data(),((TObjString*) selectedTriggerArray.At(iTrig))->GetName());
    TH1* histo3 = (TH1*) histo2->Clone(sHistNameFull);
    histo3->SetTitle(sTitleHisto[1]);
    histo3->Sumw2();
    histo3->Divide(histo1);
    histo3->SetMaximum(1.2);
    histo3->SetMinimum(1e-5);
    //outList.Add(histo3);
    hOutput.AddLast(histo3);
    
    //QA over Scalers
    sHistNameFull = Form("QA_%s_L2A",((TObjString*) selectedTriggerArray.At(iTrig))->GetName());
    TH1* histo4 = static_cast<TH1*> ( hFromQA.FindObject(sHistNameFull) );
    if (!histo4) continue;
    
    sHistNameFull = Form("%s_%s",sHisto[2].Data(),((TObjString*) selectedTriggerArray.At(iTrig))->GetName());
    TH1* histo5 = (TH1*) histo4->Clone(sHistNameFull);
    histo5->SetTitle(sTitleHisto[2]);
    histo5->Sumw2();
    histo5->Divide(histo2);
    histo5->SetMaximum(1.2);
    histo5->SetMinimum(5e-1);
    //outList.Add(histo5);
    hOutput.AddLast(histo5);
  }
  
  // Plot all on canvases (only canvases will be saved)
  const Int_t nCanvases = nScaler + nHisto;
  TString sCanvases[nCanvases];
  for (Int_t iScaler = 0; iScaler < nScaler; iScaler++) sCanvases[iScaler] = sScaler[iScaler];
  for (Int_t iHisto = 0; iHisto < nHisto; iHisto++) sCanvases[nScaler+iHisto] = sHisto[iHisto];
  
  //loop on canvases
  for ( Int_t iCan = 0; iCan < nCanvases; iCan++) {
    TCanvas* canvas = new TCanvas(sCanvases[iCan],sCanvases[iCan],200,10,600,600);
    TLegend* leg  = new TLegend(0.72,0.7,0.9,0.85);
    leg->SetBorderSize(1);
    if ( iCan != 4 ) canvas->SetLogy();
    TString optDraw = "e";
    
    //loop on trigger list
    Int_t icolor = 1;
    for ( Int_t iTrig = 0; iTrig < selectedTriggerArray.GetEntries(); iTrig++ ) {
      
      if ( iCan < nScaler ) sHistNameFull = Form("Scalers_%s_%s",selectedTriggerArray.At(iTrig)->GetName(),sCanvases[iCan].Data());
      else sHistNameFull = Form("%s_%s",sCanvases[iCan].Data(),selectedTriggerArray.At(iTrig)->GetName());
      TH1* histo1 = static_cast<TH1*> ( hOutput.FindObject(sHistNameFull) );
      if (!histo1) continue;
      
      if ( icolor == 10 ) icolor++;
      histo1->SetLineColor(icolor++);
      histo1->Draw(optDraw);
      optDraw = "esame";
      
      leg->AddEntry(histo1,selectedTriggerArray.At(iTrig)->GetName(),"l");
    }
    
    leg->Draw();
    outList.Add(canvas);
    outCanList.Add(canvas);
  }
  
  file->Close();
}

//_____________________________________________________________________________
void trigEffQA(TString fileListName, TString outFilename = "", TString defaultStorage = "raw://", Bool_t doScalers = kFALSE, TString trackerQAmergedOut="QAresults_merged.root")
{
  /// Main function
  ifstream inFile(fileListName.Data());
  TObjArray fileNameArray, runNumArray;
  fileNameArray.SetOwner();
  runNumArray.SetOwner();
  TString currString = "";
  if (inFile.is_open()) {
    while (! inFile.eof() ) {
      currString.ReadLine(inFile); // Read line
      if ( ! currString.Contains(".root") ||
          currString.BeginsWith("#") ) continue;
      fileNameArray.AddLast(new TObjString(currString.Data()));
      Int_t runNum = GetRunNumber(currString);
      runNumArray.AddLast(new TObjString(Form("%i",runNum)));
    }
    inFile.close();
  }
  else {
    printf("Fatal: cannot open input file %s\n",fileListName.Data());
    return;
  }
  
  runNumArray.Sort();
  
  // Instead of using the efficiency stored in the QA output
  // search for the new efficiency produced with trigger tracks only
  TObjArray tmpArray = fileNameArray;
  TObjArray* finalFileNameArray =  ChangeFilenames(tmpArray) ? &tmpArray : &fileNameArray;
  
  TList outCanList, outList;
  TrigEffTrending(runNumArray, *finalFileNameArray, outCanList, outList);
  if ( ! defaultStorage.IsNull() ) MaskTrending(runNumArray, defaultStorage, outCanList, outList);
  if ( ! defaultStorage.IsNull() && doScalers ) {
    if ( gSystem->AccessPathName(trackerQAmergedOut.Data()) ) {
      printf("Warning: cannot perform scaler trending:\n merged QA from tracker\n  %s\n  does not exist\n",trackerQAmergedOut.Data());
    }
    else {
      ScalerTrending(runNumArray, trackerQAmergedOut, defaultStorage, outCanList, outList);
    }
  }
  
  if ( outFilename.IsNull() ) return;
  
  TString outCanName = outFilename;
  outCanName.ReplaceAll(".root",".pdf");
  for ( Int_t ican=0; ican<outCanList.GetEntries(); ican++ ) {
    TString canName = outCanName;
    if ( ican == 0 ) canName.Append("("); // open pdf file
    else if ( ican == outCanList.GetEntries()-1 ) canName.Append(")"); // close pdf file
    static_cast<TCanvas*>(outCanList.At(ican))->Print(canName.Data());
  }
  // There is a bug when creating a pdf
  // So create a ps and then convert via epstopdf
  if ( outCanName.Contains(".ps") || outCanName.Contains(".eps") ) {
    gSystem->Exec(Form("epstopdf %s", outCanName.Data()));
    gSystem->Exec(Form("rm %s", outCanName.Data()));
  }

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