ROOT logo
// @(#)root/hist:$Id$
// Author: Axel Naumann (2011-12-20)

/*************************************************************************
 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "THnBase.h"

#include "TAxis.h"
#include "TBrowser.h"
#include "TError.h"
#include "TClass.h"
#include "TF1.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TH3D.h"
#include "THn.h"
#include "THnSparse.h"
#include "TMath.h"
#include "TRandom.h"
#include "TVirtualPad.h"

#include "HFitInterface.h"
#include "Fit/SparseData.h"
#include "Math/MinimizerOptions.h"
#include "Math/WrappedMultiTF1.h"


//______________________________________________________________________________
//
//    Multidimensional histogram base.
//
//  Defines common functionality and interfaces for THn, THnSparse.
//

ClassImp(THnBase);

//______________________________________________________________________________
THnBase::THnBase(const char* name, const char* title, Int_t dim,
                 const Int_t* nbins, const Double_t* xmin, const Double_t* xmax):
TNamed(name, title), fNdimensions(dim), fAxes(dim), fBrowsables(dim),
fEntries(0), fTsumw(0), fTsumw2(-1.), fTsumwx(dim), fTsumwx2(dim),
fIntegral(0), fIntegralStatus(kNoInt)
{
   // Construct a THnBase with "dim" dimensions,
   // "nbins" holds the number of bins for each dimension;
   // "xmin" and "xmax" the minimal and maximal value for each dimension.
   // The arrays "xmin" and "xmax" can be NULL; in that case SetBinEdges()
   // must be called for each dimension.

   for (Int_t i = 0; i < fNdimensions; ++i) {
      TAxis* axis = new TAxis(nbins[i], xmin ? xmin[i] : 0., xmax ? xmax[i] : 1.);
      axis->SetName(TString::Format("axis%d", i));
      fAxes.AddAtAndExpand(axis, i);
   }
   SetTitle(title);
   fAxes.SetOwner();
}

//______________________________________________________________________________
THnBase::~THnBase() {
   // Destruct a THnBase
   if (fIntegralStatus != kNoInt) delete [] fIntegral;
}


//______________________________________________________________________________
THnBase* THnBase::CloneEmpty(const char* name, const char* title,
                             const TObjArray* axes, Bool_t keepTargetAxis) const
{
   // Create a new THnBase object that is of the same type as *this,
   // but with dimensions and bins given by axes.
   // If keepTargetAxis is true, the axes will keep their original xmin / xmax,
   // else they will be restricted to the range selected (first / last).
   THnBase* ret = (THnBase*)IsA()->New();
   Int_t chunkSize = 1024 * 16;
   if (InheritsFrom(THnSparse::Class())) {
      chunkSize = ((const THnSparse*)this)->GetChunkSize();
   }
   ret->Init(name, title, axes, keepTargetAxis, chunkSize);
   return ret;
}


//______________________________________________________________________________
void THnBase::Init(const char* name, const char* title,
                   const TObjArray* axes, Bool_t keepTargetAxis,
                   Int_t chunkSize /*= 1024 * 16*/)
{
   // Initialize axes and name.
   SetNameTitle(name, title);

   TIter iAxis(axes);
   const TAxis* axis = 0;
   Int_t pos = 0;
   Int_t *nbins = new Int_t[axes->GetEntriesFast()];
   while ((axis = (TAxis*)iAxis())) {
      TAxis* reqaxis = new TAxis(*axis);
      if (!keepTargetAxis && axis->TestBit(TAxis::kAxisRange)) {
         Int_t binFirst = axis->GetFirst();
         // The lowest egde of the underflow is meaningless.
         if (binFirst == 0)
            binFirst = 1;
         Int_t binLast = axis->GetLast();
         // The overflow edge is implicit.
         if (binLast > axis->GetNbins())
            binLast = axis->GetNbins();
         Int_t nBins = binLast - binFirst + 1;
         if (axis->GetXbins()->GetSize()) {
            // non-uniform bins:
            reqaxis->Set(nBins, axis->GetXbins()->GetArray() + binFirst - 1);
         } else {
            // uniform bins:
            reqaxis->Set(nBins, axis->GetBinLowEdge(binFirst), axis->GetBinUpEdge(binLast));
         }
         reqaxis->ResetBit(TAxis::kAxisRange);
      }

      nbins[pos] = reqaxis->GetNbins();
      fAxes.AddAtAndExpand(new TAxis(*reqaxis), pos++);
   }
   fAxes.SetOwner();

   fNdimensions = axes->GetEntriesFast();
   InitStorage(nbins, chunkSize);
   delete [] nbins;
}


//______________________________________________________________________________
TH1* THnBase::CreateHist(const char* name, const char* title,
                         const TObjArray* axes,
                         Bool_t keepTargetAxis ) const {
   // Create an empty histogram with name and title with a given
   // set of axes. Create a TH1D/TH2D/TH3D, depending on the number
   // of elements in axes.

   const int ndim = axes->GetSize();

   TH1* hist = 0;
   // create hist with dummy axes, we fix them later.
   if (ndim == 1)
      hist = new TH1D(name, title, 1, 0., 1.);
   else if (ndim == 2)
      hist = new TH2D(name, title, 1, 0., 1., 1, 0., 1.);
   else if (ndim == 3)
      hist = new TH3D(name, title, 1, 0., 1., 1, 0., 1., 1, 0., 1.);
   else {
      Error("CreateHist", "Cannot create histogram %s with %d dimensions!", name, ndim);
      return 0;
   }

   TAxis* hax[3] = {hist->GetXaxis(), hist->GetYaxis(), hist->GetZaxis()};
   for (Int_t d = 0; d < ndim; ++d) {
      TAxis* reqaxis = (TAxis*)(*axes)[d];
      hax[d]->SetTitle(reqaxis->GetTitle());
      if (!keepTargetAxis && reqaxis->TestBit(TAxis::kAxisRange)) {
         Int_t binFirst = reqaxis->GetFirst();
         if (binFirst == 0) binFirst = 1;
         Int_t binLast = reqaxis->GetLast();
         Int_t nBins = binLast - binFirst + 1;
         if (reqaxis->GetXbins()->GetSize()) {
            // non-uniform bins:
            hax[d]->Set(nBins, reqaxis->GetXbins()->GetArray() + binFirst - 1);
         } else {
            // uniform bins:
            hax[d]->Set(nBins, reqaxis->GetBinLowEdge(binFirst), reqaxis->GetBinUpEdge(binLast));
         }
      } else {
         if (reqaxis->GetXbins()->GetSize()) {
            // non-uniform bins:
            hax[d]->Set(reqaxis->GetNbins(), reqaxis->GetXbins()->GetArray());
         } else {
            // uniform bins:
            hax[d]->Set(reqaxis->GetNbins(), reqaxis->GetXmin(), reqaxis->GetXmax());
         }
      }
   }

   hist->Rebuild();

   return hist;
}

