// @(#)root/tmva $Id$
// Author: Andreas Hoecker, Peter Speckmayer, Joerg Stelzer, Helge Voss, Jan Therhaag

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Class  : Tools                                                                 *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation (see header for description)                               *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland              *
 *      Peter Speckmayer <Peter.Speckmayer@cern.ch> - CERN, Switzerland           *
 *      Jan Therhaag       <Jan.Therhaag@cern.ch>     - U of Bonn, Germany        *
 *      Helge Voss      <Helge.Voss@cern.ch>     - MPI-K Heidelberg, Germany      *
 *      Kai Voss        <Kai.Voss@cern.ch>       - U. of Victoria, Canada         *
 *                                                                                *
 * Copyright (c) 2005-2011:                                                       *
 *      CERN, Switzerland                                                         *
 *      U. of Victoria, Canada                                                    *
 *      MPI-K Heidelberg, Germany                                                 *
 *      U. of Bonn, Germany                                                       *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://ttmva.sourceforge.net/LICENSE)                                         *
 **********************************************************************************/

#include <algorithm>
#include <cstdlib>

#include "TObjString.h"
#include "TMath.h"
#include "TString.h"
#include "TTree.h"
#include "TLeaf.h"
#include "TH1.h"
#include "TH2.h"
#include "TList.h"
#include "TSpline.h"
#include "TVector.h"
#include "TMatrixD.h"
#include "TMatrixDSymEigen.h"
#include "TVectorD.h"
#include "TTreeFormula.h"
#include "TXMLEngine.h"
#include "TROOT.h"
#include "TMatrixDSymEigen.h"

#ifndef ROOT_TMVA_Tools
#include "TMVA/Tools.h"
#endif
#ifndef ROOT_TMVA_Config
#include "TMVA/Config.h"
#endif
#ifndef ROOT_TMVA_Event
#include "TMVA/Event.h"
#endif
#ifndef ROOT_TMVA_Version
#include "TMVA/Version.h"
#endif
#ifndef ROOT_TMVA_PDF
#include "TMVA/PDF.h"
#endif
#ifndef ROOT_TMVA_MsgLogger
#include "TMVA/MsgLogger.h"
#endif

using namespace std;

#if __cplusplus > 199711L
std::atomic<TMVA::Tools*> TMVA::Tools::fgTools{0};
#else
TMVA::Tools* TMVA::Tools::fgTools = 0;
#endif

TMVA::Tools& TMVA::gTools()                 { return TMVA::Tools::Instance(); }
TMVA::Tools& TMVA::Tools::Instance()        {
#if __cplusplus > 199711L
  if(!fgTools) {
    Tools* tmp = new Tools();
    Tools* expected = 0;
    if(! fgTools.compare_exchange_strong(expected,tmp)) {
      //another thread beat us
      delete tmp;
    }
  }
  return *fgTools;
#else
  return fgTools?*(fgTools): *(fgTools = new Tools());
#endif
}
void         TMVA::Tools::DestroyInstance() {
  //NOTE: there is no thread safe way to do this so
  // one must only call this method ones in an executable
#if __cplusplus > 199711L
  if (fgTools != 0) { delete fgTools.load(); fgTools=0; }
#else
  if (fgTools != 0) { delete fgTools; fgTools=0; }
#endif
}

//_______________________________________________________________________
TMVA::Tools::Tools() :
   fRegexp("$&|!%^&()'<>?= "),
   fLogger(new MsgLogger("Tools")),
   fXMLEngine(new TXMLEngine())
{
   // constructor
}

//_______________________________________________________________________
TMVA::Tools::~Tools()
{
   // destructor
   delete fLogger;
   delete fXMLEngine;
}

//_______________________________________________________________________
Double_t TMVA::Tools::NormVariable( Double_t x, Double_t xmin, Double_t xmax )
{
   // normalise to output range: [-1, 1]
   return 2*(x - xmin)/(xmax - xmin) - 1.0;
}

//_______________________________________________________________________
Double_t TMVA::Tools::GetSeparation( TH1* S, TH1* B ) const
{
   // compute "separation" defined as
   // <s2> = (1/2) Int_-oo..+oo { (S(x) - B(x))^2/(S(x) + B(x)) dx }
   Double_t separation = 0;

   // sanity checks
   // signal and background histograms must have same number of bins and
   // same limits
   if ((S->GetNbinsX() != B->GetNbinsX()) || (S->GetNbinsX() <= 0)) {
      Log() << kFATAL << "<GetSeparation> signal and background"
            << " histograms have different number of bins: "
            << S->GetNbinsX() << " : " << B->GetNbinsX() << Endl;
   }

   if (S->GetXaxis()->GetXmin() != B->GetXaxis()->GetXmin() ||
       S->GetXaxis()->GetXmax() != B->GetXaxis()->GetXmax() ||
       S->GetXaxis()->GetXmax() <= S->GetXaxis()->GetXmin()) {
      Log() << kINFO << S->GetXaxis()->GetXmin() << " " << B->GetXaxis()->GetXmin()
            << " " << S->GetXaxis()->GetXmax() << " " << B->GetXaxis()->GetXmax()
            << " " << S->GetXaxis()->GetXmax() << " " << S->GetXaxis()->GetXmin() << Endl;
      Log() << kFATAL << "<GetSeparation> signal and background"
            << " histograms have different or invalid dimensions:" << Endl;
   }

   Int_t    nstep  = S->GetNbinsX();
   Double_t intBin = (S->GetXaxis()->GetXmax() - S->GetXaxis()->GetXmin())/nstep;
   Double_t nS     = S->GetSumOfWeights()*intBin;
   Double_t nB     = B->GetSumOfWeights()*intBin;

   if (nS > 0 && nB > 0) {
      for (Int_t bin=0; bin<nstep; bin++) {
         Double_t s = S->GetBinContent( bin+1 )/Double_t(nS);
         Double_t b = B->GetBinContent( bin+1 )/Double_t(nB);
         // separation
         if (s + b > 0) separation += 0.5*(s - b)*(s - b)/(s + b);
      }
      separation *= intBin;
   }
   else {
      Log() << kWARNING << "<GetSeparation> histograms with zero entries: "
            << nS << " : " << nB << " cannot compute separation"
            << Endl;
      separation = 0;
   }

   return separation;
}

//_______________________________________________________________________
Double_t TMVA::Tools::GetSeparation( const PDF& pdfS, const PDF& pdfB ) const
{
   // compute "separation" defined as
   // <s2> = (1/2) Int_-oo..+oo { (S(x) - B(x))2/(S(x) + B(x)) dx }

   Double_t xmin = pdfS.GetXmin();
   Double_t xmax = pdfS.GetXmax();
   // sanity check
   if (xmin != pdfB.GetXmin() || xmax != pdfB.GetXmax()) {
      Log() << kFATAL << "<GetSeparation> Mismatch in PDF limits: "
            << xmin << " " << pdfB.GetXmin() << xmax << " " << pdfB.GetXmax()  << Endl;
   }

   Double_t separation = 0;
   Int_t    nstep      = 100;
   Double_t intBin     = (xmax - xmin)/Double_t(nstep);
   for (Int_t bin=0; bin<nstep; bin++) {
      Double_t x = (bin + 0.5)*intBin + xmin;
      Double_t s = pdfS.GetVal( x );
      Double_t b = pdfB.GetVal( x );
      // separation
      if (s + b > 0) separation += (s - b)*(s - b)/(s + b);
   }
   separation *= (0.5*intBin);

   return separation;
}

//_______________________________________________________________________
void TMVA::Tools::ComputeStat( const std::vector<TMVA::Event*>& events, std::vector<Float_t>* valVec,
                               Double_t& meanS, Double_t& meanB,
                               Double_t& rmsS,  Double_t& rmsB,
                               Double_t& xmin,  Double_t& xmax,
                               Int_t signalClass, Bool_t  norm )
{
   // sanity check
   if (0 == valVec)
      Log() << kFATAL << "<Tools::ComputeStat> value vector is zero pointer" << Endl;

   if ( events.size() != valVec->size() )
      Log() << kWARNING << "<Tools::ComputeStat> event and value vector have different lengths "
            << events.size() << "!=" << valVec->size() << Endl;

   Long64_t entries = valVec->size();

   // first fill signal and background in arrays before analysis
   Double_t* varVecS  = new Double_t[entries];
   Double_t* varVecB  = new Double_t[entries];
   Double_t* wgtVecS  = new Double_t[entries];
   Double_t* wgtVecB  = new Double_t[entries];
   xmin               = +DBL_MAX;
   xmax               = -DBL_MAX;
   Long64_t nEventsS  = 0;
   Long64_t nEventsB  = 0;
   Double_t xmin_ = 0, xmax_ = 0;

   if (norm) {
      xmin_ = *std::min( valVec->begin(), valVec->end() );
      xmax_ = *std::max( valVec->begin(), valVec->end() );
   }

   for (Int_t ievt=0; ievt<entries; ievt++) {
      Double_t theVar = (*valVec)[ievt];
      if (norm) theVar = Tools::NormVariable( theVar, xmin_, xmax_ );

      if (Int_t(events[ievt]->GetClass()) == signalClass ){
         wgtVecS[nEventsS]   = events[ievt]->GetWeight(); // this is signal
         varVecS[nEventsS++] = theVar; // this is signal
      }
      else {
         wgtVecB[nEventsB]   = events[ievt]->GetWeight(); // this is signal
         varVecB[nEventsB++] = theVar; // this is background
      }

      if (theVar > xmax) xmax = theVar;
      if (theVar < xmin) xmin = theVar;
   }
   // ++nEventsS;
   // ++nEventsB;

   // basic statistics
   // !!! TMath::Mean allows for weights, but NOT for negative weights
   //     and TMath::RMS doesn't allow for weights all together...
   meanS = TMVA::Tools::Mean( nEventsS, varVecS, wgtVecS );
   meanB = TMVA::Tools::Mean( nEventsB, varVecB, wgtVecB );
   rmsS  = TMVA::Tools::RMS ( nEventsS, varVecS, wgtVecS );
   rmsB  = TMVA::Tools::RMS ( nEventsB, varVecB, wgtVecB );

   delete [] varVecS;
   delete [] varVecB;
   delete [] wgtVecS;
   delete [] wgtVecB;
}

//_______________________________________________________________________
TMatrixD* TMVA::Tools::GetSQRootMatrix( TMatrixDSym* symMat )
{
   // square-root of symmetric matrix
   // of course the resulting sqrtMat is also symmetric, but it's easier to
   // treat it as a general matrix
   Int_t n = symMat->GetNrows();

   // compute eigenvectors
   TMatrixDSymEigen* eigen = new TMatrixDSymEigen( *symMat );

   // D = ST C S
   TMatrixD* si = new TMatrixD( eigen->GetEigenVectors() );
   TMatrixD* s  = new TMatrixD( *si ); // copy
   si->Transpose( *si ); // invert (= transpose)

   // diagonal matrices
   TMatrixD* d = new TMatrixD( n, n);
   d->Mult( (*si), (*symMat) ); (*d) *= (*s);

   // sanity check: matrix must be diagonal and positive definit
   Int_t i, j;
   Double_t epsilon = 1.0e-8;
   for (i=0; i<n; i++) {
      for (j=0; j<n; j++) {
         if ((i != j && TMath::Abs((*d)(i,j))/TMath::Sqrt((*d)(i,i)*(*d)(j,j)) > epsilon) ||
             (i == j && (*d)(i,i) < 0)) {
            //d->Print();
            Log() << kWARNING << "<GetSQRootMatrix> error in matrix diagonalization; printed S and B" << Endl;
         }
      }
   }

   // make exactly diagonal
   for (i=0; i<n; i++) for (j=0; j<n; j++) if (j != i) (*d)(i,j) = 0;

   // compute the square-root C' of covariance matrix: C = C'*C'
   for (i=0; i<n; i++) (*d)(i,i) = TMath::Sqrt((*d)(i,i));

   TMatrixD* sqrtMat = new TMatrixD( n, n );
   sqrtMat->Mult( (*s), (*d) );
   (*sqrtMat) *= (*si);

   // invert square-root matrices
   sqrtMat->Invert();

   delete eigen;
   delete s;
   delete si;
   delete d;

   return sqrtMat;
}

//_______________________________________________________________________
const TMatrixD* TMVA::Tools::GetCorrelationMatrix( const TMatrixD* covMat )
{
   // turns covariance into correlation matrix
   if (covMat == 0) return 0;

   // sanity check
   Int_t nvar = covMat->GetNrows();
   if (nvar != covMat->GetNcols())
      Log() << kFATAL << "<GetCorrelationMatrix> input matrix not quadratic" << Endl;

   TMatrixD* corrMat = new TMatrixD( nvar, nvar );

   for (Int_t ivar=0; ivar<nvar; ivar++) {
      for (Int_t jvar=0; jvar<nvar; jvar++) {
         if (ivar != jvar) {
            Double_t d = (*covMat)(ivar, ivar)*(*covMat)(jvar, jvar);
            if (d > 1E-20) (*corrMat)(ivar, jvar) = (*covMat)(ivar, jvar)/TMath::Sqrt(d);
            else {
               Log() << kWARNING << "<GetCorrelationMatrix> zero variances for variables "
                     << "(" << ivar << ", " << jvar << ")" << Endl;
               (*corrMat)(ivar, jvar) = 0;
            }
            if (TMath::Abs( (*corrMat)(ivar,jvar))  > 1){
               Log() << kWARNING
                     <<  " Element  corr("<<ivar<<","<<ivar<<")=" << (*corrMat)(ivar,jvar)
                     << " sigma2="<<d
                     << " cov("<<ivar<<","<<ivar<<")=" <<(*covMat)(ivar, ivar)
                     << " cov("<<jvar<<","<<jvar<<")=" <<(*covMat)(jvar, jvar)
                     << Endl;

            }
         }
         else (*corrMat)(ivar, ivar) = 1.0;
      }
   }

   return corrMat;
}

//_______________________________________________________________________
TH1* TMVA::Tools::projNormTH1F( TTree* theTree, const TString& theVarName,
                                const TString& name, Int_t nbins,
                                Double_t xmin, Double_t xmax, const TString& cut )
{
   // projects variable from tree into normalised histogram

   // needed because of ROOT bug (feature) that excludes events that have value == xmax
   xmax += 0.00001;

   TH1* hist = new TH1F( name, name, nbins, xmin, xmax );
   hist->Sumw2(); // enable quadratic errors
   theTree->Project( name, theVarName, cut );
   NormHist( hist );
   return hist;
}

