#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <iterator>
#include <limits>

#include "SFramework/TSBreakdownCalculator.h"
#include "SFramework/TSUtils.h"

#include "TKey.h"
#include "TMath.h"
#include "Math/MinimizerOptions.h"
#include "RooNLLVar.h"
#include "RooAbsPdf.h"
#include "RooDataSet.h"
#include "RooFitResult.h"
#include "RooRealVar.h"
#include "Math/ProbFuncMathCore.h"
#include "Math/QuantFuncMathCore.h"
#include "TStopwatch.h"

#include "QFramework/TQStringUtils.h"
#include "QFramework/TQIterator.h"

// #define _DEBUG_

#include "QFramework/TQLibrary.h"

ClassImp(TSBreakdownCalculator)

#define epsilon std::numeric_limits<double>::epsilon()
#define inf std::numeric_limits<double>::infinity()
#define nan std::numeric_limits<double>::quiet_NaN()

//__________________________________________________________________________________|___________

TSBreakdownCalculator::TSBreakdownCalculator(RooWorkspace * ws, TQFolder* snapshots) : TSStatisticsCalculator("TSBreakdownCalculator",ws,snapshots) {
}


//__________________________________________________________________________________|___________

TSBreakdownCalculator::~TSBreakdownCalculator() {
}


//__________________________________________________________________________________|___________

void TSBreakdownCalculator::info(TString message) {

  std::cout << "SFramework/TSBreakdownCalculator: " << message.Data() << std::endl;
}

//__________________________________________________________________________________|___________

void TSBreakdownCalculator::storeUncertainty(const RooRealVar* poi, TQFolder * uncond) {
  TString namePOI = poi->GetName();
  TQFolder * varFolder = uncond->getFolder(namePOI + "+");
  varFolder->setTagDouble("val",     poi->getVal());
  varFolder->setTagDouble("errHigh", fabs(poi->getAsymErrorHi()) > epsilon ? poi->getAsymErrorHi() :       poi->getError() );
  varFolder->setTagDouble("errLow",  fabs(poi->getAsymErrorLo()) > epsilon ? poi->getAsymErrorLo() : -fabs(poi->getError()) );
}

	
//__________________________________________________________________________________|___________

void TSBreakdownCalculator::storeUncertainties(const RooAbsCollection& pois, TQFolder * uncond) {
  // loop over POIs and store unconditional uncertainties
  ROOFIT_ITERATE(pois,RooAbsArg,arg){
    RooRealVar * var = dynamic_cast<RooRealVar*>(arg);
    storeUncertainty(var,uncond);
  }
}

//__________________________________________________________________________________|___________