//______________________________________________________________________________
THnBase* THnBase::CreateHnAny(const char* name, const char* title,
                              const TH1* h, Bool_t sparse, Int_t chunkSize)
{
   // Create a THn / THnSparse object from a histogram deriving from TH1.

   // Get the dimension of the TH1
   int ndim = h->GetDimension();

   // Axis properties
   int nbins[3] = {0,0,0};
   double minRange[3] = {0.,0.,0.};
   double maxRange[3] = {0.,0.,0.};
   TAxis* axis[3] = { h->GetXaxis(), h->GetYaxis(), h->GetZaxis() };
   for (int i = 0; i < ndim; ++i) {
      nbins[i]    = axis[i]->GetNbins();
      minRange[i] = axis[i]->GetXmin();
      maxRange[i] = axis[i]->GetXmax();
   }

   // Create the corresponding THnSparse, depending on the storage
   // type of the TH1. The class name will be "TH??\0" where the first
   // ? is 1,2 or 3 and the second ? indicates the stograge as C, S,
   // I, F or D.
   THnBase* s = 0;
   const char* cname( h->ClassName() );
   if (cname[0] == 'T' && cname[1] == 'H'
       && cname[2] >= '1' && cname[2] <= '3' && cname[4] == 0) {

#define R__THNBCASE(TAG)                                                \
if (sparse) {                                                     \
s = new _NAME2_(THnSparse,TAG)(name, title, ndim, nbins,       \
minRange, maxRange, chunkSize); \
} else {                                                          \
s = new _NAME2_(THn,TAG)(name, title, ndim, nbins,             \
minRange, maxRange);                  \
}                                                                 \
break;

      switch (cname[3]) {
         case 'F': R__THNBCASE(F);
         case 'D': R__THNBCASE(D);
         case 'I': R__THNBCASE(I);
         case 'S': R__THNBCASE(S);
         case 'C': R__THNBCASE(C);
      }
#undef R__THNBCASE
   }
   if (!s) {
      ::Warning("THnSparse::CreateHnAny", "Unknown Type of Histogram");
      return 0;
   }

   for (int i = 0; i < ndim; ++i) {
      s->GetAxis(i)->SetTitle(axis[i]->GetTitle());
   }

   // Get the array to know the number of entries of the TH1
   const TArray *array = dynamic_cast<const TArray*>(h);
   if (!array) {
      ::Warning("THnSparse::CreateHnAny", "Unknown Type of Histogram");
      return 0;
   }

   s->Add(h);
   return s;
}


//______________________________________________________________________________
THnBase* THnBase::CreateHnAny(const char* name, const char* title,
                              const THnBase* hn, Bool_t sparse,
                              Int_t chunkSize /*= 1024 * 16*/)
{
   // Create a THnSparse (if "sparse") or THn  from "hn", possibly
   // converting THn <-> THnSparse.
   TClass* type = 0;
   if (hn->InheritsFrom(THnSparse::Class())) {
      if (sparse) type = hn->IsA();
      else {
         char bintype;
         if (hn->InheritsFrom(THnSparseD::Class())) bintype = 'D';
         else if (hn->InheritsFrom(THnSparseF::Class())) bintype = 'F';
         else if (hn->InheritsFrom(THnSparseL::Class())) bintype = 'L';
         else if (hn->InheritsFrom(THnSparseI::Class())) bintype = 'I';
         else if (hn->InheritsFrom(THnSparseS::Class())) bintype = 'S';
         else if (hn->InheritsFrom(THnSparseC::Class())) bintype = 'C';
         else {
            hn->Error("CreateHnAny", "Type %s not implemented; please inform the ROOT team!",
                      hn->IsA()->GetName());
            return 0;
         }
         type = TClass::GetClass(TString::Format("THn%c", bintype));
      }
   } else if (hn->InheritsFrom(THn::Class())) {
      if (!sparse) type = hn->IsA();
      else {
         char bintype = 0;
         if (hn->InheritsFrom(THnD::Class())) bintype = 'D';
         else if (hn->InheritsFrom(THnF::Class())) bintype = 'F';
         else if (hn->InheritsFrom(THnC::Class())) bintype = 'C';
         else if (hn->InheritsFrom(THnS::Class())) bintype = 'S';
         else if (hn->InheritsFrom(THnI::Class())) bintype = 'I';
         else if (hn->InheritsFrom(THnL::Class())) bintype = 'L';
         else if (hn->InheritsFrom(THnL64::Class())) {
            hn->Error("CreateHnAny", "Type THnSparse with Long64_t bins is not available!");
            return 0;
         }
         if (bintype) {
            type = TClass::GetClass(TString::Format("THnSparse%c", bintype));
         }
      }
   } else {
      hn->Error("CreateHnAny", "Unhandled type %s, not deriving from THn nor THnSparse!",
                hn->IsA()->GetName());
      return 0;
   }
   if (!type) {
      hn->Error("CreateHnAny", "Unhandled type %s, please inform the ROOT team!",
                hn->IsA()->GetName());
      return 0;
   }

   THnBase* ret = (THnBase*)type->New();
   ret->Init(name, title, hn->GetListOfAxes(),
             kFALSE /*keepTargetAxes*/, chunkSize);

   ret->Add(hn);
   return ret;
}


//______________________________________________________________________________
void THnBase::Add(const TH1* hist, Double_t c /*=1.*/)
{
   // Fill the THnBase with the bins of hist that have content
   // or error != 0.
   Long64_t nbins = hist->GetNbinsX() + 2;
   if (hist->GetDimension() >= 2) nbins *= hist->GetNbinsY() + 2;
   if (hist->GetDimension() >= 3) nbins *= hist->GetNbinsZ() + 2;
   int x[3] = {0,0,0};
   for (int i = 0; i < nbins; ++i) {
      double value = hist->GetBinContent(i);
      double error = hist->GetBinError(i);
      if (!value && !error) continue;
      hist->GetBinXYZ(i, x[0], x[1], x[2]);
      SetBinContent(x, value * c);
      SetBinError(x, error * c);
   }
}