//_______________________________________________________________________
Double_t TMVA::Tools::NormHist( TH1* theHist, Double_t norm )
{
   // normalises histogram
   if (!theHist) return 0;

   if (theHist->GetSumw2N() == 0) theHist->Sumw2();
   if (theHist->GetSumOfWeights() != 0) {
      Double_t   w  = ( theHist->GetSumOfWeights()
                        *(theHist->GetXaxis()->GetXmax() - theHist->GetXaxis()->GetXmin())/theHist->GetNbinsX() );
      if (w > 0) theHist->Scale( norm/w );
      return w;
   }

   return 1.0;
}

//_______________________________________________________________________
TList* TMVA::Tools::ParseFormatLine( TString formatString, const char* sep )
{
   // Parse the string and cut into labels separated by ":"
   TList*   labelList = new TList();
   labelList->SetOwner();
   while (formatString.First(sep)==0) formatString.Remove(0,1); // remove initial separators

   while (formatString.Length()>0) {
      if (formatString.First(sep) == -1) { // no more separator
         labelList->Add(new TObjString(formatString.Data()));
         formatString="";
         break;
      }

      Ssiz_t posSep = formatString.First(sep);
      labelList->Add(new TObjString(TString(formatString(0,posSep)).Data()));
      formatString.Remove(0,posSep+1);

      while (formatString.First(sep)==0) formatString.Remove(0,1); // remove additional separators

   }
   return labelList;
}

//_______________________________________________________________________
vector<Int_t>* TMVA::Tools::ParseANNOptionString( TString theOptions, Int_t nvar,
                                                  vector<Int_t>* nodes )
{
   // parse option string for ANN methods
   // default settings (should be defined in theOption string)
   TList* list  = TMVA::Tools::ParseFormatLine( theOptions, ":" );

   // format and syntax of option string: "3000:N:N+2:N-3:6"
   //
   // where:
   //        3000 - number of training cycles (epochs)
   //        N    - number of nodes in first hidden layer, where N is the number
   //               of discriminating variables used (note that the first ANN
   //               layer necessarily has N nodes, and hence is not given).
   //        N+2  - number of nodes in 2nd hidden layer (2 nodes more than
   //               number of variables)
   //        N-3  - number of nodes in 3rd hidden layer (3 nodes less than
   //               number of variables)
   //        6    - 6 nodes in last (4th) hidden layer (note that the last ANN
   //               layer in MVA has 2 nodes, each one for signal and background
   //               classes)

   // sanity check
   if (list->GetSize() < 1) {
      Log() << kFATAL << "<ParseANNOptionString> unrecognized option string: " << theOptions << Endl;
   }

   // add number of cycles
   nodes->push_back( atoi( ((TObjString*)list->At(0))->GetString() ) );

   Int_t a;
   if (list->GetSize() > 1) {
      for (Int_t i=1; i<list->GetSize(); i++) {
         TString s = ((TObjString*)list->At(i))->GetString();
         s.ToUpper();
         if (s(0) == 'N')  {
            if (s.Length() > 1) nodes->push_back( nvar + atoi(&s[1]) );
            else                nodes->push_back( nvar );
         }
         else if ((a = atoi( s )) > 0) nodes->push_back( atoi(s ) );
         else {
            Log() << kFATAL << "<ParseANNOptionString> unrecognized option string: " << theOptions << Endl;
         }
      }
   }

   return nodes;
}

Bool_t TMVA::Tools::CheckSplines( const TH1* theHist, const TSpline* theSpline )
{
   // check quality of splining by comparing splines and histograms in each bin
   const Double_t sanityCrit = 0.01; // relative deviation

   Bool_t retval = kTRUE;
   for (Int_t ibin=1; ibin<=theHist->GetNbinsX(); ibin++) {
      Double_t x  = theHist->GetBinCenter( ibin );
      Double_t yh = theHist->GetBinContent( ibin ); // the histogram output
      Double_t ys = theSpline->Eval( x );           // the spline output

      if (ys + yh > 0) {
         Double_t dev = 0.5*(ys - yh)/(ys + yh);
         if (TMath::Abs(dev) > sanityCrit) {
            Log() << kFATAL << "<CheckSplines> Spline failed sanity criterion; "
                  << " relative deviation from histogram: " << dev
                  << " in (bin, value): (" << ibin << ", " << x << ")" << Endl;
            retval = kFALSE;
         }
      }
   }

   return retval;
}

//_______________________________________________________________________
std::vector<Double_t> TMVA::Tools::MVADiff( std::vector<Double_t>& a, std::vector<Double_t>& b )
{
   // computes difference between two vectors
   if (a.size() != b.size()) {
      throw;
   }
   vector<Double_t> result(a.size());
   for (UInt_t i=0; i<a.size();i++) result[i]=a[i]-b[i];
   return result;
}

//_______________________________________________________________________
void TMVA::Tools::Scale( std::vector<Double_t>& v, Double_t f )
{
   // scales double vector
   for (UInt_t i=0; i<v.size();i++) v[i]*=f;
}

//_______________________________________________________________________
void TMVA::Tools::Scale( std::vector<Float_t>& v, Float_t f )
{
   // scales float vector
   for (UInt_t i=0; i<v.size();i++) v[i]*=f;
}

//_______________________________________________________________________
void TMVA::Tools::UsefulSortAscending( std::vector<vector<Double_t> >& v, std::vector<TString>* vs ){
   // sort 2D vector (AND in parallel a TString vector) in such a way
   // that the "first vector is sorted" and the other vectors are reshuffled
   // in the same way as necessary to have the first vector sorted.
   // I.e. the correlation between the elements is kept.
   UInt_t nArrays=v.size();
   Double_t temp;
   if (nArrays > 0) {
      UInt_t sizeofarray=v[0].size();
      for (UInt_t i=0; i<sizeofarray; i++) {
         for (UInt_t j=sizeofarray-1; j>i; j--) {
            if (v[0][j-1] > v[0][j]) {
               for (UInt_t k=0; k< nArrays; k++) {
                  temp = v[k][j-1]; v[k][j-1] = v[k][j]; v[k][j] = temp;
               }
               if (NULL != vs) {
                  TString temps = (*vs)[j-1]; (*vs)[j-1] = (*vs)[j]; (*vs)[j] = temps;
               }
            }
         }
      }
   }
}

//_______________________________________________________________________
void TMVA::Tools::UsefulSortDescending( std::vector<std::vector<Double_t> >& v, std::vector<TString>* vs )
{
   // sort 2D vector (AND in parallel a TString vector) in such a way
   // that the "first vector is sorted" and the other vectors are reshuffled
   // in the same way as necessary to have the first vector sorted.
   // I.e. the correlation between the elements is kept.
   UInt_t nArrays=v.size();
   Double_t temp;
   if (nArrays > 0) {
      UInt_t sizeofarray=v[0].size();
      for (UInt_t i=0; i<sizeofarray; i++) {
         for (UInt_t j=sizeofarray-1; j>i; j--) {
            if (v[0][j-1] < v[0][j]) {
               for (UInt_t k=0; k< nArrays; k++) {
                  temp = v[k][j-1]; v[k][j-1] = v[k][j]; v[k][j] = temp;
               }
               if (NULL != vs) {
                  TString temps = (*vs)[j-1]; (*vs)[j-1] = (*vs)[j]; (*vs)[j] = temps;
               }
            }
         }
      }
   }
}

//_______________________________________________________________________
Double_t TMVA::Tools::GetMutualInformation( const TH2F& h_ )
{
   // Mutual Information method for non-linear correlations estimates in 2D histogram
   // Author: Moritz Backes, Geneva (2009)

   Double_t hi = h_.Integral();
   if (hi == 0) return -1;

   // copy histogram and rebin to speed up procedure
   TH2F h( h_ );
   h.RebinX(2);
   h.RebinY(2);

   Double_t mutualInfo = 0.;
   Int_t maxBinX = h.GetNbinsX();
   Int_t maxBinY = h.GetNbinsY();
   for (Int_t x = 1; x <= maxBinX; x++) {
      for (Int_t y = 1; y <= maxBinY; y++) {
         Double_t p_xy = h.GetBinContent(x,y)/hi;
         Double_t p_x  = h.Integral(x,x,1,maxBinY)/hi;
         Double_t p_y  = h.Integral(1,maxBinX,y,y)/hi;
         if (p_x > 0. && p_y > 0. && p_xy > 0.){
            mutualInfo += p_xy*TMath::Log(p_xy / (p_x * p_y));
         }
      }
   }

   return mutualInfo;
}

//_______________________________________________________________________
Double_t TMVA::Tools::GetCorrelationRatio( const TH2F& h_ )
{
   // Compute Correlation Ratio of 2D histogram to estimate functional dependency between two variables
   // Author: Moritz Backes, Geneva (2009)

   Double_t hi = h_.Integral();
   if (hi == 0.) return -1;

   // copy histogram and rebin to speed up procedure
   TH2F h( h_ );
   h.RebinX(2);
   h.RebinY(2);

   Double_t corrRatio = 0.;
   Double_t y_mean = h.ProjectionY()->GetMean();
   for (Int_t ix=1; ix<=h.GetNbinsX(); ix++) {
      corrRatio += (h.Integral(ix,ix,1,h.GetNbinsY())/hi)*pow((GetYMean_binX(h,ix)-y_mean),2);
   }
   corrRatio /= pow(h.ProjectionY()->GetRMS(),2);
   return corrRatio;
}

//_______________________________________________________________________
Double_t TMVA::Tools::GetYMean_binX( const TH2& h, Int_t bin_x )
{
   // Compute the mean in Y for a given bin X of a 2D histogram

   if (h.Integral(bin_x,bin_x,1,h.GetNbinsY()) == 0.) {return 0;}
   Double_t y_bin_mean = 0.;
   TH1* py = h.ProjectionY();
   for (Int_t y = 1; y <= h.GetNbinsY(); y++){
      y_bin_mean += h.GetBinContent(bin_x,y)*py->GetBinCenter(y);
   }
   y_bin_mean /= h.Integral(bin_x,bin_x,1,h.GetNbinsY());
   return y_bin_mean;
}

//_______________________________________________________________________
TH2F* TMVA::Tools::TransposeHist( const TH2F& h )
{
   // Transpose quadratic histogram

   // sanity check
   if (h.GetNbinsX() != h.GetNbinsY()) {
      Log() << kFATAL << "<TransposeHist> cannot transpose non-quadratic histogram" << Endl;
   }

   TH2F *transposedHisto = new TH2F( h );
   for (Int_t ix=1; ix <= h.GetNbinsX(); ix++){
      for (Int_t iy=1; iy <= h.GetNbinsY(); iy++){
         transposedHisto->SetBinContent(iy,ix,h.GetBinContent(ix,iy));
      }
   }

   // copy stats (thanks to Swagato Banerjee for pointing out the missing stats information)
   Double_t stats_old[7];
   Double_t stats_new[7];

   h.GetStats(stats_old);
   stats_new[0] = stats_old[0];
   stats_new[1] = stats_old[1];
   stats_new[2] = stats_old[4];
   stats_new[3] = stats_old[5];
   stats_new[4] = stats_old[2];
   stats_new[5] = stats_old[3];
   stats_new[6] = stats_old[6];
   transposedHisto->PutStats(stats_new);

   return transposedHisto; // ownership returned
}

//_______________________________________________________________________
Bool_t TMVA::Tools::CheckForSilentOption( const TString& cs ) const
{
   // check for "silence" option in configuration option string
   Bool_t isSilent = kFALSE;

   TString s( cs );
   s.ToLower();
   s.ReplaceAll(" ","");
   if (s.Contains("silent") && !s.Contains("silent=f")) {
      if (!s.Contains("!silent") || s.Contains("silent=t")) isSilent = kTRUE;
   }

   return isSilent;
}

//_______________________________________________________________________
Bool_t TMVA::Tools::CheckForVerboseOption( const TString& cs ) const
{
   // check if verbosity "V" set in option
   Bool_t isVerbose = kFALSE;

   TString s( cs );
   s.ToLower();
   s.ReplaceAll(" ","");
   std::vector<TString> v = SplitString( s, ':' );
   for (std::vector<TString>::iterator it = v.begin(); it != v.end(); it++) {
      if ((*it == "v" || *it == "verbose") && !it->Contains("!")) isVerbose = kTRUE;
   }

   return isVerbose;
}

//_______________________________________________________________________
void TMVA::Tools::UsefulSortDescending( std::vector<Double_t>& v )
{
   // sort vector
   vector< vector<Double_t> > vtemp;
   vtemp.push_back(v);
   UsefulSortDescending(vtemp);
   v = vtemp[0];
}

//_______________________________________________________________________
void TMVA::Tools::UsefulSortAscending( std::vector<Double_t>& v )
{
   // sort vector
   vector<vector<Double_t> > vtemp;
   vtemp.push_back(v);
   UsefulSortAscending(vtemp);
   v = vtemp[0];
}

//_______________________________________________________________________
Int_t TMVA::Tools::GetIndexMaxElement( std::vector<Double_t>& v )
{
   // find index of maximum entry in vector
   if (v.empty()) return -1;

   Int_t pos=0; Double_t mx=v[0];
   for (UInt_t i=0; i<v.size(); i++){
      if (v[i] > mx){
         mx=v[i];
         pos=i;
      }
   }
   return pos;
}

//_______________________________________________________________________
Int_t TMVA::Tools::GetIndexMinElement( std::vector<Double_t>& v )
{
   // find index of minimum entry in vector
   if (v.empty()) return -1;

   Int_t pos=0; Double_t mn=v[0];
   for (UInt_t i=0; i<v.size(); i++){
      if (v[i] < mn){
         mn=v[i];
         pos=i;
      }
   }
   return pos;
}


//_______________________________________________________________________
Bool_t TMVA::Tools::ContainsRegularExpression( const TString& s )
{
   // check if regular expression
   // helper function to search for "$!%^&()'<>?= " in a string

   Bool_t  regular = kFALSE;
   for (Int_t i = 0; i < Tools::fRegexp.Length(); i++)
      if (s.Contains( Tools::fRegexp[i] )) { regular = kTRUE; break; }

   return regular;
}