void TSBreakdownCalculator::compareUncertainties(const TString& name, const RooAbsCollection* pois, TQFolder* uncond, TQFolder * cond, TQFolder* target) {
  // loop over POIs and determine uncertainties
  ROOFIT_ITERATE(*pois,RooAbsArg,var){
    TString namePOI = var->GetName();
    int nOK;
    
    // get unconditional uncertainties
    Double_t val_uncond = 0.;
    Double_t errHi_uncond = 0.;
    Double_t errLo_uncond = 0.;
    nOK=2;
    if(uncond){
      TQFolder * poi_uncond = uncond->getFolder(namePOI);
      if (!poi_uncond) {
        warn(TString::Format("POI '%s' not contained in fit result '%s'",namePOI.Data(),uncond->GetName()));
        continue;
      }
      double err_uncond = poi_uncond->getTagDoubleDefault("err",0.);
      errHi_uncond = err_uncond;
      errLo_uncond = err_uncond;      
      if(!poi_uncond->getTagDouble("val", val_uncond)){
        error(TString::Format("unable to obtain value of '%s' from unconditional fit result!",namePOI.Data()));
      }
      if(!poi_uncond->getTagDouble("errHigh", errHi_uncond)){
        error(TString::Format("unable to obtain '+' error of '%s' from unconditional fit result!",namePOI.Data()));
        nOK--;
      }
      if(!poi_uncond->getTagDouble("errLow", errLo_uncond)){
        error(TString::Format("unable to obtain '-' error of '%s' from unconditional fit result!",namePOI.Data()));
        nOK--;
      }

      if(fabs(errHi_uncond) < epsilon){
        warn(TString::Format("'+' error of '%s' from unconditional fit result is zero!",namePOI.Data()));
        errHi_uncond = fabs(errLo_uncond);
        errLo_uncond = -fabs(errLo_uncond);        
        nOK--;
      }
      if(fabs(errLo_uncond) < epsilon){
        warn(TString::Format("'-' error of '%s' from unconditional fit result is zero!",namePOI.Data()));
        errHi_uncond = fabs(errLo_uncond);
        errLo_uncond = -fabs(errLo_uncond);        
        nOK--;
      }
			
#ifdef _DEBUG_
      std::cout<<"--------------------------------------------------------------\nTest printout UNcond:\n-----------------------------------------------"<<std::endl;
      poi_uncond->print("rdt");
#endif
    } 
    bool ok_uncond = (nOK>0);

    // get conditional uncertainties
    Double_t val_cond = 0.;
    Double_t errHi_cond = 0.;
    Double_t errLo_cond = 0.;
    nOK=2;
    if(cond){
      TQFolder * poi_cond = cond->getFolder(namePOI);
      if (!poi_cond) {
        warn(TString::Format("POI '%s' not contained in fit result '%s'",namePOI.Data(),cond->GetName()));        
        continue;
      }
      double err_cond = poi_cond->getTagDoubleDefault("err",0.);
      errHi_cond = err_cond;
      errLo_cond = err_cond;      
      if(!poi_cond->getTagDouble("val", val_cond)){
        error(TString::Format("unable to obtain value of '%s' from conditional fit result!",namePOI.Data()));
      }
      if(!poi_cond->getTagDouble("errHigh", errHi_cond)){
        error(TString::Format("unable to obtain '+' error of '%s' from conditional fit result!",namePOI.Data()));
        nOK--;
      }
      if(!poi_cond->getTagDouble("errLow", errLo_cond)){
        error(TString::Format("unable to obtain '-' error of '%s' from conditional fit result!",namePOI.Data()));
        nOK--;
      }

      if(fabs(errHi_cond) < epsilon){
        warn(TString::Format("'+' error of '%s' from conditional fit result is zero!",namePOI.Data()));
        errHi_cond = fabs(errLo_cond);
        errLo_cond = -fabs(errLo_cond);
        nOK--;
      }
      if(fabs(errLo_cond) < epsilon){
        warn(TString::Format("'-' error of '%s' from conditional fit result is zero!",namePOI.Data()));
        errHi_cond = fabs(errHi_cond);
        errLo_cond = -fabs(errHi_cond);        
        nOK--;
      }
#ifdef _DEBUG_
      std::cout<<"--------------------------------------------------------------\nTest printout cond:\n-----------------------------------------------"<<std::endl;
      poi_cond->print("rdt");
#endif
    }
    bool ok_cond = (nOK>0);
    
    
    // why do whe take the absolute value here?
    // in principle, the conditional should *never* be larger than the unconditional
    // however, for very small systematic, numeric fluctuations can twist the systematic in the "wrong" direction 
    // and cause the expression under the square root to be negative
    // by taking the absolute value, we ensure that the impact is always as least as big as the numerical fluctuations it is subject to
    Double_t high = TMath::Sqrt(std::abs(TMath::Power(errHi_uncond, 2.) - TMath::Power(errHi_cond, 2.)));
    Double_t low  = TMath::Sqrt(std::abs(TMath::Power(errLo_uncond, 2.) - TMath::Power(errLo_cond, 2.)));
    Double_t span = TMath::Sqrt(std::abs(TMath::Power(errHi_uncond - errLo_uncond, 2.) - TMath::Power(errHi_cond - errLo_cond, 2.)));

    TQFolder * f_breakdown = target->getFolder(TQFolder::concatPaths(namePOI, name) + "+");
    f_breakdown->setTagBool("IsHessian",false);
    f_breakdown->setTagBool("IsOK",ok_cond && ok_uncond);
    f_breakdown->setTagDouble("Avg", (low + high) / 2.);
    f_breakdown->setTagDouble("Low", -low);
    f_breakdown->setTagDouble("High", high);
    f_breakdown->setTagDouble("Span", span);
    f_breakdown->setTagDouble("Low_RelUnc", -low / fabs(errLo_uncond));
    f_breakdown->setTagDouble("High_RelUnc", high / fabs(errHi_uncond));
    f_breakdown->setTagDouble("Span_RelUnc", 0.5 * span / fabs( errHi_uncond - errLo_uncond ));    
    if(uncond){
      f_breakdown->setTagDouble("Avg_Rel", (low + high) / (2. * val_uncond) );
      f_breakdown->setTagDouble("Low_Rel", -low / val_uncond );
      f_breakdown->setTagDouble("High_Rel", high / val_uncond );
      f_breakdown->setTagDouble("Span_Rel", span / val_uncond );
    }
    f_breakdown->setTagString("comment",TString::Format("%s - %s",uncond ? uncond->GetName() : "NULL",cond ? cond->GetName() : "NULL"));
  }
}

//__________________________________________________________________________________|___________