//______________________________________________________________________________
TFitResultPtr THnBase::Fit(TF1 *f ,Option_t *option ,Option_t *goption)
{
   //   Fit a THnSparse with function f
   //
   //   since the data is sparse by default a likelihood fit is performed
   //   merging all the regions with empty bins for betetr performance efficiency
   //
   //  Since the THnSparse is not drawn no graphics options are passed
   //  Here is the list of possible options
   //
   //                = "I"  Use integral of function in bin instead of value at bin center
   //                = "X"  Use chi2 method (default is log-likelihood method)
   //                = "U"  Use a User specified fitting algorithm (via SetFCN)
   //                = "Q"  Quiet mode (minimum printing)
   //                = "V"  Verbose mode (default is between Q and V)
   //                = "E"  Perform better Errors estimation using Minos technique
   //                = "B"  Use this option when you want to fix one or more parameters
   //                       and the fitting function is like "gaus", "expo", "poln", "landau".
   //                = "M"  More. Improve fit results
   //                = "R"  Use the Range specified in the function range


   Foption_t fitOption;

   if (!TH1::FitOptionsMake(option,fitOption)) return 0;

   // The function used to fit cannot be stored in a THnSparse. It
   // cannot be drawn either. Perhaps in the future.
   fitOption.Nostore = true;
   // Use likelihood fit if not specified
   if (!fitOption.Chi2) fitOption.Like = true;
   // create range and minimizer options with default values
   ROOT::Fit::DataRange range(GetNdimensions());
   for ( int i = 0; i < GetNdimensions(); ++i ) {
      TAxis *axis = GetAxis(i);
      range.AddRange(i, axis->GetXmin(), axis->GetXmax());
   }
   ROOT::Math::MinimizerOptions minOption;

   return ROOT::Fit::FitObject(this, f , fitOption , minOption, goption, range);
}

//______________________________________________________________________________
void THnBase::GetRandom(Double_t *rand, Bool_t subBinRandom /* = kTRUE */)
{
   // Generate an n-dimensional random tuple based on the histogrammed
   // distribution. If subBinRandom, the returned tuple will be additionally
   // randomly distributed within the randomized bin, using a flat
   // distribution.

   // check whether the integral array is valid
   if (fIntegralStatus != kValidInt)
      ComputeIntegral();

   // generate a random bin
   Double_t p = gRandom->Rndm();
   Long64_t idx = TMath::BinarySearch(GetNbins() + 1, fIntegral, p);
   const Int_t nStaticBins = 40;
   Int_t bin[nStaticBins];
   Int_t* pBin = bin;
   if (GetNdimensions() > nStaticBins) {
      pBin = new Int_t[GetNdimensions()];
   }
   GetBinContent(idx, pBin);

   // convert bin coordinates to real values
   for (Int_t i = 0; i < fNdimensions; i++) {
      rand[i] = GetAxis(i)->GetBinCenter(pBin[i]);

      // randomize the vector withing a bin
      if (subBinRandom)
         rand[i] += (gRandom->Rndm() - 0.5) * GetAxis(i)->GetBinWidth(pBin[i]);
   }
   if (pBin != bin) {
      delete [] pBin;
   }

   return;
}

//______________________________________________________________________________
Bool_t THnBase::IsInRange(Int_t *coord) const
{
   // Check whether bin coord is in range, as defined by TAxis::SetRange().

   Int_t min = 0;
   Int_t max = 0;
   for (Int_t i = 0; i < fNdimensions; ++i) {
      TAxis *axis = GetAxis(i);
      if (!axis->TestBit(TAxis::kAxisRange)) continue;
      min = axis->GetFirst();
      max = axis->GetLast();
      if (coord[i] < min || coord[i] > max)
         return kFALSE;
   }
   return kTRUE;
}