//_______________________________________________________________________
TString TMVA::Tools::ReplaceRegularExpressions( const TString& s, const TString& r )
{
   // replace regular expressions
   // helper function to remove all occurences "$!%^&()'<>?= " from a string
   // and replace all ::,$,*,/,+,- with _M_,_S_,_T_,_D_,_P_,_M_ respectively

   TString snew = s;
   for (Int_t i = 0; i < Tools::fRegexp.Length(); i++)
      snew.ReplaceAll( Tools::fRegexp[i], r );

   snew.ReplaceAll( "::", r );
   snew.ReplaceAll( "$", "_S_" );
   snew.ReplaceAll( "&", "_A_" );
   snew.ReplaceAll( "%", "_MOD_" );
   snew.ReplaceAll( "|", "_O_" );
   snew.ReplaceAll( "*", "_T_" );
   snew.ReplaceAll( "/", "_D_" );
   snew.ReplaceAll( "+", "_P_" );
   snew.ReplaceAll( "-", "_M_" );
   snew.ReplaceAll( " ", "_" );
   snew.ReplaceAll( "[", "_" );
   snew.ReplaceAll( "]", "_" );
   snew.ReplaceAll( "=", "_E_" );
   snew.ReplaceAll( ">", "_GT_" );
   snew.ReplaceAll( "<", "_LT_" );
   snew.ReplaceAll( "(", "_" );
   snew.ReplaceAll( ")", "_" );

   return snew;
}

//_______________________________________________________________________
const TString& TMVA::Tools::Color( const TString& c )
{
   // human readable color strings
   static const TString gClr_none         = "" ;
   static const TString gClr_white        = "\033[1;37m";  // white
   static const TString gClr_black        = "\033[30m";    // black
   static const TString gClr_blue         = "\033[34m";    // blue
   static const TString gClr_red          = "\033[1;31m" ; // red
   static const TString gClr_yellow       = "\033[1;33m";  // yellow
   static const TString gClr_darkred      = "\033[31m";    // dark red
   static const TString gClr_darkgreen    = "\033[32m";    // dark green
   static const TString gClr_darkyellow   = "\033[33m";    // dark yellow

   static const TString gClr_bold         = "\033[1m"    ; // bold
   static const TString gClr_black_b      = "\033[30m"   ; // bold black
   static const TString gClr_lblue_b      = "\033[1;34m" ; // bold light blue
   static const TString gClr_cyan_b       = "\033[0;36m" ; // bold cyan
   static const TString gClr_lgreen_b     = "\033[1;32m";  // bold light green

   static const TString gClr_blue_bg      = "\033[44m";    // blue background
   static const TString gClr_red_bg       = "\033[1;41m";  // white on red background
   static const TString gClr_whiteonblue  = "\033[1;44m";  // white on blue background
   static const TString gClr_whiteongreen = "\033[1;42m";  // white on green background
   static const TString gClr_grey_bg      = "\033[47m";    // grey background

   static const TString gClr_reset  = "\033[0m";     // reset

   if (!gConfig().UseColor()) return gClr_none;

   if (c == "white" )         return gClr_white;
   if (c == "blue"  )         return gClr_blue;
   if (c == "black"  )        return gClr_black;
   if (c == "lightblue")      return gClr_cyan_b;
   if (c == "yellow")         return gClr_yellow;
   if (c == "red"   )         return gClr_red;
   if (c == "dred"  )         return gClr_darkred;
   if (c == "dgreen")         return gClr_darkgreen;
   if (c == "lgreenb")        return gClr_lgreen_b;
   if (c == "dyellow")        return gClr_darkyellow;

   if (c == "bold")           return gClr_bold;
   if (c == "bblack")         return gClr_black_b;

   if (c == "blue_bgd")       return gClr_blue_bg;
   if (c == "red_bgd" )       return gClr_red_bg;

   if (c == "white_on_blue" ) return gClr_whiteonblue;
   if (c == "white_on_green") return gClr_whiteongreen;

   if (c == "reset") return gClr_reset;

   std::cout << "Unknown color " << c << std::endl;
   exit(1);

   return gClr_none;
}

//_______________________________________________________________________
void TMVA::Tools::FormattedOutput( const std::vector<Double_t>& values, const std::vector<TString>& V,
                                   const TString titleVars, const TString titleValues, MsgLogger& logger,
                                   TString format )
{
   // formatted output of simple table

   // sanity check
   UInt_t nvar = V.size();
   if ((UInt_t)values.size() != nvar) {
      logger << kFATAL << "<FormattedOutput> fatal error with dimensions: "
             << values.size() << " OR " << " != " << nvar << Endl;
   }

   // find maximum length in V (and column title)
   UInt_t maxL = 7;
   std::vector<UInt_t> vLengths;
   for (UInt_t ivar=0; ivar<nvar; ivar++) maxL = TMath::Max( (UInt_t)V[ivar].Length(), maxL );
   maxL = TMath::Max( (UInt_t)titleVars.Length(), maxL );

   // column length
   UInt_t maxV = 7;
   maxV = TMath::Max( (UInt_t)titleValues.Length() + 1, maxL );

   // full column length
   UInt_t clen = maxL + maxV + 3;

   // bar line
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;

   // title bar
   logger << setw(maxL) << titleVars << ":";
   logger << setw(maxV+1) << titleValues << ":";
   logger << Endl;
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;

   // the numbers
   for (UInt_t irow=0; irow<nvar; irow++) {
      logger << setw(maxL) << V[irow] << ":";
      logger << setw(maxV+1) << Form( format.Data(), values[irow] );
      logger << Endl;
   }

   // bar line
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;
}

//_______________________________________________________________________
void TMVA::Tools::FormattedOutput( const TMatrixD& M, const std::vector<TString>& V, MsgLogger& logger )
{
   // formatted output of matrix (with labels)

   // sanity check: matrix must be quadratic
   UInt_t nvar = V.size();
   if ((UInt_t)M.GetNcols() != nvar || (UInt_t)M.GetNrows() != nvar) {
      logger << kFATAL << "<FormattedOutput> fatal error with dimensions: "
             << M.GetNcols() << " OR " << M.GetNrows() << " != " << nvar << " ==> abort" << Endl;
   }

   // get length of each variable, and maximum length
   UInt_t minL = 7;
   UInt_t maxL = minL;
   std::vector<UInt_t> vLengths;
   for (UInt_t ivar=0; ivar<nvar; ivar++) {
      vLengths.push_back(TMath::Max( (UInt_t)V[ivar].Length(), minL ));
      maxL = TMath::Max( vLengths.back(), maxL );
   }

   // count column length
   UInt_t clen = maxL+1;
   for (UInt_t icol=0; icol<nvar; icol++) clen += vLengths[icol]+1;

   // bar line
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;

   // title bar
   logger << setw(maxL+1) << " ";
   for (UInt_t icol=0; icol<nvar; icol++) logger << setw(vLengths[icol]+1) << V[icol];
   logger << Endl;

   // the numbers
   for (UInt_t irow=0; irow<nvar; irow++) {
      logger << setw(maxL) << V[irow] << ":";
      for (UInt_t icol=0; icol<nvar; icol++) {
         logger << setw(vLengths[icol]+1) << Form( "%+1.3f", M(irow,icol) );
      }
      logger << Endl;
   }

   // bar line
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;
}

//_______________________________________________________________________
void TMVA::Tools::FormattedOutput( const TMatrixD& M,
                                   const std::vector<TString>& vert, const std::vector<TString>& horiz,
                                   MsgLogger& logger )
{
   // formatted output of matrix (with labels)

   // sanity check: matrix must be quadratic
   UInt_t nvvar = vert.size();
   UInt_t nhvar = horiz.size();

   // get length of each variable, and maximum length
   UInt_t minL = 7;
   UInt_t maxL = minL;
   std::vector<UInt_t> vLengths;
   for (UInt_t ivar=0; ivar<nvvar; ivar++) {
      vLengths.push_back(TMath::Max( (UInt_t)vert[ivar].Length(), minL ));
      maxL = TMath::Max( vLengths.back(), maxL );
   }

   // count column length
   UInt_t minLh = 7;
   UInt_t maxLh = minLh;
   std::vector<UInt_t> hLengths;
   for (UInt_t ivar=0; ivar<nhvar; ivar++) {
      hLengths.push_back(TMath::Max( (UInt_t)horiz[ivar].Length(), minL ));
      maxLh = TMath::Max( hLengths.back(), maxLh );
   }

   UInt_t clen = maxLh+1;
   for (UInt_t icol=0; icol<nhvar; icol++) clen += hLengths[icol]+1;

   // bar line
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;

   // title bar
   logger << setw(maxL+1) << " ";
   for (UInt_t icol=0; icol<nhvar; icol++) logger << setw(hLengths[icol]+1) << horiz[icol];
   logger << Endl;

   // the numbers
   for (UInt_t irow=0; irow<nvvar; irow++) {
      logger << setw(maxL) << vert[irow] << ":";
      for (UInt_t icol=0; icol<nhvar; icol++) {
         logger << setw(hLengths[icol]+1) << Form( "%+1.3f", M(irow,icol) );
      }
      logger << Endl;
   }

   // bar line
   for (UInt_t i=0; i<clen; i++) logger << "-";
   logger << Endl;
}

//_______________________________________________________________________
TString TMVA::Tools::GetXTitleWithUnit( const TString& title, const TString& unit )
{
   // histogramming utility
   return ( unit == "" ? title : ( title + "  [" + unit + "]" ) );
}

//_______________________________________________________________________
TString TMVA::Tools::GetYTitleWithUnit( const TH1& h, const TString& unit, Bool_t normalised )
{
   // histogramming utility
   TString retval = ( normalised ? "(1/N) " : "" );
   retval += Form( "dN_{ }/^{ }%.3g %s", h.GetXaxis()->GetBinWidth(1), unit.Data() );
   return retval;
}

//_______________________________________________________________________
void TMVA::Tools::WriteFloatArbitraryPrecision( Float_t val, ostream& os )
{
   // writes a float value with the available precision to a stream
   os << val << " :: ";
   void * c = &val;
   for (int i=0; i<4; i++) {
      Int_t ic = *((char*)c+i)-'\0';
      if (ic<0) ic+=256;
      os << ic << " ";
   }
   os << ":: ";
}

//_______________________________________________________________________
void TMVA::Tools::ReadFloatArbitraryPrecision( Float_t& val, istream& is )
{
   // reads a float value with the available precision from a stream
   Float_t a = 0;
   is >> a;
   TString dn;
   is >> dn;
   Int_t c[4];
   void * ap = &a;
   for (int i=0; i<4; i++) {
      is >> c[i];
      *((char*)ap+i) = '\0'+c[i];
   }
   is >> dn;
   val = a;
}


// XML file reading/writing helper functions

//_______________________________________________________________________
Bool_t TMVA::Tools::HasAttr( void* node, const char* attrname )
{
   // add attribute from xml
   return xmlengine().HasAttr(node, attrname);
}

//_______________________________________________________________________
void TMVA::Tools::ReadAttr( void* node, const char* attrname, TString& value )
{
   // add attribute from xml
   if (!HasAttr(node, attrname)) {
      const char * nodename = xmlengine().GetNodeName(node);
      Log() << kFATAL << "Trying to read non-existing attribute '" << attrname << "' from xml node '" << nodename << "'" << Endl;
   }
   const char* val = xmlengine().GetAttr(node, attrname);
   value = TString(val);
}

//_______________________________________________________________________
void TMVA::Tools::AddAttr( void* node, const char* attrname, const char* value )
{
   // add attribute to node
   if( node == 0 ) return;
   gTools().xmlengine().NewAttr(node, 0, attrname, value );
}

//_______________________________________________________________________
void* TMVA::Tools::AddChild( void* parent, const char* childname, const char* content, bool isRootNode )
{
   // add child node
   if( !isRootNode && parent == 0 ) return 0;
   return gTools().xmlengine().NewChild(parent, 0, childname, content);
}

//_______________________________________________________________________
Bool_t TMVA::Tools::AddComment( void* node, const char* comment ) {
   if( node == 0 ) return kFALSE;
   return gTools().xmlengine().AddComment(node, comment);
}
//_______________________________________________________________________
void* TMVA::Tools::GetParent( void* child)
{
   // get parent node
   void* par = xmlengine().GetParent(child);

   return par;
}
//_______________________________________________________________________
void* TMVA::Tools::GetChild( void* parent, const char* childname )
{
   // get child node
   void* ch = xmlengine().GetChild(parent);
   if (childname != 0) {
      while (ch!=0 && strcmp(xmlengine().GetNodeName(ch),childname) != 0) ch = xmlengine().GetNext(ch);
   }
   return ch;
}

//_______________________________________________________________________
void* TMVA::Tools::GetNextChild( void* prevchild, const char* childname )
{
   // XML helpers
   void* ch = xmlengine().GetNext(prevchild);
   if (childname != 0) {
      while (ch!=0 && strcmp(xmlengine().GetNodeName(ch),childname)!=0) ch = xmlengine().GetNext(ch);
   }
   return ch;
}

//_______________________________________________________________________
const char* TMVA::Tools::GetContent( void* node )
{
   // XML helpers
   return xmlengine().GetNodeContent(node);
}

//_______________________________________________________________________
const char* TMVA::Tools::GetName( void* node )
{
   // XML helpers
   return xmlengine().GetNodeName(node);
}

//_______________________________________________________________________
Bool_t TMVA::Tools::AddRawLine( void* node, const char * raw )
{
   // XML helpers
   return xmlengine().AddRawLine( node, raw );
}

//_______________________________________________________________________
std::vector<TString> TMVA::Tools::SplitString(const TString& theOpt, const char separator ) const
{
   // splits the option string at 'separator' and fills the list
   // 'splitV' with the primitive strings
   std::vector<TString> splitV;
   TString splitOpt(theOpt);
   splitOpt.ReplaceAll("\n"," ");
   splitOpt = splitOpt.Strip(TString::kBoth,separator);
   while (splitOpt.Length()>0) {
      if ( !splitOpt.Contains(separator) ) {
         splitV.push_back(splitOpt);
         break;
      }
      else {
         TString toSave = splitOpt(0,splitOpt.First(separator));
         splitV.push_back(toSave);
         splitOpt = splitOpt(splitOpt.First(separator),splitOpt.Length());
      }
      splitOpt = splitOpt.Strip(TString::kLeading,separator);
   }
   return splitV;
}

