ROOT logo
/**
 * @file   ChainBuilder.C
 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
 * @date   Tue Oct 16 17:54:26 2012
 * 
 * @brief  Build a chain
 * 
 * @ingroup pwglf_forward_trains_util
 */

#ifndef CHAINBUILDER_C
#define CHAINBUILDER_C
#ifndef __CINT__
# include <TUrl.h>
# include <TString.h>
# include <TChain.h>
# include <TChainElement.h>
# include <TSystemDirectory.h>
# include <TSystem.h>
# include <TFile.h>
# include <TFileInfo.h>
# include <TList.h>
# include <TError.h>
# include <TROOT.h>
# include <TGridCollection.h>
# include <TFileCollection.h>
# include <THashList.h>
# include <TKey.h>
# include <TRegexp.h>
# include <fstream>
#else 
class TString;
class TChain;
class TSystemDirectory;
class TUrl;
#endif

// ===================================================================
/**
 * Build a chain 
 *
 * @ingroup pwglf_forward_trains_util
 */
struct ChainBuilder 
{
  enum {
    kVerbose   =  0x1,
    kRecursive =  0x2,
    kMC        =  0x4,
    kCheck     =  0x8,
    kClean     = 0x10,
    kScan      = 0x20
  };
  enum { 
    kInvalid,
    kDirectory, 
    kXML, 
    kAscii, 
    kROOT
  };
  //------------------------------------------------------------------
  static UShort_t CheckSource(TString& src, UShort_t flags)
  {
    // Local copy 
    TString tmp(src);

    // --- Normalize the path ----------------------------------------
    if (tmp == ".") tmp = "";
    if (!tmp.BeginsWith("/")) tmp.Prepend("../");
    if (gSystem->ExpandPathName(tmp)) { 
      Error("ChainBuilder::CheckSource", 
	    "Failed to expand source %s", src.Data());
      return kInvalid;
    }

    // --- Stat the file ---------------------------------------------
    FileStat_t stat; 
    if (gSystem->GetPathInfo(tmp, stat)) return kInvalid;
    src = tmp;

    // --- Check if directory or file --------------------------------
    if (R_ISDIR(stat.fMode)) {
      if (flags & kVerbose) 
	Info("ChainBuilder::CheckSource", "%s is a directory", tmp.Data());
      return kDirectory;
    }

    // --- check file type -------------------------------------------
    TString type(gSystem->GetFromPipe(Form("file -b %s", src.Data())));
    if ((flags & kVerbose))
      Info("ChainBuilder::CheckSource", "file -b %s -> %s", 
	   tmp.Data(), type.Data());
    UShort_t ret = kInvalid;
    if      (type.Contains("ROOT"))  ret = kROOT;
    else if (type.Contains("XML"))   ret = kXML;
    else if (type.Contains("ASCII")) ret = kAscii;

    if (ret == kInvalid) {
      Error("ChainBuilder::CheckSource", 
	    "Do not now how to process %s of type %s", 
	    src.Data(), type.Data());
    }
    return ret;
  }
  //------------------------------------------------------------------
  /** 
   * Create a TChain from a URL specification.
   *
   * The URL should have the format 
   * 
   * @verbatim
   *   PROTOCOL://PATH?OPTIONS#TREENAME
   * @endverbatim
   *
   * where 
   * - @c PROTOCOL is any protocol
   * - @c PATH is a file, top-directory, file containing a
   *   TFileCollection, ASCII file with list of files, etc.
   * - @c OPTIONS is a list of options, separate by @c &
   * - @c TREENAME is the tree name 
   *
   * @c OPTIONS can be one or more of 
   * - @c mc  Also check for auxiliary MC files
   * - @c recursive When scanning directories, do so recursively
   * - @c verbose Be verbose
   * - @c check Check files by trying to open them 
   * - @c clean Remove invalid files 
   * - @c pattern=PATTERN Search pattern when scanning directories 
   * 
   * @param url The input url 
   * 
   * @return Pointer to newly allocated TChain object or null
   */
  static TChain* Create(const TUrl& url)
  {
    TString     source   = url.GetFile();
    TString     treeName = url.GetAnchor();
    TString     pattern  = "";
    UShort_t    flags    = 0;
    TString     options  = url.GetOptions();
    TObjArray*  tokens   = options.Tokenize("&");
    TObjString* token    = 0; 
    TIter       next(tokens);
    while ((token = static_cast<TObjString*>(next()))) {
      const TString& str = token->String();
      if (str.EqualTo("mc", TString::kIgnoreCase)) 
	flags |= kMC;
      else if (str.EqualTo("recursive", TString::kIgnoreCase)) 
	flags |= kRecursive;
      else if (str.EqualTo("verbose", TString::kIgnoreCase)) 
	flags |= kVerbose;
      else if (str.EqualTo("check", TString::kIgnoreCase)) 
	flags |= kCheck;
      else if (str.EqualTo("clean", TString::kIgnoreCase)) 
	flags |= kClean; 
      else if (str.EqualTo("scan", TString::kIgnoreCase)) 
	flags |= kScan; 
      else if (str.BeginsWith("pattern=", TString::kIgnoreCase)) { 
	Int_t eq = str.Index("=");
	pattern  = str(eq+1, str.Length()-eq-1);
	pattern.ReplaceAll("@", "#");
      }
      else 
	Warning("", "Option %s unknown", str.Data());
    }
    delete tokens;

    TString tmp(source);
    UShort_t type = CheckSource(tmp, flags);
    
    return Create(type, tmp, treeName, pattern, flags);
  }
  //------------------------------------------------------------------
  /** 
   * Create a chain
   * 
   * @param src          Source 
   * @param treeName     Tree name 
   * @param pattern      Pattern for scans
   * @param mc           If true, check for MC files
   * @param recursive    If true, scan recursively
   * @param verbose      If true, be verbose
   * @param checkFiles   If true, check that files can be opened
   * @param removeFiles  If true, remove bad files 
   * 
   * @return Pointer to newly allocated TChain or null
   */
  static TChain* Create(const TString& src, 
			const TString& treeName, 
			const TString& pattern, 
			Bool_t         mc, 
			Bool_t         recursive,
			Bool_t         verbose=false,
			Bool_t         checkFiles=false, 
			Bool_t         removeFiles=false)
  {
    UShort_t flags = 0;
    if (verbose)     flags |= kVerbose;
    if (recursive)   flags |= kRecursive;
    if (mc)          flags |= kMC;
    if (checkFiles)  flags |= kCheck;
    if (removeFiles) flags |= kClean;

    TString tmp(src);
    UShort_t type = CheckSource(tmp, flags);

    return Create(type, tmp, treeName, pattern, flags);
  }
  //------------------------------------------------------------------
  /** 
   * Create a chain
   * 
   * @param type         Type of input
   * @param src          Source 
   * @param treeName     Tree name 
   * @param pattern      Pattern for scans
   * @param mc           If true, check for MC files
   * @param recursive    If true, scan recursively
   * @param verbose      If true, be verbose
   * @param checkFiles   If true, check that files can be opened
   * @param removeFiles  If true, remove bad files 
   * 
   * @return Pointer to newly allocated TChain or null
   */
  static TChain* Create(UShort_t       type,
			const TString& src, 
			const TString& treeName, 
			const TString& pattern, 
			Bool_t         mc, 
			Bool_t         recursive,
			Bool_t         verbose=false,
			Bool_t         checkFiles=false, 
			Bool_t         removeFiles=false)
  {
    // Info("ChainBuilder::Create", 
    // "src=%s treeName=%s pattern=%s mc=%s recursive=%s",
    // src.Data(), treeName.Data(), pattern.Data(), 
    // (mc ? "true" : "false"), (recursive ? "true" : "false"));
    // --- Create flags 
    UShort_t flags = 0;
    if (verbose)     flags |= kVerbose;
    if (recursive)   flags |= kRecursive;
    if (mc)          flags |= kMC;
    if (checkFiles)  flags |= kCheck;
    if (removeFiles) flags |= kClean;

    return Create(type, src, treeName, pattern, flags);
  }
  //------------------------------------------------------------------
  /** 
   * Create a chain from the inputs
   * 
   * @param type        Type of input
   * @param src         Source 
   * @param treeName    Tree name
   * @param pattern     Pattern for scans 
   * @param flags       Flags 
   * 
   * @return Pointer to newly allocated TChain object or null
   */
  static TChain* Create(UShort_t       type, 
			const TString& src, 
			const TString& treeName, 
			const TString& pattern,
			UShort_t       flags)
  {
    // --- check input -----------------------------------------------
    if (type == kInvalid) {
      Error("ChainBuilder::Create", "Source %s isn't a file or directory",
	    src.Data());
      return 0;
    }

    TString tN(treeName);
    if (tN.IsNull()) 
      Warning("ChainBuilder::Create", "No tree name specified, assuming T");

    TString pat(pattern);
    if (pat.IsNull()) {
      if      (tN.EqualTo("esdTree")) pat = "AliESD*";
      else if (tN.EqualTo("aodTree")) pat = "AliAOD*";
      if ((flags & kVerbose)) Info("", "Pattern set to %s", pat.Data());
    }
    if ((flags & kVerbose))
      Info("ChainBuilder::Create", "Type=%s, tree=%s, pattern=%s", 
      (type == kDirectory ? "directory" : 
      type == kXML       ? "XML" : 
      type == kAscii     ? "ASCII" : 
      type == kROOT      ? "ROOT" : "unknown"),
      tN.Data(), pat.Data());
    
    // --- Create output ---------------------------------------------
    TChain* chain = new TChain(tN);

    // --- ZIP archives ----------------------------------------------
    TString anchor;
    TString tmp(pat);
    ExtractAnchor(pat, anchor);
    if ((flags & kVerbose)) 
      Info("", "Full pattern: '%s' filename pattern: '%s' anchor: '%s'",
	   tmp.Data(), pat.Data(), anchor.Data());

    // --- execute based on type 
    Bool_t ret = true;
    switch (type) { 
    case kROOT:      ret = CreateFromFile(chain, src, anchor, flags); break;
    case kXML:       ret = CreateFromXML(chain,  src); break;
    case kAscii:     ret = CreateFromList(chain, src); break;
    case kDirectory: ret = CreateFromDirectory(chain, src, 
					       pat, anchor, 
					       flags); break;
    default:         ret = false;
    }

    // --- Clean-up --------------------------------------------------
    if (chain->GetListOfFiles()->GetEntries() <= 0) ret = false;
    if (!ret) { 
      delete chain;
      chain = 0;
    }
    return chain;
  }
  //------------------------------------------------------------------
  /** 
   * Create a collection  
   * 
   * @param output Output file 
   * @param url    Input url 
   */
  static void CreateCollection(const TString& output, 
			       const TUrl&    url)
  {
    TChain* chain = Create(url);
    if (!chain) return;

    CreateCollection(output, chain);
  }
  //------------------------------------------------------------------
  /** 
   * Create a collection 
   * 
   * @param output Input url 
   * @param chain  Chain to make collection from 
   */
  static void CreateCollection(const TString& output, 
			       const TChain* chain)
  {
    if (!chain) return;
    TDirectory* savDir = gDirectory;
    TFile* out = TFile::Open(output, "RECREATE");
    if (!out) { 
      Error("", "Failed to open %s for output", output.Data());
      return;
    }
    TFileCollection* collection = new TFileCollection(chain->GetName());
    TObjArray*       files      = chain->GetListOfFiles();
    TChainElement*   element    = 0;
    TIter            next(files);


    collection->SetDefaultTreeName(chain->GetName());
    Long64_t nEntries = 0;
    while ((element = static_cast<TChainElement*>(next()))) {
      Info("", "Element: '%s' - '%s' %lld", 
	   element->GetName(), element->GetTitle(), 
	   element->GetEntries());
      TFileInfo*     info = new TFileInfo(element->GetTitle());
      TFileInfoMeta* meta = new TFileInfoMeta(Form("/%s",element->GetName()),
					      "TTree", element->GetEntries());
      info->AddMetaData(meta);
      info->SetBit(TFileInfo::kStaged);
      // info->AddUrl(Form("file://%s", element->GetTitle()));
      collection->Add(info);
      
      Long64_t n = element->GetEntries();
      if (n >= 0) nEntries += n;
      
    }
    collection->Update();
    TFileInfoMeta* cMeta = new TFileInfoMeta(chain->GetName(), 
					     "TTree", nEntries);
    collection->AddMetaData(cMeta);
    out->cd();
    collection->Write();
    Printf("A total of %lld entries", nEntries);
    // collection->Print("MFL");
    out->Close();
    savDir->cd();
  }
  //------------------------------------------------------------------
  /** 
   * Exrtact the anchor 
   * 
   * @param src    Source url 
   * @param anchor On return, contains the anchor
   */
  static void ExtractAnchor(TString& src, TString& anchor)
  {
    anchor         = "";
    Int_t idxHash  = src.Index("#");
    
    if (idxHash == kNPOS) return;

    TString tmp = src(0,idxHash);
    anchor      = src(idxHash+1, src.Length()-idxHash-1);
    src = tmp;
  }