//______________________________________________________________________________
TObject* THnBase::ProjectionAny(Int_t ndim, const Int_t* dim,
                                Bool_t wantNDim,
                                Option_t* option /*= ""*/) const
{
   // Project all bins into a ndim-dimensional THn / THnSparse (whatever
   // *this is) or if (ndim < 4 and !wantNDim) a TH1/2/3 histogram,
   // keeping only axes in dim (specifying ndim dimensions).
   // If "option" contains "E" errors will be calculated.
   //                      "A" ranges of the taget axes will be ignored.
   //                      "O" original axis range of the taget axes will be
   //                          kept, but only bins inside the selected range
   //                          will be filled.

   TString name(GetName());
   name +="_proj";

   for (Int_t d = 0; d < ndim; ++d) {
      name += "_";
      name += dim[d];
   }

   TString title(GetTitle());
   Ssiz_t posInsert = title.First(';');
   if (posInsert == kNPOS) {
      title += " projection ";
      for (Int_t d = 0; d < ndim; ++d)
         title += GetAxis(dim[d])->GetTitle();
   } else {
      for (Int_t d = ndim - 1; d >= 0; --d) {
         title.Insert(posInsert, GetAxis(d)->GetTitle());
         if (d)
            title.Insert(posInsert, ", ");
      }
      title.Insert(posInsert, " projection ");
   }

   TObjArray newaxes(ndim);
   for (Int_t d = 0; d < ndim; ++d) {
      newaxes.AddAt(GetAxis(dim[d]),d);
   }

   THnBase* hn = 0;
   TH1* hist = 0;
   TObject* ret = 0;

   Bool_t* hadRange = 0;
   Bool_t ignoreTargetRange = (option && (strchr(option, 'A') || strchr(option, 'a')));
   Bool_t keepTargetAxis = ignoreTargetRange || (option && (strchr(option, 'O') || strchr(option, 'o')));
   if (ignoreTargetRange) {
      hadRange = new Bool_t[ndim];
      for (Int_t d = 0; d < ndim; ++d){
         TAxis *axis = GetAxis(dim[d]);
         hadRange[d] = axis->TestBit(TAxis::kAxisRange);
         axis->SetBit(TAxis::kAxisRange, kFALSE);
      }
   }

   if (wantNDim)
      ret = hn = CloneEmpty(name, title, &newaxes, keepTargetAxis);
   else
      ret = hist = CreateHist(name, title, &newaxes, keepTargetAxis);

   if (keepTargetAxis) {
      // make the whole axes visible, i.e. unset the range
      if (wantNDim) {
         for (Int_t d = 0; d < ndim; ++d) {
            hn->GetAxis(d)->SetRange(0, 0);
         }
      } else {
         hist->GetXaxis()->SetRange(0, 0);
         hist->GetYaxis()->SetRange(0, 0);
         hist->GetZaxis()->SetRange(0, 0);
      }
   }

   Bool_t haveErrors = GetCalculateErrors();
   Bool_t wantErrors = haveErrors || (option && (strchr(option, 'E') || strchr(option, 'e')));

   Int_t* bins  = new Int_t[ndim];
   Long64_t myLinBin = 0;

   THnIter iter(this, kTRUE /*use axis range*/);

   while ((myLinBin = iter.Next()) >= 0) {
      Double_t v = GetBinContent(myLinBin);

      for (Int_t d = 0; d < ndim; ++d) {
         bins[d] = iter.GetCoord(dim[d]);
         if (!keepTargetAxis && GetAxis(dim[d])->TestBit(TAxis::kAxisRange)) {
            Int_t binOffset = GetAxis(dim[d])->GetFirst();
            // Don't subtract even more if underflow is alreday included:
            if (binOffset > 0) --binOffset;
            bins[d] -= binOffset;
         }
      }

      Long64_t targetLinBin = -1;
      if (!wantNDim) {
         if (ndim == 1) targetLinBin = bins[0];
         else if (ndim == 2) targetLinBin = hist->GetBin(bins[0], bins[1]);
         else if (ndim == 3) targetLinBin = hist->GetBin(bins[0], bins[1], bins[2]);
      } else {
         targetLinBin = hn->GetBin(bins, kTRUE /*allocate*/);
      }

      if (wantErrors) {
         Double_t err2 = 0.;
         if (haveErrors) {
            err2 = GetBinError2(myLinBin);
         } else {
            err2 = v;
         }
         if (wantNDim) {
            hn->AddBinError2(targetLinBin, err2);
         } else {
            Double_t preverr = hist->GetBinError(targetLinBin);
            hist->SetBinError(targetLinBin, TMath::Sqrt(preverr * preverr + err2));
         }
      }

      // only _after_ error calculation, or sqrt(v) is taken into account!
      if (wantNDim)
         hn->AddBinContent(targetLinBin, v);
      else
         hist->AddBinContent(targetLinBin, v);
   }

   delete [] bins;

   if (wantNDim) {
      hn->SetEntries(fEntries);
   } else {
      if (!iter.HaveSkippedBin()) {
         hist->SetEntries(fEntries);
      } else {
         // re-compute the entries
         // in case of error calculation (i.e. when Sumw2() is set)
         // use the effective entries for the entries
         // since this  is the only way to estimate them
         hist->ResetStats();
         Double_t entries = hist->GetEffectiveEntries();
         if (!wantErrors) {
            // to avoid numerical rounding
            entries = TMath::Floor(entries + 0.5);
         }
         hist->SetEntries(entries);
      }
   }

   if (hadRange) {
      // reset kAxisRange bit:
      for (Int_t d = 0; d < ndim; ++d)
         GetAxis(dim[d])->SetBit(TAxis::kAxisRange, hadRange[d]);

      delete [] hadRange;
   }

   return ret;
}

//______________________________________________________________________________
void THnBase::Scale(Double_t c)
{
   // Scale contents and errors of this histogram by c:
   // this = this * c
   // It does not modify the histogram's number of entries.


   Double_t nEntries = GetEntries();
   // Scale the contents & errors
   Bool_t haveErrors = GetCalculateErrors();
   Long64_t i = 0;
   THnIter iter(this);
   while ((i = iter.Next()) >= 0) {
      // Get the content of the bin from the current histogram
      Double_t v = GetBinContent(i);
      SetBinContent(i, c * v);
      if (haveErrors) {
         Double_t err2 = GetBinError2(i);
         SetBinError2(i, c * c * err2);
      }
   }
   SetEntries(nEntries);
}

//______________________________________________________________________________
void THnBase::AddInternal(const THnBase* h, Double_t c, Bool_t rebinned)
{
   // Add() implementation for both rebinned histograms and those with identical
   // binning. See THnBase::Add().

   if (fNdimensions != h->GetNdimensions()) {
      Warning("RebinnedAdd", "Different number of dimensions, cannot carry out operation on the histograms");
      return;
   }

   // Trigger error calculation if h has it
   if (!GetCalculateErrors() && h->GetCalculateErrors())
      Sumw2();
   Bool_t haveErrors = GetCalculateErrors();

   Double_t* x = 0;
   if (rebinned) {
      x = new Double_t[fNdimensions];
   }
   Int_t* coord = new Int_t[fNdimensions];

   // Expand the exmap if needed, to reduce collisions
   Long64_t numTargetBins = GetNbins() + h->GetNbins();
   Reserve(numTargetBins);

   Long64_t i = 0;
   THnIter iter(h);
   // Add to this whatever is found inside the other histogram
   while ((i = iter.Next(coord)) >= 0) {
      // Get the content of the bin from the second histogram
      Double_t v = h->GetBinContent(i);

      Long64_t mybinidx = -1;
      if (rebinned) {
         // Get the bin center given a coord
         for (Int_t j = 0; j < fNdimensions; ++j)
            x[j] = h->GetAxis(j)->GetBinCenter(coord[j]);

         mybinidx = GetBin(x, kTRUE /* allocate*/);
      } else {
         mybinidx = GetBin(coord, kTRUE /*allocate*/);
      }

      if (haveErrors) {
         Double_t err2 = h->GetBinError2(i) * c * c;
         AddBinError2(mybinidx, err2);
      }
      // only _after_ error calculation, or sqrt(v) is taken into account!
      AddBinContent(mybinidx, c * v);
   }

   delete [] coord;
   delete [] x;

   Double_t nEntries = GetEntries() + c * h->GetEntries();
   SetEntries(nEntries);
}

//______________________________________________________________________________
void THnBase::Add(const THnBase* h, Double_t c)
{
   // Add contents of h scaled by c to this histogram:
   // this = this + c * h
   // Note that if h has Sumw2 set, Sumw2 is automatically called for this
   // if not already set.

   // Check consistency of the input
   if (!CheckConsistency(h, "Add")) return;

   AddInternal(h, c, kFALSE);
}

//______________________________________________________________________________
void THnBase::RebinnedAdd(const THnBase* h, Double_t c)
{
   // Add contents of h scaled by c to this histogram:
   // this = this + c * h
   // Note that if h has Sumw2 set, Sumw2 is automatically called for this
   // if not already set.
   // In contrast to Add(), RebinnedAdd() does not require consistent binning of
   // this and h; instead, each bin's center is used to determine the target bin.

   AddInternal(h, c, kTRUE);
}