//_______________________________________________________________________
TString TMVA::Tools::StringFromInt( Long_t i )
{
   // string tools
   std::stringstream s;
   s << i;
   return TString(s.str().c_str());
}

//_______________________________________________________________________
TString TMVA::Tools::StringFromDouble( Double_t d )
{
   // string tools
   std::stringstream s;
   s << Form( "%5.8e", d );
   return TString(s.str().c_str());
}

//_______________________________________________________________________
void TMVA::Tools::WriteTMatrixDToXML( void* node, const char* name, TMatrixD* mat )
{
   // XML helpers
   void* matnode = xmlengine().NewChild(node, 0, name);
   xmlengine().NewAttr(matnode,0,"Rows", StringFromInt(mat->GetNrows()) );
   xmlengine().NewAttr(matnode,0,"Columns", StringFromInt(mat->GetNcols()) );
   std::stringstream s;
   for (Int_t row = 0; row<mat->GetNrows(); row++) {
      for (Int_t col = 0; col<mat->GetNcols(); col++) {
         s << Form( "%5.15e ", (*mat)[row][col] );
      }
   }
   xmlengine().AddRawLine( matnode, s.str().c_str() );
}

//_______________________________________________________________________
void TMVA::Tools::WriteTVectorDToXML( void* node, const char* name, TVectorD* vec )
{
   TMatrixD mat(1,vec->GetNoElements(),&((*vec)[0]));
   WriteTMatrixDToXML( node, name, &mat );
}

//_______________________________________________________________________
void TMVA::Tools::ReadTVectorDFromXML( void* node, const char* name, TVectorD* vec )
{
   TMatrixD mat(1,vec->GetNoElements(),&((*vec)[0]));
   ReadTMatrixDFromXML( node, name, &mat );
   for (int i=0;i<vec->GetNoElements();++i) (*vec)[i] = mat[0][i];
}

//_______________________________________________________________________
void TMVA::Tools::ReadTMatrixDFromXML( void* node, const char* name, TMatrixD* mat )
{
   if (strcmp(xmlengine().GetNodeName(node),name)!=0){
      Log() << kWARNING << "Possible Error: Name of matrix in weight file"
            << " does not match name of matrix passed as argument!" << Endl;
   }
   Int_t nrows, ncols;
   ReadAttr( node, "Rows",    nrows );
   ReadAttr( node, "Columns", ncols );
   if (mat->GetNrows() != nrows || mat->GetNcols() != ncols){
      Log() << kWARNING << "Possible Error: Dimension of matrix in weight file"
            << " does not match dimension of matrix passed as argument!" << Endl;
      mat->ResizeTo(nrows,ncols);
   }
   const char* content = xmlengine().GetNodeContent(node);
   std::stringstream s(content);
   for (Int_t row = 0; row<nrows; row++) {
      for (Int_t col = 0; col<ncols; col++) {
         s >> (*mat)[row][col];
      }
   }
}

//_______________________________________________________________________
void TMVA::Tools::TMVAWelcomeMessage()
{
   // direct output, eg, when starting ROOT session -> no use of Logger here
   std::cout << std::endl;
   std::cout << Color("bold") << "TMVA -- Toolkit for Multivariate Data Analysis" << Color("reset") << std::endl;
   std::cout << "        " << "Version " << TMVA_RELEASE << ", " << TMVA_RELEASE_DATE << std::endl;
   std::cout << "        " << "Copyright (C) 2005-2010 CERN, MPI-K Heidelberg, Us of Bonn and Victoria" << std::endl;
   std::cout << "        " << "Home page:     http://tmva.sf.net" << std::endl;
   std::cout << "        " << "Citation info: http://tmva.sf.net/citeTMVA.html" << std::endl;
   std::cout << "        " << "License:       http://tmva.sf.net/LICENSE" << std::endl << std::endl;
}

//_______________________________________________________________________
void TMVA::Tools::TMVAVersionMessage( MsgLogger& logger )
{
   // prints the TMVA release number and date
   logger << "___________TMVA Version " << TMVA_RELEASE << ", " << TMVA_RELEASE_DATE
          << "" << Endl;
}

//_______________________________________________________________________
void TMVA::Tools::ROOTVersionMessage( MsgLogger& logger )
{
   // prints the ROOT release number and date
   static const char * const months[] = { "Jan","Feb","Mar","Apr","May",
                                   "Jun","Jul","Aug","Sep","Oct",
                                   "Nov","Dec" };
   Int_t   idatqq = gROOT->GetVersionDate();
   Int_t   iday   = idatqq%100;
   Int_t   imonth = (idatqq/100)%100;
   Int_t   iyear  = (idatqq/10000);
   TString versionDate = Form("%s %d, %4d",months[imonth-1],iday,iyear);

   logger << "You are running ROOT Version: " << gROOT->GetVersion() << ", " << versionDate << Endl;
}

//_______________________________________________________________________
void TMVA::Tools::TMVAWelcomeMessage( MsgLogger& logger, EWelcomeMessage msgType )
{
   // various kinds of welcome messages
   // ASCII text generated by this site: http://www.network-science.de/ascii/

   switch (msgType) {

   case kStandardWelcomeMsg:
      logger << Color("white") << "TMVA -- Toolkit for Multivariate Analysis" << Color("reset") << Endl;
      logger << "Copyright (C) 2005-2006 CERN, LAPP & MPI-K Heidelberg and Victoria U." << Endl;
      logger << "Home page http://tmva.sourceforge.net" << Endl;
      logger << "All rights reserved, please read http://tmva.sf.net/license.txt" << Endl << Endl;
      break;

   case kIsometricWelcomeMsg:
      logger << "   ___           ___           ___           ___      " << Endl;
      logger << "  /\\  \\         /\\__\\         /\\__\\         /\\  \\     " << Endl;
      logger << "  \\:\\  \\       /::|  |       /:/  /        /::\\  \\    " << Endl;
      logger << "   \\:\\  \\     /:|:|  |      /:/  /        /:/\\:\\  \\   " << Endl;
      logger << "   /::\\  \\   /:/|:|__|__   /:/__/  ___   /::\\~\\:\\  \\  " << Endl;
      logger << "  /:/\\:\\__\\ /:/ |::::\\__\\  |:|  | /\\__\\ /:/\\:\\ \\:\\__\\ " << Endl;
      logger << " /:/  \\/__/ \\/__/~~/:/  /  |:|  |/:/  / \\/__\\:\\/:/  / " << Endl;
      logger << "/:/  /            /:/  /   |:|__/:/  /       \\::/  /  " << Endl;
      logger << "\\/__/            /:/  /     \\::::/__/        /:/  /   " << Endl;
      logger << "                /:/  /       ~~~~           /:/  /    " << Endl;
      logger << "                \\/__/                       \\/__/     " << Endl << Endl;
      break;

   case kBlockWelcomeMsg:
      logger << Endl;
      logger << "_|_|_|_|_|  _|      _|  _|      _|    _|_|    " << Endl;
      logger << "    _|      _|_|  _|_|  _|      _|  _|    _|  " << Endl;
      logger << "    _|      _|  _|  _|  _|      _|  _|_|_|_|  " << Endl;
      logger << "    _|      _|      _|    _|  _|    _|    _|  " << Endl;
      logger << "    _|      _|      _|      _|      _|    _|  " << Endl << Endl;
      break;

   case kLeanWelcomeMsg:
      logger << Endl;
      logger << "_/_/_/_/_/  _/      _/  _/      _/    _/_/   " << Endl;
      logger << "   _/      _/_/  _/_/  _/      _/  _/    _/  " << Endl;
      logger << "  _/      _/  _/  _/  _/      _/  _/_/_/_/   " << Endl;
      logger << " _/      _/      _/    _/  _/    _/    _/    " << Endl;
      logger << "_/      _/      _/      _/      _/    _/     " << Endl << Endl;
      break;

   case kLogoWelcomeMsg:
      logger << Endl;
      logger << "_/_/_/_/_/ _|      _|  _|      _|    _|_|   " << Endl;
      logger << "   _/      _|_|  _|_|  _|      _|  _|    _| " << Endl;
      logger << "  _/       _|  _|  _|  _|      _|  _|_|_|_| " << Endl;
      logger << " _/        _|      _|    _|  _|    _|    _| " << Endl;
      logger << "_/         _|      _|      _|      _|    _| " << Endl << Endl;
      break;

   case kSmall1WelcomeMsg:
      logger << " _____ __  ____   ___   " << Endl;
      logger << "|_   _|  \\/  \\ \\ / /_\\  " << Endl;
      logger << "  | | | |\\/| |\\ V / _ \\ " << Endl;
      logger << "  |_| |_|  |_| \\_/_/ \\_\\" << Endl << Endl;
      break;

   case kSmall2WelcomeMsg:
      logger << " _____ __  ____     ___     " << Endl;
      logger << "|_   _|  \\/  \\ \\   / / \\    " << Endl;
      logger << "  | | | |\\/| |\\ \\ / / _ \\   " << Endl;
      logger << "  | | | |  | | \\ V / ___ \\  " << Endl;
      logger << "  |_| |_|  |_|  \\_/_/   \\_\\ " << Endl << Endl;
      break;

   case kOriginalWelcomeMsgColor:
      logger << kINFO << "" << Color("red")
             << "_______________________________________" << Color("reset") << Endl;
      logger << kINFO << "" << Color("blue")
             << Color("red_bgd") << Color("bwhite") << " // " << Color("reset")
             << Color("white") << Color("blue_bgd")
             << "|\\  /|| \\  //  /\\\\\\\\\\\\\\\\\\\\\\\\ \\ \\ \\ " << Color("reset") << Endl;
      logger << kINFO << ""<< Color("blue")
             << Color("red_bgd") << Color("white") << "//  " << Color("reset")
             << Color("white") << Color("blue_bgd")
             << "| \\/ ||  \\//  /--\\\\\\\\\\\\\\\\\\\\\\\\ \\ \\ \\" << Color("reset") << Endl;
      break;

   case kOriginalWelcomeMsgBW:
      logger << kINFO << ""
             << "_______________________________________" << Endl;
      logger << kINFO << " // "
             << "|\\  /|| \\  //  /\\\\\\\\\\\\\\\\\\\\\\\\ \\ \\ \\ " << Endl;
      logger << kINFO << "//  "
             << "| \\/ ||  \\//  /--\\\\\\\\\\\\\\\\\\\\\\\\ \\ \\ \\" << Endl;
      break;

   default:
      logger << kFATAL << "unknown message type: " << msgType << Endl;
   }
}

//_______________________________________________________________________
void TMVA::Tools::TMVACitation( MsgLogger& logger, ECitation citType )
{
   // kinds of TMVA citation

   switch (citType) {

   case kPlainText:
      logger << "A. Hoecker, P. Speckmayer, J. Stelzer, J. Therhaag, E. von Toerne, H. Voss" << Endl;
      logger << "\"TMVA - Toolkit for Multivariate Data Analysis\" PoS ACAT:040,2007. e-Print: physics/0703039" << Endl;
      break;

   case kBibTeX:
      logger << "@Article{TMVA2007," << Endl;
      logger << "     author    = \"Hoecker, Andreas and Speckmayer, Peter and Stelzer, Joerg " << Endl;
      logger << "                   and Therhaag, Jan and von Toerne, Eckhard and Voss, Helge\"," << Endl;
      logger << "     title     = \"{TMVA: Toolkit for multivariate data analysis}\"," << Endl;
      logger << "     journal   = \"PoS\"," << Endl;
      logger << "     volume    = \"ACAT\"," << Endl;
      logger << "     year      = \"2007\"," << Endl;
      logger << "     pages     = \"040\"," << Endl;
      logger << "     eprint    = \"physics/0703039\"," << Endl;
      logger << "     archivePrefix = \"arXiv\"," << Endl;
      logger << "     SLACcitation  = \"%%CITATION = PHYSICS/0703039;%%\"" << Endl;
      logger << "}" << Endl;
      break;

   case kLaTeX:
      logger << "%\\cite{TMVA2007}" << Endl;
      logger << "\\bibitem{TMVA2007}" << Endl;
      logger << "  A.~Hoecker, P.~Speckmayer, J.~Stelzer, J.~Therhaag, E.~von Toerne, H.~Voss" << Endl;
      logger << "  %``TMVA: Toolkit for multivariate data analysis,''" << Endl;
      logger << "  PoS A {\\bf CAT} (2007) 040" << Endl;
      logger << "  [arXiv:physics/0703039]." << Endl;
      logger << "  %%CITATION = POSCI,ACAT,040;%%" << Endl;
      break;

   case kHtmlLink:
      logger << kINFO << "  " << Endl;
      logger << kINFO << gTools().Color("bold")
             << "Thank you for using TMVA!" << gTools().Color("reset") << Endl;
      logger << kINFO << gTools().Color("bold")
             << "For citation information, please visit: http://tmva.sf.net/citeTMVA.html"
             << gTools().Color("reset") << Endl;
   }
}

//_______________________________________________________________________
Bool_t TMVA::Tools::HistoHasEquidistantBins(const TH1& h)
{
   return !(h.GetXaxis()->GetXbins()->fN);
}

//_______________________________________________________________________
std::vector<TMatrixDSym*>*
TMVA::Tools::CalcCovarianceMatrices( const std::vector<const Event*>& events, Int_t maxCls, VariableTransformBase* transformBase )
{
   std::vector<Event*> eventVector;
   for (std::vector<const Event*>::const_iterator it = events.begin(), itEnd = events.end(); it != itEnd; ++it)
   {
      eventVector.push_back (new Event(*(*it)));
   }
   std::vector<TMatrixDSym*>* returnValue = CalcCovarianceMatrices (eventVector, maxCls, transformBase);
   for (std::vector<Event*>::const_iterator it = eventVector.begin(), itEnd = eventVector.end(); it != itEnd; ++it)
   {
      delete (*it);
   }
   return returnValue;
}

