    // @(#)root/star:$Name:  $:$Id: TTable.cxx,v 1.10 2005/02/10 07:24:49 brun Exp $
    // Author: Valery Fine(fine@bnl.gov)   03/07/98
    // Copyright (C) Valery Fine (Valeri Faine) 1998-2001. All right reserved

    ////////////////////////////////////////////////////////////////////////////
    //                                                                        //
    // TTable                                                                 //
    //                                                                        //
    // Wraps the array of the plain C-structures (one C-structure per element)//
    //                                                                        //
    // class TTable provides the automatic schema evolution for               //
    // the derived "table" classes saved with ROOT format.                    //
    //                                                                        //
    // "Automatic Schema evolution" provides:                                 //
    //   -  skipping data-member if it is not present for the current         //
    //      implementation of the "table" but was present at the time the     //
    //      table was written;                                                //
    //   -  assign a default value ZERO for the brand-new data-members,       //
    //      those were not in the structure when the object was written but   //
    //      present now;                                                      //
    //   -  trace propely any change in the order of the data-members         //
    //                                                                        //
    // To enjoy this class one has to derive his/her own custom class:        //
    //                                                                        //
    // St_dst_track_Table.h:                                                  //
    // ---------------------                                                  //
    //  #ifndef STAF_St_dst_track_Table                                       //
    //  #define STAF_St_dst_track_Table                                       //
    //                                                                        //
    //  #include "TTable.h"                                                   //
    //                                                                        //
    // // #include "dst_track.h"  the C-structure defintion may be kept       //
    //                            separately                                  //
    //  typedef struct dst_track_st {                                         //
    //  	float r0;             /* radius at start (cm). See also comments*/
    //  	float phi0;           /* azimuthal angle at start (deg)         */
    //  	float z0;             /* z-coord. at start (cm)                 */
    //  	float psi;            /* azimuthal angle of pT vector (deg)     */
    //  	float tanl;           /* tan(dip) =pz/pt at start               */
    //  	float invpt;          /* 1/pt at start (GeV/c)^(-1)             */
    //  	float curvature;      /* Track curvature (1/cm)                 */
    //  	float covar[15];      /* full covariance matrix                 */
    //  	float chisq[2];       /* Chi-square per degree of freedom       */
    //  	float x_first[3];     /* coord. of first measured point (cm)    */
    //  	float x_last[3];      /* coord. of last measured point (cm)     */
    //  	float length;         /* from first to last point (cm)          */
    //  	float impact;         /* primary vertex (cm)                    */
    //  	unsigned long map[2]; /* extrap. info. (see preceeding comments)*/
    //  	int id;               /* Primary key (see comments)             */
    //  	int iflag;            /* bitmask quality info. (see comments)   */
    //  	int det_id;           /* Detector id information                */
    //  	int method;           /* Track finding/fitting method, packed   */
    //  	int pid;              /* Geant particle ID for assumed mass     */
    //  	int n_point;          /* SVT, TPC, FTPC component #s are packed */
    //  	int n_max_point;      /* SVT, TPC, FTPC component #s are packed */
    //  	int n_fit_point;      /* SVT, TPC, FTPC component #s are packed */
    //  	int icharge;          /* Particle charge in units of |e|        */
    //  	int id_start_vertex;  /* final fit and primary track candidates */
    //  } DST_TRACK_ST;                                                       //
    //                                                                        //
    //  class St_dst_track : public TTable                                    //
    //  {                                                                     //
    //   public:                                                              //
    //     ClassDefTable(St_dst_track,dst_track_st)                           //
    //     ClassDef(St_dst_track,2) //C++ wrapper for <dst_track> StAF table  //
    //  };                                                                    //
    //  #endif                                                                //
    // ---------------------                                                  //
    //                                                                        //
    //  where the CPP macro defines several convinient methods for the        //
    //  "table" class (see: $ROOTSYS/star/inc/Ttypes.h for details:           //
    //                                                                        //
    //  #define ClassDefTable(className,structName)
    //    protected:
    //       static TTableDescriptor *fgColDescriptors;
    //       virtual TTableDescriptor *GetDescriptorPointer() const { return fgColDescriptors;}
    //       virtual void SetDescriptorPointer(TTableDescriptor *list) const { fgColDescriptors = list;}
    //    public:
    //      typedef structName* iterator;
    //      className() : TTable(_QUOTE_(className),sizeof(structName))    {SetType(_QUOTE_(structName));}
    //      className(const Text_t *name) : TTable(name,sizeof(structName)) {SetType(_QUOTE_(structName));}
    //      className(Int_t n) : TTable(_QUOTE_(className),n,sizeof(structName)) {SetType(_QUOTE_(structName));}
    //      className(const Text_t *name,Int_t n) : TTable(name,n,sizeof(structName)) {SetType(_QUOTE_(structName));}
    //      structName *GetTable(Int_t i=0) const { return ((structName *)GetArray())+i;}
    //      structName &operator[](Int_t i){ assert(i>=0 && i < GetNRows()); return *GetTable(i); }
    //      const structName &operator[](Int_t i) const { assert(i>=0 && i < GetNRows()); return *((const structName *)(GetTable(i))); }
    //      structName *begin() const  {                      return GetNRows()? GetTable(0):0;}
    //      structName *end()   const  {Int_t i = GetNRows(); return          i? GetTable(i):0;}
    //                                                                        //
    //  The class implementation file may 2 lines and look as follows:        //
    //  (for the example above):                                              //
    //                                                                        //
    //  St_dst_track_Table.cxx:                                               //
    //  -----------------------                                               //
    //       #include "St_dst_track_Table.h"                                  //
    //       TableClassImpl(St_dst_track, dst_track_st)                       //
    //  -----------------------                                               //
    //  LinkDef.h                                                             //
    //  -----------------------                                               //
    //  To provide ROOT I/O for this class TWO CINT dictonary entries         //
    //  should be defined with your custom LinkDef.h file                     //
    //     1. First entry (as usually) for the class derived from TTable      //
    //        for example:                                                    //
    // #pragma C++ class St_dst_track                                         //
    //     2. Second entry for the C-structure wrapped into the class.        //
    //         Since C-structuire is not derived from TObject it must be      //
    //         properly defined as "foreign" ROOT class                       //
    //    #pragma C++ class dst_track_st+;                                    //
    //  -----------------------                                               //
    // meta-variables i$ and n$ introduced                                    //
    // where "i$" stands for the current row index                            //
    //       "n$" stands for the total number of rows                         //
    // meta-variable can be used along the normal                             //
    // table column names in the expressions (see for example                 //
    // method TTable::Draw                                                    //
    //                                                                        //
    ////////////////////////////////////////////////////////////////////////////

    #include <assert.h>

    #ifdef WIN32
    # include <float.h>
    #endif

    //#if ROOT_VERSION_CODE >= ROOT_VERSION(3,03,5)
    #include "Riosfwd.h"
    #include "Riostream.h"
    //#include <iomanip.h>

    // #endif

    #include "TROOT.h"
    #include "TBaseClass.h"
    #include "TSystem.h"
    #include "TBuffer.h"
    #include "TMath.h"
    #include "TClass.h"
    #include "TBrowser.h"
    #include "TString.h"
    #include "Api.h"
    #include "TDataSetIter.h"
    #include "TTable.h"
    #include "TTableDescriptor.h"
    #include "TColumnView.h"
    #include "TFile.h"

    #include "TGaxis.h"
    #include "TH1.h"
    #include "TH2.h"
    #include "TProfile.h"
    #include "TVirtualPad.h"
    #include "TEventList.h"
    #include "TPolyMarker.h"
    #include "TView.h"
    #include "TGaxis.h"
    #include "TPolyMarker3D.h"

    #include "THLimitsFinder.h"

    #include "TTableMap.h"

    static TH1 *gCurrentTableHist = 0;

    static const char *dtorName = "dtor";
    static   Int_t         fNbins[4] = {100,100,100,100};     //Number of bins per dimension
    static   Float_t       fVmin[4]  = {0,0,0,0};             //Minima of varexp columns
    static   Float_t       fVmax[4]  = {20,20,20,20};         //Maxima of varexp columns

    const char *TTable::fgTypeName[] = {
                           "NAN", "float", "int", "long", "short", "double"
                         , "unsigned int", "unsigned long","unsigned short"
                         , "unsigned char", "char", "Ptr_t"
                                       };

    //______________________________________________________________________________
    static void ArrayLayout(UInt_t *layout,const UInt_t *size, Int_t dim)
    {
      //
      // ArrayLayout - calculates the array layout recursively
      //
      // Input:
      // -----
      // dim   - dimension of the targeted array
      // size  - the max index for each dimension
      //
      // Output:
      // ------
      // layout - the "start index" for each dimension of an array
      //

      if (dim && layout && size) {
        if (++layout[dim-1] >= size[dim-1]) {
            layout[dim-1] = 0;
            dim--;
            ArrayLayout(layout,size, dim);
        }
      }
    }

    ClassImp(TTable)

    //______________________________________________________________________________
     TTableDescriptor *TTable::GetTableDescriptors() const {
     // protected: create a new TTableDescriptor descriptor for this table
       assert(0);
       return new TTableDescriptor(this);
    }

    //______________________________________________________________________________
     void TTable::AsString(void *buf, EColumnType type, Int_t width,ostream &out) const
    {
      //
      // AsString represents the value provided via "void *b" with type defined
      //          by "name"
      //
      //   void *buf  - the pointer to the value to be printed out.
      //        type  - the basic data type for the value above
      //       width  - the number of psotion to be used to print the value out
      //
       switch (type) {
        case kFloat:
             out << dec  << setw(width) << setprecision(width-3) << *(float *)buf;
             break;
        case kInt:
             out << dec  <<  setw(width) << *(int *)buf;
             break;
        case kLong:
             out << dec  << setw(width) << *(long *)buf;
             break;
        case kShort:
             out << dec  << setw(width) << *(short *)buf;
             break;
        case kDouble:
             out << dec  << setw(width) << setprecision(width-3) << *(double *)buf;
             break;
        case kUInt:
             out << dec  << setw(width) << *(unsigned int *)buf;
             break;
        case kULong:
             out << dec  << setw(width) << *(unsigned long *)buf;
             break;
        case kUShort:
             out  << setw(width) << "0x" << hex << *(unsigned short *)buf;
             break;
        case kUChar:
             out  << setw(width) << "0x" << hex << int(*(unsigned char *)buf);
             break;
        case kChar:
             out << setw(width) << *(char *)buf;
             break;
        case kBool:
             out << setw(width) << *(bool *)buf;
             break;
        case kPtr:
             out << "->" << setw(width) << *(void **)buf;
             break;
        default:
             out << "\"NaN\"";
             break;
       };
    }

    //______________________________________________________________________________
     const void *TTable::At(Int_t i) const
    {
     // Returns a pointer to the i-th row of the table
       if (!BoundsOk("TTable::At", i)) {
           Warning("TTable::At","%s.%s",GetName(),GetType());
          i = 0;
       }
       return (const void *)(fTable+i*fSize);
    }

    //______________________________________________________________________________
     Int_t TTable::CopyRows(const TTable *srcTable, Long_t srcRow, Long_t dstRow, Long_t nRows, Bool_t expand)
    {
     // CopyRows copies nRows from starting from the srcRow of srcTable
     // to the dstRow in this table upto nRows or by the end of this table.
     //
     // This table if automaticaly increased if expand = kTRUE.
     // The old values of this table rows are to be destroyed and
     // replaced with the new ones.
     //
     // PARAMETERS:
     //   srcTable - a pointer to the table "donor"
     //   srcRow   - the index of the first row of the table donor to copy from
     //   dstRow   - the index of the first row of this table to copy to
     //   nRows    - the total number of rows to be copied. This table will be expanded
     //              as needed if expand = kTRUE (it is kFALSE "by default")
     //          = 0 to copy ALL remain rows from the srcTable.
     //   expand   - flag whether this table should reallocated if needed.
     //
     // RETURN:
     //          the number of the rows been copied

     assert(!TestBit(kIsNotOwn));
     if (!(srcTable && srcTable->GetNRows()) ||
              srcRow > srcTable->GetNRows()-1   )   return 0;

     if (strcmp(GetType(),srcTable->GetType())) {
       // check this table current capacity
       if (!nRows) nRows = srcTable->GetNRows();
       Long_t tSize = GetTableSize();
       Long_t extraRows = (tSize - dstRow) - nRows;
       if (extraRows < 0) {
         if (expand) {
           ReAllocate(tSize - extraRows);
           extraRows = 0;
         }
         nRows += extraRows;
       }
       if (dstRow+nRows > GetNRows()) SetNRows(dstRow+nRows);
       ::memmove((*this)[dstRow],(*srcTable)[srcRow],(size_t)GetRowSize()*nRows);
       return nRows;
     } else
         Error("CopyRows",
               "This table is <%s> but the src table has a wrong type <%s>",GetType()
               ,srcTable->GetType());
     return 0;
    }
    //______________________________________________________________________________
     void TTable::DeleteRows(Long_t indx, UInt_t nRows)
    {
      // Delete one or several rows from the table
      //
      //  Int_t indx  - index of the first row to be deleted
      //  Int_t nRows - the total number of rows to be deleted
      //              = 1 "by default
      if (CopyRows(this, indx+nRows, indx, GetNRows()-indx-nRows))
           SetUsedRows(GetNRows() - nRows);
    }
    //______________________________________________________________________________
     TH1  *TTable::Draw(TCut varexp, TCut selection, Option_t *option, Int_t nentries, Int_t firstentry)
    {
    //*-*-*-*-*-*-*-*-*-*-*Draw expression varexp for specified entries-*-*-*-*-*
    //*-*                  ===========================================
    //
    //   This function accepts TCut objects as arguments.
    //   Useful to use the string operator +
    //         example:
    //            table.Draw("x",cut1+cut2+cut3);
    //
    //   TCutG object with "CUTG" name can be created via the graphics editor.
    //

       return TTable::Draw(varexp.GetTitle(), selection.GetTitle(), option, nentries, firstentry);
    }

    //______________________________________________________________________________
     TH1 *TTable::Draw(const Text_t *varexp00, const Text_t *selection, Option_t *option,Int_t nentries, Int_t firstentry)
    {
    //*-*-*-*-*-*-*-*-*-*-*Draw expression varexp for specified entries-*-*-*-*-*
    //*-*                  ===========================================
    //
    //  varexp is an expression of the general form e1:e2:e3
    //    where e1,etc is a C++ expression referencing a combination of the TTable columns
    //          One can use two extra meta variable "i$" and "n$" along with the table
    //          column names.
    //          i$ is to involve the current row number
    //          n$ refers the total num,ber of rows of this table provided by TTable::GetNRows()
    //
    //  Example:
    //     varexp = x     simplest case: draw a 1-Dim distribution of column named x
    //            = sqrt(x)            : draw distribution of sqrt(x)
    //            = x*y/z
    //            = y:sqrt(x) 2-Dim dsitribution of y versus sqrt(x)
    //            = i$:sqrt(x) 2-Dim dsitribution of i versus sqrt(x[i])
    //            = phep[0]:sqrt(phep[3]) 2-Dim dsitribution of phep[0] versus sqrt(phep[3])
    //
    //  Note that the variables e1, e2 or e3 may contain a boolean expression as well.
    //  example, if e1= x*(y<0), the value histogrammed will be x if y<0
    //  and will be 0 otherwise.
    //
    //  selection is a C++ expression with a combination of the columns.
    //  The value corresponding to the selection expression is used as a weight
    //  to fill the histogram.
    //  If the expression includes only boolean operations, the result
    //  is 0 or 1. If the result is 0, the histogram is not filled.
    //  In general, the expression may be of the form:
    //
    //      value*(boolean expression)
    //
    //  if boolean expression is true, the histogram is filled with
    //  a weight = value.
    //  Examples:
    //      selection1 = "x<y && sqrt(z)>3.2 && 6 < i$ && i$ < n$"
    //      selection2 = "(x+y)*(sqrt(z)>3.2"
    //      selection3 = "signal*(log(signal)>1.2)"
    //  selection1 returns a weigth = 0 or 1
    //  selection2 returns a weight = x+y if sqrt(z)>3.2
    //             returns a weight = 0 otherwise.
    //  selection3 returns a weight = signal if log(signal)>1.2
    //
    //  option is the drawing option
    //      see TH1::Draw for the list of all drawing options.
    //      If option contains the string "goff", no graphics is generated.
    //
    //  nentries is the number of entries to process (default is all)
    //  first is the first entry to process (default is 0)
    //
    //     Saving the result of Draw to an histogram
    //     =========================================
    //  By default the temporary histogram created is called htemp.
    //  If varexp0 contains >>hnew (following the variable(s) name(s),
    //  the new histogram created is called hnew and it is kept in the current
    //  directory.
    //  Example:
    //    tree.Draw("sqrt(x)>>hsqrt","y>0")
    //    will draw sqrt(x) and save the histogram as "hsqrt" in the current
    //    directory.
    //
    //  By default, the specified histogram is reset.
    //  To continue to append data to an existing histogram, use "+" in front
    //  of the histogram name;
    //    table.Draw("sqrt(x)>>+hsqrt","y>0")
    //      will not reset hsqrt, but will continue filling.
    //
    //     Making a Profile histogram
    //     ==========================
    //  In case of a 2-Dim expression, one can generate a TProfile histogram
    //  instead of a TH2F histogram by specyfying option=prof or option=profs.
    //  The option=prof is automatically selected in case of y:x>>pf
    //  where pf is an existing TProfile histogram.
    //
    //     Saving the result of Draw to a TEventList
    //     =========================================
    //  TTable::Draw can be used to fill a TEventList object (list of entry numbers)
    //  instead of histogramming one variable.
    //  If varexp0 has the form >>elist , a TEventList object named "elist"
    //  is created in the current directory. elist will contain the list
    //  of entry numbers satisfying the current selection.
    //  Example:
    //    tree.Draw(">>yplus","y>0")
    //    will create a TEventList object named "yplus" in the current directory.
    //    In an interactive session, one can type (after TTable::Draw)
    //       yplus.Print("all")
    //    to print the list of entry numbers in the list.
    //
    //  By default, the specified entry list is reset.
    //  To continue to append data to an existing list, use "+" in front
    //  of the list name;
    //    table.Draw(">>+yplus","y>0")
    //      will not reset yplus, but will enter the selected entries at the end
    //      of the existing list.
    //

       if (GetNRows() == 0 || varexp00 == 0 || varexp00[0]==0) return 0;
       TString  opt;
    //   Text_t *hdefault = (char *)"htemp";
       const char *hdefault = "htemp";
       Int_t i,j,action;
       Int_t hkeep = 0;
       opt = option;
       opt.ToLower();
       Text_t *varexp0 = StrDup(varexp00);
       Text_t *hname = strstr(varexp0,">>");
       TH1 *oldh1 = 0;
       TEventList *elist = 0;
       Bool_t profile = kFALSE;

       gCurrentTableHist = 0;
       if (hname) {
         *hname  = 0;
          hname += 2;
          hkeep  = 1;
          i = strcspn(varexp0,">>");
          Bool_t hnameplus = kFALSE;
          while (*hname == ' ') hname++;
          if (*hname == '+') {
             hnameplus = kTRUE;
             hname++;
             while (*hname == ' ') hname++;
             j = strlen(hname)-1;
             while (j) {
                if (hname[j] != ' ') break;
                hname[j] = 0;
                j--;
             }
          }
          if (i) {
             oldh1 = (TH1*)gDirectory->Get(hname);
             if (oldh1 && !hnameplus) oldh1->Reset();
          } else {
             elist = (TEventList*)gDirectory->Get(hname);
             if (!elist) {
                elist = new TEventList(hname,selection,1000,0);
             }
             if (elist && !hnameplus) elist->Reset();
          }
       }
       if (!hname || *hname==0) {
          hkeep  = 0;
          if (gDirectory) {
             oldh1 = (TH1*)gDirectory->Get(hdefault);
             if (oldh1 ) { oldh1->Delete(); oldh1 = 0;}
          }
       }

      // Look for colons
      const Char_t *expressions[] ={varexp0,0,0,0,selection};
      Int_t maxExpressions = sizeof(expressions)/sizeof(Char_t *);
      Char_t *nextColon    = varexp0;
      Int_t colIndex       = 1;
      while ((nextColon = strchr(nextColon,':')) && ( colIndex < maxExpressions - 1 ) ) {
        *nextColon = 0;
         nextColon++;
         expressions[colIndex] = nextColon;
         colIndex++;
      }

      expressions[colIndex] = selection;

    //--------------------------------------------------
        printf(" Draw %s for <%s>\n", varexp00, selection);
        Char_t *exprFileName = MakeExpression(expressions,colIndex+1);
        if (!exprFileName) {
          delete [] varexp0;
          return 0;
        }

    //--------------------------------------------------
    //   if (!fVar1 && !elist) return 0;

    //*-*- In case oldh1 exists, check dimensionality
       Int_t dimension = colIndex;

       TString title = expressions[0];
       for (i=1;i<colIndex;i++) {
         title += ":";
         title += expressions[i];
       }
       Int_t nsel = strlen(selection);
       if (nsel > 1) {
          if (nsel < 80-title.Length()) {
            title += "{";
            title += selection;
            title += "}";
          }
          else
            title += "{...}";
       }

       const Char_t *htitle = title.Data();

       if (oldh1) {
          Int_t mustdelete = 0;
          if (oldh1->InheritsFrom("TProfile")) profile = kTRUE;
          if (opt.Contains("prof")) {
             if (!profile) mustdelete = 1;
          } else {
             if (oldh1->GetDimension() != dimension) mustdelete = 1;
          }
          if (mustdelete) {
             Warning("Draw","Deleting old histogram with different dimensions");
             delete oldh1; oldh1 = 0;
          }
       }
    //*-*- Create a default canvas if none exists
       if (!gPad && !opt.Contains("goff") && dimension > 0) {
          if (!gROOT->GetMakeDefCanvas()) return 0;
          (gROOT->GetMakeDefCanvas())();
       }
    #if 0
       Int_t         fNbins[4] = {100,100,100,100};     //Number of bins per dimension
       Float_t       fVmin[4]  = {0,0,0,0};             //Minima of varexp columns
       Float_t       fVmax[4]  = {20,20,20,20};         //Maxima of varexp columns
    #endif
    //*-*- 1-D distribution
       if (dimension == 1) {
          action = 1;
          if (!oldh1) {
             fNbins[0] = 100;
             if (gPad && opt.Contains("same")) {
                 TH1 *oldhtemp = (TH1*)gPad->FindObject(hdefault);
                 if (oldhtemp) {
                    fNbins[0] = oldhtemp->GetXaxis()->GetNbins();
                    fVmin[0]  = oldhtemp->GetXaxis()->GetXmin();
                    fVmax[0]  = oldhtemp->GetXaxis()->GetXmax();
                 } else {
                    fVmin[0]  = gPad->GetUxmin();
                    fVmax[0]  = gPad->GetUxmax();
                 }
             } else {
                 action = -1;
             }
          }
          TH1F *h1;
          if (oldh1) {
             h1 = (TH1F*)oldh1;
             fNbins[0] = h1->GetXaxis()->GetNbins();  // for proofserv
          } else {
             h1 = new TH1F(hname,htitle,fNbins[0],fVmin[0],fVmax[0]);
             if (!hkeep) {
                h1->SetBit(kCanDelete);
                h1->SetDirectory(0);
             }
             if (opt.Length() && opt[0] == 'e') h1->Sumw2();
          }

          EntryLoop(exprFileName,action, h1, nentries, firstentry, option);

    //      if (!fDraw && !opt.Contains("goff")) h1->Draw(option);
            if (!opt.Contains("goff")) h1->Draw(option);

    //*-*- 2-D distribution
       } else if (dimension == 2) {
          action = 2;
          if (!opt.Contains("same") && gPad)  gPad->Clear();
          if (!oldh1 || !opt.Contains("same")) {
             fNbins[0] = 40;
             fNbins[1] = 40;
             if (opt.Contains("prof")) fNbins[1] = 100;
             if (opt.Contains("same")) {
                 TH1 *oldhtemp = (TH1*)gPad->FindObject(hdefault);
                 if (oldhtemp) {
                    fNbins[1] = oldhtemp->GetXaxis()->GetNbins();
                    fVmin[1]  = oldhtemp->GetXaxis()->GetXmin();
                    fVmax[1]  = oldhtemp->GetXaxis()->GetXmax();
                    fNbins[0] = oldhtemp->GetYaxis()->GetNbins();
                    fVmin[0]  = oldhtemp->GetYaxis()->GetXmin();
                    fVmax[0]  = oldhtemp->GetYaxis()->GetXmax();
                 } else {
                    fNbins[1] = 40;
                    fVmin[1]  = gPad->GetUxmin();
                    fVmax[1]  = gPad->GetUxmax();
                    fNbins[0] = 40;
                    fVmin[0]  = gPad->GetUymin();
                    fVmax[0]  = gPad->GetUymax();
                 }
             } else {
                 action = -2;
             }
          }
          if (profile || opt.Contains("prof")) {
             TProfile *hp;
             if (oldh1) {
                action = 4;
                hp = (TProfile*)oldh1;
             } else {
                if (action < 0) action = -4;
                if (opt.Contains("profs"))
                   hp = new TProfile(hname,htitle,fNbins[1],fVmin[1], fVmax[1],"s");
                else
                   hp = new TProfile(hname,htitle,fNbins[1],fVmin[1], fVmax[1],"");
                if (!hkeep) {
                   hp->SetBit(kCanDelete);
                   hp->SetDirectory(0);
                }
             }

             EntryLoop(exprFileName,action,hp,nentries, firstentry, option);

             if (!opt.Contains("goff")) hp->Draw(option);
          } else {
             TH2F *h2;
             if (oldh1) {
                h2 = (TH2F*)oldh1;
             } else {
                h2 = new TH2F(hname,htitle,fNbins[1],fVmin[1], fVmax[1], fNbins[0], fVmin[0], fVmax[0]);
                if (!hkeep) {
                   const Int_t kNoStats = BIT(9);
                   h2->SetBit(kCanDelete);
                   h2->SetBit(kNoStats);
                   h2->SetDirectory(0);
                }
             }
             Int_t noscat = strlen(option);
             if (opt.Contains("same")) noscat -= 4;
             if (noscat) {
                EntryLoop(exprFileName,action,h2,nentries, firstentry, option);
     //           if (!fDraw && !opt.Contains("goff")) h2->Draw(option);
                if (!opt.Contains("goff")) h2->Draw(option);
             } else {
                action = 12;
                if (!oldh1 && !opt.Contains("same")) action = -12;
                EntryLoop(exprFileName,action,h2,nentries, firstentry, option);
    //            if (oldh1 && !fDraw && !opt.Contains("goff")) h2->Draw(option);
                if (oldh1 && !opt.Contains("goff")) h2->Draw(option);
             }
          }

    //*-*- 3-D distribution
       } else if (dimension == 3) {
          action = 13;
          if (!opt.Contains("same")) action = -13;
          EntryLoop(exprFileName,action,0,nentries, firstentry, option);

    //*-* an Event List
       } else {
          action = 5;
    //      Int_t oldEstimate = fEstimate;
    //      SetEstimate(1);
          EntryLoop(exprFileName,action,elist,nentries, firstentry, option);
    //      SetEstimate(oldEstimate);
       }
      delete [] exprFileName;
      delete [] varexp0;
      return gCurrentTableHist;
    }

    //______________________________________________________________________________
    static void FindGoodLimits(Int_t nbins, Int_t &newbins, Float_t &xmin, Float_t &xmax)
    {
    //*-*-*-*-*-*-*-*-*Find reasonable bin values*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
    //*-*              ==========================
    //*-*  This mathod is a straight copy of void TTree::FindGoodLimits method
    //*-*

       Double_t binlow,binhigh,binwidth;
       Int_t n;
       Double_t dx = 0.1*(xmax-xmin);
       Double_t umin = xmin - dx;
       Double_t umax = xmax + dx;
       if (umin < 0 && xmin >= 0) umin = 0;
       if (umax > 0 && xmax <= 0) umax = 0;

    #if ROOT_VERSION_CODE >= ROOT_VERSION(3,03,5)
       THLimitsFinder::Optimize(umin,umax,nbins,binlow,binhigh,n,binwidth,"");
    #else
       TGaxis::Optimize(umin,umax,nbins,binlow,binhigh,n,binwidth,"");
    #endif

       if (binwidth <= 0 || binwidth > 1.e+39) {
          xmin = -1;
          xmax = 1;
       } else {
          xmin    = binlow;
          xmax    = binhigh;
       }

       newbins = nbins;
    }

    //______________________________________________________________________________
     Bool_t TTable::EntryLoop(const Char_t *exprFileName,Int_t &action, TObject *obj
                              ,Int_t nentries, Int_t firstentry, Option_t *option)
    {
     //
     // EntryLoop creates a CINT bytecode to evaluate the given expressions for
     // all table rows in loop and fill the appropriated histograms.
     //
     // Solution for Byte code
     // From: Masaharu Goto <MXJ02154@nifty.ne.jp>
     // To: <fine@bnl.gov>
     // Cc: <rootdev@hpsalo.cern.ch>
     // Sent: 13-th august 1999 year  23:01
     //
     //  action =  1  Fill 1-D histogram obj
     //         =  2  Fill 2-D histogram obj
     //         =  3  Fill 3-D histogram obj
     //         =  4  Fill Profile histogram obj
     //         =  5  Fill a TEventlist
     //         = 11  Estimate Limits
     //         = 12  Fill 2-D PolyMarker obj
     //         = 13  Fill 3-D PolyMarker obj
     //  action < 0   Evaluate Limits for case abs(action)
     //
     //  Load file
      Float_t rmin[3],rmax[3];
      switch(G__loadfile((Char_t *)exprFileName)) {
      case G__LOADFILE_SUCCESS:
      case G__LOADFILE_DUPLICATE:
        break;
      default:
        fprintf(stderr,"Error: loading file %s\n",exprFileName);
        G__unloadfile((Char_t *)exprFileName);
        return kFALSE; // can not load file
      }

      // Float_t  Selection(Float_t *results[], void *address[], int& i$, int n$)
      //   where  i$ - meta variable to set current row index
      //          n$ - meta variable to set the total table size
      const Char_t *funcName = "SelectionQWERTY";
    #define BYTECODE
    #ifdef BYTECODE
      const Char_t *argtypes = "Float_t *,float **, int&, int& ";
      long offset;
      G__ClassInfo globals;
      G__MethodInfo func = globals.GetMethod(funcName,argtypes,&offset);

      // Compile bytecode
      struct G__bytecodefunc *pbc = func.GetBytecode();
      if(!pbc) {
        fprintf(stderr,"Error: Bytecode compilation %s\n",funcName);
        G__unloadfile((Char_t *)exprFileName);
        return kFALSE; // can not get bytecode
      }
    #endif
      // Prepare callfunc object
      int i;
      int nRows =  GetNRows();
      TTableDescriptor    *tabsDsc   = GetRowDescriptors();
      tableDescriptor_st  *descTable = tabsDsc->GetTable();
      Float_t  results[]    = {1,1,1,1,1};
      Char_t **addressArray = (Char_t **)new ULong_t[tabsDsc->GetNRows()];
      Char_t *thisTable     = (Char_t *)GetArray();
    #ifdef BYTECODE
      G__CallFunc callfunc;
      callfunc.SetBytecode(pbc);

      callfunc.SetArg((long)(&results[0]));   // give 'Float_t *results[5]'     as 1st argument
      callfunc.SetArg((long)(addressArray));  // give 'void    *addressArray[]' as 2nd argument
      callfunc.SetArg((long)(&i));            // give 'int& i$'                 as 3nd argument
      callfunc.SetArg((long)(&nRows));        // give 'int& n$= nRows           as 4th argument
    #else
      char buf[200];
      sprintf(buf,"%s((Float_t*)(%ld),(void**)(%ld),*(int*)(%ld),*(int*)(%ld))"
                 ,funcName
                 ,(long int)results,(long int)addressArray,(long int)(&i),(long int)(&nRows));
    #endif

      // Call bytecode in loop

    #ifdef BYTECODE
    #  define CALLMETHOD callfunc.Exec(0);
    #else
    #  define CALLMETHOD G__calc(buf);
    #endif

    #define TAKEACTION_BEGIN                                                                    \
                descTable = tabsDsc->GetTable();                                                \
                for (i=0; i < tabsDsc->GetNRows(); i++,descTable++ )                            \
                   addressArray[i] = addressEntry + descTable->fOffset;                         \
                for(i=firstentry;i<lastEntry;i++) {                                             \
                CALLMETHOD

    #define TAKEACTION_END  for (int j=0; j < tabsDsc->GetNRows(); j++ ) addressArray[j] += rSize;}

      if (firstentry < nRows ) {
          Long_t rSize         = GetRowSize();
          Char_t *addressEntry = thisTable + rSize*firstentry;
          Int_t lastEntry = TMath::Min(UInt_t(firstentry+nentries),UInt_t(nRows));
          if (action < 0) {
            fVmin[0] = fVmin[1] = fVmin[2] = 1e30;
            fVmax[0] = fVmax[1] = fVmax[2] = -fVmin[0];
          }
          Int_t nchans = 0;
          switch ( action ) {
            case -1: {
                 TAKEACTION_BEGIN
                  if (results[1]) {
                     if (fVmin[0] > results[0]) fVmin[0] = results[0];
                     if (fVmax[0] < results[0]) fVmax[0] = results[0];
                  }
                 TAKEACTION_END

                 nchans = fNbins[0];
                 if (fVmin[0] >= fVmax[0]) { fVmin[0] -= 1; fVmax[0] += 1;}
                 FindGoodLimits(nchans,fNbins[0],fVmin[0],fVmax[0]);
                 ((TH1 *)obj)->SetBins(fNbins[0],fVmin[0],fVmax[0]);
               }
            case  1:
                TAKEACTION_BEGIN
                   if (results[1]) ((TH1 *)obj)->Fill(Axis_t(results[0]),Stat_t(results[1]));
                TAKEACTION_END
                gCurrentTableHist = ((TH1 *)obj);
                break;
            case  -2:
                TAKEACTION_BEGIN
                  if (results[2]) {
                    if (fVmin[0] > results[1]) fVmin[0] = results[1];
                    if (fVmax[0] < results[1]) fVmax[0] = results[1];
                    if (fVmin[1] > results[0]) fVmin[1] = results[0];
                    if (fVmax[1] < results[0]) fVmax[1] = results[0];
                  }
                TAKEACTION_END
                nchans = fNbins[0];
                if (fVmin[0] >= fVmax[0]) { fVmin[0] -= 1; fVmax[0] += 1;}
                FindGoodLimits(nchans,fNbins[0],fVmin[0],fVmax[0]);
                if (fVmin[1] >= fVmax[1]) { fVmin[1] -= 1; fVmax[1] += 1;}
                FindGoodLimits(nchans,fNbins[1],fVmin[1],fVmax[1]);
                ((TH1*)obj)->SetBins(fNbins[1],fVmin[1],fVmax[1],fNbins[0],fVmin[0],fVmax[0]);
            case   2:
                  if (obj->IsA() == TH2F::Class()) {
                     TAKEACTION_BEGIN
                       if (results[2]) ((TH2F*)obj)->Fill(Axis_t(results[0]),Axis_t(results[1]),Stat_t(results[2]));
                     TAKEACTION_END
                  }
                  else if (obj->IsA() == TH2S::Class()) {
                     TAKEACTION_BEGIN
                      if (results[2]) ((TH2S*)obj)->Fill(Axis_t(results[0]),Axis_t(results[1]),Stat_t(results[2]));
                     TAKEACTION_END
                  }
                  else if (obj->IsA() == TH2C::Class()) {
                     TAKEACTION_BEGIN
                       if (results[2]) ((TH2C*)obj)->Fill(Axis_t(results[0]),Axis_t(results[1]),Stat_t(results[2]));
                     TAKEACTION_END
                  }
                  else if (obj->IsA() == TH2D::Class()) {
                     TAKEACTION_BEGIN
                       if (results[2]) ((TH2D*)obj)->Fill(Axis_t(results[0]),Axis_t(results[1]),Stat_t(results[2]));
                     TAKEACTION_END
                  }
                gCurrentTableHist =  ((TH1 *)obj);
                break;
            case -4:
                TAKEACTION_BEGIN
                  if (results[2]) {
                    if (fVmin[0] > results[1]) fVmin[0] = results[1];
                    if (fVmax[0] < results[1]) fVmax[0] = results[1];
                    if (fVmin[1] > results[0]) fVmin[1] = results[0];
                    if (fVmax[1] < results[0]) fVmax[1] = results[0];
                  }
                TAKEACTION_END
                nchans = fNbins[1];
                if (fVmin[1] >= fVmax[1]) { fVmin[1] -= 1; fVmax[1] += 1;}
                FindGoodLimits(nchans,fNbins[1],fVmin[1],fVmax[1]);
                ((TProfile*)obj)->SetBins(fNbins[1],fVmin[1],fVmax[1]);
            case  4:
                TAKEACTION_BEGIN
                   if (results[2]) ((TProfile*)obj)->Fill(Axis_t(results[0]),Axis_t(results[1]),Stat_t(results[2]));
                TAKEACTION_END
                break;
            case -12:
                TAKEACTION_BEGIN
                  if (results[2]) {
                    if (fVmin[0] > results[1]) fVmin[0] = results[1];
                    if (fVmax[0] < results[1]) fVmax[0] = results[1];
                    if (fVmin[1] > results[0]) fVmin[1] = results[0];
                    if (fVmax[1] < results[0]) fVmax[1] = results[0];
                  }
                TAKEACTION_END
                nchans = fNbins[0];
                if (fVmin[0] >= fVmax[0]) { fVmin[0] -= 1; fVmax[0] += 1;}
                FindGoodLimits(nchans,fNbins[0],fVmin[0],fVmax[0]);
                if (fVmin[1] >= fVmax[1]) { fVmin[1] -= 1; fVmax[1] += 1;}
                FindGoodLimits(nchans,fNbins[1],fVmin[1],fVmax[1]);
                ((TH2F*)obj)->SetBins(fNbins[1],fVmin[1],fVmax[1],fNbins[0],fVmin[0],fVmax[0]);
            case  12: {
                if (!strstr(option,"same") && !strstr(option,"goff")) {
                  ((TH2F*)obj)->DrawCopy(option);
                  gPad->Update();
                }
    //            pm->SetMarkerStyle(GetMarkerStyle());
    //            pm->SetMarkerColor(GetMarkerColor());
    //            pm->SetMarkerSize(GetMarkerSize());
                Float_t *x = new Float_t[lastEntry-firstentry]; // pm->GetX();
                Float_t *y = new Float_t[lastEntry-firstentry]; // pm->GetY();
                Float_t u, v;
                Float_t umin = gPad->GetUxmin();
                Float_t umax = gPad->GetUxmax();
                Float_t vmin = gPad->GetUymin();
                Float_t vmax = gPad->GetUymax();
                Int_t pointIndex = 0;
                TAKEACTION_BEGIN
                 if (results[2]) {
                    u = gPad->XtoPad(results[0]);
                    v = gPad->YtoPad(results[1]);
                    if (u < umin) u = umin;
                    if (u > umax) u = umax;
                    if (v < vmin) v = vmin;
                    if (v > vmax) v = vmax;
                    x[pointIndex] = u;
                    y[pointIndex] = v;
                    pointIndex++;
                 }
                TAKEACTION_END
                if (pointIndex && !strstr(option,"goff")) {
                    TPolyMarker *pm = new TPolyMarker(pointIndex,x,y);
                    pm->Draw();
                    pm->SetBit(kCanDelete);
                }
                if (!((TH2F*)obj)->TestBit(kCanDelete))
                   if (pointIndex)
                      for(i=0;i<pointIndex;i++) ((TH2F*)obj)->Fill(x[i], y[i]);
                delete [] x; delete [] y;
                gCurrentTableHist = ((TH1*)obj);
              }
              break;
            case -13:
                TAKEACTION_BEGIN
                  if (results[3]) {
                    if (fVmin[0] > results[2]) fVmin[0] = results[2];
                    if (fVmax[0] < results[2]) fVmax[0] = results[2];
                    if (fVmin[1] > results[1]) fVmin[1] = results[1];
                    if (fVmax[1] < results[1]) fVmax[1] = results[1];
                    if (fVmin[2] > results[0]) fVmin[2] = results[0];
                    if (fVmax[2] < results[0]) fVmax[2] = results[0];
                  }
                TAKEACTION_END
                rmin[0] = fVmin[2]; rmin[1] = fVmin[1]; rmin[2] = fVmin[0];
                rmax[0] = fVmax[2]; rmax[1] = fVmax[1]; rmax[2] = fVmax[0];
                gPad->Clear();
                gPad->Range(-1,-1,1,1);
                new TView(rmin,rmax,1);
            case 13: {
                TPolyMarker3D *pm3d = new TPolyMarker3D(lastEntry-firstentry);
                pm3d->SetBit(kCanDelete);
    //            pm3d->SetMarkerStyle(GetMarkerStyle());
    //            pm3d->SetMarkerColor(GetMarkerColor());
    //            pm3d->SetMarkerSize(GetMarkerSize());
                TAKEACTION_BEGIN
                    if (results[3]) pm3d->SetNextPoint(results[0],results[1],results[2]);
                TAKEACTION_END
                pm3d->Draw();
              }
                break;
            default:
              Error("EntryLoop","unknown action \"%d\" for table <%s>", action, GetName());
              break;
          };
      }
      G__unloadfile((Char_t *)exprFileName);
      delete [] addressArray;
      return kTRUE;
    }

    //______________________________________________________________________________
     TTable::TTable(const Text_t *name, Int_t size) : TDataSet(name),
             fSize(size),fN(0), fTable(0),fMaxIndex(0)
    {
       // Default TTable ctor.
       if (size == 0) Warning("TTable(0)","Wrong table format");
    }

    //______________________________________________________________________________
     TTable::TTable(const Text_t *name, Int_t n,Int_t size) : TDataSet(name),
            fSize(size),fN(0),fTable(0),fMaxIndex(0)
    {
       // Create TTable object and set array size to n longs.
       if (n > 0) Set(n);
    }

    //______________________________________________________________________________
     TTable::TTable(const Text_t *name, Int_t n, Char_t *table,Int_t size) : TDataSet(name),
             fSize(size),fN(0),fTable(0),fMaxIndex(0)
    {
       // Create TTable object and initialize it with values of array.

       Set(n, table);
    }

    //______________________________________________________________________________
     TTable::TTable(const Text_t *name, const Text_t *type, Int_t n, Char_t *array, Int_t size)
             : TDataSet(name),fSize(size),fTable(0),fMaxIndex(0)
    {
       // Create TTable object and initialize it with values of array.

       fTable = array;
       SetType(type);
       SetfN(n);
    }

    //______________________________________________________________________________
     TTable::TTable(const TTable &table):TDataSet(table)
    {
       // Copy constructor.
       fTable    = 0;
       SetUsedRows(table.GetNRows());
       fSize     = table.GetRowSize();
       Set(table.fN, table.fTable);
    }

    //______________________________________________________________________________
    TTable &TTable::operator=(const TTable &rhs)
    {
       // TTable assignment operator.
       // This operator REALLOCATEs this table to fit the number of
       // the USED rows of the source table if any

      if (strcmp(GetType(),rhs.GetType()) == 0) {
        if (this != &rhs && rhs.GetNRows() >0 ){
            Set(rhs.GetNRows(), rhs.fTable);
            SetUsedRows(rhs.GetNRows());
        }
      }
      else
        Error("operator=","Can not copy <%s> table into <%s> table", rhs.GetType(),GetType());
      return *this;
    }

    //______________________________________________________________________________
     TTable::~TTable()
    {
       // Delete TTable object.
       Delete();
    }

    //______________________________________________________________________________
     void TTable::Adopt(Int_t n, void *arr)
    {
       // Adopt array arr into TTable, i.e. don't copy arr but use it directly
       // in TTable. User may not delete arr, TTable dtor will do it.

       Clear();

       SetfN(n); SetUsedRows(n);
       fTable = (char *)arr;
    }

    //______________________________________________________________________________
     Int_t TTable::AddAt(const void *row)
    {
      // Add        the "row" at the GetNRows() position, and
      // reallocate the table if neccesary,               and
      // return     the row index the "row" has occupied.
      //
      // row == 0 see method TTable::AddAt(const void *row, Int_t i)

      Int_t gap = GetTableSize() - GetNRows();
      // do we need to add an extra space?
      if (gap < 1) ReAllocate(GetTableSize() + TMath::Max(1,Int_t(0.3*GetTableSize())));
      Int_t indx = GetNRows();
      AddAt(row,indx);
      return indx;
    }
    //______________________________________________________________________________
     void TTable::AddAt(const void *row, Int_t i)
    {
       // Add    one element ("row") of structure at position "i".
       // Check  for out of bounds.
       //
       //        If the row == 0 the "i" cell is still occupied and
       // filled with the pattern "ff"

       if (!BoundsOk("TTable::AddAt", i))
          i = 0;
       if (row) memcpy(fTable+i*fSize,row,fSize);
       else memset(fTable+i*fSize,127,fSize);
       SetUsedRows(TMath::Max((Int_t)i+1,Int_t(fMaxIndex)));
    }

    //______________________________________________________________________________
     void TTable::CopyStruct(Char_t *dest, const Char_t *src)
    {
     // Copy the C-structure src into the new location
     // the length of the strucutre is defined by this class descriptor
        ::memcpy(dest,src,fSize*fN);
    }
    //______________________________________________________________________________
     void TTable::CopySet(TTable &array)
    {
      array.Set(fN);
      CopyStruct(array.fTable,fTable);
    }
    //______________________________________________________________________________
     const Char_t *TTable::GetColumnComment(Int_t columnIndex) const {
       // Get a comment from the table descriptor

       TDataSetIter nextComment(GetRowDescriptors()->MakeCommentField(kFALSE));
       TDataSet *nxc = 0;
       for (int i=0; i<= columnIndex; i++) nxc = nextComment();
       return nxc ? nxc->GetTitle() : 0;
    }
    //______________________________________________________________________________
     Long_t TTable::AppendRows(const void *row, UInt_t nRows)
    {
       // Append nRows row of the array "row" to the table
       // return
       //    - the new table size (# of table rows)
       //    - 0 if the object doesn't own the internal array and can not expand it
       Long_t size = 0;
       if (!TestBit(kIsNotOwn) && row && nRows ) {
         Int_t indx = GetNRows();
         ReAllocate(nRows);
         // Copy (insert) the extra staff in
         ::memmove(fTable+indx*fSize,row,fSize*nRows);
         size = GetSize();
       }
       return TestBit(kIsNotOwn) ? 0 : GetSize();
    }
    //______________________________________________________________________________
     Long_t TTable::InsertRows(const void *row, Long_t indx, UInt_t nRows)
    {
      // void InsertRows(cons void *row, Long_t indx, UInt_t nRows)
      //
      // Insert one or several rows into the table at "indx" position
      // The rest table stuff is shifted down
      //
      //  cons void    - a pointer to the array of rows to be inserted
      //  Long_t indx =  The position these rows will be inserted to
      //  Int_t nRows  - the total number of rows to be inserted
      //                 = 1 "by default
      //  return:
      //  The number of the rows has been shifted to accomodate
      //  the new rows.
      //
      Long_t nShifted = 0;
      if (nRows > 0) {
         // Shift the table down
         nShifted = CopyRows(this, indx, indx+nRows, GetNRows()+nRows);
         // Copy (insert) the extra staff in
         ::memmove(fTable+indx*fSize,row,fSize*nRows);
      }
      return nShifted;

    }
    //______________________________________________________________________________
     void *TTable::ReAllocate()
    {
      // Reallocate this table leaving only (used rows)+1 allocated
      // GetTableSize() = GetNRows() + 1
      // returns a pointer to the first row of the reallocated table
      // Note:
      // The table is reallocated if it is an owner of the internal array

       ReAlloc(GetNRows()+1);
       return (void *)fTable;
    }
    //______________________________________________________________________________
     void *TTable::ReAllocate(Int_t newsize)
    {
      // Reallocate this table leaving only <newsize> allocated
      // GetTableSize() = newsize;
      // returns a pointer to the first row of the reallocated table
      // Note:
      // The table is reallocated if it is an owner of the internal array

      if (newsize > fN) ReAlloc(newsize);
      return (void *)fTable;
    }

    //______________________________________________________________________________
     void TTable::ReAlloc(Int_t newsize)
    {
      // The table is reallocated if it is an owner of the internal array
      if (!TestBit(kIsNotOwn) && newsize > 0) {
        void *arr = 0;
        Int_t sleepCounter = 0;
        while (!(arr =  realloc(fTable,fSize*newsize)))
        {
          sleepCounter++;
          Warning("ReAlloc",
                  "Not enough memory to Reallocate %d bytes for table <%s::%s>. Please cancel some jobs",
                  newsize, GetType(),GetName());
          gSystem->Sleep(1000*600);
          if (sleepCounter > 30){
            Error("ReAlloc","I can not wait anymore. Good bye");
            assert(0);
          }
        }
        SetfN(newsize);
        fTable = (char *)arr;
      }
    }

    //______________________________________________________________________________
     Char_t *TTable::Create()
    {
      // Allocate a space for the new table, if any
      // Sleep for a while if space is not available and try again
      if (!fTable)
      {
        void *ptr = 0;
        Int_t sleepCounter = 0;
        while (!(ptr = malloc(fSize*fN)))
        {
          sleepCounter++;
          Warning("Create",
                "Not enough memory to allocate %d rows for table <%s::%s>. Please cancel some jobs",
                fN, GetType(),GetName());
          gSystem->Sleep(1000*600);
          if (sleepCounter > 30){
            Error("Create","I can not wait anymore. Good bye");
            assert(0);
          }
        }
        fTable = (Char_t *)ptr;
        // make sure all link-columns are zero
        memset(fTable,0,fSize*fN);
      }
      return fTable;
    }

    //______________________________________________________________________________
     void TTable::Browse(TBrowser *b){
      // Wrap each table coulumn with TColumnView object to browse.
      if (!b) return;
      TDataSet::Browse(b);
      Int_t nrows = TMath::Min(Int_t(GetNRows()),6);
      if (nrows == 0) nrows = 1;
      Print(0,nrows);
      // Add the table columns to the browser
      UInt_t nCol = GetNumberOfColumns();
      for (UInt_t i = 0;i<nCol;i++){
         TColumnView *view = 0;
         UInt_t nDim = GetDimensions(i);
         const Char_t *colName = GetColumnName(i);
         if (!nDim) { // scalar
            // This will cause a small memory leak
            // unless TBrowser recognizes kCanDelete bit
             if( GetColumnType(i)== kPtr) {
                 UInt_t offset = GetOffset(i);
                 TTableMap *m = *(TTableMap **)(((char *)GetArray())+offset);
                 if (m) {
                   TString nameMap = "*";
                   nameMap += m->Table()->GetName();
                   b->Add(m,nameMap.Data());
                 }
             } else {
                 view = new TColumnView(GetColumnName(i),this);
                 view->SetBit(kCanDelete);
                 b->Add(view,view->GetName());
             }
         } else {     // array
           const UInt_t *indx = GetIndexArray(i);
           UInt_t totalSize = 1;
           UInt_t k;
           for (k=0;k<nDim; k++) totalSize *= indx[k];
           for (k=0;k<totalSize;k++){
              char *buffer =  new char[strlen(colName)+13];
              sprintf(buffer,"%s[%d]",colName,k);
              view = new TColumnView(buffer,this);
              view->SetBit(kCanDelete);
              b->Add(view,view->GetName());
              delete [] buffer;
           }
         }
      }
    }

    //______________________________________________________________________________
     void TTable::Clear(Option_t *opt)
    {
      // Deletes the internal array of this class
      // if this object does own its internal table

      if (!fTable) return;
      Bool_t dtor = kFALSE;
      dtor = opt && (strcmp(opt,dtorName)==0);
      if (!opt || !opt[0] || dtor ) {
          if (! TestBit(kIsNotOwn)) {
              if (!dtor) ResetMap();
              free(fTable);
          }
        fTable    = 0;
        fMaxIndex = 0;
        SetfN(0);
        return;
      }
    }

    //______________________________________________________________________________
     void TTable::Delete(Option_t *opt)
    {
       //
       // Delete the internal array and free the memory it occupied
       // if this object did own this array
       //
       // Then perform TDataSet::Delete(opt)
      Clear(dtorName);
      TDataSet::Delete(opt);
    }

    //______________________________________________________________________________
     TClass  *TTable::GetRowClass() const
    {
      TClass *cl = 0;
      TTableDescriptor *dsc = GetRowDescriptors();
      if (dsc) cl = dsc->RowClass();
      else Error("GetRowClass()","Table descriptor of <%s::%s> table lost",
                 GetName(),GetType());
      return cl;
    }

    //______________________________________________________________________________
     Long_t TTable::GetNRows() const {
    // Returns the number of the used rows for the wrapped table
    return fMaxIndex;
    }

    //______________________________________________________________________________
     Long_t TTable::GetRowSize() const {
    // Returns the size (in bytes) of one table row
      return fSize;
    }

    //______________________________________________________________________________
     Long_t TTable::GetTableSize() const {
    // Returns the number of the allocated rows
    return fN;
    }

    //______________________________________________________________________________
     void TTable::Fit(const Text_t *formula ,const Text_t *varexp, const Text_t *selection,Option_t *option ,Option_t *goption,Int_t nentries, Int_t firstentry)
    {
    //*-*-*-*-*-*-*-*-*Fit a projected item(s) from a TTable*-*-*-*-*-*-*-*-*-*
    //*-*              =======================================
    //
    //  formula is a TF1 expression.
    //
    //  See TTable::Draw for explanations of the other parameters.
    //
    //  By default the temporary histogram created is called htemp.
    //  If varexp contains >>hnew , the new histogram created is called hnew
    //  and it is kept in the current directory.
    //  Example:
    //    table.Fit(pol4,"sqrt(x)>>hsqrt","y>0")
    //    will fit sqrt(x) and save the histogram as "hsqrt" in the current
    //    directory.
    //

       Int_t nch = strlen(option) + 10;
       char *opt = new char[nch];
       if (option) sprintf(opt,"%sgoff",option);
       else        strcpy(opt,"goff");

       Draw(varexp,selection,opt,nentries,firstentry);

       delete [] opt;

       TH1 *hfit = gCurrentTableHist;
       if (hfit) {
          printf("hname=%s, formula=%s, option=%s, goption=%s\n",hfit->GetName(),formula,option,goption);
          // remove bit temporary
          Bool_t canDeleteBit = hfit->TestBit(kCanDelete);
          if (canDeleteBit)  hfit->ResetBit(kCanDelete);
          hfit->Fit(formula,option,goption);
          if (TestBit(canDeleteBit))   hfit->SetBit(kCanDelete);
       }
       else      printf("ERROR hfit=0\n");
    }

    //______________________________________________________________________________
     const Char_t *TTable::GetType() const
    {
    //Returns the type of the wrapped C-structure kept as the TNamed title
      return GetTitle();
    }

    //______________________________________________________________________________
     Bool_t TTable::IsFolder() const {
      // return Folder flag to be used by TBrowse object
      // The table is a folder if
      //  - it has sub-dataset
      //    or
      //  - GetNRows > 0
      return kTRUE; // to provide the "fake" folder bit to workaround TKey::Browse()

    #if 0
      // this became useless due TKey::Browse new implementation
      return
    	 (fList && fList->Last() ? kTRUE : kFALSE)
       ||
         (GetNRows() > 0);
    #endif
    }

    //______________________________________________________________________________
     Int_t TTable::NaN()
    {
    //
    // return the total number of the NaN for float/double cells of this table
    // Thanks Victor Perevoztchikov
    //

      EColumnType code;
      char const *cell,*colname,*table;
      double word;
      int icol,irow,colsize,wordsize,nwords,iword,nerr,offset;

      TTableDescriptor *rowDes = GetRowDescriptors();
      assert(rowDes!=0);
      table = (const char*)GetArray();

      int ncols = rowDes->GetNumberOfColumns();

      int lrow  = GetRowSize();
      int nrows = GetNRows  ();
      nerr =0;
      for (icol=0; icol < ncols; icol++) {// loop over cols
         code = rowDes->GetColumnType(icol);
         if (code!=kFloat && code!=kDouble) continue;

         offset   = rowDes->GetOffset    (icol);
         colsize  = rowDes->GetColumnSize(icol);
         wordsize = rowDes->GetTypeSize  (icol);
         nwords = colsize/wordsize;
         for (irow=0; irow < nrows; irow++) { //loop over rows
            cell = table + offset + irow*lrow;
            for (iword=0;iword<nwords; iword++,cell+=wordsize) { //words in col
               word = (code==kDouble) ? *(double*)cell : *(float*)cell;
               if (TMath::Finite(word))     continue;
    //              ERROR FOUND
               nerr++; colname = rowDes->GetColumnName(icol);
               Warning("NaN"," Table %s.%s.%d\n",GetName(),colname,irow);
            }
          }
       }
       return nerr;
    }

    //______________________________________________________________________________
     TTable *TTable::New(const Char_t *name, const Char_t *type, void *array, UInt_t size)
    {
      // This static method creates a new TTable object if provided

      TTable *table = 0;
      if (type && name)
      {
        TString TableType(type);
        TString t = TableType.Strip();
    //    t.ToLower();  // remove this

        const Char_t *classprefix="St_";
        const Int_t extralen = strlen(classprefix) + 1;
        Char_t *classname = new Char_t[strlen(t.Data())+extralen];
        strcpy(classname,classprefix);
        strcat(classname,t.Data());
        TClass *cl = gROOT->GetClass(classname);
        if (cl) {
          table = (TTable *)cl->New();
          if (table) {
             table->SetTablePointer(array);
             table->SetName(name);
             table->SetfN(size);
             table->SetUsedRows(size);
          }
        }
        delete [] classname;
      }
      return table;
    }
    //______________________________________________________________________________
     Bool_t TTable::OutOfBoundsError(const char *where, Int_t i) const
    {
       // Generate an out-of-bounds error. Always returns false.
       Error(where, "index %d out of bounds (size: %d, this: 0x%08x)", i, fN, this);
       return kFALSE;
    }
    //______________________________________________________________________________
     Char_t *TTable::Print(Char_t *strbuf,Int_t lenbuf) const
    {
      // Create IDL table defintion (to be used for XDF I/O)
      Int_t iOut = 0;

      TTableDescriptor *dscT = GetRowDescriptors();
      if (!dscT ) {
         Error("Print"," No dictionary entry for <%s> structure", GetTitle());
         if (lenbuf>0) iOut += sprintf(strbuf+iOut," *** Errror ***");
         return strbuf;
      }

      TROOT::IndentLevel();
      if (lenbuf>0) {
        // cut of the "_st" suffix
           Char_t *typenam =  new Char_t [strlen(dscT->GetName())+1];
           strcpy(typenam,dscT->GetName());
        // look for the last "_"
           Char_t *last = strrchr(typenam,'_');
        // Check whether it is "_st"
           Char_t *eon = 0;
           if (last) eon = strstr(last,"_st");
        // Cut it off if any
           if (eon) *eon = '\0';
           iOut += sprintf(strbuf+iOut,"struct %s {",typenam);
           delete [] typenam;
       } else {
           cout << "struct " << dscT->GetName() << " {" << endl;
       }

       tableDescriptor_st dsc  = dscT->begin();
       tableDescriptor_st dscE = dscT->end();
       TDataSetIter nextComment(dscT->MakeCommentField(kFALSE));
       for (;dsc != dscE; dsc++) {
         TROOT::IndentLevel();
         TString name = GetTypeName(EColumnType((*dsc).fType));
         if (lenbuf>0) {
           // convert C type names to CORBA type names
           name.ReplaceAll("unsigned char","octet");
           name.ReplaceAll("int","long");
           iOut += sprintf(strbuf+iOut," %s %s",name.Data(),(*dsc).fColumnName);
         }
         else
           cout << '\t'<< name.Data() << '\t'<< (*dsc).fColumnName;

         Int_t indx;
         Int_t dim = (*dsc).fDimensions;
         for  (indx = 0; indx < dim; indx++) {
           if (lenbuf>0)
             iOut += sprintf(strbuf+iOut,"[%d]",(*dsc).fIndexArray[indx]);
           else
             cout <<  "[" << dec << (*dsc).fIndexArray[indx]<<"]";
         }
         // print comment if any
         TDataSet *nxc = nextComment();
         if (lenbuf>0)
           iOut += sprintf(strbuf+iOut, ";");
         else {
           const char *title = nxc ? nxc->GetTitle() : " ";
           cout << ";\t//" << title << endl;
         }
       } /* dsc */

       TROOT::IndentLevel();
       if (lenbuf>0)
         iOut += sprintf(strbuf+iOut, "}");
       else
         cout << "}" << endl;
       return strbuf;
    }

    //______________________________________________________________________________
     const Char_t *TTable::PrintHeader() const
    {
      // Print general table inforamtion
         cout << endl << " ---------------------------------------------------------------------------------------" << endl
              <<  " " << Path()
                     <<"  Allocated rows: "<<fN
                     <<"\t Used rows: "<<fMaxIndex
                     <<"\t Row size: "      << fSize << " bytes"
          <<endl;
         return 0;
    }

    //______________________________________________________________________________
     const Char_t *TTable::Print(Int_t row, Int_t rownumber, const Char_t *, const Char_t *) const
    {
       //const Char_t *TTable::Print(Int_t row, Int_t rownumber, const Char_t *colfirst, const Char_t *collast) const
      //
      //  Print the contents of internal table per COLUMN.
      //
      //  row       - the index of the first row to print (counting from ZERO)
      //  rownumber - the total number of rows to print out (=10 by default)
      //
      //  (No use !) Char_t *colfirst, *collast - the names of the first/last
      //                                          to print out (not implemented yet)
      //
      //--------------------------------------------------------------
       // Check bounds and adjust it
       Int_t const width = 8;
       Int_t rowStep = 10; // The maximun values to print per line
       Int_t rowNumber = rownumber;
       if (row  > Int_t(GetSize()) || GetSize() == UInt_t(0))  {
            PrintHeader();
            cout  << " ======================================================================================" << endl
                  << "   There are " << GetSize() << " allocated rows for this table only"                     << endl
                  << " ======================================================================================" << endl;
            return 0;
       }
       if (rowNumber > Int_t(GetSize()-row)) rowNumber = GetSize()-row;
       if (!rowNumber) return 0;
       rowStep = TMath::Min(rowStep,rowNumber);

       Int_t cdate = 0;
       Int_t ctime = 0;
       UInt_t *cdatime = 0;
       Bool_t isdate = kFALSE;

       TTableDescriptor *dscT = GetRowDescriptors();
       if (!dscT ) return 0;

       //  3. Loop by "rowStep x lines"

       const Char_t  *startRow = (const Char_t *)GetArray() + row*GetRowSize();
       Int_t rowCount = rowNumber;
       Int_t thisLoopLenth = 0;
       const Char_t  *nextRow = 0;
       while (rowCount) {
         PrintHeader();
         if  (GetNRows() == 0) {// to Print empty table header
           cout  << " ======================================================================================" << endl
                 << "   There is NO filled row in this table"                                                 << endl
                 << " ======================================================================================" << endl;
           return 0;
         }
         cout << " Table: " << dscT->GetName()<< "\t";
         for (Int_t j = row+rowNumber-rowCount; j<row+rowNumber-rowCount+rowStep && j < row+rowNumber ;j++)
         {
           Int_t hW = width-2;
           if (j>=10) hW -= (int)TMath::Log10(float(j))-1;
           cout  << setw(hW) << "["<<j<<"]";
           cout  << " :" ;
         }
         cout << endl
         <<       " ======================================================================================" << endl;
         tableDescriptor_st member = dscT->begin();
         tableDescriptor_st   dscE = dscT->end();
         TDataSetIter nextComment(dscT->MakeCommentField(kFALSE));

         for (; member != dscE; member++){
           TString membertype = GetTypeName(EColumnType((*member).fType));
           isdate = kFALSE;
           if (strcmp((*member).fColumnName,"fDatime") == 0 && membertype == "UInt_t")
                                                                                       isdate = kTRUE;
           cout << membertype.Data();

           // Add the dimensions to "array" members
           Int_t dim = (*member).fDimensions;
           Int_t indx = 0;
           UInt_t *arrayLayout = 0;
           if (dim) {
             arrayLayout = new UInt_t[dim];
             memset(arrayLayout,0,dim*sizeof(Int_t));
           }
           Int_t arrayLength  = 1;
           while (indx < dim ){ // Take in account the room this index will occupy
             arrayLength *= (*member).fIndexArray[indx];
             indx++;
           }
           // Encode data value or pointer value
           Int_t offset = (*member).fOffset;
           Int_t thisStepRows;
           thisLoopLenth = TMath::Min(rowCount,rowStep);
           Int_t indexOffset;
           Bool_t breakLoop = kFALSE;

           for (indexOffset=0; indexOffset < arrayLength && !breakLoop; indexOffset++) {
             nextRow = startRow;

             if (!indexOffset) cout << "\t" << (*member).fColumnName;
             else              cout << "\t" << setw(strlen((*member).fColumnName)) << " ";

             if (dim) {
    	   for (Int_t i=0;i<dim;i++) cout << "["<<dec<<arrayLayout[i]<<"]";
               ArrayLayout(arrayLayout,(*member).fIndexArray,dim);
             }
             cout << "\t";
             if ( strlen((*member).fColumnName)+3*dim < 8) cout << "\t";

             for (thisStepRows = 0;thisStepRows < thisLoopLenth; thisStepRows++,nextRow += GetRowSize()) {
               const char *pointer = nextRow + offset  + indexOffset*(*member).fTypeSize;
    	   if (isdate) {
                 cdatime = (UInt_t*)pointer;
                 TDatime::GetDateTime(cdatime[0],cdate,ctime);
                 cout << cdate << "/" << ctime;
               } else if ((*member).fType == kChar && dim == 1) {
                 char charbuffer[11];
                 strncpy(charbuffer,pointer,TMath::Min(10,arrayLength));
                 charbuffer[10] = 0;
                 cout << "\"" << charbuffer;
                 if (arrayLength > 10)
    	                            cout << " . . . ";
                 cout << "\"";
                 breakLoop = kTRUE;
               } else {
                 AsString((void *)pointer,EColumnType((*member).fType),width,cout);
                 cout << " :";
               }
             }
             // Encode  the column's comment
             if (indexOffset==0) {
               TDataSet *nxc = nextComment();
               cout << " " << (const char *)(nxc ? nxc->GetTitle() : "no comment");
             }
             cout << endl;
           }
           if (arrayLayout) delete [] arrayLayout;
         }
         rowCount -= thisLoopLenth;
         startRow  = nextRow;
      }
      cout << "---------------------------------------------------------------------------------------" << endl;
      return 0;
     }
    //______________________________________________________________________________
     void TTable::PrintContents(Option_t *) const
    {
      TDataSet::PrintContents();
      TROOT::IndentLevel();
      printf("\tclass %s: public TTable\t --> Allocated rows: %d\t Used rows: %d\t Row size: %d bytes\n",
             IsA()->GetName(),int(fN),int(fMaxIndex),int(fSize));

    }

    //______________________________________________________________________________
     void TTable::Project(const Text_t *hname, const Text_t *varexp, const Text_t *selection, Option_t *option,Int_t nentries, Int_t firstentry)
    {
    //*-*-*-*-*-*-*-*-*Make a projection of a TTable using selections*-*-*-*-*-*-*
    //*-*              =============================================
    //
    //   Depending on the value of varexp (described in Draw) a 1-D,2-D,etc
    //   projection of the TTable will be filled in histogram hname.
    //   Note that the dimension of hname must match with the dimension of varexp.
    //

       Int_t nch = strlen(hname) + strlen(varexp);
       char *var = new char[nch+5];
       sprintf(var,"%s>>%s",varexp,hname);
       nch = strlen(option) + 10;
       char *opt = new char[nch];
       if (option) sprintf(opt,"%sgoff",option);
       else        strcpy(opt,"goff");

       Draw(var,selection,opt,nentries,firstentry);

       delete [] var;
       delete [] opt;
    }

    //______________________________________________________________________________
     Int_t TTable::Purge(Option_t *opt)
    {
      // Shrink the table to free the unused but still allocated rows
      ReAllocate();
      return TDataSet::Purge(opt);
    }

    //______________________________________________________________________________
     void TTable::SavePrimitive(ofstream &out, Option_t *)
    {
    //   Save a primitive as a C++ statement(s) on output stream "out".
      UInt_t arrayLayout[10],arraySize[10];
      const unsigned char *pointer=0,*startRow=0;
      int i,rowCount;unsigned char ic;

      out << "TDataSet *CreateTable() { " << endl;

      Int_t rowNumber =  GetNRows();
      TTableDescriptor *dscT = GetRowDescriptors();

    //                      Is anything Wrong??
      if (!rowNumber || !dscT ) {//
         out << "// The output table was bad-defined!" << endl
             << " fprintf(stderr, \"Bad table found. Please remove me\\n\");" << endl
             << " return 0; } "    << endl;
         return;
      }

      startRow = (const UChar_t *)GetArray();
      assert(startRow!=0);

      const Char_t *rowId = "row";
      const Char_t *tableId = "tableSet";

    //                      Generate the header

      const char *className = IsA()->GetName();

      out << "// -----------------------------------------------------------------" << endl;
      out << "// "   << Path()
          << " Allocated rows: "<< rowNumber
          <<"  Used rows: "<<      rowNumber
          <<"  Row size: " << fSize << " bytes"                 << endl;
      out << "// "  << " Table: " << dscT->GetName()<<"[0]--> "
          << dscT->GetName()<<"["<<rowNumber-1 <<"]"            << endl;
      out << "// ====================================================================" << endl;
      out << "// ------  Test whether this table share library was loaded ------"      << endl;
      out << "  if (!gROOT->GetClass(\"" << className << "\")) return 0;"    << endl;
      out <<    dscT->GetName() << " " << rowId << ";" << endl
          <<  className << " *" << tableId << " = new "
          <<  className
          << "(\""<<GetName()<<"\"," << GetNRows() << ");" << endl
          << "//" <<endl ;

    //              Row loop
      TDataSetIter nextComment(dscT->MakeCommentField(kFALSE));
      for (rowCount=0;rowCount<rowNumber; rowCount++,startRow += fSize, nextComment.Reset()) {     //row loop
        out << "memset(" << "&" << rowId << ",0," << tableId << "->GetRowSize()" << ");" << endl ;

    //              Member loop
       tableDescriptor_st member  = dscT->begin();
       tableDescriptor_st   dscE  = dscT->end();
       for (; member != dscE; member++) {  //LOOP over members
          TString memberType = GetTypeName(EColumnType((*member).fType));
          TString memberName((*member).fColumnName);

          // Encode  the column's comment
          TDataSet *nxc = nextComment();
          TString memberTitle(nxc ? nxc->GetTitle() : "no comment");

          Int_t offset = (*member).fOffset;
          int mayBeName = 0;
          if (memberName.Index("name",0,TString::kIgnoreCase)>=0) mayBeName=1999;
          if (memberName.Index("file",0,TString::kIgnoreCase)>=0) mayBeName=1999;
          int typeSize = (*member).fTypeSize;

    //              Add the dimensions to "array" members
          Int_t dim = (*member).fDimensions;
          if (dim) memset(arrayLayout,0,dim*sizeof(Int_t));
          Int_t arrayLength  = 1;
          for (int indx=0;indx < dim ;indx++){
             arraySize[indx] =  (*member).fIndexArray[indx];;
             arrayLength *= arraySize[indx];
          }

    //                      Special case, character array
          int charLen = (memberType.CompareTo("char")==0);
          if (charLen) {    //Char case
            charLen=arrayLength;
            pointer = startRow + offset;
    //                      Actual size of char array
            if (mayBeName) {
              charLen = strlen((const char*)pointer)+1;
              if (charLen>arrayLength) charLen = arrayLength;
            } else {
              for(;charLen && !pointer[charLen-1];charLen--){;}
              if (!charLen) charLen=1;
            }

            out << " memcpy(&" << rowId << "." << (const char*)memberName;
            out << ",\"";
            for (int ii=0; ii<charLen;ii++) {
              ic = pointer[ii];
              if (ic && (isalnum(ic)
              || strchr("!#$%&()*+-,./:;<>=?@{}[]_|~",ic))) {//printable
                out << ic;
              } else {                                      //nonprintable
                out << "\\x" << setw(2) << setfill('0') << hex << (unsigned)ic ;
                out << setw(1) << setfill(' ') << dec;
              }
            }
            out << "\"," << dec << charLen << ");";
            out << "// " << (const char*)memberTitle << endl;
            continue;
          } //EndIf of char case

    //                      Normal member
          Int_t indexOffset;
          for (indexOffset=0; indexOffset < arrayLength ; indexOffset++) {//array loop
            out << setw(3) << " " ;
            out << " " << rowId << "." << (const char*)memberName;

            if (dim) {
              for (i=0;i<dim;i++) {out << "["<<dec<<arrayLayout[i]<<"]";}
              ArrayLayout(arrayLayout,arraySize,dim);}

    //                      Generate "="
            out << "\t = ";

            pointer = startRow + offset  + indexOffset*typeSize;

            AsString((void *)pointer,EColumnType((*member).fType),10,out);

    //                      Encode data member title
            if (indexOffset==0)  out << "; // " << (const char*)memberTitle;
             out << ";" << endl;
          }//end array loop
        }//end of member loop

        out << tableId << "->AddAt(&" << rowId <<");" << endl;

      }//end of row loop
      out << "// ----------------- end of code ---------------" << endl
          << " return (TDataSet *)tableSet;" << endl
          << "}"  << endl;
      return;
    }

    //______________________________________________________________________________
     void TTable::Set(Int_t n)
    {
       // Set array size of TTable object to n longs. If n<0 leave array unchanged.
       if (n < 0) return;
       if (fN != n)  Clear();
       SetfN(n);
       if (fN == 0) return;
       Create();
       if (TTable::GetNRows()) Reset();
    }
    //______________________________________________________________________________
     void TTable::SetTablePointer(void *table)
    {
       if (fTable) free(fTable);
       fTable = (Char_t *)table;
    }

    //______________________________________________________________________________
     void TTable::SetType(const Text_t *const type)
    {
       SetTitle(type);
    }

    //______________________________________________________________________________
    static Char_t *GetExpressionFileName()
    {
      // Create a name of the file in the temporary directory if any
      const Char_t *tempDirs =  gSystem->Getenv("TEMP");
      if (!tempDirs)  tempDirs =  gSystem->Getenv("TMP");
      if (!tempDirs) tempDirs = "/tmp";
      if (gSystem->AccessPathName(tempDirs)) tempDirs = ".";
      if (gSystem->AccessPathName(tempDirs)) return 0;
      Char_t buffer[16];
      sprintf(buffer,"C.%d.tmp",gSystem->GetPid());
      TString fileName = "Selection.";
      fileName += buffer;
      return  gSystem->ConcatFileName(tempDirs,fileName.Data());
    }

    //______________________________________________________________________________
     Char_t *TTable::MakeExpression(const Char_t *expressions[],Int_t nExpressions)
    {
      // Create CINT macro to evaluate the user-provided expresssion
      // Expression may contains:
      //   -  the table columen names
      //   - 2 meta names: i$ - the current column index,
      //                   n$ - the total table size provided by TTable::GetNRows() method
      //
      // return the name of temporary file with the current expressions
      //
       const Char_t *typeNames[] = {"NAN","float", "int",  "long",  "short",         "double"
                                    ,"unsigned int","unsigned long", "unsigned short","unsigned char"
                                    ,"char", "TTableMap &"};
       const char *resID     = "results";
       const char *addressID = "address";
       Char_t *fileName = GetExpressionFileName();
       if (!fileName) {
           Error("MakeExpression","Can not create a temporary file");
           return 0;
       }

       ofstream str;
       str.open(fileName);
       if (str.bad() ) {
           Error("MakeExpression","Can not open the temporary file <%s>",fileName);
           delete [] fileName;
           return 0;
       }

       TTableDescriptor *dsc = GetRowDescriptors();
       const tableDescriptor_st *descTable  = dsc->GetTable();
       // Create function
       str << "void SelectionQWERTY(float *"<<resID<<", float **"<<addressID<< ", int& i$, int& n$ )"   << endl;
       str << "{"                                                        << endl;
       int i = 0;
       for (i=0; i < dsc->GetNRows(); i++,descTable++ ) {
        // Take the column name
        const Char_t *columnName = descTable->fColumnName;
        const Char_t *type = 0;
        // First check whether we do need this column
        for (Int_t exCount = 0; exCount < nExpressions; exCount++) {
           if (expressions[exCount] && expressions[exCount][0] && strstr(expressions[exCount],columnName)) goto LETSTRY;
        }
        continue;
    LETSTRY:
        Bool_t isScalar = !(descTable->fDimensions);
        Bool_t isFloat = descTable->fType == kFloat;
        type = typeNames[descTable->fType];
                        str << type << " ";
        if (!isScalar)  str << "*";

                        str << columnName << " = " ;
        if (isScalar)   str << "*(";
        if (!isFloat)   str << "(" << type << "*)";
                        str << addressID << "[" << i << "]";
        if (isScalar)   str << ")" ;
                        str << ";" << endl;
       }
       // Create expressions
       for (i=0; i < nExpressions; i++ ) {
          if (expressions[i] && expressions[i][0])
                       str << " "<<resID<<"["<<i<<"]=(float)(" << expressions[i] << ");"  << endl;
    //      if (i == nExpressions-1 && i !=0 )
    //          str  << "  if ("<<resID<<"["<<i<<"] == 0){ return; }" << endl;
       };
       str << "}" << endl;
       str.close();
       // Create byte code and check syntax
       if (str.good()) return fileName;
       delete [] fileName;
       return 0;
    }

    //______________________________________________________________________________
     void TTable::Reset(Int_t c)
    {
      // Fill the entire table with byte "c" ;
      ///     c=0 "be default"
      if (fTable) {
          ResetMap(kTRUE);
          ::memset(fTable,c,fSize*fN);
          if (c) ResetMap(kFALSE);
      }
    }

    //______________________________________________________________________________
     void TTable::ResetMap(Bool_t wipe)
    {
      // Clean all filled columns with the pointers to TTableMap
      // if any
      //  wipe = kTRUE - delete all object the Map's point to
      //         kFALSE - zero pointer, do not call "delete" though
      piterator links     = pbegin();
      piterator lastLinks = pend();
      for (;links != lastLinks;links++) {
          TTableMap **mp = (TTableMap **)(*links);
          if (wipe) delete *mp;
          *mp = 0;
      }
    }
    //______________________________________________________________________________
     void TTable::Set(Int_t n, Char_t *array)
    {
       // Set array size of TTable object to n longs and copy array.
       // If n<0 leave array unchanged.

       if (n < 0) return;
       if (fN < n) Clear();

       SetfN(n);

       if (fN == 0) return;
       Create();
       CopyStruct(fTable,array);
       fMaxIndex = n;
    }

    //_______________________________________________________________________
     void TTable::StreamerTable(TBuffer &b,Version_t version)
    {
       // Stream an object of class TTable.
       if (b.IsReading()) {
         TDataSet::Streamer(b);
         b >> fN;
         StreamerHeader(b,version);
         //   Create a table to fit nok rows
         Set(fMaxIndex);
       } else {
          TDataSet::Streamer(b);
          b << fN;
          StreamerHeader(b,version);
       }
    }

    //_______________________________________________________________________
     void TTable::StreamerHeader(TBuffer &b, Version_t version)
    {
      // Read "table parameters first"
      if (b.IsReading())
      {
       Long_t rbytes;
       if (version) { }   // version to remove compiler warning
    #ifdef __STAR__
       if (version < 3) {
         // skip obsolete  STAR fields (for the sake of the backward compatibility)
         //   char name[20];   /* table name */
         //   char type[20];   /* table type */
         //   long maxlen;     /* # rows allocated */
         long len = b.Length() + (20+4) + (20+4) + 4;
         b.SetBufferOffset(len);
       }
    #endif
       b >> fMaxIndex;         // fTableHeader->nok;          /* # rows filled */
       b >> rbytes;            /* number of bytes per row */
       if (GetRowSize() == -1) fSize = rbytes;
       if (rbytes - GetRowSize()) {
          Warning("StreamerHeader","Schema evolution warning: row size mismatch: expected %d, read %d bytes\n",GetRowSize(),rbytes);
       }

    #ifdef __STAR__
       if (version < 3) {
         // skip obsolete  STAR fields (for the sake of the backward compatibility)
         //    long dsl_pointer;  /* swizzled (DS_DATASET_T*) */
         //    long data_pointer; /* swizzled (char*) */
         long len = b.Length() + (4) + (4);
         b.SetBufferOffset(len);
       }
    #endif
      }
      else {
        b << fMaxIndex;         //fTableHeader->nok;          /* # rows filled */
        b << fSize;             //  fTableHeader->rbytes;     /* number of bytes per row */
      }
    }
    //_______________________________________________________________________
     Int_t TTable::SetfN(Long_t len)
    {
       fN = len;
       return fN;
    }
    //____________________________________________________________________________
    #ifdef StreamElelement
    #define __StreamElelement__ StreamElelement
    #undef StreamElelement
    #endif

    #define StreamElementIn(type)  case TTableDescriptor::_NAME2_(k,type):        \
     if (evolutionOn) {                                  \
         if (nextCol->fDimensions)  {                    \
           if (nextCol->fOffset != UInt_t(-1)) {         \
              R__b.ReadFastArray((_NAME2_(type,_t) *)(row+nextCol->fOffset),nextCol->fSize/sizeof(_NAME2_(type,_t)));   \
           } else {                                        \
               _NAME2_(type,_t) *readPtrV = new _NAME2_(type,_t)[nextCol->fSize/sizeof(_NAME2_(type,_t))];              \
               R__b.ReadFastArray((_NAME2_(type,_t) *)(row+nextCol->fOffset),nextCol->fSize/sizeof(_NAME2_(type,_t)));  \
               delete [] readPtrV;                       \
               readPtrV = 0;                             \
           }                                             \
         }                                               \
         else  {                                         \
           _NAME2_(type,_t) skipBuffer;                  \
           _NAME2_(type,_t) *readPtr =  (_NAME2_(type,_t) *)(row+nextCol->fOffset); \
           if (nextCol->fOffset == UInt_t(-1)) readPtr = &skipBuffer;               \
           R__b >> *readPtr;                             \
         }                                               \
     } else {                                            \
       if (nextCol->fDimensions)  {                      \
         R__b.ReadFastArray  ((_NAME2_(type,_t) *)(row+nextCol->fOffset),nextCol->fSize/sizeof(_NAME2_(type,_t)));  \
       } else                                                       \
         R__b >> *(_NAME2_(type,_t) *)(row+nextCol->fOffset);       \
     }                                                              \
     break

    #define StreamElementOut(type) case TTableDescriptor::_NAME2_(k,type):    \
     if (nextCol->fDimensions)                                    \
        R__b.WriteFastArray((_NAME2_(type,_t) *)(row+nextCol->fOffset), nextCol->fSize/sizeof(_NAME2_(type,_t))); \
     else                                                         \
        R__b << *(_NAME2_(type,_t) *)(row+nextCol->fOffset);      \
     break

    //______________________________________________________________________________
     TTableDescriptor  *TTable::GetRowDescriptors() const
    {
      TTableDescriptor *dsc = 0;
      if (IsA()) dsc = GetDescriptorPointer();
      if (!dsc) {
        Error("GetRowDescriptors()","%s has no dictionary !",GetName());
        dsc = GetTableDescriptors();
        ((TTableDescriptor *)this)->SetDescriptorPointer(dsc);
      }
      return dsc;
    }
    //______________________________________________________________________________
     TTableDescriptor *TTable::GetDescriptorPointer() const
    {
       assert(0);
       return 0;
    }

    //______________________________________________________________________________
     void TTable::SetDescriptorPointer(TTableDescriptor *)
    {
       assert(0);
    }

    //______________________________________________________________________________
     void TTable::Streamer(TBuffer &R__b)
    {
       // Stream an array of the "plain" C-structures
       TTableDescriptor *ioDescriptor = GetRowDescriptors();
       TTableDescriptor *currentDescriptor = ioDescriptor;
       Version_t R__v = 0;
       if (R__b.IsReading()) {
          // Check whether the file is the "obsolete" one
          R__v = R__b.ReadVersion();
          Bool_t evolutionOn = kFALSE;
          if (R__v>=2) {
            if (IsA() != TTableDescriptor::Class()) {
    	  if (R__v>3) {
      	     R__b >> ioDescriptor;
              } else {  // backward compatibility
                ioDescriptor =  new TTableDescriptor();
                ioDescriptor->Streamer(R__b);
              }
              if (!currentDescriptor) {
    	     currentDescriptor = ioDescriptor;
    	     SetDescriptorPointer(currentDescriptor);
              }
              if (currentDescriptor->fSecondDescriptor != ioDescriptor) {
                 // Protection against of memory leak.
                 delete currentDescriptor->fSecondDescriptor;
                 currentDescriptor->fSecondDescriptor = ioDescriptor;
              }

               // compare two descriptors
               evolutionOn = (Bool_t)ioDescriptor->UpdateOffsets(currentDescriptor);
            }
          }
          TTable::StreamerTable(R__b,R__v);
          if (fMaxIndex <= 0) return;
          char *row= fTable;
          Int_t maxColumns = ioDescriptor->NumberOfColumns();
          Int_t rowSize = GetRowSize();
          if (evolutionOn) Reset(0); // Clean table
          for (Int_t indx=0;indx<fMaxIndex;indx++,row += rowSize) {
            tableDescriptor_st *nextCol = ioDescriptor->GetTable();
            for (Int_t colCounter=0; colCounter < maxColumns; colCounter++,nextCol++)
            {
              // Stream one table row supplied
              switch(nextCol->fType) {
               StreamElementIn(Float);
               StreamElementIn(Int);
               StreamElementIn(Long);
               StreamElementIn(Short);
               StreamElementIn(Double);
               StreamElementIn(UInt);
               StreamElementIn(ULong);
               StreamElementIn(UChar);
               StreamElementIn(Char);
               StreamElementIn(Bool);
              case TTableDescriptor::kPtr: {
                Ptr_t readPtr;
                R__b >> readPtr;
                if (evolutionOn) {
                   // TTableMap skipBuffer;
                   //  R__b >> readPtr;
                   if (nextCol->fOffset == UInt_t(-1)) delete readPtr; // skip this member
                   else *(Ptr_t *)(row+nextCol->fOffset) = readPtr;
                } else {
                   *(Ptr_t *)(row+nextCol->fOffset) = readPtr;
                }
                break;
                                           }
              default:
                break;
            };
          }
         }
       } else {
          TSeqCollection *save = fList;
          R__b.WriteVersion(TTable::IsA());

         //      if (Class_Version()==2)
          if (IsA() != TTableDescriptor::Class()) {
            if ( Class_Version()>3 ) {
              R__b << ioDescriptor;
            } else {  // backward compatibility
              ioDescriptor->Streamer(R__b);
            }
          } else {
            if ( Class_Version()<=3 ) fList = 0;
          }

          TTable::StreamerTable(R__b);
          if (fMaxIndex <= 0) return;
          char *row= fTable;
          Int_t maxColumns = ioDescriptor->NumberOfColumns();
          Int_t rowSize = GetRowSize();
          for (Int_t indx=0;indx<fMaxIndex;indx++,row += rowSize) {
            tableDescriptor_st *nextCol = ioDescriptor->GetTable();
            for (Int_t colCounter=0; colCounter < maxColumns; colCounter++,nextCol++)
            {
              // Stream one table row supplied
              switch(nextCol->fType) {
               StreamElementOut(Float);
               StreamElementOut(Int);
               StreamElementOut(Long);
               StreamElementOut(Short);
               StreamElementOut(Double);
               StreamElementOut(UInt);
               StreamElementOut(ULong);
               StreamElementOut(UChar);
               StreamElementOut(Char);
               StreamElementOut(Bool);
              case TTableDescriptor::kPtr:
                  R__b << *(Ptr_t *)(row+nextCol->fOffset);
                  break;
              default:
                break;
            };
          }
         }
         fList = save;
       }
    }
    #ifdef __StreamElelement__
    #define StreamElelement __StreamElelement__
    #undef __StreamElelement__
    #endif

    //_______________________________________________________________________
     void TTable::Update()
    {
    }

    //_______________________________________________________________________
     void TTable::Update(TDataSet *set, UInt_t opt)
    {
     // Kill the table current data
     // and adopt those from set
      if (set->HasData())
      {
        // Check whether the new table has the same type
        if (strcmp(GetTitle(),set->GetTitle()) == 0 )
        {
          TTable *table =  (TTable *)set;
          Adopt(table->GetSize(),table->GetArray());
          // Adopt can not distniguish the "allocated" and "used"
          // rows,
          // correct the corrupted number of the "used" rows
          SetUsedRows(table->GetNRows());
          // mark that object lost the STAF table and can not delete it anymore
          table->SetBit(kIsNotOwn);
          // mark we took over of this STAF table
          ResetBit(kIsNotOwn);
        }
        else
           Error("Update",
                 "This table is <%s> but the updating one has a wrong type <%s>",GetTitle(),set->GetTitle());
      }
      TDataSet::Update(set,opt);
    }
    //_______________________________________________________________________
     const char *TTable::TableDictionary(const char *className,const char *structName,TTableDescriptor *&ColDescriptors)
    {
       // Query the TClass instance for the C-stucture dicitonary
       // This method is to be used  with TableImp CPP macro (see $ROOTSYS/table/inc/Ttypes.h
       if (className){/*NotUsed*/};
       TClass *r = gROOT->GetClass(structName,1);
       ColDescriptors = new TTableDescriptor(r);
       return structName;
    }

     //  ----   Table descriptor service   ------
     Int_t        TTable::GetColumnIndex(const Char_t *columnName) const {return GetRowDescriptors()->ColumnByName(columnName);}
     const Char_t *TTable::GetColumnName(Int_t columnIndex) const {return GetRowDescriptors()->ColumnName(columnIndex); }
     const UInt_t *TTable::GetIndexArray(Int_t columnIndex) const {return GetRowDescriptors()->IndexArray(columnIndex); }
     UInt_t       TTable::GetNumberOfColumns()              const {return GetRowDescriptors()->NumberOfColumns();       }

     UInt_t       TTable::GetOffset(Int_t columnIndex)      const {return GetRowDescriptors()->Offset(columnIndex); }
     Int_t        TTable::GetOffset(const Char_t *columnName) const {return GetRowDescriptors()->Offset(columnName); }

     UInt_t       TTable::GetColumnSize(Int_t columnIndex)  const {return GetRowDescriptors()->ColumnSize(columnIndex); }
     Int_t        TTable::GetColumnSize(const Char_t *columnName) const {return GetRowDescriptors()->ColumnSize(columnName); }

     UInt_t       TTable::GetTypeSize(Int_t columnIndex)    const {return GetRowDescriptors()->TypeSize(columnIndex); }
     Int_t        TTable::GetTypeSize(const Char_t *columnName) const {return GetRowDescriptors()->TypeSize(columnName); }

     UInt_t       TTable::GetDimensions(Int_t columnIndex)  const {return GetRowDescriptors()->Dimensions(columnIndex); }
     Int_t        TTable::GetDimensions(const Char_t *columnName) const {return GetRowDescriptors()->Dimensions(columnName); }

    TTable::EColumnType  TTable::GetColumnType(Int_t columnIndex)  const {return GetRowDescriptors()->ColumnType(columnIndex); }
    TTable::EColumnType  TTable::GetColumnType(const Char_t *columnName) const {return GetRowDescriptors()->ColumnType(columnName); }

    //  pointer iterator
    //________________________________________________________________________________________________________________
    TTable::piterator::piterator(const TTable *t,EColumnType type): fCurrentRowIndex(0),fCurrentColIndex(0),fCurrentRowPtr(0)
    {
       Int_t sz = 0;
       if (t) sz = t->GetNRows();
       if (sz) {
         fRowSize       = t->GetRowSize();
         fCurrentRowPtr = (const Char_t *)t->GetArray();

         TTableDescriptor    *tabsDsc       = t->GetRowDescriptors();
         tableDescriptor_st ptr     = tabsDsc->begin();
         tableDescriptor_st lastPtr = tabsDsc->end();
         UInt_t i =0;
         for( i = 0; ptr != lastPtr; ptr++,i++)
           if ( tabsDsc->ColumnType(i) == type ) fPtrs.push_back(tabsDsc->Offset(i));
         if (fPtrs.size()==0) {
           MakeEnd(t->GetNRows());
         } else {
           column();
         }
      } else {
         MakeEnd(0);
      }
    } // piterator(TTable *)