//______________________________________________________________________________
Long64_t THnBase::Merge(TCollection* list)
{
   // Merge this with a list of THnBase's. All THnBase's provided
   // in the list must have the same bin layout!

   if (!list) return 0;
   if (list->IsEmpty()) return (Long64_t)GetEntries();

   Long64_t sumNbins = GetNbins();
   TIter iter(list);
   const TObject* addMeObj = 0;
   while ((addMeObj = iter())) {
      const THnBase* addMe = dynamic_cast<const THnBase*>(addMeObj);
      if (addMe) {
         sumNbins += addMe->GetNbins();
      }
   }
   Reserve(sumNbins);

   iter.Reset();
   while ((addMeObj = iter())) {
      const THnBase* addMe = dynamic_cast<const THnBase*>(addMeObj);
      if (!addMe)
         Error("Merge", "Object named %s is not THnBase! Skipping it.",
               addMeObj->GetName());
      else
         Add(addMe);
   }
   return (Long64_t)GetEntries();
}


//______________________________________________________________________________
void THnBase::Multiply(const THnBase* h)
{
   // Multiply this histogram by histogram h
   // this = this * h
   // Note that if h has Sumw2 set, Sumw2 is automatically called for this
   // if not already set.

   // Check consistency of the input
   if(!CheckConsistency(h, "Multiply"))return;

   // Trigger error calculation if h has it
   Bool_t wantErrors = kFALSE;
   if (GetCalculateErrors() || h->GetCalculateErrors())
      wantErrors = kTRUE;

   if (wantErrors) Sumw2();

   Double_t nEntries = GetEntries();
   // Now multiply the contents: in this case we have the intersection of the sets of bins
   Int_t* coord = new Int_t[fNdimensions];
   Long64_t i = 0;
   THnIter iter(this);
   // Add to this whatever is found inside the other histogram
   while ((i = iter.Next(coord)) >= 0) {
      // Get the content of the bin from the current histogram
      Double_t v1 = GetBinContent(i);
      // Now look at the bin with the same coordinates in h
      Long64_t idxh = h->GetBin(coord);
      Double_t v2 = 0.;
      if (idxh >= 0) v2 = h->GetBinContent(idxh);
      SetBinContent(i, v1 * v2);
      if (wantErrors) {
         Double_t err1 = GetBinError(i) * v2;
         Double_t err2 = 0.;
         if (idxh >= 0) err2 = h->GetBinError(idxh) * v1;
         SetBinError(i, TMath::Sqrt((err2 * err2 + err1 * err1)));
      }
   }
   SetEntries(nEntries);

   delete [] coord;
}

//______________________________________________________________________________
void THnBase::Multiply(TF1* f, Double_t c)
{
   // Performs the operation: this = this*c*f1
   // if errors are defined, errors are also recalculated.
   //
   // Only bins inside the function range are recomputed.
   // IMPORTANT NOTE: If you intend to use the errors of this histogram later
   // you should call Sumw2 before making this operation.
   // This is particularly important if you fit the histogram after
   // calling Multiply()

   Int_t* coord = new Int_t[fNdimensions];
   Double_t* x = new Double_t[fNdimensions];

   Bool_t wantErrors = GetCalculateErrors();
   if (wantErrors) Sumw2();

   Long64_t i = 0;
   THnIter iter(this);
   // Add to this whatever is found inside the other histogram
   while ((i = iter.Next(coord)) >= 0) {
      Double_t value = GetBinContent(i);

      // Get the bin coordinates given an index array
      for (Int_t j = 0; j < fNdimensions; ++j)
         x[j] = GetAxis(j)->GetBinCenter(coord[j]);

      if (!f->IsInside(x))
         continue;
      TF1::RejectPoint(kFALSE);

      // Evaluate function at points
      Double_t fvalue = f->EvalPar(x, NULL);

      SetBinContent(i, c * fvalue * value);
      if (wantErrors) {
         Double_t error = GetBinError(i);
         SetBinError(i, c * fvalue * error);
      }
   }

   delete [] x;
   delete [] coord;
}

//______________________________________________________________________________
void THnBase::Divide(const THnBase *h)
{
   // Divide this histogram by h
   // this = this/(h)
   // Note that if h has Sumw2 set, Sumw2 is automatically called for
   // this if not already set.
   // The resulting errors are calculated assuming uncorrelated content.

   // Check consistency of the input
   if (!CheckConsistency(h, "Divide"))return;

   // Trigger error calculation if h has it
   Bool_t wantErrors=GetCalculateErrors();
   if (!GetCalculateErrors() && h->GetCalculateErrors())
      wantErrors=kTRUE;

   // Remember original histogram statistics
   Double_t nEntries = fEntries;

   if (wantErrors) Sumw2();
   Bool_t didWarn = kFALSE;

   // Now divide the contents: also in this case we have the intersection of the sets of bins
   Int_t* coord = new Int_t[fNdimensions];
   Long64_t i = 0;
   THnIter iter(this);
   // Add to this whatever is found inside the other histogram
   while ((i = iter.Next(coord)) >= 0) {
      // Get the content of the bin from the first histogram
      Double_t v1 = GetBinContent(i);
      // Now look at the bin with the same coordinates in h
      Long64_t hbin = h->GetBin(coord);
      Double_t v2 = h->GetBinContent(hbin);
      if (!v2) {
         v1 = 0.;
         v2 = 1.;
         if (!didWarn) {
            Warning("Divide(h)", "Histogram h has empty bins - division by zero! Setting bin to 0.");
            didWarn = kTRUE;
         }
      }
      SetBinContent(i, v1 / v2);
      if (wantErrors) {
         Double_t err1 = GetBinError(i) * v2;
         Double_t err2 = h->GetBinError(hbin) * v1;
         Double_t b22 = v2 * v2;
         Double_t err = (err1 * err1 + err2 * err2) / (b22 * b22);
         SetBinError2(i, err);
      }
   }
   delete [] coord;
   SetEntries(nEntries);
}