//_______________________________________________________________________
std::vector<TMatrixDSym*>*
TMVA::Tools::CalcCovarianceMatrices( const std::vector<Event*>& events, Int_t maxCls, VariableTransformBase* transformBase )
{
   // compute covariance matrices

   if (events.empty()) {
      Log() << kWARNING << " Asked to calculate a covariance matrix for an empty event vectors.. sorry cannot do that -> return NULL"<<Endl;
      return 0;
   }

   UInt_t nvars=0, ntgts=0, nspcts=0;
   if (transformBase)
      transformBase->CountVariableTypes( nvars, ntgts, nspcts );
   else {
      nvars =events.at(0)->GetNVariables ();
      ntgts =events.at(0)->GetNTargets   ();
      nspcts=events.at(0)->GetNSpectators();
   }


   // init matrices
   Int_t matNum = maxCls;
   if (maxCls > 1 ) matNum++; // if more than one classes, then produce one matrix for all events as well (beside the matrices for each class)

   std::vector<TVectorD*>* vec = new std::vector<TVectorD*>(matNum);
   std::vector<TMatrixD*>* mat2 = new std::vector<TMatrixD*>(matNum);
   std::vector<Double_t> count(matNum);
   count.assign(matNum,0);

   Int_t cls = 0;
   TVectorD* v;
   TMatrixD* m;
   UInt_t ivar=0, jvar=0;
   for (cls = 0; cls < matNum ; cls++) {
      vec->at(cls) = new TVectorD(nvars);
      mat2->at(cls) = new TMatrixD(nvars,nvars);
      v = vec->at(cls);
      m = mat2->at(cls);

      for (ivar=0; ivar<nvars; ivar++) {
         (*v)(ivar) = 0;
         for (jvar=0; jvar<nvars; jvar++) {
            (*m)(ivar, jvar) = 0;
         }
      }
   }

   // perform event loop
   for (UInt_t i=0; i<events.size(); i++) {

      // fill the event
      const Event * ev = events[i];
      cls = ev->GetClass();
      Double_t weight = ev->GetWeight();

      std::vector<Float_t> input;
      std::vector<Char_t> mask; // entries with kTRUE must not be transformed
      // Bool_t hasMaskedEntries = kFALSE;
      if (transformBase) {
         /* hasMaskedEntries = */ transformBase->GetInput (ev, input, mask);
      } else {
         for (ivar=0; ivar<nvars; ++ivar) {
            input.push_back (ev->GetValue(ivar));
         }
      }

      if (maxCls > 1) {
         v = vec->at(matNum-1);
         m = mat2->at(matNum-1);

         count.at(matNum-1)+=weight; // count used events
         for (ivar=0; ivar<nvars; ivar++) {

            Double_t xi = input.at (ivar);
            (*v)(ivar) += xi*weight;
            (*m)(ivar, ivar) += (xi*xi*weight);

            for (jvar=ivar+1; jvar<nvars; jvar++) {
               Double_t xj = input.at (jvar);
               (*m)(ivar, jvar) += (xi*xj*weight);
               (*m)(jvar, ivar) = (*m)(ivar, jvar); // symmetric matrix
            }
         }
      }

      count.at(cls)+=weight; // count used events
      v = vec->at(cls);
      m = mat2->at(cls);
      for (ivar=0; ivar<nvars; ivar++) {
         Double_t xi = input.at (ivar);
         (*v)(ivar) += xi*weight;
         (*m)(ivar, ivar) += (xi*xi*weight);

         for (jvar=ivar+1; jvar<nvars; jvar++) {
            Double_t xj = input.at (jvar);
            (*m)(ivar, jvar) += (xi*xj*weight);
            (*m)(jvar, ivar) = (*m)(ivar, jvar); // symmetric matrix
         }
      }
   }

   // variance-covariance
   std::vector<TMatrixDSym*>* mat = new std::vector<TMatrixDSym*>(matNum);
   for (cls = 0; cls < matNum; cls++) {
      v = vec->at(cls);
      m = mat2->at(cls);

      mat->at(cls) = new TMatrixDSym(nvars);

      Double_t n = count.at(cls);
      for (ivar=0; ivar<nvars; ivar++) {
         for (jvar=0; jvar<nvars; jvar++) {
            (*(mat->at(cls)))(ivar, jvar) = (*m)(ivar, jvar)/n - (*v)(ivar)*(*v)(jvar)/(n*n);
         }
      }
      delete v;
      delete m;
   }

   delete mat2;
   delete vec;

   return mat;
}

template <typename Iterator, typename WeightIterator>
Double_t TMVA::Tools::Mean ( Iterator first,  Iterator last,  WeightIterator w)
{
   // Return the weighted mean of an array defined by the first and
   // last iterators. The w iterator should point to the first element
   // of a vector of weights of the same size as the main array.

   Double_t sum = 0;
   Double_t sumw = 0;
   int i = 0;
   if (w==NULL)
   {
      while ( first != last )
      {
         // if ( *w < 0) {
         //    ::Error("TMVA::Tools::Mean","w[%d] = %.4e < 0 ?!",i,*w);
         //    return 0;
         // } // SURE, why wouldn't you allow for negative event weights here ?? :)
         sum  += (*first);
         sumw += 1.0 ;
         ++first;
         ++i;
      }
      if (sumw <= 0) {
         ::Error("TMVA::Tools::Mean","sum of weights <= 0 ?! that's a bit too much of negative event weights :) ");
         return 0;
      }
   }
   else
   {
      while ( first != last )
      {
         // if ( *w < 0) {
         //    ::Error("TMVA::Tools::Mean","w[%d] = %.4e < 0 ?!",i,*w);
         //    return 0;
         // } // SURE, why wouldn't you allow for negative event weights here ?? :)
         sum  += (*w) * (*first);
         sumw += (*w) ;
         ++w;
         ++first;
         ++i;
      }
      if (sumw <= 0) {
         ::Error("TMVA::Tools::Mean","sum of weights <= 0 ?! that's a bit too much of negative event weights :) ");
         return 0;
      }
   }
   return sum/sumw;
}

template <typename T>
Double_t TMVA::Tools::Mean(Long64_t n, const T *a, const Double_t *w)
{
   // Return the weighted mean of an array a with length n.

   if (w) {
      return TMVA::Tools::Mean(a, a+n, w);
   } else {
      return TMath::Mean(a, a+n);
   }
}

template <typename Iterator, typename WeightIterator>
Double_t TMVA::Tools::RMS(Iterator first, Iterator last, WeightIterator w)
{
   // Return the Standard Deviation of an array defined by the iterators.
   // Note that this function returns the sigma(standard deviation) and
   // not the root mean square of the array.

   Double_t sum = 0;
   Double_t sum2 = 0;
   Double_t sumw = 0;

   Double_t adouble;
   if (w==NULL)
   {
      while ( first != last ) {
         adouble=Double_t(*first);
         sum  += adouble;
         sum2 += adouble*adouble;
         sumw += 1.0;
         ++first;
      }
   }
   else
   {
      while ( first != last ) {
         adouble=Double_t(*first);
         sum  += adouble * (*w);
         sum2 += adouble*adouble * (*w);
         sumw += (*w);
         ++first;
         ++w;
      }
   }
   Double_t norm = 1./sumw;
   Double_t mean = sum*norm;
   Double_t rms = TMath::Sqrt(TMath::Abs(sum2*norm -mean*mean));
   return rms;
}

template <typename T>
Double_t TMVA::Tools::RMS(Long64_t n, const T *a, const Double_t *w)
{
   // Return the Standard Deviation of an array a with length n.
   // Note that this function returns the sigma(standard deviation) and
   // not the root mean square of the array.

   if (w) {
      return TMVA::Tools::RMS(a, a+n, w);
   } else {
      return TMath::RMS(a, a+n);
   }
}