  //------------------------------------------------------------------
  /** 
   * Create a chain consiting of a single file 
   * 
   * @param chain The chain
   * @param anchor Anchor (tree name)
   * @param src File name. 
   * @param flags       Flags 
   * 
   * @return Chain or null
   */
  static Bool_t CreateFromFile(TChain*        chain, 
			       const TString& src, 
			       const TString& anchor,
			       UShort_t       flags=0)
  {
    // Info("CreateFromFile", "Making from single file %s", src.Data());
    
    if (!CheckFile(src, anchor, chain, flags)) return false;
    return true;
  }
  //------------------------------------------------------------------
  /** 
   * Create a chain from an XML containing an collection
   * 
   * @return Newly allocated chain or null
   */
  static Bool_t CreateFromXML(TChain* chain, const TString& src) 
  {
    // Info("ChainBuilder::CreateFromXML", "Create from XML");
    Long_t ret = gROOT->ProcessLine(Form("TAlienCollection(\"%s\")", 
					 src.Data()));
    if (!ret) { 
      Error("ChainBuilder::CreateFromXML", 
	    "Cannot create AliEn collection from XML file %s", src.Data());
      return false;
    }
    
    TGridCollection* collection = reinterpret_cast<TGridCollection*>(ret);
#if 0
    if (!collection) { 
      Error("ChainBuilder::CreateFromXML", 
	    "Cannot create AliEn collection from XML file %s", src.Data());
      return false;
    }
#endif

    collection->Reset();
    while (collection->Next()) chain->Add(collection->GetTURL(""));
    
    return true;
  }
  //------------------------------------------------------------------
  /** 
   * Create a chain from a file containing a list of files
   * 
   * @return Newly allocated chain or null
   */
  static Bool_t CreateFromList(TChain*        chain, 
			       const TString& src,
			       UShort_t       flags=0)
  {
    // Info("ChainBuilder::CreateFromList", "Creating from list");
    std::ifstream in(src.Data());
    if (!in) { 
      Error("ChainBuilder::CreateFromList", 
	    "Failed to open list %s", src.Data());
      return false;
    }
    
    while (in.good()) { 
      TString line;
      line.ReadToDelim(in);
      TString l(line.Strip(TString::kBoth));
      if (l.IsWhitespace() || l.BeginsWith("#")) continue;
      
      TString anchor;
      ExtractAnchor(l, anchor);
      if (!CheckFile(l, anchor, chain, flags))
	Warning("ChainBuilder::CreateFromList", 
		"Failed to add %s to chain", l.Data());
    }
    return true;
  }
  //------------------------------------------------------------------
  /** 
   * Make a chain from a base directory, pattern, and treename -
   * possibly recursively
   * 
   * @return true on success 
   */
  static Bool_t CreateFromDirectory(TChain* chain, 
				    const TString& src, 
				    const TString& pattern, 
				    const TString& anchor,
				    UShort_t       flags)
  {
    // Info("", "Scanning src=%s, pattern=%s, mc=%d recursive=%d", 
    //      src.Data(), pattern.Data(), mc, recursive);
    // Save current directory 
    TString savdir(gSystem->WorkingDirectory());
    TSystemDirectory d(gSystem->BaseName(src.Data()), src.Data());
    if (flags & kVerbose) Info("", "Will scan %s", d.GetTitle());
    if (!ScanDirectory(chain, &d, pattern, anchor, flags))
      return false;
    // Go back to the saved directory 
    gSystem->ChangeDirectory(savdir);
    
    return true;
  }
  static void RemoveFile(const TString& path)
  {
    Info("", "Removing bad file %s", path.Data());
    gSystem->RedirectOutput("/dev/null", "w");
    // gSystem->Unlink(path);
    gSystem->Rename(path, Form("%s.bad", path.Data()));
    gSystem->RedirectOutput(0);    
  }
  //------------------------------------------------------------------
  /** 
   * Check if we can add a file to the chain 
   * 
   * @param path   Full path to file 
   * @param anchor Anchor (tree name)
   * @param chain  Chain 
   * @param flags  Some flags
   * 
   * @return true on success, false otherwise
   */
  static Bool_t CheckFile(const TString& path, 
			  const TString& anchor, 
			  TChain* chain,
			  UShort_t flags=0)
  {
    // Info("", "Checking %s", path.Data());
    TString fn   = path;
    if (!anchor.IsNull()) fn.Append(TString::Format("#%s", anchor.Data()));

    gSystem->RedirectOutput("/dev/null", "w");
    TFile*  test = TFile::Open(fn, "READ");
    gSystem->RedirectOutput(0);
    if (!test) { 
      Warning("ChainBuilder::CheckFile", "Failed to open %s", fn.Data());
      if (flags & kClean) RemoveFile(path);
      return false;
    }
    
    Bool_t           ok = false;
    TObject*         o  = test->Get(chain->GetName());
    TTree*           t  = dynamic_cast<TTree*>(o);
    TFileCollection* c  = dynamic_cast<TFileCollection*>(o);
    if (t) {
      test->Close();
      ok = true;
      if (flags & kMC) { 
	const char*  auxs[] = { "galice", "Kinematics", "TrackRefs", 0 };
	const char** aux    = auxs;
	while ((*aux)) { 
	  TString t1;
	  if (anchor.IsNull()) 
	    t1 = gSystem->ConcatFileName(gSystem->DirName(path.Data()),
					 Form("%s.root", *aux));
	  else 
	    t1 = TString::Format("%s#%s.root", path.Data(), *aux);
	  
	  TFile* t2 = TFile::Open(t1, "READ");
	  if (!t2) { 
	    Error("", "Needed MC file %s not found", t1.Data());
	    ok = false;
	    break;
	  }
	  t2->Close();
	  aux++;
	}
      }
      if (ok) chain->Add(fn, kScan ? -1 : TChain::kBigNumber);
    } else if (c) {
      chain->AddFileInfoList(c->GetList());
      ok = true;
    } else {
      // Let's try to find a TFileCollection 
      TList* l = test->GetListOfKeys();
      TIter next(l);
      TKey* k = 0;
      while ((k = static_cast<TKey*>(next()))) {
	TString cl(k->GetClassName());
	if (!cl.EqualTo("TFileCollection")) continue;
	c = dynamic_cast<TFileCollection*>(k->ReadObj());
	if (!c) { 
	  Warning("", "Returned collection invalid");
	  continue;
	}
	// Info("", "Adding file collection");
	chain->AddFileInfoList(c->GetList());
	ok = true;
      }
      test->Close();
    }

    if (!ok) {
      Warning("ChainBuilder::CheckFile", 
	      "The file %s does not contain the tree %s or a file collection", 
	      path.Data(), chain->GetName());
      if (flags & kClean) RemoveFile(path);
    }
    return ok;
  }
  //------------------------------------------------------------------
  /** 
   * Scan directory @a dir (possibly recursive) for tree files to add
   * to the chain.    This does not follow sym-links
   * 
   * @param dir        Directory to scan
   * @param chain      Chain to add to
   * @param pattern    File name pattern 
   * @param anchor     Anchor (tree name)
   * @param flags      Flags
   *
   * @return true if any files where added 
   */
  static Bool_t ScanDirectory(TChain*           chain, 
			      TSystemDirectory* dir,
			      const TString&    pattern,
			      const TString&    anchor,
			      UShort_t          flags)
  {
    // Assume failure 
    Bool_t ret = false;
    TRegexp wild(pattern, true);

    // Get list of files, and go back to old working directory
    TString oldDir(gSystem->WorkingDirectory());
    TList*  files = dir->GetListOfFiles();
    if (!gSystem->ChangeDirectory(oldDir)) { 
      Error("ChainBuilder::ScanDirectory", "Failed to go back to %s", 
	    oldDir.Data());
      return false;
    }
    if (!files) {
      Warning("ChainBuilder::ScanDirectory", "No files");
      return false;
    }

    TList toAdd;
    toAdd.SetOwner();
    
    // Sort list of files and check if we should add it 
    files->Sort();
    TIter next(files);
    TSystemFile* file = 0;
    while ((file = static_cast<TSystemFile*>(next()))) {
      TString name(file->GetName());
      TString title(file->GetTitle());
      TString full(gSystem->ConcatFileName(file->GetTitle(), name.Data()));
      if (file->IsA()->InheritsFrom(TSystemDirectory::Class())) full = title;
      // Ignore special links 
      if (name == "." || name == "..") { 
	// Info("ChainBuilder::ScanDirectory", "Ignoring %s", name.Data());
	continue;
      }
      if ((flags & kVerbose)) Info("", "Got file %s", full.Data());

      FileStat_t fs;
      if (gSystem->GetPathInfo(full.Data(), fs)) {
	Warning("ChainBuilder::ScanDirectory", "Cannot stat %s (%s)", 
		full.Data(), gSystem->WorkingDirectory());
	continue;
      }
      // Check if this is a directory 
      if (file->IsDirectory(full)) { 
	if ((flags & kVerbose)) Info("", "Recursive scan of %s", full.Data());
	if ((flags & kRecursive)) {
	  // if (title[0] == '/') 
	  TSystemDirectory* d = new TSystemDirectory(file->GetName(),
						     full.Data());
	  if (ScanDirectory(chain, d, pattern, anchor, flags))
	    ret = true;
	  delete d;
	}
        continue;
      }
    
      // If this is not a root file, ignore 
      if (!name.EndsWith(".root") && !name.EndsWith(".zip")) {
	if ((flags & kVerbose))
	  Info("ScanDirectory", "File %s does not end in .root/.zip", 
	       name.Data());
	continue;
      }

      // If this file does not contain AliESDs, ignore 
      if (!name.Contains(wild)) { 
	if ((flags & kVerbose))
	  Info("ChainBuilder::ScanDirectory", 
	       "%s does not match pattern %s", 
	       name.Data(), pattern.Data());
	continue;
      }
    
      // Add 
      // Info("ChainBuilder::ScanDirectory", "Adding %s", full.Data());
      toAdd.Add(new TObjString(full));
    }

    TIter nextAdd(&toAdd);
    TObjString* s = 0;
    Int_t added = 0;
    while ((s = static_cast<TObjString*>(nextAdd()))) {
      // Info("ChainBuilder::ScanDirectory", 
      //      "Adding %s", s->GetString().Data());
      TString fn = s->GetString();
      if (!CheckFile(fn, anchor, chain, flags)) continue;

      added++;
    }
    if (added > 0) ret = true;

    gSystem->ChangeDirectory(oldDir);
    return ret;
  }
};
#endif
//
// EOF
//
 ChainBuilder.C:1
 ChainBuilder.C:2
 ChainBuilder.C:3
 ChainBuilder.C:4
 ChainBuilder.C:5
 ChainBuilder.C:6
 ChainBuilder.C:7
 ChainBuilder.C:8
 ChainBuilder.C:9
 ChainBuilder.C:10
 ChainBuilder.C:11
 ChainBuilder.C:12
 ChainBuilder.C:13
 ChainBuilder.C:14
 ChainBuilder.C:15
 ChainBuilder.C:16
 ChainBuilder.C:17
 ChainBuilder.C:18
 ChainBuilder.C:19
 ChainBuilder.C:20
 ChainBuilder.C:21
 ChainBuilder.C:22
 ChainBuilder.C:23
 ChainBuilder.C:24
 ChainBuilder.C:25
 ChainBuilder.C:26
 ChainBuilder.C:27
 ChainBuilder.C:28
 ChainBuilder.C:29
 ChainBuilder.C:30
 ChainBuilder.C:31
 ChainBuilder.C:32
 ChainBuilder.C:33
 ChainBuilder.C:34
 ChainBuilder.C:35
 ChainBuilder.C:36
 ChainBuilder.C:37
 ChainBuilder.C:38
 ChainBuilder.C:39
 ChainBuilder.C:40
 ChainBuilder.C:41
 ChainBuilder.C:42
 ChainBuilder.C:43
 ChainBuilder.C:44
 ChainBuilder.C:45
 ChainBuilder.C:46
 ChainBuilder.C:47
 ChainBuilder.C:48
 ChainBuilder.C:49
 ChainBuilder.C:50
 ChainBuilder.C:51
 ChainBuilder.C:52
 ChainBuilder.C:53
 ChainBuilder.C:54
 ChainBuilder.C:55
 ChainBuilder.C:56
 ChainBuilder.C:57
 ChainBuilder.C:58
 ChainBuilder.C:59
 ChainBuilder.C:60
 ChainBuilder.C:61
 ChainBuilder.C:62
 ChainBuilder.C:63
 ChainBuilder.C:64
 ChainBuilder.C:65
 ChainBuilder.C:66
 ChainBuilder.C:67
 ChainBuilder.C:68
 ChainBuilder.C:69
 ChainBuilder.C:70
 ChainBuilder.C:71
 ChainBuilder.C:72
 ChainBuilder.C:73
 ChainBuilder.C:74
 ChainBuilder.C:75
 ChainBuilder.C:76
 ChainBuilder.C:77
 ChainBuilder.C:78
 ChainBuilder.C:79
 ChainBuilder.C:80
 ChainBuilder.C:81
 ChainBuilder.C:82
 ChainBuilder.C:83
 ChainBuilder.C:84
 ChainBuilder.C:85
 ChainBuilder.C:86
 ChainBuilder.C:87
 ChainBuilder.C:88
 ChainBuilder.C:89
 ChainBuilder.C:90
 ChainBuilder.C:91
 ChainBuilder.C:92
 ChainBuilder.C:93
 ChainBuilder.C:94
 ChainBuilder.C:95
 ChainBuilder.C:96
 ChainBuilder.C:97
 ChainBuilder.C:98
 ChainBuilder.C:99
 ChainBuilder.C:100
 ChainBuilder.C:101
 ChainBuilder.C:102
 ChainBuilder.C:103
 ChainBuilder.C:104
 ChainBuilder.C:105
 ChainBuilder.C:106
 ChainBuilder.C:107
 ChainBuilder.C:108
 ChainBuilder.C:109
 ChainBuilder.C:110
 ChainBuilder.C:111
 ChainBuilder.C:112
 ChainBuilder.C:113
 ChainBuilder.C:114
 ChainBuilder.C:115
 ChainBuilder.C:116
 ChainBuilder.C:117
 ChainBuilder.C:118
 ChainBuilder.C:119
 ChainBuilder.C:120
 ChainBuilder.C:121
 ChainBuilder.C:122
 ChainBuilder.C:123
 ChainBuilder.C:124
 ChainBuilder.C:125
 ChainBuilder.C:126
 ChainBuilder.C:127
 ChainBuilder.C:128
 ChainBuilder.C:129
 ChainBuilder.C:130
 ChainBuilder.C:131
 ChainBuilder.C:132
 ChainBuilder.C:133
 ChainBuilder.C:134
 ChainBuilder.C:135
 ChainBuilder.C:136
 ChainBuilder.C:137
 ChainBuilder.C:138
 ChainBuilder.C:139
 ChainBuilder.C:140
 ChainBuilder.C:141
 ChainBuilder.C:142
 ChainBuilder.C:143
 ChainBuilder.C:144
 ChainBuilder.C:145
 ChainBuilder.C:146
 ChainBuilder.C:147
 ChainBuilder.C:148
 ChainBuilder.C:149
 ChainBuilder.C:150
 ChainBuilder.C:151
 ChainBuilder.C:152
 ChainBuilder.C:153
 ChainBuilder.C:154
 ChainBuilder.C:155
 ChainBuilder.C:156
 ChainBuilder.C:157
 ChainBuilder.C:158
 ChainBuilder.C:159
 ChainBuilder.C:160
 ChainBuilder.C:161
 ChainBuilder.C:162
 ChainBuilder.C:163
 ChainBuilder.C:164
 ChainBuilder.C:165
 ChainBuilder.C:166
 ChainBuilder.C:167
 ChainBuilder.C:168
 ChainBuilder.C:169
 ChainBuilder.C:170
 ChainBuilder.C:171
 ChainBuilder.C:172
 ChainBuilder.C:173
 ChainBuilder.C:174
 ChainBuilder.C:175
 ChainBuilder.C:176
 ChainBuilder.C:177
 ChainBuilder.C:178
 ChainBuilder.C:179
 ChainBuilder.C:180
 ChainBuilder.C:181
 ChainBuilder.C:182
 ChainBuilder.C:183
 ChainBuilder.C:184
 ChainBuilder.C:185
 ChainBuilder.C:186
 ChainBuilder.C:187
 ChainBuilder.C:188
 ChainBuilder.C:189
 ChainBuilder.C:190
 ChainBuilder.C:191
 ChainBuilder.C:192
 ChainBuilder.C:193
 ChainBuilder.C:194
 ChainBuilder.C:195
 ChainBuilder.C:196
 ChainBuilder.C:197
 ChainBuilder.C:198
 ChainBuilder.C:199
 ChainBuilder.C:200
 ChainBuilder.C:201
 ChainBuilder.C:202
 ChainBuilder.C:203
 ChainBuilder.C:204
 ChainBuilder.C:205
 ChainBuilder.C:206
 ChainBuilder.C:207
 ChainBuilder.C:208
 ChainBuilder.C:209
 ChainBuilder.C:210
 ChainBuilder.C:211
 ChainBuilder.C:212
 ChainBuilder.C:213
 ChainBuilder.C:214
 ChainBuilder.C:215
 ChainBuilder.C:216
 ChainBuilder.C:217
 ChainBuilder.C:218
 ChainBuilder.C:219
 ChainBuilder.C:220
 ChainBuilder.C:221
 ChainBuilder.C:222
 ChainBuilder.C:223
 ChainBuilder.C:224
 ChainBuilder.C:225
 ChainBuilder.C:226
 ChainBuilder.C:227
 ChainBuilder.C:228
 ChainBuilder.C:229
 ChainBuilder.C:230
 ChainBuilder.C:231
 ChainBuilder.C:232
 ChainBuilder.C:233
 ChainBuilder.C:234
 ChainBuilder.C:235
 ChainBuilder.C:236
 ChainBuilder.C:237
 ChainBuilder.C:238
 ChainBuilder.C:239
 ChainBuilder.C:240
 ChainBuilder.C:241
 ChainBuilder.C:242
 ChainBuilder.C:243
 ChainBuilder.C:244
 ChainBuilder.C:245
 ChainBuilder.C:246
 ChainBuilder.C:247
 ChainBuilder.C:248
 ChainBuilder.C:249
 ChainBuilder.C:250
 ChainBuilder.C:251
 ChainBuilder.C:252
 ChainBuilder.C:253
 ChainBuilder.C:254
 ChainBuilder.C:255
 ChainBuilder.C:256
 ChainBuilder.C:257
 ChainBuilder.C:258
 ChainBuilder.C:259
 ChainBuilder.C:260
 ChainBuilder.C:261
 ChainBuilder.C:262
 ChainBuilder.C:263
 ChainBuilder.C:264
 ChainBuilder.C:265
 ChainBuilder.C:266
 ChainBuilder.C:267
 ChainBuilder.C:268
 ChainBuilder.C:269
 ChainBuilder.C:270
 ChainBuilder.C:271
 ChainBuilder.C:272
 ChainBuilder.C:273
 ChainBuilder.C:274
 ChainBuilder.C:275
 ChainBuilder.C:276
 ChainBuilder.C:277
 ChainBuilder.C:278
 ChainBuilder.C:279
 ChainBuilder.C:280
 ChainBuilder.C:281
 ChainBuilder.C:282
 ChainBuilder.C:283
 ChainBuilder.C:284
 ChainBuilder.C:285
 ChainBuilder.C:286
 ChainBuilder.C:287
 ChainBuilder.C:288
 ChainBuilder.C:289
 ChainBuilder.C:290
 ChainBuilder.C:291
 ChainBuilder.C:292
 ChainBuilder.C:293
 ChainBuilder.C:294
 ChainBuilder.C:295
 ChainBuilder.C:296
 ChainBuilder.C:297
 ChainBuilder.C:298
 ChainBuilder.C:299
 ChainBuilder.C:300
 ChainBuilder.C:301
 ChainBuilder.C:302
 ChainBuilder.C:303
 ChainBuilder.C:304
 ChainBuilder.C:305
 ChainBuilder.C:306
 ChainBuilder.C:307
 ChainBuilder.C:308
 ChainBuilder.C:309
 ChainBuilder.C:310
 ChainBuilder.C:311
 ChainBuilder.C:312
 ChainBuilder.C:313
 ChainBuilder.C:314
 ChainBuilder.C:315
 ChainBuilder.C:316
 ChainBuilder.C:317
 ChainBuilder.C:318
 ChainBuilder.C:319
 ChainBuilder.C:320
 ChainBuilder.C:321
 ChainBuilder.C:322
 ChainBuilder.C:323
 ChainBuilder.C:324
 ChainBuilder.C:325
 ChainBuilder.C:326
 ChainBuilder.C:327
 ChainBuilder.C:328
 ChainBuilder.C:329
 ChainBuilder.C:330
 ChainBuilder.C:331
 ChainBuilder.C:332
 ChainBuilder.C:333
 ChainBuilder.C:334
 ChainBuilder.C:335
 ChainBuilder.C:336
 ChainBuilder.C:337
 ChainBuilder.C:338
 ChainBuilder.C:339
 ChainBuilder.C:340
 ChainBuilder.C:341
 ChainBuilder.C:342
 ChainBuilder.C:343
 ChainBuilder.C:344
 ChainBuilder.C:345
 ChainBuilder.C:346
 ChainBuilder.C:347
 ChainBuilder.C:348
 ChainBuilder.C:349
 ChainBuilder.C:350
 ChainBuilder.C:351
 ChainBuilder.C:352
 ChainBuilder.C:353
 ChainBuilder.C:354
 ChainBuilder.C:355
 ChainBuilder.C:356
 ChainBuilder.C:357
 ChainBuilder.C:358
 ChainBuilder.C:359
 ChainBuilder.C:360
 ChainBuilder.C:361
 ChainBuilder.C:362
 ChainBuilder.C:363
 ChainBuilder.C:364
 ChainBuilder.C:365
 ChainBuilder.C:366
 ChainBuilder.C:367
 ChainBuilder.C:368
 ChainBuilder.C:369
 ChainBuilder.C:370
 ChainBuilder.C:371
 ChainBuilder.C:372
 ChainBuilder.C:373
 ChainBuilder.C:374
 ChainBuilder.C:375
 ChainBuilder.C:376
 ChainBuilder.C:377
 ChainBuilder.C:378
 ChainBuilder.C:379
 ChainBuilder.C:380
 ChainBuilder.C:381
 ChainBuilder.C:382
 ChainBuilder.C:383
 ChainBuilder.C:384
 ChainBuilder.C:385
 ChainBuilder.C:386
 ChainBuilder.C:387
 ChainBuilder.C:388
 ChainBuilder.C:389
 ChainBuilder.C:390
 ChainBuilder.C:391
 ChainBuilder.C:392
 ChainBuilder.C:393
 ChainBuilder.C:394
 ChainBuilder.C:395
 ChainBuilder.C:396
 ChainBuilder.C:397
 ChainBuilder.C:398
 ChainBuilder.C:399
 ChainBuilder.C:400
 ChainBuilder.C:401
 ChainBuilder.C:402
 ChainBuilder.C:403
 ChainBuilder.C:404
 ChainBuilder.C:405
 ChainBuilder.C:406
 ChainBuilder.C:407
 ChainBuilder.C:408
 ChainBuilder.C:409
 ChainBuilder.C:410
 ChainBuilder.C:411
 ChainBuilder.C:412
 ChainBuilder.C:413
 ChainBuilder.C:414
 ChainBuilder.C:415
 ChainBuilder.C:416
 ChainBuilder.C:417
 ChainBuilder.C:418
 ChainBuilder.C:419
 ChainBuilder.C:420
 ChainBuilder.C:421
 ChainBuilder.C:422
 ChainBuilder.C:423
 ChainBuilder.C:424
 ChainBuilder.C:425
 ChainBuilder.C:426
 ChainBuilder.C:427
 ChainBuilder.C:428
 ChainBuilder.C:429
 ChainBuilder.C:430
 ChainBuilder.C:431
 ChainBuilder.C:432
 ChainBuilder.C:433
 ChainBuilder.C:434
 ChainBuilder.C:435
 ChainBuilder.C:436
 ChainBuilder.C:437
 ChainBuilder.C:438
 ChainBuilder.C:439
 ChainBuilder.C:440
 ChainBuilder.C:441
 ChainBuilder.C:442
 ChainBuilder.C:443
 ChainBuilder.C:444
 ChainBuilder.C:445
 ChainBuilder.C:446
 ChainBuilder.C:447
 ChainBuilder.C:448
 ChainBuilder.C:449
 ChainBuilder.C:450
 ChainBuilder.C:451
 ChainBuilder.C:452
 ChainBuilder.C:453
 ChainBuilder.C:454
 ChainBuilder.C:455
 ChainBuilder.C:456
 ChainBuilder.C:457
 ChainBuilder.C:458
 ChainBuilder.C:459
 ChainBuilder.C:460
 ChainBuilder.C:461
 ChainBuilder.C:462
 ChainBuilder.C:463
 ChainBuilder.C:464
 ChainBuilder.C:465
 ChainBuilder.C:466
 ChainBuilder.C:467
 ChainBuilder.C:468
 ChainBuilder.C:469
 ChainBuilder.C:470
 ChainBuilder.C:471
 ChainBuilder.C:472
 ChainBuilder.C:473
 ChainBuilder.C:474
 ChainBuilder.C:475
 ChainBuilder.C:476
 ChainBuilder.C:477
 ChainBuilder.C:478
 ChainBuilder.C:479
 ChainBuilder.C:480
 ChainBuilder.C:481
 ChainBuilder.C:482
 ChainBuilder.C:483
 ChainBuilder.C:484
 ChainBuilder.C:485
 ChainBuilder.C:486
 ChainBuilder.C:487
 ChainBuilder.C:488
 ChainBuilder.C:489
 ChainBuilder.C:490
 ChainBuilder.C:491
 ChainBuilder.C:492
 ChainBuilder.C:493
 ChainBuilder.C:494
 ChainBuilder.C:495
 ChainBuilder.C:496
 ChainBuilder.C:497
 ChainBuilder.C:498
 ChainBuilder.C:499
 ChainBuilder.C:500
 ChainBuilder.C:501
 ChainBuilder.C:502
 ChainBuilder.C:503
 ChainBuilder.C:504
 ChainBuilder.C:505
 ChainBuilder.C:506
 ChainBuilder.C:507
 ChainBuilder.C:508
 ChainBuilder.C:509
 ChainBuilder.C:510
 ChainBuilder.C:511
 ChainBuilder.C:512
 ChainBuilder.C:513
 ChainBuilder.C:514
 ChainBuilder.C:515
 ChainBuilder.C:516
 ChainBuilder.C:517
 ChainBuilder.C:518
 ChainBuilder.C:519
 ChainBuilder.C:520
 ChainBuilder.C:521
 ChainBuilder.C:522
 ChainBuilder.C:523
 ChainBuilder.C:524
 ChainBuilder.C:525
 ChainBuilder.C:526
 ChainBuilder.C:527
 ChainBuilder.C:528
 ChainBuilder.C:529
 ChainBuilder.C:530
 ChainBuilder.C:531
 ChainBuilder.C:532
 ChainBuilder.C:533
 ChainBuilder.C:534
 ChainBuilder.C:535
 ChainBuilder.C:536
 ChainBuilder.C:537
 ChainBuilder.C:538
 ChainBuilder.C:539
 ChainBuilder.C:540
 ChainBuilder.C:541
 ChainBuilder.C:542
 ChainBuilder.C:543
 ChainBuilder.C:544
 ChainBuilder.C:545
 ChainBuilder.C:546
 ChainBuilder.C:547
 ChainBuilder.C:548
 ChainBuilder.C:549
 ChainBuilder.C:550
 ChainBuilder.C:551
 ChainBuilder.C:552
 ChainBuilder.C:553
 ChainBuilder.C:554
 ChainBuilder.C:555
 ChainBuilder.C:556
 ChainBuilder.C:557
 ChainBuilder.C:558
 ChainBuilder.C:559
 ChainBuilder.C:560
 ChainBuilder.C:561
 ChainBuilder.C:562
 ChainBuilder.C:563
 ChainBuilder.C:564
 ChainBuilder.C:565
 ChainBuilder.C:566
 ChainBuilder.C:567
 ChainBuilder.C:568
 ChainBuilder.C:569
 ChainBuilder.C:570
 ChainBuilder.C:571
 ChainBuilder.C:572
 ChainBuilder.C:573
 ChainBuilder.C:574
 ChainBuilder.C:575
 ChainBuilder.C:576
 ChainBuilder.C:577
 ChainBuilder.C:578
 ChainBuilder.C:579
 ChainBuilder.C:580
 ChainBuilder.C:581
 ChainBuilder.C:582
 ChainBuilder.C:583
 ChainBuilder.C:584
 ChainBuilder.C:585
 ChainBuilder.C:586
 ChainBuilder.C:587
 ChainBuilder.C:588
 ChainBuilder.C:589
 ChainBuilder.C:590
 ChainBuilder.C:591
 ChainBuilder.C:592
 ChainBuilder.C:593
 ChainBuilder.C:594
 ChainBuilder.C:595
 ChainBuilder.C:596
 ChainBuilder.C:597
 ChainBuilder.C:598
 ChainBuilder.C:599
 ChainBuilder.C:600
 ChainBuilder.C:601
 ChainBuilder.C:602
 ChainBuilder.C:603
 ChainBuilder.C:604
 ChainBuilder.C:605
 ChainBuilder.C:606
 ChainBuilder.C:607
 ChainBuilder.C:608
 ChainBuilder.C:609
 ChainBuilder.C:610
 ChainBuilder.C:611
 ChainBuilder.C:612
 ChainBuilder.C:613
 ChainBuilder.C:614
 ChainBuilder.C:615
 ChainBuilder.C:616
 ChainBuilder.C:617
 ChainBuilder.C:618
 ChainBuilder.C:619
 ChainBuilder.C:620
 ChainBuilder.C:621
 ChainBuilder.C:622
 ChainBuilder.C:623
 ChainBuilder.C:624
 ChainBuilder.C:625
 ChainBuilder.C:626
 ChainBuilder.C:627
 ChainBuilder.C:628
 ChainBuilder.C:629
 ChainBuilder.C:630
 ChainBuilder.C:631
 ChainBuilder.C:632
 ChainBuilder.C:633
 ChainBuilder.C:634
 ChainBuilder.C:635
 ChainBuilder.C:636
 ChainBuilder.C:637
 ChainBuilder.C:638
 ChainBuilder.C:639
 ChainBuilder.C:640
 ChainBuilder.C:641
 ChainBuilder.C:642
 ChainBuilder.C:643
 ChainBuilder.C:644
 ChainBuilder.C:645
 ChainBuilder.C:646
 ChainBuilder.C:647
 ChainBuilder.C:648
 ChainBuilder.C:649
 ChainBuilder.C:650
 ChainBuilder.C:651
 ChainBuilder.C:652
 ChainBuilder.C:653
 ChainBuilder.C:654
 ChainBuilder.C:655
 ChainBuilder.C:656
 ChainBuilder.C:657
 ChainBuilder.C:658
 ChainBuilder.C:659
 ChainBuilder.C:660
 ChainBuilder.C:661
 ChainBuilder.C:662
 ChainBuilder.C:663
 ChainBuilder.C:664
 ChainBuilder.C:665
 ChainBuilder.C:666
 ChainBuilder.C:667
 ChainBuilder.C:668
 ChainBuilder.C:669
 ChainBuilder.C:670
 ChainBuilder.C:671
 ChainBuilder.C:672
 ChainBuilder.C:673
 ChainBuilder.C:674
 ChainBuilder.C:675
 ChainBuilder.C:676
 ChainBuilder.C:677
 ChainBuilder.C:678
 ChainBuilder.C:679
 ChainBuilder.C:680
 ChainBuilder.C:681
 ChainBuilder.C:682
 ChainBuilder.C:683
 ChainBuilder.C:684
 ChainBuilder.C:685
 ChainBuilder.C:686
 ChainBuilder.C:687
 ChainBuilder.C:688
 ChainBuilder.C:689
 ChainBuilder.C:690
 ChainBuilder.C:691
 ChainBuilder.C:692
 ChainBuilder.C:693
 ChainBuilder.C:694
 ChainBuilder.C:695
 ChainBuilder.C:696
 ChainBuilder.C:697
 ChainBuilder.C:698
 ChainBuilder.C:699
 ChainBuilder.C:700
 ChainBuilder.C:701
 ChainBuilder.C:702
 ChainBuilder.C:703
 ChainBuilder.C:704
 ChainBuilder.C:705
 ChainBuilder.C:706
 ChainBuilder.C:707
 ChainBuilder.C:708
 ChainBuilder.C:709
 ChainBuilder.C:710
 ChainBuilder.C:711
 ChainBuilder.C:712
 ChainBuilder.C:713
 ChainBuilder.C:714
 ChainBuilder.C:715
 ChainBuilder.C:716
 ChainBuilder.C:717
 ChainBuilder.C:718
 ChainBuilder.C:719
 ChainBuilder.C:720
 ChainBuilder.C:721
 ChainBuilder.C:722
 ChainBuilder.C:723
 ChainBuilder.C:724
 ChainBuilder.C:725
 ChainBuilder.C:726
 ChainBuilder.C:727
 ChainBuilder.C:728
 ChainBuilder.C:729
 ChainBuilder.C:730
 ChainBuilder.C:731
 ChainBuilder.C:732
 ChainBuilder.C:733
 ChainBuilder.C:734