//______________________________________________________________________________
void THnBase::Divide(const THnBase *h1, const THnBase *h2, Double_t c1, Double_t c2, Option_t *option)
{
   // Replace contents of this histogram by multiplication of h1 by h2
   // this = (c1*h1)/(c2*h2)
   // Note that if h1 or h2 have Sumw2 set, Sumw2 is automatically called for
   // this if not already set.
   // The resulting errors are calculated assuming uncorrelated content.
   // However, if option ="B" is specified, Binomial errors are computed.
   // In this case c1 and c2 do not make real sense and they are ignored.


   TString opt = option;
   opt.ToLower();
   Bool_t binomial = kFALSE;
   if (opt.Contains("b")) binomial = kTRUE;

   // Check consistency of the input
   if (!CheckConsistency(h1, "Divide") || !CheckConsistency(h2, "Divide"))return;
   if (!c2) {
      Error("Divide","Coefficient of dividing histogram cannot be zero");
      return;
   }

   Reset();

   // Trigger error calculation if h1 or h2 have it
   if (!GetCalculateErrors() && (h1->GetCalculateErrors()|| h2->GetCalculateErrors() != 0))
      Sumw2();

   // Count filled bins
   Long64_t nFilledBins=0;

   // Now divide the contents: we have the intersection of the sets of bins

   Int_t* coord = new Int_t[fNdimensions];
   memset(coord, 0, sizeof(Int_t) * fNdimensions);
   Bool_t didWarn = kFALSE;

   Long64_t i = 0;
   THnIter iter(h1);
   // Add to this whatever is found inside the other histogram
   while ((i = iter.Next(coord)) >= 0) {
      // Get the content of the bin from the first histogram
      Double_t v1 = h1->GetBinContent(i);
      // Now look at the bin with the same coordinates in h2
      Long64_t h2bin = h2->GetBin(coord);
      Double_t v2 = h2->GetBinContent(h2bin);
      if (!v2) {
         v1 = 0.;
         v2 = 1.;
         if (!didWarn) {
            Warning("Divide(h1, h2)", "Histogram h2 has empty bins - division by zero! Setting bin to 0.");
            didWarn = kTRUE;
         }
      }
      nFilledBins++;
      Long64_t myBin = GetBin(coord);
      SetBinContent(myBin, c1 * v1 / c2 / v2);
      if(GetCalculateErrors()){
         Double_t err1 = h1->GetBinError(i);
         Double_t err2 = h2->GetBinError(h2bin);
         Double_t errSq = 0.;
         if (binomial) {
            if (v1 != v2) {
               Double_t w = v1 / v2;
               err2 *= w;
               errSq = TMath::Abs( ( (1. - 2.*w) * err1 * err1 + err2 * err2 ) / (v2 * v2) );
            }
         } else {
            c1 *= c1;
            c2 *= c2;
            Double_t b22 = v2 * v2 * c2;
            err1 *= v2;
            err2 *= v1;
            errSq = c1 * c2 * (err1 * err1 + err2 * err2) / (b22 * b22);
         }
         SetBinError2(myBin, errSq);
      }
   }

   delete [] coord;
   SetFilledBins(nFilledBins);

   // Set as entries in the result histogram the entries in the numerator
   SetEntries(h1->GetEntries());
}

//______________________________________________________________________________
Bool_t THnBase::CheckConsistency(const THnBase *h, const char *tag) const
{
   // Consistency check on (some of) the parameters of two histograms (for operations).

   if (fNdimensions != h->GetNdimensions()) {
      Warning(tag, "Different number of dimensions, cannot carry out operation on the histograms");
      return kFALSE;
   }
   for (Int_t dim = 0; dim < fNdimensions; dim++){
      if (GetAxis(dim)->GetNbins() != h->GetAxis(dim)->GetNbins()) {
         Warning(tag, "Different number of bins on axis %i, cannot carry out operation on the histograms", dim);
         return kFALSE;
      }
   }
   return kTRUE;
}

//______________________________________________________________________________
void THnBase::SetBinEdges(Int_t idim, const Double_t* bins)
{
   // Set the axis # of bins and bin limits on dimension idim

   TAxis* axis = (TAxis*) fAxes[idim];
   axis->Set(axis->GetNbins(), bins);
}

//______________________________________________________________________________
void THnBase::SetTitle(const char *title)
{
   // Change (i.e. set) the title.
   //
   // If title is in the form "stringt;string0;string1;string2 ..."
   // the histogram title is set to stringt, the title of axis0 to string0,
   // of axis1 to string1, of axis2 to string2, etc, just like it is done
   // for TH1/TH2/TH3.
   // To insert the character ";" in one of the titles, one should use "#;"
   // or "#semicolon".

   fTitle = title;
   fTitle.ReplaceAll("#;",2,"#semicolon",10);

   Int_t endHistTitle = fTitle.First(';');
   if (endHistTitle >= 0) {
      // title contains a ';' so parse the axis titles
      Int_t posTitle = endHistTitle + 1;
      Int_t lenTitle = fTitle.Length();
      Int_t dim = 0;
      while (posTitle > 0 && posTitle < lenTitle && dim < fNdimensions){
         Int_t endTitle = fTitle.Index(";", posTitle);
         TString axisTitle = fTitle(posTitle, endTitle - posTitle);
         axisTitle.ReplaceAll("#semicolon", 10, ";", 1);
         GetAxis(dim)->SetTitle(axisTitle);
         dim++;
         if (endTitle > 0)
            posTitle = endTitle + 1;
         else
            posTitle = -1;
      }
      // Remove axis titles from histogram title
      fTitle.Remove(endHistTitle, lenTitle - endHistTitle);
   }

   fTitle.ReplaceAll("#semicolon", 10, ";", 1);

}

//______________________________________________________________________________
THnBase* THnBase::RebinBase(Int_t group) const
{
   // Combine the content of "group" neighboring bins into
   // a new bin and return the resulting THnBase.
   // For group=2 and a 3 dimensional histogram, all "blocks"
   // of 2*2*2 bins will be put into a bin.

   Int_t* ngroup = new Int_t[GetNdimensions()];
   for (Int_t d = 0; d < GetNdimensions(); ++d)
      ngroup[d] = group;
   THnBase* ret = RebinBase(ngroup);
   delete [] ngroup;
   return ret;
}