bool TSBreakdownCalculator::runPreFit(TQTaggable* options, const RooAbsCollection& listOfPOIs, TQFolder* target){
  TQTaggable snapshotoptions;

  TString datasetName = options->getTagStringDefault("dataset",options->getTagStringDefault("datasetName", "asimovData_1"));
  snapshotoptions.importTagsWithoutPrefix(options,"fit.");
  snapshotoptions.setTagString("datasetName",datasetName);

  std::vector<TString> namesOfPOIs;
  TSUtils::getParameterNames(listOfPOIs,namesOfPOIs);
  TString poinames = TQStringUtils::concat(namesOfPOIs,",");

  std::vector<TString> namesOfNPs;
  TSUtils::getParameterNames(this->getNuisanceParameters(),namesOfNPs);
  TString npnames = TQStringUtils::concat(namesOfNPs,",");
	
  TString snapshot_uncond = options->getTagStringDefault("snapshot.unconditional","SnSh_AllVars_Breakdown_Unconditional_"+datasetName);
  TString snapshot_cond   = options->getTagStringDefault("snapshot.conditional",  "SnSh_AllVars_Breakdown_Conditional_"+datasetName);  
	
  snapshotoptions.setTagBool("runHesse", false);
  snapshotoptions.setTagString("POI", poinames);
  snapshotoptions.setTagBool("runMinos", true);
  snapshotoptions.setTagList("runMinosVars", namesOfPOIs);
	
  snapshotoptions.setTagString("id","unconditional");
  snapshotoptions.setTagString("snapshot",snapshot_uncond);
  snapshotoptions.setTagList("floatPars",namesOfNPs);
        
  snapshotoptions.setTagString("resultName","unconditional");
        
  if(!this->loadSnapshot(&snapshotoptions)){
    error("failed obtaining unconditional snapshot!");
    return false;
  }
  snapshotoptions.removeTags("floatPars.*");
  this->storeUncertainties(listOfPOIs,target->getFolder("unconditional+"));
	
	
  snapshotoptions.setTagString("id","conditional");
  snapshotoptions.setTagString("snapshot",snapshot_cond);
  snapshotoptions.setTagList("constPars",namesOfNPs);
  snapshotoptions.setTagString("resultName","conditional");
  snapshotoptions.setTagString("snapshot.nominal",snapshot_uncond);
  
  std::vector<TString> allPOIs;
  TSUtils::getParameterNames(fModelConfig->GetParametersOfInterest(),allPOIs);
  for(auto poi:allPOIs){
    RooRealVar* poiReal = dynamic_cast<RooRealVar*>(listOfPOIs.find(poi));
    if(poiReal){
      snapshotoptions.setTagDouble(TString::Format("presetParamError.%s",poi.Data()),poiReal->getError());
    }
  }
  
  if(!this->loadSnapshot(&snapshotoptions)){
    error("failed obtaining conditional snapshot!");
    return false;
  }
  snapshotoptions.removeTags("constPars.*");
  this->storeUncertainties(listOfPOIs,target->getFolder("conditional+"));

  return true;
}

//__________________________________________________________________________________|___________