TH1* TMVA::Tools::GetCumulativeDist( TH1* h)
{
   // get the cumulative distribution of a histogram
   TH1* cumulativeDist= (TH1*) h->Clone(Form("%sCumul",h->GetTitle()));
   //cumulativeDist->Smooth(5); // with this, I get less beautiful ROC curves, hence out!

   Float_t partialSum = 0;
   Float_t inverseSum = 0.;

   Float_t val;
   for (Int_t ibinEnd=1, ibin=cumulativeDist->GetNbinsX(); ibin >=ibinEnd ; ibin--){
      val = cumulativeDist->GetBinContent(ibin);
      if (val>0) inverseSum += val;
   }
   inverseSum = 1/inverseSum; // as I learned multiplications are much faster than division, and later I need one per bin. Well, not that it would really matter here I guess :)

   for (Int_t ibinEnd=1, ibin=cumulativeDist->GetNbinsX(); ibin >=ibinEnd ; ibin--){
      val = cumulativeDist->GetBinContent(ibin);
      if (val>0) partialSum += val;
      cumulativeDist->SetBinContent(ibin,partialSum*inverseSum);
   }
   return cumulativeDist;
}
 Tools.cxx:1
 Tools.cxx:2
 Tools.cxx:3
 Tools.cxx:4
 Tools.cxx:5
 Tools.cxx:6
 Tools.cxx:7
 Tools.cxx:8
 Tools.cxx:9
 Tools.cxx:10
 Tools.cxx:11
 Tools.cxx:12
 Tools.cxx:13
 Tools.cxx:14
 Tools.cxx:15
 Tools.cxx:16
 Tools.cxx:17
 Tools.cxx:18
 Tools.cxx:19
 Tools.cxx:20
 Tools.cxx:21
 Tools.cxx:22
 Tools.cxx:23
 Tools.cxx:24
 Tools.cxx:25
 Tools.cxx:26
 Tools.cxx:27
 Tools.cxx:28
 Tools.cxx:29
 Tools.cxx:30
 Tools.cxx:31
 Tools.cxx:32
 Tools.cxx:33
 Tools.cxx:34
 Tools.cxx:35
 Tools.cxx:36
 Tools.cxx:37
 Tools.cxx:38
 Tools.cxx:39
 Tools.cxx:40
 Tools.cxx:41
 Tools.cxx:42
 Tools.cxx:43
 Tools.cxx:44
 Tools.cxx:45
 Tools.cxx:46
 Tools.cxx:47
 Tools.cxx:48
 Tools.cxx:49
 Tools.cxx:50
 Tools.cxx:51
 Tools.cxx:52
 Tools.cxx:53
 Tools.cxx:54
 Tools.cxx:55
 Tools.cxx:56
 Tools.cxx:57
 Tools.cxx:58
 Tools.cxx:59
 Tools.cxx:60
 Tools.cxx:61
 Tools.cxx:62
 Tools.cxx:63
 Tools.cxx:64
 Tools.cxx:65
 Tools.cxx:66
 Tools.cxx:67
 Tools.cxx:68
 Tools.cxx:69
 Tools.cxx:70
 Tools.cxx:71
 Tools.cxx:72
 Tools.cxx:73
 Tools.cxx:74
 Tools.cxx:75
 Tools.cxx:76
 Tools.cxx:77
 Tools.cxx:78
 Tools.cxx:79
 Tools.cxx:80
 Tools.cxx:81
 Tools.cxx:82
 Tools.cxx:83
 Tools.cxx:84
 Tools.cxx:85
 Tools.cxx:86
 Tools.cxx:87
 Tools.cxx:88
 Tools.cxx:89
 Tools.cxx:90
 Tools.cxx:91
 Tools.cxx:92
 Tools.cxx:93
 Tools.cxx:94
 Tools.cxx:95
 Tools.cxx:96
 Tools.cxx:97
 Tools.cxx:98
 Tools.cxx:99
 Tools.cxx:100
 Tools.cxx:101
 Tools.cxx:102
 Tools.cxx:103
 Tools.cxx:104
 Tools.cxx:105
 Tools.cxx:106
 Tools.cxx:107
 Tools.cxx:108
 Tools.cxx:109
 Tools.cxx:110
 Tools.cxx:111
 Tools.cxx:112
 Tools.cxx:113
 Tools.cxx:114
 Tools.cxx:115
 Tools.cxx:116
 Tools.cxx:117
 Tools.cxx:118
 Tools.cxx:119
 Tools.cxx:120
 Tools.cxx:121
 Tools.cxx:122
 Tools.cxx:123
 Tools.cxx:124
 Tools.cxx:125
 Tools.cxx:126
 Tools.cxx:127
 Tools.cxx:128
 Tools.cxx:129
 Tools.cxx:130
 Tools.cxx:131
 Tools.cxx:132
 Tools.cxx:133
 Tools.cxx:134
 Tools.cxx:135
 Tools.cxx:136
 Tools.cxx:137
 Tools.cxx:138
 Tools.cxx:139
 Tools.cxx:140
 Tools.cxx:141
 Tools.cxx:142
 Tools.cxx:143
 Tools.cxx:144
 Tools.cxx:145
 Tools.cxx:146
 Tools.cxx:147
 Tools.cxx:148
 Tools.cxx:149
 Tools.cxx:150
 Tools.cxx:151
 Tools.cxx:152
 Tools.cxx:153
 Tools.cxx:154
 Tools.cxx:155
 Tools.cxx:156
 Tools.cxx:157
 Tools.cxx:158
 Tools.cxx:159
 Tools.cxx:160
 Tools.cxx:161
 Tools.cxx:162
 Tools.cxx:163
 Tools.cxx:164
 Tools.cxx:165
 Tools.cxx:166
 Tools.cxx:167
 Tools.cxx:168
 Tools.cxx:169
 Tools.cxx:170
 Tools.cxx:171
 Tools.cxx:172
 Tools.cxx:173
 Tools.cxx:174
 Tools.cxx:175
 Tools.cxx:176
 Tools.cxx:177
 Tools.cxx:178
 Tools.cxx:179
 Tools.cxx:180
 Tools.cxx:181
 Tools.cxx:182
 Tools.cxx:183
 Tools.cxx:184
 Tools.cxx:185
 Tools.cxx:186
 Tools.cxx:187
 Tools.cxx:188
 Tools.cxx:189
 Tools.cxx:190
 Tools.cxx:191
 Tools.cxx:192
 Tools.cxx:193
 Tools.cxx:194
 Tools.cxx:195
 Tools.cxx:196
 Tools.cxx:197
 Tools.cxx:198
 Tools.cxx:199
 Tools.cxx:200
 Tools.cxx:201
 Tools.cxx:202
 Tools.cxx:203
 Tools.cxx:204
 Tools.cxx:205
 Tools.cxx:206
 Tools.cxx:207
 Tools.cxx:208
 Tools.cxx:209
 Tools.cxx:210
 Tools.cxx:211
 Tools.cxx:212
 Tools.cxx:213
 Tools.cxx:214
 Tools.cxx:215
 Tools.cxx:216
 Tools.cxx:217
 Tools.cxx:218
 Tools.cxx:219
 Tools.cxx:220
 Tools.cxx:221
 Tools.cxx:222
 Tools.cxx:223
 Tools.cxx:224
 Tools.cxx:225
 Tools.cxx:226
 Tools.cxx:227
 Tools.cxx:228
 Tools.cxx:229
 Tools.cxx:230
 Tools.cxx:231
 Tools.cxx:232
 Tools.cxx:233
 Tools.cxx:234
 Tools.cxx:235
 Tools.cxx:236
 Tools.cxx:237
 Tools.cxx:238
 Tools.cxx:239
 Tools.cxx:240
 Tools.cxx:241
 Tools.cxx:242
 Tools.cxx:243
 Tools.cxx:244
 Tools.cxx:245
 Tools.cxx:246
 Tools.cxx:247
 Tools.cxx:248
 Tools.cxx:249
 Tools.cxx:250
 Tools.cxx:251
 Tools.cxx:252
 Tools.cxx:253
 Tools.cxx:254
 Tools.cxx:255
 Tools.cxx:256
 Tools.cxx:257
 Tools.cxx:258
 Tools.cxx:259
 Tools.cxx:260
 Tools.cxx:261
 Tools.cxx:262
 Tools.cxx:263
 Tools.cxx:264
 Tools.cxx:265
 Tools.cxx:266
 Tools.cxx:267
 Tools.cxx:268
 Tools.cxx:269
 Tools.cxx:270
 Tools.cxx:271
 Tools.cxx:272
 Tools.cxx:273
 Tools.cxx:274
 Tools.cxx:275
 Tools.cxx:276
 Tools.cxx:277
 Tools.cxx:278
 Tools.cxx:279
 Tools.cxx:280
 Tools.cxx:281
 Tools.cxx:282
 Tools.cxx:283
 Tools.cxx:284
 Tools.cxx:285
 Tools.cxx:286
 Tools.cxx:287
 Tools.cxx:288
 Tools.cxx:289
 Tools.cxx:290
 Tools.cxx:291
 Tools.cxx:292
 Tools.cxx:293
 Tools.cxx:294
 Tools.cxx:295
 Tools.cxx:296
 Tools.cxx:297
 Tools.cxx:298
 Tools.cxx:299
 Tools.cxx:300
 Tools.cxx:301
 Tools.cxx:302
 Tools.cxx:303
 Tools.cxx:304
 Tools.cxx:305
 Tools.cxx:306
 Tools.cxx:307
 Tools.cxx:308
 Tools.cxx:309
 Tools.cxx:310
 Tools.cxx:311
 Tools.cxx:312
 Tools.cxx:313
 Tools.cxx:314
 Tools.cxx:315
 Tools.cxx:316
 Tools.cxx:317
 Tools.cxx:318
 Tools.cxx:319
 Tools.cxx:320
 Tools.cxx:321
 Tools.cxx:322
 Tools.cxx:323
 Tools.cxx:324
 Tools.cxx:325
 Tools.cxx:326
 Tools.cxx:327
 Tools.cxx:328
 Tools.cxx:329
 Tools.cxx:330
 Tools.cxx:331
 Tools.cxx:332
 Tools.cxx:333
 Tools.cxx:334
 Tools.cxx:335
 Tools.cxx:336
 Tools.cxx:337
 Tools.cxx:338
 Tools.cxx:339
 Tools.cxx:340
 Tools.cxx:341
 Tools.cxx:342
 Tools.cxx:343
 Tools.cxx:344
 Tools.cxx:345
 Tools.cxx:346
 Tools.cxx:347
 Tools.cxx:348
 Tools.cxx:349
 Tools.cxx:350
 Tools.cxx:351
 Tools.cxx:352
 Tools.cxx:353
 Tools.cxx:354
 Tools.cxx:355
 Tools.cxx:356
 Tools.cxx:357
 Tools.cxx:358
 Tools.cxx:359
 Tools.cxx:360
 Tools.cxx:361
 Tools.cxx:362
 Tools.cxx:363
 Tools.cxx:364
 Tools.cxx:365
 Tools.cxx:366
 Tools.cxx:367
 Tools.cxx:368
 Tools.cxx:369
 Tools.cxx:370
 Tools.cxx:371
 Tools.cxx:372
 Tools.cxx:373
 Tools.cxx:374
 Tools.cxx:375
 Tools.cxx:376
 Tools.cxx:377
 Tools.cxx:378
 Tools.cxx:379
 Tools.cxx:380
 Tools.cxx:381
 Tools.cxx:382
 Tools.cxx:383
 Tools.cxx:384
 Tools.cxx:385
 Tools.cxx:386
 Tools.cxx:387
 Tools.cxx:388
 Tools.cxx:389
 Tools.cxx:390
 Tools.cxx:391
 Tools.cxx:392
 Tools.cxx:393
 Tools.cxx:394
 Tools.cxx:395
 Tools.cxx:396
 Tools.cxx:397
 Tools.cxx:398
 Tools.cxx:399
 Tools.cxx:400
 Tools.cxx:401
 Tools.cxx:402
 Tools.cxx:403
 Tools.cxx:404
 Tools.cxx:405
 Tools.cxx:406
 Tools.cxx:407
 Tools.cxx:408
 Tools.cxx:409
 Tools.cxx:410
 Tools.cxx:411
 Tools.cxx:412
 Tools.cxx:413
 Tools.cxx:414
 Tools.cxx:415
 Tools.cxx:416
 Tools.cxx:417
 Tools.cxx:418
 Tools.cxx:419
 Tools.cxx:420
 Tools.cxx:421
 Tools.cxx:422
 Tools.cxx:423
 Tools.cxx:424
 Tools.cxx:425
 Tools.cxx:426
 Tools.cxx:427
 Tools.cxx:428
 Tools.cxx:429
 Tools.cxx:430
 Tools.cxx:431
 Tools.cxx:432
 Tools.cxx:433
 Tools.cxx:434
 Tools.cxx:435
 Tools.cxx:436
 Tools.cxx:437
 Tools.cxx:438
 Tools.cxx:439
 Tools.cxx:440
 Tools.cxx:441
 Tools.cxx:442
 Tools.cxx:443
 Tools.cxx:444
 Tools.cxx:445
 Tools.cxx:446
 Tools.cxx:447
 Tools.cxx:448
 Tools.cxx:449
 Tools.cxx:450
 Tools.cxx:451
 Tools.cxx:452
 Tools.cxx:453
 Tools.cxx:454
 Tools.cxx:455
 Tools.cxx:456
 Tools.cxx:457
 Tools.cxx:458
 Tools.cxx:459
 Tools.cxx:460
 Tools.cxx:461
 Tools.cxx:462
 Tools.cxx:463
 Tools.cxx:464
 Tools.cxx:465
 Tools.cxx:466
 Tools.cxx:467
 Tools.cxx:468
 Tools.cxx:469
 Tools.cxx:470
 Tools.cxx:471
 Tools.cxx:472
 Tools.cxx:473
 Tools.cxx:474
 Tools.cxx:475
 Tools.cxx:476
 Tools.cxx:477
 Tools.cxx:478
 Tools.cxx:479
 Tools.cxx:480
 Tools.cxx:481
 Tools.cxx:482
 Tools.cxx:483
 Tools.cxx:484
 Tools.cxx:485
 Tools.cxx:486
 Tools.cxx:487
 Tools.cxx:488
 Tools.cxx:489
 Tools.cxx:490
 Tools.cxx:491
 Tools.cxx:492
 Tools.cxx:493
 Tools.cxx:494
 Tools.cxx:495
 Tools.cxx:496
 Tools.cxx:497
 Tools.cxx:498
 Tools.cxx:499
 Tools.cxx:500
 Tools.cxx:501
 Tools.cxx:502
 Tools.cxx:503
 Tools.cxx:504
 Tools.cxx:505
 Tools.cxx:506
 Tools.cxx:507
 Tools.cxx:508
 Tools.cxx:509
 Tools.cxx:510
 Tools.cxx:511
 Tools.cxx:512
 Tools.cxx:513
 Tools.cxx:514
 Tools.cxx:515
 Tools.cxx:516
 Tools.cxx:517
 Tools.cxx:518
 Tools.cxx:519
 Tools.cxx:520
 Tools.cxx:521
 Tools.cxx:522
 Tools.cxx:523
 Tools.cxx:524
 Tools.cxx:525
 Tools.cxx:526
 Tools.cxx:527
 Tools.cxx:528
 Tools.cxx:529
 Tools.cxx:530
 Tools.cxx:531
 Tools.cxx:532
 Tools.cxx:533
 Tools.cxx:534
 Tools.cxx:535
 Tools.cxx:536
 Tools.cxx:537
 Tools.cxx:538
 Tools.cxx:539
 Tools.cxx:540
 Tools.cxx:541
 Tools.cxx:542
 Tools.cxx:543
 Tools.cxx:544
 Tools.cxx:545
 Tools.cxx:546
 Tools.cxx:547
 Tools.cxx:548
 Tools.cxx:549
 Tools.cxx:550
 Tools.cxx:551
 Tools.cxx:552
 Tools.cxx:553
 Tools.cxx:554
 Tools.cxx:555
 Tools.cxx:556
 Tools.cxx:557
 Tools.cxx:558
 Tools.cxx:559
 Tools.cxx:560
 Tools.cxx:561
 Tools.cxx:562
 Tools.cxx:563
 Tools.cxx:564
 Tools.cxx:565
 Tools.cxx:566
 Tools.cxx:567
 Tools.cxx:568
 Tools.cxx:569
 Tools.cxx:570
 Tools.cxx:571
 Tools.cxx:572
 Tools.cxx:573
 Tools.cxx:574
 Tools.cxx:575
 Tools.cxx:576
 Tools.cxx:577
 Tools.cxx:578
 Tools.cxx:579
 Tools.cxx:580
 Tools.cxx:581
 Tools.cxx:582
 Tools.cxx:583
 Tools.cxx:584
 Tools.cxx:585
 Tools.cxx:586
 Tools.cxx:587
 Tools.cxx:588
 Tools.cxx:589
 Tools.cxx:590
 Tools.cxx:591
 Tools.cxx:592
 Tools.cxx:593
 Tools.cxx:594
 Tools.cxx:595
 Tools.cxx:596
 Tools.cxx:597
 Tools.cxx:598
 Tools.cxx:599
 Tools.cxx:600
 Tools.cxx:601
 Tools.cxx:602
 Tools.cxx:603
 Tools.cxx:604
 Tools.cxx:605
 Tools.cxx:606
 Tools.cxx:607
 Tools.cxx:608
 Tools.cxx:609
 Tools.cxx:610
 Tools.cxx:611
 Tools.cxx:612
 Tools.cxx:613
 Tools.cxx:614
 Tools.cxx:615
 Tools.cxx:616
 Tools.cxx:617
 Tools.cxx:618
 Tools.cxx:619
 Tools.cxx:620
 Tools.cxx:621
 Tools.cxx:622
 Tools.cxx:623
 Tools.cxx:624
 Tools.cxx:625
 Tools.cxx:626
 Tools.cxx:627
 Tools.cxx:628
 Tools.cxx:629
 Tools.cxx:630
 Tools.cxx:631
 Tools.cxx:632
 Tools.cxx:633
 Tools.cxx:634
 Tools.cxx:635
 Tools.cxx:636
 Tools.cxx:637
 Tools.cxx:638
 Tools.cxx:639
 Tools.cxx:640
 Tools.cxx:641
 Tools.cxx:642
 Tools.cxx:643
 Tools.cxx:644
 Tools.cxx:645
 Tools.cxx:646
 Tools.cxx:647
 Tools.cxx:648
 Tools.cxx:649
 Tools.cxx:650
 Tools.cxx:651
 Tools.cxx:652
 Tools.cxx:653
 Tools.cxx:654
 Tools.cxx:655
 Tools.cxx:656
 Tools.cxx:657
 Tools.cxx:658
 Tools.cxx:659
 Tools.cxx:660
 Tools.cxx:661
 Tools.cxx:662
 Tools.cxx:663
 Tools.cxx:664
 Tools.cxx:665
 Tools.cxx:666
 Tools.cxx:667
 Tools.cxx:668
 Tools.cxx:669
 Tools.cxx:670
 Tools.cxx:671
 Tools.cxx:672
 Tools.cxx:673
 Tools.cxx:674
 Tools.cxx:675
 Tools.cxx:676
 Tools.cxx:677
 Tools.cxx:678
 Tools.cxx:679
 Tools.cxx:680
 Tools.cxx:681
 Tools.cxx:682
 Tools.cxx:683
 Tools.cxx:684
 Tools.cxx:685
 Tools.cxx:686
 Tools.cxx:687
 Tools.cxx:688
 Tools.cxx:689
 Tools.cxx:690
 Tools.cxx:691
 Tools.cxx:692
 Tools.cxx:693
 Tools.cxx:694
 Tools.cxx:695
 Tools.cxx:696
 Tools.cxx:697
 Tools.cxx:698
 Tools.cxx:699
 Tools.cxx:700
 Tools.cxx:701
 Tools.cxx:702
 Tools.cxx:703
 Tools.cxx:704
 Tools.cxx:705
 Tools.cxx:706
 Tools.cxx:707
 Tools.cxx:708
 Tools.cxx:709
 Tools.cxx:710
 Tools.cxx:711
 Tools.cxx:712
 Tools.cxx:713
 Tools.cxx:714
 Tools.cxx:715
 Tools.cxx:716
 Tools.cxx:717
 Tools.cxx:718
 Tools.cxx:719
 Tools.cxx:720
 Tools.cxx:721
 Tools.cxx:722
 Tools.cxx:723
 Tools.cxx:724
 Tools.cxx:725
 Tools.cxx:726
 Tools.cxx:727
 Tools.cxx:728
 Tools.cxx:729
 Tools.cxx:730
 Tools.cxx:731
 Tools.cxx:732
 Tools.cxx:733
 Tools.cxx:734
 Tools.cxx:735
 Tools.cxx:736
 Tools.cxx:737
 Tools.cxx:738
 Tools.cxx:739
 Tools.cxx:740
 Tools.cxx:741
 Tools.cxx:742
 Tools.cxx:743
 Tools.cxx:744
 Tools.cxx:745
 Tools.cxx:746
 Tools.cxx:747
 Tools.cxx:748
 Tools.cxx:749
 Tools.cxx:750
 Tools.cxx:751
 Tools.cxx:752
 Tools.cxx:753
 Tools.cxx:754
 Tools.cxx:755
 Tools.cxx:756
 Tools.cxx:757
 Tools.cxx:758
 Tools.cxx:759
 Tools.cxx:760
 Tools.cxx:761
 Tools.cxx:762
 Tools.cxx:763
 Tools.cxx:764
 Tools.cxx:765
 Tools.cxx:766
 Tools.cxx:767
 Tools.cxx:768
 Tools.cxx:769
 Tools.cxx:770
 Tools.cxx:771
 Tools.cxx:772
 Tools.cxx:773
 Tools.cxx:774
 Tools.cxx:775
 Tools.cxx:776
 Tools.cxx:777
 Tools.cxx:778
 Tools.cxx:779
 Tools.cxx:780
 Tools.cxx:781
 Tools.cxx:782
 Tools.cxx:783
 Tools.cxx:784
 Tools.cxx:785
 Tools.cxx:786
 Tools.cxx:787
 Tools.cxx:788
 Tools.cxx:789
 Tools.cxx:790
 Tools.cxx:791
 Tools.cxx:792
 Tools.cxx:793
 Tools.cxx:794
 Tools.cxx:795
 Tools.cxx:796
 Tools.cxx:797
 Tools.cxx:798
 Tools.cxx:799
 Tools.cxx:800
 Tools.cxx:801
 Tools.cxx:802
 Tools.cxx:803
 Tools.cxx:804
 Tools.cxx:805
 Tools.cxx:806
 Tools.cxx:807
 Tools.cxx:808
 Tools.cxx:809
 Tools.cxx:810
 Tools.cxx:811
 Tools.cxx:812
 Tools.cxx:813
 Tools.cxx:814
 Tools.cxx:815
 Tools.cxx:816
 Tools.cxx:817
 Tools.cxx:818
 Tools.cxx:819
 Tools.cxx:820
 Tools.cxx:821
 Tools.cxx:822
 Tools.cxx:823
 Tools.cxx:824
 Tools.cxx:825
 Tools.cxx:826
 Tools.cxx:827
 Tools.cxx:828
 Tools.cxx:829
 Tools.cxx:830
 Tools.cxx:831
 Tools.cxx:832
 Tools.cxx:833
 Tools.cxx:834
 Tools.cxx:835
 Tools.cxx:836
 Tools.cxx:837
 Tools.cxx:838
 Tools.cxx:839
 Tools.cxx:840
 Tools.cxx:841
 Tools.cxx:842
 Tools.cxx:843
 Tools.cxx:844
 Tools.cxx:845
 Tools.cxx:846
 Tools.cxx:847
 Tools.cxx:848
 Tools.cxx:849
 Tools.cxx:850
 Tools.cxx:851
 Tools.cxx:852
 Tools.cxx:853
 Tools.cxx:854
 Tools.cxx:855
 Tools.cxx:856
 Tools.cxx:857
 Tools.cxx:858
 Tools.cxx:859
 Tools.cxx:860
 Tools.cxx:861
 Tools.cxx:862
 Tools.cxx:863
 Tools.cxx:864
 Tools.cxx:865
 Tools.cxx:866
 Tools.cxx:867
 Tools.cxx:868
 Tools.cxx:869
 Tools.cxx:870
 Tools.cxx:871
 Tools.cxx:872
 Tools.cxx:873
 Tools.cxx:874
 Tools.cxx:875
 Tools.cxx:876
 Tools.cxx:877
 Tools.cxx:878
 Tools.cxx:879
 Tools.cxx:880
 Tools.cxx:881
 Tools.cxx:882
 Tools.cxx:883
 Tools.cxx:884
 Tools.cxx:885
 Tools.cxx:886
 Tools.cxx:887
 Tools.cxx:888
 Tools.cxx:889
 Tools.cxx:890
 Tools.cxx:891
 Tools.cxx:892
 Tools.cxx:893
 Tools.cxx:894
 Tools.cxx:895
 Tools.cxx:896
 Tools.cxx:897
 Tools.cxx:898
 Tools.cxx:899
 Tools.cxx:900
 Tools.cxx:901
 Tools.cxx:902
 Tools.cxx:903
 Tools.cxx:904
 Tools.cxx:905
 Tools.cxx:906
 Tools.cxx:907
 Tools.cxx:908
 Tools.cxx:909
 Tools.cxx:910
 Tools.cxx:911
 Tools.cxx:912
 Tools.cxx:913
 Tools.cxx:914
 Tools.cxx:915
 Tools.cxx:916
 Tools.cxx:917
 Tools.cxx:918
 Tools.cxx:919
 Tools.cxx:920
 Tools.cxx:921
 Tools.cxx:922
 Tools.cxx:923
 Tools.cxx:924
 Tools.cxx:925
 Tools.cxx:926
 Tools.cxx:927
 Tools.cxx:928
 Tools.cxx:929
 Tools.cxx:930
 Tools.cxx:931
 Tools.cxx:932
 Tools.cxx:933
 Tools.cxx:934
 Tools.cxx:935
 Tools.cxx:936
 Tools.cxx:937
 Tools.cxx:938
 Tools.cxx:939
 Tools.cxx:940
 Tools.cxx:941
 Tools.cxx:942
 Tools.cxx:943
 Tools.cxx:944
 Tools.cxx:945
 Tools.cxx:946
 Tools.cxx:947
 Tools.cxx:948
 Tools.cxx:949
 Tools.cxx:950
 Tools.cxx:951
 Tools.cxx:952
 Tools.cxx:953
 Tools.cxx:954
 Tools.cxx:955
 Tools.cxx:956
 Tools.cxx:957
 Tools.cxx:958
 Tools.cxx:959
 Tools.cxx:960
 Tools.cxx:961
 Tools.cxx:962
 Tools.cxx:963
 Tools.cxx:964
 Tools.cxx:965
 Tools.cxx:966
 Tools.cxx:967
 Tools.cxx:968
 Tools.cxx:969
 Tools.cxx:970
 Tools.cxx:971
 Tools.cxx:972
 Tools.cxx:973
 Tools.cxx:974
 Tools.cxx:975
 Tools.cxx:976
 Tools.cxx:977
 Tools.cxx:978
 Tools.cxx:979
 Tools.cxx:980
 Tools.cxx:981
 Tools.cxx:982
 Tools.cxx:983
 Tools.cxx:984
 Tools.cxx:985
 Tools.cxx:986
 Tools.cxx:987
 Tools.cxx:988
 Tools.cxx:989
 Tools.cxx:990
 Tools.cxx:991
 Tools.cxx:992
 Tools.cxx:993
 Tools.cxx:994
 Tools.cxx:995
 Tools.cxx:996
 Tools.cxx:997
 Tools.cxx:998
 Tools.cxx:999
 Tools.cxx:1000
 Tools.cxx:1001
 Tools.cxx:1002
 Tools.cxx:1003
 Tools.cxx:1004
 Tools.cxx:1005
 Tools.cxx:1006
 Tools.cxx:1007
 Tools.cxx:1008
 Tools.cxx:1009
 Tools.cxx:1010
 Tools.cxx:1011
 Tools.cxx:1012
 Tools.cxx:1013
 Tools.cxx:1014
 Tools.cxx:1015
 Tools.cxx:1016
 Tools.cxx:1017
 Tools.cxx:1018
 Tools.cxx:1019
 Tools.cxx:1020
 Tools.cxx:1021
 Tools.cxx:1022
 Tools.cxx:1023
 Tools.cxx:1024
 Tools.cxx:1025
 Tools.cxx:1026
 Tools.cxx:1027
 Tools.cxx:1028
 Tools.cxx:1029
 Tools.cxx:1030
 Tools.cxx:1031
 Tools.cxx:1032
 Tools.cxx:1033
 Tools.cxx:1034
 Tools.cxx:1035
 Tools.cxx:1036
 Tools.cxx:1037
 Tools.cxx:1038
 Tools.cxx:1039
 Tools.cxx:1040
 Tools.cxx:1041
 Tools.cxx:1042
 Tools.cxx:1043
 Tools.cxx:1044
 Tools.cxx:1045
 Tools.cxx:1046
 Tools.cxx:1047
 Tools.cxx:1048
 Tools.cxx:1049
 Tools.cxx:1050
 Tools.cxx:1051
 Tools.cxx:1052
 Tools.cxx:1053
 Tools.cxx:1054
 Tools.cxx:1055
 Tools.cxx:1056
 Tools.cxx:1057
 Tools.cxx:1058
 Tools.cxx:1059
 Tools.cxx:1060
 Tools.cxx:1061
 Tools.cxx:1062
 Tools.cxx:1063
 Tools.cxx:1064
 Tools.cxx:1065
 Tools.cxx:1066
 Tools.cxx:1067
 Tools.cxx:1068
 Tools.cxx:1069
 Tools.cxx:1070
 Tools.cxx:1071
 Tools.cxx:1072
 Tools.cxx:1073
 Tools.cxx:1074
 Tools.cxx:1075
 Tools.cxx:1076
 Tools.cxx:1077
 Tools.cxx:1078
 Tools.cxx:1079
 Tools.cxx:1080
 Tools.cxx:1081
 Tools.cxx:1082
 Tools.cxx:1083
 Tools.cxx:1084
 Tools.cxx:1085
 Tools.cxx:1086
 Tools.cxx:1087
 Tools.cxx:1088
 Tools.cxx:1089
 Tools.cxx:1090
 Tools.cxx:1091
 Tools.cxx:1092
 Tools.cxx:1093
 Tools.cxx:1094
 Tools.cxx:1095
 Tools.cxx:1096
 Tools.cxx:1097
 Tools.cxx:1098
 Tools.cxx:1099
 Tools.cxx:1100
 Tools.cxx:1101
 Tools.cxx:1102
 Tools.cxx:1103
 Tools.cxx:1104
 Tools.cxx:1105
 Tools.cxx:1106
 Tools.cxx:1107
 Tools.cxx:1108
 Tools.cxx:1109
 Tools.cxx:1110
 Tools.cxx:1111
 Tools.cxx:1112
 Tools.cxx:1113
 Tools.cxx:1114
 Tools.cxx:1115
 Tools.cxx:1116
 Tools.cxx:1117
 Tools.cxx:1118
 Tools.cxx:1119
 Tools.cxx:1120
 Tools.cxx:1121
 Tools.cxx:1122
 Tools.cxx:1123
 Tools.cxx:1124
 Tools.cxx:1125
 Tools.cxx:1126
 Tools.cxx:1127
 Tools.cxx:1128
 Tools.cxx:1129
 Tools.cxx:1130
 Tools.cxx:1131
 Tools.cxx:1132
 Tools.cxx:1133
 Tools.cxx:1134
 Tools.cxx:1135
 Tools.cxx:1136
 Tools.cxx:1137
 Tools.cxx:1138
 Tools.cxx:1139
 Tools.cxx:1140
 Tools.cxx:1141
 Tools.cxx:1142
 Tools.cxx:1143
 Tools.cxx:1144
 Tools.cxx:1145
 Tools.cxx:1146
 Tools.cxx:1147
 Tools.cxx:1148
 Tools.cxx:1149
 Tools.cxx:1150
 Tools.cxx:1151
 Tools.cxx:1152
 Tools.cxx:1153
 Tools.cxx:1154
 Tools.cxx:1155
 Tools.cxx:1156
 Tools.cxx:1157
 Tools.cxx:1158
 Tools.cxx:1159
 Tools.cxx:1160
 Tools.cxx:1161
 Tools.cxx:1162
 Tools.cxx:1163
 Tools.cxx:1164
 Tools.cxx:1165
 Tools.cxx:1166
 Tools.cxx:1167
 Tools.cxx:1168
 Tools.cxx:1169
 Tools.cxx:1170
 Tools.cxx:1171
 Tools.cxx:1172
 Tools.cxx:1173
 Tools.cxx:1174
 Tools.cxx:1175
 Tools.cxx:1176
 Tools.cxx:1177
 Tools.cxx:1178
 Tools.cxx:1179
 Tools.cxx:1180
 Tools.cxx:1181
 Tools.cxx:1182
 Tools.cxx:1183
 Tools.cxx:1184
 Tools.cxx:1185
 Tools.cxx:1186
 Tools.cxx:1187
 Tools.cxx:1188
 Tools.cxx:1189
 Tools.cxx:1190
 Tools.cxx:1191
 Tools.cxx:1192
 Tools.cxx:1193
 Tools.cxx:1194
 Tools.cxx:1195
 Tools.cxx:1196
 Tools.cxx:1197
 Tools.cxx:1198
 Tools.cxx:1199
 Tools.cxx:1200
 Tools.cxx:1201
 Tools.cxx:1202
 Tools.cxx:1203
 Tools.cxx:1204
 Tools.cxx:1205
 Tools.cxx:1206
 Tools.cxx:1207
 Tools.cxx:1208
 Tools.cxx:1209
 Tools.cxx:1210
 Tools.cxx:1211
 Tools.cxx:1212
 Tools.cxx:1213
 Tools.cxx:1214
 Tools.cxx:1215
 Tools.cxx:1216
 Tools.cxx:1217
 Tools.cxx:1218
 Tools.cxx:1219
 Tools.cxx:1220
 Tools.cxx:1221
 Tools.cxx:1222
 Tools.cxx:1223
 Tools.cxx:1224
 Tools.cxx:1225
 Tools.cxx:1226
 Tools.cxx:1227
 Tools.cxx:1228
 Tools.cxx:1229
 Tools.cxx:1230
 Tools.cxx:1231
 Tools.cxx:1232
 Tools.cxx:1233
 Tools.cxx:1234
 Tools.cxx:1235
 Tools.cxx:1236
 Tools.cxx:1237
 Tools.cxx:1238
 Tools.cxx:1239
 Tools.cxx:1240
 Tools.cxx:1241
 Tools.cxx:1242
 Tools.cxx:1243
 Tools.cxx:1244
 Tools.cxx:1245
 Tools.cxx:1246
 Tools.cxx:1247
 Tools.cxx:1248
 Tools.cxx:1249
 Tools.cxx:1250
 Tools.cxx:1251
 Tools.cxx:1252
 Tools.cxx:1253
 Tools.cxx:1254
 Tools.cxx:1255
 Tools.cxx:1256
 Tools.cxx:1257
 Tools.cxx:1258
 Tools.cxx:1259
 Tools.cxx:1260
 Tools.cxx:1261
 Tools.cxx:1262
 Tools.cxx:1263
 Tools.cxx:1264
 Tools.cxx:1265
 Tools.cxx:1266
 Tools.cxx:1267
 Tools.cxx:1268
 Tools.cxx:1269
 Tools.cxx:1270
 Tools.cxx:1271
 Tools.cxx:1272
 Tools.cxx:1273
 Tools.cxx:1274
 Tools.cxx:1275
 Tools.cxx:1276
 Tools.cxx:1277
 Tools.cxx:1278
 Tools.cxx:1279
 Tools.cxx:1280
 Tools.cxx:1281
 Tools.cxx:1282
 Tools.cxx:1283
 Tools.cxx:1284
 Tools.cxx:1285
 Tools.cxx:1286
 Tools.cxx:1287
 Tools.cxx:1288
 Tools.cxx:1289
 Tools.cxx:1290
 Tools.cxx:1291
 Tools.cxx:1292
 Tools.cxx:1293
 Tools.cxx:1294
 Tools.cxx:1295
 Tools.cxx:1296
 Tools.cxx:1297
 Tools.cxx:1298
 Tools.cxx:1299
 Tools.cxx:1300
 Tools.cxx:1301
 Tools.cxx:1302
 Tools.cxx:1303
 Tools.cxx:1304
 Tools.cxx:1305
 Tools.cxx:1306
 Tools.cxx:1307
 Tools.cxx:1308
 Tools.cxx:1309
 Tools.cxx:1310
 Tools.cxx:1311
 Tools.cxx:1312
 Tools.cxx:1313
 Tools.cxx:1314
 Tools.cxx:1315
 Tools.cxx:1316
 Tools.cxx:1317
 Tools.cxx:1318
 Tools.cxx:1319
 Tools.cxx:1320
 Tools.cxx:1321
 Tools.cxx:1322
 Tools.cxx:1323
 Tools.cxx:1324
 Tools.cxx:1325
 Tools.cxx:1326
 Tools.cxx:1327
 Tools.cxx:1328
 Tools.cxx:1329
 Tools.cxx:1330
 Tools.cxx:1331
 Tools.cxx:1332
 Tools.cxx:1333
 Tools.cxx:1334
 Tools.cxx:1335
 Tools.cxx:1336
 Tools.cxx:1337
 Tools.cxx:1338
 Tools.cxx:1339
 Tools.cxx:1340
 Tools.cxx:1341
 Tools.cxx:1342
 Tools.cxx:1343
 Tools.cxx:1344
 Tools.cxx:1345
 Tools.cxx:1346
 Tools.cxx:1347
 Tools.cxx:1348
 Tools.cxx:1349
 Tools.cxx:1350
 Tools.cxx:1351
 Tools.cxx:1352
 Tools.cxx:1353
 Tools.cxx:1354
 Tools.cxx:1355
 Tools.cxx:1356
 Tools.cxx:1357
 Tools.cxx:1358
 Tools.cxx:1359
 Tools.cxx:1360
 Tools.cxx:1361
 Tools.cxx:1362
 Tools.cxx:1363
 Tools.cxx:1364
 Tools.cxx:1365
 Tools.cxx:1366
 Tools.cxx:1367
 Tools.cxx:1368
 Tools.cxx:1369
 Tools.cxx:1370
 Tools.cxx:1371
 Tools.cxx:1372
 Tools.cxx:1373
 Tools.cxx:1374
 Tools.cxx:1375
 Tools.cxx:1376
 Tools.cxx:1377
 Tools.cxx:1378
 Tools.cxx:1379
 Tools.cxx:1380
 Tools.cxx:1381
 Tools.cxx:1382
 Tools.cxx:1383
 Tools.cxx:1384
 Tools.cxx:1385
 Tools.cxx:1386
 Tools.cxx:1387
 Tools.cxx:1388
 Tools.cxx:1389
 Tools.cxx:1390
 Tools.cxx:1391
 Tools.cxx:1392
 Tools.cxx:1393
 Tools.cxx:1394
 Tools.cxx:1395
 Tools.cxx:1396
 Tools.cxx:1397
 Tools.cxx:1398
 Tools.cxx:1399
 Tools.cxx:1400
 Tools.cxx:1401
 Tools.cxx:1402
 Tools.cxx:1403
 Tools.cxx:1404
 Tools.cxx:1405
 Tools.cxx:1406
 Tools.cxx:1407
 Tools.cxx:1408
 Tools.cxx:1409
 Tools.cxx:1410
 Tools.cxx:1411
 Tools.cxx:1412
 Tools.cxx:1413
 Tools.cxx:1414
 Tools.cxx:1415
 Tools.cxx:1416
 Tools.cxx:1417
 Tools.cxx:1418
 Tools.cxx:1419
 Tools.cxx:1420
 Tools.cxx:1421
 Tools.cxx:1422
 Tools.cxx:1423
 Tools.cxx:1424
 Tools.cxx:1425
 Tools.cxx:1426
 Tools.cxx:1427
 Tools.cxx:1428
 Tools.cxx:1429
 Tools.cxx:1430
 Tools.cxx:1431
 Tools.cxx:1432
 Tools.cxx:1433
 Tools.cxx:1434
 Tools.cxx:1435
 Tools.cxx:1436
 Tools.cxx:1437
 Tools.cxx:1438
 Tools.cxx:1439
 Tools.cxx:1440
 Tools.cxx:1441
 Tools.cxx:1442
 Tools.cxx:1443
 Tools.cxx:1444
 Tools.cxx:1445
 Tools.cxx:1446
 Tools.cxx:1447
 Tools.cxx:1448
 Tools.cxx:1449
 Tools.cxx:1450
 Tools.cxx:1451
 Tools.cxx:1452
 Tools.cxx:1453
 Tools.cxx:1454
 Tools.cxx:1455
 Tools.cxx:1456
 Tools.cxx:1457
 Tools.cxx:1458
 Tools.cxx:1459
 Tools.cxx:1460
 Tools.cxx:1461
 Tools.cxx:1462
 Tools.cxx:1463
 Tools.cxx:1464
 Tools.cxx:1465
 Tools.cxx:1466
 Tools.cxx:1467
 Tools.cxx:1468
 Tools.cxx:1469
 Tools.cxx:1470
 Tools.cxx:1471
 Tools.cxx:1472
 Tools.cxx:1473
 Tools.cxx:1474
 Tools.cxx:1475
 Tools.cxx:1476
 Tools.cxx:1477
 Tools.cxx:1478
 Tools.cxx:1479
 Tools.cxx:1480
 Tools.cxx:1481
 Tools.cxx:1482
 Tools.cxx:1483
 Tools.cxx:1484
 Tools.cxx:1485
 Tools.cxx:1486
 Tools.cxx:1487
 Tools.cxx:1488
 Tools.cxx:1489
 Tools.cxx:1490
 Tools.cxx:1491
 Tools.cxx:1492
 Tools.cxx:1493
 Tools.cxx:1494
 Tools.cxx:1495
 Tools.cxx:1496
 Tools.cxx:1497
 Tools.cxx:1498
 Tools.cxx:1499
 Tools.cxx:1500
 Tools.cxx:1501
 Tools.cxx:1502
 Tools.cxx:1503
 Tools.cxx:1504
 Tools.cxx:1505
 Tools.cxx:1506
 Tools.cxx:1507
 Tools.cxx:1508
 Tools.cxx:1509
 Tools.cxx:1510
 Tools.cxx:1511
 Tools.cxx:1512
 Tools.cxx:1513
 Tools.cxx:1514
 Tools.cxx:1515
 Tools.cxx:1516
 Tools.cxx:1517
 Tools.cxx:1518
 Tools.cxx:1519
 Tools.cxx:1520
 Tools.cxx:1521
 Tools.cxx:1522
 Tools.cxx:1523
 Tools.cxx:1524
 Tools.cxx:1525
 Tools.cxx:1526
 Tools.cxx:1527
 Tools.cxx:1528
 Tools.cxx:1529
 Tools.cxx:1530
 Tools.cxx:1531
 Tools.cxx:1532
 Tools.cxx:1533
 Tools.cxx:1534
 Tools.cxx:1535
 Tools.cxx:1536
 Tools.cxx:1537
 Tools.cxx:1538
 Tools.cxx:1539
 Tools.cxx:1540
 Tools.cxx:1541
 Tools.cxx:1542
 Tools.cxx:1543
 Tools.cxx:1544
 Tools.cxx:1545
 Tools.cxx:1546
 Tools.cxx:1547
 Tools.cxx:1548
 Tools.cxx:1549
 Tools.cxx:1550
 Tools.cxx:1551
 Tools.cxx:1552
 Tools.cxx:1553
 Tools.cxx:1554
 Tools.cxx:1555
 Tools.cxx:1556
 Tools.cxx:1557
 Tools.cxx:1558
 Tools.cxx:1559
 Tools.cxx:1560
 Tools.cxx:1561
 Tools.cxx:1562
 Tools.cxx:1563
 Tools.cxx:1564
 Tools.cxx:1565
 Tools.cxx:1566
 Tools.cxx:1567
 Tools.cxx:1568
 Tools.cxx:1569
 Tools.cxx:1570
 Tools.cxx:1571
 Tools.cxx:1572
 Tools.cxx:1573
 Tools.cxx:1574
 Tools.cxx:1575
 Tools.cxx:1576
 Tools.cxx:1577
 Tools.cxx:1578
 Tools.cxx:1579
 Tools.cxx:1580
 Tools.cxx:1581
 Tools.cxx:1582
 Tools.cxx:1583
 Tools.cxx:1584
 Tools.cxx:1585
 Tools.cxx:1586
 Tools.cxx:1587
 Tools.cxx:1588
 Tools.cxx:1589
 Tools.cxx:1590
 Tools.cxx:1591
 Tools.cxx:1592
 Tools.cxx:1593
 Tools.cxx:1594
 Tools.cxx:1595
 Tools.cxx:1596
 Tools.cxx:1597
 Tools.cxx:1598
 Tools.cxx:1599
 Tools.cxx:1600
 Tools.cxx:1601
 Tools.cxx:1602
 Tools.cxx:1603
 Tools.cxx:1604
 Tools.cxx:1605
 Tools.cxx:1606
 Tools.cxx:1607
 Tools.cxx:1608
 Tools.cxx:1609
 Tools.cxx:1610
 Tools.cxx:1611
 Tools.cxx:1612
 Tools.cxx:1613
 Tools.cxx:1614
 Tools.cxx:1615
 Tools.cxx:1616
 Tools.cxx:1617
 Tools.cxx:1618
 Tools.cxx:1619
 Tools.cxx:1620
 Tools.cxx:1621
 Tools.cxx:1622
 Tools.cxx:1623
 Tools.cxx:1624
 Tools.cxx:1625
 Tools.cxx:1626
 Tools.cxx:1627
 Tools.cxx:1628
 Tools.cxx:1629
 Tools.cxx:1630
 Tools.cxx:1631
 Tools.cxx:1632
 Tools.cxx:1633
 Tools.cxx:1634
 Tools.cxx:1635
 Tools.cxx:1636
 Tools.cxx:1637
 Tools.cxx:1638
 Tools.cxx:1639
 Tools.cxx:1640
 Tools.cxx:1641
 Tools.cxx:1642
 Tools.cxx:1643
 Tools.cxx:1644
 Tools.cxx:1645
 Tools.cxx:1646
 Tools.cxx:1647
 Tools.cxx:1648
 Tools.cxx:1649
 Tools.cxx:1650
 Tools.cxx:1651
 Tools.cxx:1652
 Tools.cxx:1653
 Tools.cxx:1654
 Tools.cxx:1655
 Tools.cxx:1656
 Tools.cxx:1657
 Tools.cxx:1658
 Tools.cxx:1659
 Tools.cxx:1660
 Tools.cxx:1661
 Tools.cxx:1662
 Tools.cxx:1663
 Tools.cxx:1664
 Tools.cxx:1665
 Tools.cxx:1666
 Tools.cxx:1667
 Tools.cxx:1668
 Tools.cxx:1669
 Tools.cxx:1670
 Tools.cxx:1671
 Tools.cxx:1672
 Tools.cxx:1673
 Tools.cxx:1674
 Tools.cxx:1675
 Tools.cxx:1676
 Tools.cxx:1677
 Tools.cxx:1678
 Tools.cxx:1679
 Tools.cxx:1680
 Tools.cxx:1681
 Tools.cxx:1682
 Tools.cxx:1683
 Tools.cxx:1684
 Tools.cxx:1685
 Tools.cxx:1686
 Tools.cxx:1687
 Tools.cxx:1688
 Tools.cxx:1689
 Tools.cxx:1690
 Tools.cxx:1691
 Tools.cxx:1692
 Tools.cxx:1693
 Tools.cxx:1694
 Tools.cxx:1695
 Tools.cxx:1696
 Tools.cxx:1697
 Tools.cxx:1698
 Tools.cxx:1699
 Tools.cxx:1700
 Tools.cxx:1701
 Tools.cxx:1702
 Tools.cxx:1703
 Tools.cxx:1704
 Tools.cxx:1705
 Tools.cxx:1706
 Tools.cxx:1707
 Tools.cxx:1708
 Tools.cxx:1709
 Tools.cxx:1710
 Tools.cxx:1711
 Tools.cxx:1712
 Tools.cxx:1713
 Tools.cxx:1714
 Tools.cxx:1715
 Tools.cxx:1716
 Tools.cxx:1717
 Tools.cxx:1718
 Tools.cxx:1719
 Tools.cxx:1720
 Tools.cxx:1721
 Tools.cxx:1722
 Tools.cxx:1723
 Tools.cxx:1724
 Tools.cxx:1725
 Tools.cxx:1726
 Tools.cxx:1727
 Tools.cxx:1728
 Tools.cxx:1729
 Tools.cxx:1730
 Tools.cxx:1731
 Tools.cxx:1732