//______________________________________________________________________________
THnBase* THnBase::RebinBase(const Int_t* group) const
{
   // Combine the content of "group" neighboring bins for each dimension
   // into a new bin and return the resulting THnBase.
   // For group={2,1,1} and a 3 dimensional histogram, pairs of x-bins
   // will be grouped.

   Int_t ndim = GetNdimensions();
   TString name(GetName());
   for (Int_t d = 0; d < ndim; ++d)
      name += Form("_%d", group[d]);


   TString title(GetTitle());
   Ssiz_t posInsert = title.First(';');
   if (posInsert == kNPOS) {
      title += " rebin ";
      for (Int_t d = 0; d < ndim; ++d)
         title += Form("{%d}", group[d]);
   } else {
      for (Int_t d = ndim - 1; d >= 0; --d)
         title.Insert(posInsert, Form("{%d}", group[d]));
      title.Insert(posInsert, " rebin ");
   }

   TObjArray newaxes(ndim);
   newaxes.SetOwner();
   for (Int_t d = 0; d < ndim; ++d) {
      newaxes.AddAt(new TAxis(*GetAxis(d) ),d);
      if (group[d] > 1) {
         TAxis* newaxis = (TAxis*) newaxes.At(d);
         Int_t newbins = (newaxis->GetNbins() + group[d] - 1) / group[d];
         if (newaxis->GetXbins() && newaxis->GetXbins()->GetSize()) {
            // variable bins
            Double_t *edges = new Double_t[newbins + 1];
            for (Int_t i = 0; i < newbins + 1; ++i)
               if (group[d] * i <= newaxis->GetNbins())
                  edges[i] = newaxis->GetXbins()->At(group[d] * i);
               else edges[i] = newaxis->GetXmax();
            newaxis->Set(newbins, edges);
            delete [] edges;
         } else {
            newaxis->Set(newbins, newaxis->GetXmin(), newaxis->GetXmax());
         }
      }
   }

   THnBase* h = CloneEmpty(name.Data(), title.Data(), &newaxes, kTRUE);
   Bool_t haveErrors = GetCalculateErrors();
   Bool_t wantErrors = haveErrors;

   Int_t* bins  = new Int_t[ndim];
   Int_t* coord = new Int_t[fNdimensions];

   Long64_t i = 0;
   THnIter iter(this);
   while ((i = iter.Next(coord)) >= 0) {
      Double_t v = GetBinContent(i);
      for (Int_t d = 0; d < ndim; ++d) {
         bins[d] = TMath::CeilNint( (double) coord[d]/group[d] );
      }
      Long64_t idxh = h->GetBin(bins, kTRUE /*allocate*/);

      if (wantErrors) {
         Double_t err2 = 0.;
         if (haveErrors) {
            err2 = GetBinError2(i);
         } else err2 = v;
         h->AddBinError2(idxh, err2);
      }

      // only _after_ error calculation, or sqrt(v) is taken into account!
      h->AddBinContent(idxh, v);
   }

   delete [] bins;
   delete [] coord;

   h->SetEntries(fEntries);

   return h;

}

//______________________________________________________________________________
void THnBase::ResetBase(Option_t * /*option = ""*/)
{
   // Clear the histogram
   fEntries = 0.;
   fTsumw = 0.;
   fTsumw2 = -1.;
   if (fIntegralStatus != kNoInt) {
      delete [] fIntegral;
      fIntegralStatus = kNoInt;
   }
}

//______________________________________________________________________________
Double_t THnBase::ComputeIntegral()
{
   // Calculate the integral of the histogram

   // delete old integral
   if (fIntegralStatus != kNoInt) {
      delete [] fIntegral;
      fIntegralStatus = kNoInt;
   }

   // check number of bins
   if (GetNbins() == 0) {
      Error("ComputeIntegral", "The histogram must have at least one bin.");
      return 0.;
   }

   // allocate integral array
   fIntegral = new Double_t [GetNbins() + 1];
   fIntegral[0] = 0.;

   // fill integral array with contents of regular bins (non over/underflow)
   Int_t* coord = new Int_t[fNdimensions];
   Long64_t i = 0;
   THnIter iter(this);
   while ((i = iter.Next(coord)) >= 0) {
      Double_t v = GetBinContent(i);

      // check whether the bin is regular
      bool regularBin = true;
      for (Int_t dim = 0; dim < fNdimensions; dim++) {
         if (coord[dim] < 1 || coord[dim] > GetAxis(dim)->GetNbins()) {
            regularBin = false;
            break;
         }
      }

      // if outlayer, count it with zero weight
      if (!regularBin) v = 0.;

      fIntegral[i + 1] = fIntegral[i] + v;
   }
   delete [] coord;

   // check sum of weights
   if (fIntegral[GetNbins()] == 0.) {
      Error("ComputeIntegral", "No hits in regular bins (non over/underflow).");
      delete [] fIntegral;
      return 0.;
   }

   // normalize the integral array
   for (Long64_t j = 0; j <= GetNbins(); ++j)
      fIntegral[j] = fIntegral[j] / fIntegral[GetNbins()];

   // set status to valid
   fIntegralStatus = kValidInt;
   return fIntegral[GetNbins()];
}

//______________________________________________________________________________
void THnBase::PrintBin(Long64_t idx, Option_t* options) const
{
   // Print bin with linex index "idx".
   // For valid options see PrintBin(Long64_t idx, Int_t* bin, Option_t* options).
   Int_t* coord = new Int_t[fNdimensions];
   PrintBin(idx, coord, options);
   delete [] coord;
}

//______________________________________________________________________________
Bool_t THnBase::PrintBin(Long64_t idx, Int_t* bin, Option_t* options) const
{
   // Print one bin. If "idx" is != -1 use that to determine the bin,
   // otherwise (if "idx" == -1) use the coordinate in "bin".
   // If "options" contains:
   //   '0': only print bins with an error or content != 0
   // Return whether the bin was printed (depends on options)

   Double_t v = -42;
   if (idx == -1) {
      idx = GetBin(bin);
      v = GetBinContent(idx);
   } else {
      v = GetBinContent(idx, bin);
   }

   Double_t err = 0.;
   if (GetCalculateErrors()) {
      if (idx != -1) {
         err = GetBinError(idx);
      }
   }

   if (v == 0. && err == 0. && options && strchr(options, '0')) {
      // suppress zeros, and we have one.
      return kFALSE;
   }

   TString coord;
   for (Int_t dim = 0; dim < fNdimensions; ++dim) {
      coord += bin[dim];
      coord += ',';
   }
   coord.Remove(coord.Length() - 1);

   if (GetCalculateErrors()) {
      Printf("Bin at (%s) = %g (+/- %g)", coord.Data(), v, err);
   } else {
      Printf("Bin at (%s) = %g", coord.Data(), v);
   }

   return kTRUE;
}