TQFolder * TSBreakdownCalculator::runCalculation(TQFolder * config) {

  if (!fWorkspace || !fModelConfig || !config) {
    return NULL;
  }
  /* get the Point Of Interest, PDF, and data */
  TString datasetName = config->getTagStringDefault("dataset",config->getTagStringDefault("datasetName", "asimovData_1"));
  RooArgSet 	nuis		= this->getNuisanceParameters(config);
  RooArgSet	listOfPOIs	= this->getPOIs(config);
  
  if (listOfPOIs.getSize() == 0) {
    error("no POIs found!");
    return NULL;
  }

  RooArgSet nuisAndPOIs(nuis,listOfPOIs);
  // iterate over groups ("group.*") and determine individual uncertainties on POIs
  TSUtils::expandKeys(&nuisAndPOIs,config);
  TQIterator itrGroups(config->getListOfKeys("group.*"), true);
  
  std::vector<TString> namesOfPOIs;
  //Remove the parameters set as const from the POIs if there are any
  std::vector<TString> userPOIs = config->getTagVString("POI");
  if(userPOIs.size() == 0){
    TSUtils::getParameterNames(listOfPOIs,namesOfPOIs);
  } else {
    std::vector<TString> currentPOInames;
    TSUtils::getParameterNames(listOfPOIs,currentPOInames);
    for(auto name:currentPOInames){
      bool use = false;
      for(auto poi:userPOIs){
        if(TQStringUtils::matches(name,poi)){
          use = true;
        }
      }
      if(use) namesOfPOIs.push_back(name);
    }
  }
  RooArgSet newListOfPOIs;
  for(auto poiname:namesOfPOIs){
    newListOfPOIs.add(*(listOfPOIs.find(poiname.Data())));
  }
  TString poinames = TQStringUtils::concat(namesOfPOIs,",");
  
  // the folder to write the results to 
  TQFolder* retval = TQFolder::newFolder(config->GetName());
  if(!runPreFit(config,newListOfPOIs,retval)){
    return NULL;
  }
  bool invert = config->getTagBoolDefault("invert",false);
  TString startingsnapshot = TString::Format("SnSh_AllVars_%s_%s",invert ? "Conditional" : "Unconditional",datasetName.Data());
  config->getTagString("snapshot",startingsnapshot);

  TQTaggable startingsnapshotoptions(config);
  startingsnapshotoptions.setTagBool("runHesse", false);
  startingsnapshotoptions.setTagBool("runMinos", true);  
  startingsnapshotoptions.setTagString("snapshot",startingsnapshot);
  if(!this->loadSnapshot(&startingsnapshotoptions)){
    error("failed obtaining initial snapshot!");
    return NULL;
  }

  TQFolder* full_uncond = retval->getFolder("unconditional");
  TQFolder* full_cond   = retval->getFolder("conditional");

  TQFolder* fitresults = retval->getFolder("FitResults+");
  TQFolder* breakdown = retval->getFolder(this->fFolderName+"+");
  RooAbsPdf* pdf = fModelConfig->GetPdf();
  RooDataSet* data = dynamic_cast<RooDataSet*>(fWorkspace->data(datasetName));

  TQTaggable fitOptions;
  fitOptions.importTagsWithoutPrefix(config,"fit.");	

  fitOptions.setTagString("snapshot",startingsnapshot);
  fitOptions.setTagBool("runHesse", false);
  fitOptions.setTagBool("runMinos", true);

  TString constPars = fitOptions.getTagStringDefault("constPars","");
  fitOptions.removeTags("constPars.*");
  fitOptions.removeTags("constPars.except.*");

  std::vector<TString> namesOfNPs;
  TSUtils::getParameterNames(this->getNuisanceParameters(),namesOfNPs);
  TString npnames = TQStringUtils::concat(namesOfNPs,",");

  fitOptions.setTagBool("runMinos", true);  
  fitOptions.setTagList("runMinosVars", namesOfPOIs);
  // do not change paramteter values, we're re-using the snapshot from the unconditional fit.
  // Changing paramter values here increases the chances to converge to a different minimum causing all sorts of problems!
  fitOptions.removeTags("initParam.*");	
 
  while (itrGroups.hasNext()) {
    TString name = itrGroups.readNext()->GetName();
    TString filter;
    if(!config->getTagString(name, filter)){
      error(TString::Format("failed to retrieve filter for group '%s'",name.Data()));
      continue;
    }
    TString filterException = config->getTagStringDefault("config."+name+".except",""); //blacklist for parameters not to be included in this group

    std::vector<TString> nps = TSUtils::expandNames(this->getNuisanceParameters(),filter,filterException);

    bool invertCalculation = config->getTagBoolDefault("config."+name+".invert",false);
    TQStringUtils::removeLeadingText(name, "group.");
		
    fitOptions.setTagString("id",name);
    TString floatPars = fitOptions.getTagStringDefault("floatPars","");
    fitOptions.removeTags("floatPars.*");
    fitOptions.removeTags("floatPars.except.*");
    fitOptions.removeTags("constPars.*");
    fitOptions.removeTags("constPars.except.*");

    fitOptions.setTagInteger("verbose",0);    

    if(invert && !invertCalculation) {
      fitOptions.setTagList("floatPars",nps);
      info(TString::Format("Running fit '%s' with filter '%s' and filter exceptions '%s' (%lu matches)", name.Data(), filter.Data(), filterException.Data(),nps.size()));      
    } else {
      fitOptions.setTagList("constPars",nps);
      info(TString::Format("Running fit '%s' with inverted filter '%s' and filter exceptions '%s' (%lu matches)", name.Data(), filter.Data(), filterException.Data(),nps.size()));
    }

    TQFolder * result = fitPdfToData(pdf,data, nuis, &fitOptions);
    result->SetName(name);
    fitresults->addObject(result);
    TQFolder* cond = result->getFolder("floatParsFinal");
    if(invertCalculation){
      this->compareUncertainties(name,&newListOfPOIs,NULL,cond,breakdown);
    } else if(invert){
      this->compareUncertainties(name,&newListOfPOIs,full_cond,cond,breakdown);
    } else {
      this->compareUncertainties(name,&newListOfPOIs,cond,full_uncond,breakdown);
    }
    fitOptions.setTagString("constPars",constPars);
  }
    
  fitresults->sortByName();
  breakdown->sortByName();

  fWorkspace->loadSnapshot(startingsnapshot);
  
  return retval;
}
 TSBreakdownCalculator.cxx:1
 TSBreakdownCalculator.cxx:2
 TSBreakdownCalculator.cxx:3
 TSBreakdownCalculator.cxx:4
 TSBreakdownCalculator.cxx:5
 TSBreakdownCalculator.cxx:6
 TSBreakdownCalculator.cxx:7
 TSBreakdownCalculator.cxx:8
 TSBreakdownCalculator.cxx:9
 TSBreakdownCalculator.cxx:10
 TSBreakdownCalculator.cxx:11
 TSBreakdownCalculator.cxx:12
 TSBreakdownCalculator.cxx:13
 TSBreakdownCalculator.cxx:14
 TSBreakdownCalculator.cxx:15
 TSBreakdownCalculator.cxx:16
 TSBreakdownCalculator.cxx:17
 TSBreakdownCalculator.cxx:18
 TSBreakdownCalculator.cxx:19
 TSBreakdownCalculator.cxx:20
 TSBreakdownCalculator.cxx:21
 TSBreakdownCalculator.cxx:22
 TSBreakdownCalculator.cxx:23
 TSBreakdownCalculator.cxx:24
 TSBreakdownCalculator.cxx:25
 TSBreakdownCalculator.cxx:26
 TSBreakdownCalculator.cxx:27
 TSBreakdownCalculator.cxx:28
 TSBreakdownCalculator.cxx:29
 TSBreakdownCalculator.cxx:30
 TSBreakdownCalculator.cxx:31
 TSBreakdownCalculator.cxx:32
 TSBreakdownCalculator.cxx:33
 TSBreakdownCalculator.cxx:34
 TSBreakdownCalculator.cxx:35
 TSBreakdownCalculator.cxx:36
 TSBreakdownCalculator.cxx:37
 TSBreakdownCalculator.cxx:38
 TSBreakdownCalculator.cxx:39
 TSBreakdownCalculator.cxx:40
 TSBreakdownCalculator.cxx:41
 TSBreakdownCalculator.cxx:42
 TSBreakdownCalculator.cxx:43
 TSBreakdownCalculator.cxx:44
 TSBreakdownCalculator.cxx:45
 TSBreakdownCalculator.cxx:46
 TSBreakdownCalculator.cxx:47
 TSBreakdownCalculator.cxx:48
 TSBreakdownCalculator.cxx:49
 TSBreakdownCalculator.cxx:50
 TSBreakdownCalculator.cxx:51
 TSBreakdownCalculator.cxx:52
 TSBreakdownCalculator.cxx:53
 TSBreakdownCalculator.cxx:54
 TSBreakdownCalculator.cxx:55
 TSBreakdownCalculator.cxx:56
 TSBreakdownCalculator.cxx:57
 TSBreakdownCalculator.cxx:58
 TSBreakdownCalculator.cxx:59
 TSBreakdownCalculator.cxx:60
 TSBreakdownCalculator.cxx:61
 TSBreakdownCalculator.cxx:62
 TSBreakdownCalculator.cxx:63
 TSBreakdownCalculator.cxx:64
 TSBreakdownCalculator.cxx:65
 TSBreakdownCalculator.cxx:66
 TSBreakdownCalculator.cxx:67
 TSBreakdownCalculator.cxx:68
 TSBreakdownCalculator.cxx:69
 TSBreakdownCalculator.cxx:70
 TSBreakdownCalculator.cxx:71
 TSBreakdownCalculator.cxx:72
 TSBreakdownCalculator.cxx:73
 TSBreakdownCalculator.cxx:74
 TSBreakdownCalculator.cxx:75
 TSBreakdownCalculator.cxx:76
 TSBreakdownCalculator.cxx:77
 TSBreakdownCalculator.cxx:78
 TSBreakdownCalculator.cxx:79
 TSBreakdownCalculator.cxx:80
 TSBreakdownCalculator.cxx:81
 TSBreakdownCalculator.cxx:82
 TSBreakdownCalculator.cxx:83
 TSBreakdownCalculator.cxx:84
 TSBreakdownCalculator.cxx:85
 TSBreakdownCalculator.cxx:86
 TSBreakdownCalculator.cxx:87
 TSBreakdownCalculator.cxx:88
 TSBreakdownCalculator.cxx:89
 TSBreakdownCalculator.cxx:90
 TSBreakdownCalculator.cxx:91
 TSBreakdownCalculator.cxx:92
 TSBreakdownCalculator.cxx:93
 TSBreakdownCalculator.cxx:94
 TSBreakdownCalculator.cxx:95
 TSBreakdownCalculator.cxx:96
 TSBreakdownCalculator.cxx:97
 TSBreakdownCalculator.cxx:98
 TSBreakdownCalculator.cxx:99
 TSBreakdownCalculator.cxx:100
 TSBreakdownCalculator.cxx:101
 TSBreakdownCalculator.cxx:102
 TSBreakdownCalculator.cxx:103
 TSBreakdownCalculator.cxx:104
 TSBreakdownCalculator.cxx:105
 TSBreakdownCalculator.cxx:106
 TSBreakdownCalculator.cxx:107
 TSBreakdownCalculator.cxx:108
 TSBreakdownCalculator.cxx:109
 TSBreakdownCalculator.cxx:110
 TSBreakdownCalculator.cxx:111
 TSBreakdownCalculator.cxx:112
 TSBreakdownCalculator.cxx:113
 TSBreakdownCalculator.cxx:114
 TSBreakdownCalculator.cxx:115
 TSBreakdownCalculator.cxx:116
 TSBreakdownCalculator.cxx:117
 TSBreakdownCalculator.cxx:118
 TSBreakdownCalculator.cxx:119
 TSBreakdownCalculator.cxx:120
 TSBreakdownCalculator.cxx:121
 TSBreakdownCalculator.cxx:122
 TSBreakdownCalculator.cxx:123
 TSBreakdownCalculator.cxx:124
 TSBreakdownCalculator.cxx:125
 TSBreakdownCalculator.cxx:126
 TSBreakdownCalculator.cxx:127
 TSBreakdownCalculator.cxx:128
 TSBreakdownCalculator.cxx:129
 TSBreakdownCalculator.cxx:130
 TSBreakdownCalculator.cxx:131
 TSBreakdownCalculator.cxx:132
 TSBreakdownCalculator.cxx:133
 TSBreakdownCalculator.cxx:134
 TSBreakdownCalculator.cxx:135
 TSBreakdownCalculator.cxx:136
 TSBreakdownCalculator.cxx:137
 TSBreakdownCalculator.cxx:138
 TSBreakdownCalculator.cxx:139
 TSBreakdownCalculator.cxx:140
 TSBreakdownCalculator.cxx:141
 TSBreakdownCalculator.cxx:142
 TSBreakdownCalculator.cxx:143
 TSBreakdownCalculator.cxx:144
 TSBreakdownCalculator.cxx:145
 TSBreakdownCalculator.cxx:146
 TSBreakdownCalculator.cxx:147
 TSBreakdownCalculator.cxx:148
 TSBreakdownCalculator.cxx:149
 TSBreakdownCalculator.cxx:150
 TSBreakdownCalculator.cxx:151
 TSBreakdownCalculator.cxx:152
 TSBreakdownCalculator.cxx:153
 TSBreakdownCalculator.cxx:154
 TSBreakdownCalculator.cxx:155
 TSBreakdownCalculator.cxx:156
 TSBreakdownCalculator.cxx:157
 TSBreakdownCalculator.cxx:158
 TSBreakdownCalculator.cxx:159
 TSBreakdownCalculator.cxx:160
 TSBreakdownCalculator.cxx:161
 TSBreakdownCalculator.cxx:162
 TSBreakdownCalculator.cxx:163
 TSBreakdownCalculator.cxx:164
 TSBreakdownCalculator.cxx:165
 TSBreakdownCalculator.cxx:166
 TSBreakdownCalculator.cxx:167
 TSBreakdownCalculator.cxx:168
 TSBreakdownCalculator.cxx:169
 TSBreakdownCalculator.cxx:170
 TSBreakdownCalculator.cxx:171
 TSBreakdownCalculator.cxx:172
 TSBreakdownCalculator.cxx:173
 TSBreakdownCalculator.cxx:174
 TSBreakdownCalculator.cxx:175
 TSBreakdownCalculator.cxx:176
 TSBreakdownCalculator.cxx:177
 TSBreakdownCalculator.cxx:178
 TSBreakdownCalculator.cxx:179
 TSBreakdownCalculator.cxx:180
 TSBreakdownCalculator.cxx:181
 TSBreakdownCalculator.cxx:182
 TSBreakdownCalculator.cxx:183
 TSBreakdownCalculator.cxx:184
 TSBreakdownCalculator.cxx:185
 TSBreakdownCalculator.cxx:186
 TSBreakdownCalculator.cxx:187
 TSBreakdownCalculator.cxx:188
 TSBreakdownCalculator.cxx:189
 TSBreakdownCalculator.cxx:190
 TSBreakdownCalculator.cxx:191
 TSBreakdownCalculator.cxx:192
 TSBreakdownCalculator.cxx:193
 TSBreakdownCalculator.cxx:194
 TSBreakdownCalculator.cxx:195
 TSBreakdownCalculator.cxx:196
 TSBreakdownCalculator.cxx:197
 TSBreakdownCalculator.cxx:198
 TSBreakdownCalculator.cxx:199
 TSBreakdownCalculator.cxx:200
 TSBreakdownCalculator.cxx:201
 TSBreakdownCalculator.cxx:202
 TSBreakdownCalculator.cxx:203
 TSBreakdownCalculator.cxx:204
 TSBreakdownCalculator.cxx:205
 TSBreakdownCalculator.cxx:206
 TSBreakdownCalculator.cxx:207
 TSBreakdownCalculator.cxx:208
 TSBreakdownCalculator.cxx:209
 TSBreakdownCalculator.cxx:210
 TSBreakdownCalculator.cxx:211
 TSBreakdownCalculator.cxx:212
 TSBreakdownCalculator.cxx:213
 TSBreakdownCalculator.cxx:214
 TSBreakdownCalculator.cxx:215
 TSBreakdownCalculator.cxx:216
 TSBreakdownCalculator.cxx:217
 TSBreakdownCalculator.cxx:218
 TSBreakdownCalculator.cxx:219
 TSBreakdownCalculator.cxx:220
 TSBreakdownCalculator.cxx:221
 TSBreakdownCalculator.cxx:222
 TSBreakdownCalculator.cxx:223
 TSBreakdownCalculator.cxx:224
 TSBreakdownCalculator.cxx:225
 TSBreakdownCalculator.cxx:226
 TSBreakdownCalculator.cxx:227
 TSBreakdownCalculator.cxx:228
 TSBreakdownCalculator.cxx:229
 TSBreakdownCalculator.cxx:230
 TSBreakdownCalculator.cxx:231
 TSBreakdownCalculator.cxx:232
 TSBreakdownCalculator.cxx:233
 TSBreakdownCalculator.cxx:234
 TSBreakdownCalculator.cxx:235
 TSBreakdownCalculator.cxx:236
 TSBreakdownCalculator.cxx:237
 TSBreakdownCalculator.cxx:238
 TSBreakdownCalculator.cxx:239
 TSBreakdownCalculator.cxx:240
 TSBreakdownCalculator.cxx:241
 TSBreakdownCalculator.cxx:242
 TSBreakdownCalculator.cxx:243
 TSBreakdownCalculator.cxx:244
 TSBreakdownCalculator.cxx:245
 TSBreakdownCalculator.cxx:246
 TSBreakdownCalculator.cxx:247
 TSBreakdownCalculator.cxx:248
 TSBreakdownCalculator.cxx:249
 TSBreakdownCalculator.cxx:250
 TSBreakdownCalculator.cxx:251
 TSBreakdownCalculator.cxx:252
 TSBreakdownCalculator.cxx:253
 TSBreakdownCalculator.cxx:254
 TSBreakdownCalculator.cxx:255
 TSBreakdownCalculator.cxx:256
 TSBreakdownCalculator.cxx:257
 TSBreakdownCalculator.cxx:258
 TSBreakdownCalculator.cxx:259
 TSBreakdownCalculator.cxx:260
 TSBreakdownCalculator.cxx:261
 TSBreakdownCalculator.cxx:262
 TSBreakdownCalculator.cxx:263
 TSBreakdownCalculator.cxx:264
 TSBreakdownCalculator.cxx:265
 TSBreakdownCalculator.cxx:266
 TSBreakdownCalculator.cxx:267
 TSBreakdownCalculator.cxx:268
 TSBreakdownCalculator.cxx:269
 TSBreakdownCalculator.cxx:270
 TSBreakdownCalculator.cxx:271
 TSBreakdownCalculator.cxx:272
 TSBreakdownCalculator.cxx:273
 TSBreakdownCalculator.cxx:274
 TSBreakdownCalculator.cxx:275
 TSBreakdownCalculator.cxx:276
 TSBreakdownCalculator.cxx:277
 TSBreakdownCalculator.cxx:278
 TSBreakdownCalculator.cxx:279
 TSBreakdownCalculator.cxx:280
 TSBreakdownCalculator.cxx:281
 TSBreakdownCalculator.cxx:282
 TSBreakdownCalculator.cxx:283
 TSBreakdownCalculator.cxx:284
 TSBreakdownCalculator.cxx:285
 TSBreakdownCalculator.cxx:286
 TSBreakdownCalculator.cxx:287
 TSBreakdownCalculator.cxx:288
 TSBreakdownCalculator.cxx:289
 TSBreakdownCalculator.cxx:290
 TSBreakdownCalculator.cxx:291
 TSBreakdownCalculator.cxx:292
 TSBreakdownCalculator.cxx:293
 TSBreakdownCalculator.cxx:294
 TSBreakdownCalculator.cxx:295
 TSBreakdownCalculator.cxx:296
 TSBreakdownCalculator.cxx:297
 TSBreakdownCalculator.cxx:298
 TSBreakdownCalculator.cxx:299
 TSBreakdownCalculator.cxx:300
 TSBreakdownCalculator.cxx:301
 TSBreakdownCalculator.cxx:302
 TSBreakdownCalculator.cxx:303
 TSBreakdownCalculator.cxx:304
 TSBreakdownCalculator.cxx:305
 TSBreakdownCalculator.cxx:306
 TSBreakdownCalculator.cxx:307
 TSBreakdownCalculator.cxx:308
 TSBreakdownCalculator.cxx:309
 TSBreakdownCalculator.cxx:310
 TSBreakdownCalculator.cxx:311
 TSBreakdownCalculator.cxx:312
 TSBreakdownCalculator.cxx:313
 TSBreakdownCalculator.cxx:314
 TSBreakdownCalculator.cxx:315
 TSBreakdownCalculator.cxx:316
 TSBreakdownCalculator.cxx:317
 TSBreakdownCalculator.cxx:318
 TSBreakdownCalculator.cxx:319
 TSBreakdownCalculator.cxx:320
 TSBreakdownCalculator.cxx:321
 TSBreakdownCalculator.cxx:322
 TSBreakdownCalculator.cxx:323
 TSBreakdownCalculator.cxx:324
 TSBreakdownCalculator.cxx:325
 TSBreakdownCalculator.cxx:326
 TSBreakdownCalculator.cxx:327
 TSBreakdownCalculator.cxx:328
 TSBreakdownCalculator.cxx:329
 TSBreakdownCalculator.cxx:330
 TSBreakdownCalculator.cxx:331
 TSBreakdownCalculator.cxx:332
 TSBreakdownCalculator.cxx:333
 TSBreakdownCalculator.cxx:334
 TSBreakdownCalculator.cxx:335
 TSBreakdownCalculator.cxx:336
 TSBreakdownCalculator.cxx:337
 TSBreakdownCalculator.cxx:338
 TSBreakdownCalculator.cxx:339
 TSBreakdownCalculator.cxx:340
 TSBreakdownCalculator.cxx:341
 TSBreakdownCalculator.cxx:342
 TSBreakdownCalculator.cxx:343
 TSBreakdownCalculator.cxx:344
 TSBreakdownCalculator.cxx:345
 TSBreakdownCalculator.cxx:346
 TSBreakdownCalculator.cxx:347
 TSBreakdownCalculator.cxx:348
 TSBreakdownCalculator.cxx:349
 TSBreakdownCalculator.cxx:350
 TSBreakdownCalculator.cxx:351
 TSBreakdownCalculator.cxx:352
 TSBreakdownCalculator.cxx:353
 TSBreakdownCalculator.cxx:354
 TSBreakdownCalculator.cxx:355
 TSBreakdownCalculator.cxx:356
 TSBreakdownCalculator.cxx:357
 TSBreakdownCalculator.cxx:358
 TSBreakdownCalculator.cxx:359
 TSBreakdownCalculator.cxx:360
 TSBreakdownCalculator.cxx:361
 TSBreakdownCalculator.cxx:362
 TSBreakdownCalculator.cxx:363
 TSBreakdownCalculator.cxx:364
 TSBreakdownCalculator.cxx:365
 TSBreakdownCalculator.cxx:366
 TSBreakdownCalculator.cxx:367
 TSBreakdownCalculator.cxx:368
 TSBreakdownCalculator.cxx:369
 TSBreakdownCalculator.cxx:370
 TSBreakdownCalculator.cxx:371
 TSBreakdownCalculator.cxx:372
 TSBreakdownCalculator.cxx:373
 TSBreakdownCalculator.cxx:374
 TSBreakdownCalculator.cxx:375
 TSBreakdownCalculator.cxx:376
 TSBreakdownCalculator.cxx:377
 TSBreakdownCalculator.cxx:378
 TSBreakdownCalculator.cxx:379
 TSBreakdownCalculator.cxx:380
 TSBreakdownCalculator.cxx:381
 TSBreakdownCalculator.cxx:382
 TSBreakdownCalculator.cxx:383
 TSBreakdownCalculator.cxx:384
 TSBreakdownCalculator.cxx:385
 TSBreakdownCalculator.cxx:386
 TSBreakdownCalculator.cxx:387
 TSBreakdownCalculator.cxx:388
 TSBreakdownCalculator.cxx:389
 TSBreakdownCalculator.cxx:390
 TSBreakdownCalculator.cxx:391
 TSBreakdownCalculator.cxx:392
 TSBreakdownCalculator.cxx:393
 TSBreakdownCalculator.cxx:394
 TSBreakdownCalculator.cxx:395
 TSBreakdownCalculator.cxx:396
 TSBreakdownCalculator.cxx:397
 TSBreakdownCalculator.cxx:398
 TSBreakdownCalculator.cxx:399
 TSBreakdownCalculator.cxx:400
 TSBreakdownCalculator.cxx:401
 TSBreakdownCalculator.cxx:402
 TSBreakdownCalculator.cxx:403
 TSBreakdownCalculator.cxx:404
 TSBreakdownCalculator.cxx:405
 TSBreakdownCalculator.cxx:406
 TSBreakdownCalculator.cxx:407
 TSBreakdownCalculator.cxx:408
 TSBreakdownCalculator.cxx:409
 TSBreakdownCalculator.cxx:410
 TSBreakdownCalculator.cxx:411
 TSBreakdownCalculator.cxx:412
 TSBreakdownCalculator.cxx:413
 TSBreakdownCalculator.cxx:414