//______________________________________________________________________________
void THnBase::PrintEntries(Long64_t from /*=0*/, Long64_t howmany /*=-1*/,
                           Option_t* options /*=0*/) const
{
   // Print "howmany" entries starting at "from". If "howmany" is -1, print all.
   // If "options" contains:
   //   'x': print in the order of axis bins, i.e. (0,0,...,0), (0,0,...,1),...
   //   '0': only print bins with content != 0

   if (from < 0) from = 0;
   if (howmany == -1) howmany = GetNbins();

   Int_t* bin = new Int_t[fNdimensions];

   if (options && (strchr(options, 'x') || strchr(options, 'X'))) {
      Int_t* nbins = new Int_t[fNdimensions];
      for (Int_t dim = fNdimensions - 1; dim >= 0; --dim) {
         nbins[dim] = GetAxis(dim)->GetNbins();
         bin[dim] = from % nbins[dim];
         from /= nbins[dim];
      }

      for (Long64_t i = 0; i < howmany; ++i) {
         if (!PrintBin(-1, bin, options))
            ++howmany;
         // Advance to next bin:
         ++bin[fNdimensions - 1];
         for (Int_t dim = fNdimensions - 1; dim >= 0; --dim) {
            if (bin[dim] >= nbins[dim]) {
               bin[dim] = 0;
               if (dim > 0) {
                  ++bin[dim - 1];
               } else {
                  howmany = -1; // aka "global break"
               }
            }
         }
      }
      delete [] nbins;
   } else {
      for (Long64_t i = from; i < from + howmany; ++i) {
         if (!PrintBin(i, bin, options))
            ++howmany;
      }
   }
   delete [] bin;
}

//______________________________________________________________________________
void THnBase::Print(Option_t* options) const
{
   // Print a THnBase. If "option" contains:
   //   'a': print axis details
   //   'm': print memory usage
   //   's': print statistics
   //   'c': print its content, too (this can generate a LOT of output!)
   // Other options are forwarded to PrintEntries().

   Bool_t optAxis    = options && (strchr(options, 'A') || (strchr(options, 'a')));
   Bool_t optMem     = options && (strchr(options, 'M') || (strchr(options, 'm')));
   Bool_t optStat    = options && (strchr(options, 'S') || (strchr(options, 's')));
   Bool_t optContent = options && (strchr(options, 'C') || (strchr(options, 'c')));

   Printf("%s (*0x%lx): \"%s\" \"%s\"", IsA()->GetName(), (unsigned long)this, GetName(), GetTitle());
   Printf("  %d dimensions, %g entries in %lld filled bins", GetNdimensions(), GetEntries(), GetNbins());

   if (optAxis) {
      for (Int_t dim = 0; dim < fNdimensions; ++dim) {
         TAxis* axis = GetAxis(dim);
         Printf("    axis %d \"%s\": %d bins (%g..%g), %s bin sizes", dim,
                axis->GetTitle(), axis->GetNbins(), axis->GetXmin(), axis->GetXmax(),
                (axis->GetXbins() ? "variable" : "fixed"));
      }
   }

   if (optStat) {
      Printf("  %s error calculation", (GetCalculateErrors() ? "with" : "without"));
      if (GetCalculateErrors()) {
         Printf("    Sum(w)=%g, Sum(w^2)=%g", GetSumw(), GetSumw2());
         for (Int_t dim = 0; dim < fNdimensions; ++dim) {
            Printf("    axis %d: Sum(w*x)=%g, Sum(w*x^2)=%g", dim, GetSumwx(dim), GetSumwx2(dim));
         }
      }
   }

   if (optMem && InheritsFrom(THnSparse::Class())) {
      const THnSparse* hsparse = dynamic_cast<const THnSparse*>(this);
      Printf("  coordinates stored in %d chunks of %d entries\n    %g of bins filled using %g of memory compared to an array",
             hsparse->GetNChunks(), hsparse->GetChunkSize(),
             hsparse->GetSparseFractionBins(), hsparse->GetSparseFractionMem());
   }

   if (optContent) {
      Printf("  BIN CONTENT:");
      PrintEntries(0, -1, options);
   }
}


//______________________________________________________________________________
void THnBase::Browse(TBrowser *b)
{
   // Browse a THnSparse: create an entry (ROOT::THnSparseBrowsable) for each
   // dimension.
   if (fBrowsables.IsEmpty()) {
      for (Int_t dim = 0; dim < fNdimensions; ++dim) {
         fBrowsables.AddAtAndExpand(new ROOT::THnBaseBrowsable(this, dim), dim);
      }
      fBrowsables.SetOwner();
   }

   for (Int_t dim = 0; dim < fNdimensions; ++dim) {
      b->Add(fBrowsables[dim]);
   }
}



//______________________________________________________________________________
//
//
//    Iterator over THnBase bins; internal implementation.
//
//______________________________________________________________________________
ROOT::THnBaseBinIter::~THnBaseBinIter() {
   // Destruct a bin iterator.

   // Not much to do, but pin vtable
}


//______________________________________________________________________________
//
//
//    Iterator over THnBase bins
//
//______________________________________________________________________________
ClassImp(THnIter);

THnIter::~THnIter() {
   // Destruct a bin iterator.
   delete fIter;
}




//______________________________________________________________________________
//
// TBrowser helper for THnBase.
//
//______________________________________________________________________________
ClassImp(ROOT::THnBaseBrowsable);

//______________________________________________________________________________
ROOT::THnBaseBrowsable::THnBaseBrowsable(THnBase* hist, Int_t axis):
fHist(hist), fAxis(axis), fProj(0)
{
   // Construct a THnBaseBrowsable.
   TString axisName = hist->GetAxis(axis)->GetName();
   if (axisName.IsNull()) {
      axisName = TString::Format("axis%d", axis);
   }

   SetNameTitle(axisName,
                TString::Format("Projection on %s of %s", axisName.Data(),
                                hist->IsA()->GetName()).Data());
}

//______________________________________________________________________________
ROOT::THnBaseBrowsable::~THnBaseBrowsable()
{
   // Destruct a THnBaseBrowsable.
   delete fProj;
}

//______________________________________________________________________________
void ROOT::THnBaseBrowsable::Browse(TBrowser* b)
{
   // Browse an axis of a THnBase, i.e. draw its projection.
   if (!fProj) {
      fProj = fHist->Projection(fAxis);
   }
   fProj->Draw(b ? b->GetDrawOption() : "");
   gPad->Update();
}

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