ROOT logo
#include <string.h>
#include <iostream>
#include <iomanip>
#include "TClass.h"
#include "TROOT.h"
#include "TFile.h"
#include "TTree.h"
#include "TBranch.h"
#include "TInterpreter.h"
#include "TDatime.h"
#include "TSystem.h"
#include "TChain.h"
#include "hades.h"
#include "htree.h"
#include "hdebug.h"
#include "hruntimedb.h"
#include "htaskset.h"
#include "hreconstructor.h"
#include "hspectrometer.h"
#include "hdatasource.h"
#include "heventheader.h"
#include "hevent.h"
#include "hrecevent.h"
#include "hmessagemgr.h"
#include "hldfileoutput.h"
#include "hpario.h"
#include "hldfilesource.h"
#include "hrootsource.h"
#include "hgeantmedia.h"
#include "hsrckeeper.h"

using namespace std;

//*-- Author : Manuel Sanchez
//*-- Modified : 23/07/2004 bj J.Wuestenfeld
//*-- Modified : 09/02/2004 by R. Holzmann
//*-- Modified : 16/09/2003 by R. Holzmann
//*-- Modified : 21/02/2003 by I. Koenig
//*-- Modified : 29/10/2002 by R. Holzmann
//*-- Modified : 24/04/2002 by Joern Wuestenfeld
//*-- Modified : 07/01/2002 by Ilse Koenig
//*-- Modified : 23/11/2001 by Ilse Koenig
//*-- Modified : 10/05/2001 by R. Holzmann
//*-- Modified : 21/04/2001 by R. Holzmann
//*-- Modified : 15/02/2000 by Ilse Koenig
//*-- Modified : 03/03/2000 by Ilse Koenig
//*-- Modified : 01/02/2000 by Manuel Sanchez
//*-- Modified : 16/3/99 by R. Holzmann
//*-- Modified : 26/11/98 by Ilse Koenig
//*-- Modified : 3/11/98/ by Manuel Sanchez
//*-- Modified : 1/10/1998 by Manuel Sanchez
//*-- Modified : 27/05/98 12:01 by Manuel Sanchez
//*-- Copyright : GENP (Univ. Santiago de Comp.)
//_HADES_CLASS_DESCRIPTION
/////////////////////////////////////////
//  Hades Begin_Html <a href="Hades_class.gif">(UML Diagram)</a> End_Html
//
//  Hades is the main control class for the reconstruction program.
//
//  There must be one and only one object of this class in the program. This
//  object will be accesible anywhere in the reconstruction program or the
//  external macros through the global pointer gHades.
//
//  See the initialization section in the HYDRA manual for more information..
/////////////////////////////////////////////////////


Int_t Hades::EventCounter = 0;
Int_t Hades::doEmbedding  = 0;
Int_t Hades::doEmbeddingDebug  = 0;
Bool_t Hades::forceNoSkip = kFALSE;
Int_t Hades::fembeddingRealTrackId=-500;

ClassImp(Hades)

Hades::Hades(void)
{
    //Default constructor for Hades. It sets the global pointer gHades.
    //This constructor also creates one HDebug object if none exists.
    gHades = this;
    if (!gDebuger) { gDebuger = new HDebug; }

    fCurrentEvent     = NULL;
    fDataSource       = NULL;
    fSecondDataSource = NULL;
    fHldOutput        = NULL;
    fOutputFile       = NULL;
    fSplitLevel       = 2;
    fTree             = NULL;
    fCounter          = 0;
    rtdb              = HRuntimeDb::instance();
    setup             = new HSpectrometer();

    defineTaskSets();

    quiet            = 0;
    fFirstEventLoop  = kTRUE;
    fCycleNumber     = 0;
    fOutputSizeLimit = 1900000000;
    TTree::SetMaxTreeSize(2000000000); // set >fOutputSizeLimit to avoid conflict
    // with Root's TTree::Fill() size checking
    treeBufferSize   = 8000;
    // Adding new messsage handler
    oldHdlr    = GetErrorHandler();
    msgHandler = new HMessageMgr("Hades","Hades");
    SetErrorHandler(&msgHandler->hydraErrorHandler);
    reqEvents  = 0;
    enableCloseInput = kTRUE;
    isHldSource = kFALSE;
    writeHades  = kFALSE;
    writeEvent  = kTRUE;
    fTaskListStatus = 0;
    fgeantMedia = 0;
    fsrckeeper  = new HSrcKeeper("Hades_src","Hades_src");
    fbeamtimeID = 0; // unknown
    fExtEvent   = kFALSE;
}


Hades::~Hades(void)
{
    //Closes the reconstruction program. If there are unsaved data, it saves them
    //When using Hades within a macro don't forget to call the destructor,
    //or data won't be saved.
    closeOutput();
    if (fTree)             delete fTree;
    if (fCurrentEvent)     delete fCurrentEvent;
    if (fHldOutput)        delete fHldOutput;
    if (fDataSource)       delete fDataSource;
    if (fSecondDataSource) delete fSecondDataSource;
    if (rtdb)              delete rtdb;
    if (setup)             delete setup;
    if (fTaskList) {
	fTaskList->Delete();
	delete fTaskList;
	fTaskList = NULL;
	fTask     = NULL;
    }
    if(msgHandler) delete msgHandler;
    SetErrorHandler(oldHdlr);
    if(fgeantMedia) {
	delete fgeantMedia;
	fgeantMedia = NULL;
    }
    gHades = NULL;
}

void Hades::defineTaskSets()
{  // set up empty task sets for all trigger types

    // Do not remove old names ...only add new once
    // The tasklists have to be created before they
    // are configured since they might be called
    // before the first event
    fTask = NULL;

    fTaskList = new TObjArray(25);

    fTaskList->AddAt(new HTaskSet("simulation"        ,"Main task for simulation events")       , 0);

    fTaskList->AddAt(new HTaskSet("real1"             ,"Main task for real1 events")            , 1);
    fTaskList->AddAt(new HTaskSet("real2"             ,"Main task for real2 events")            , 2);
    fTaskList->AddAt(new HTaskSet("real3"             ,"Main task for real3 events")            , 3);
    fTaskList->AddAt(new HTaskSet("real4"             ,"Main task for real4 events")            , 4);
    fTaskList->AddAt(new HTaskSet("real5"             ,"Main task for real5 events")            , 5);
    fTaskList->AddAt(new HTaskSet("real6"             ,"Main task for real6 events")            , 6);
    fTaskList->AddAt(new HTaskSet("real7"             ,"Main task for real7 events")            , 7);
    fTaskList->AddAt(new HTaskSet("real8"             ,"Main task for real8 events")            , 8);

    fTaskList->AddAt(new HTaskSet("MDCcalibration"    ,"Main task for MDC calibration events")  , 9);
    fTaskList->AddAt(new HTaskSet("SHOWERcalibration" ,"Main task for SHOWERcalibration events"), 10);
    fTaskList->AddAt(new HTaskSet("SHOWERpedestals"   ,"SHOWERpedestals")                       , 11);
    fTaskList->AddAt(new HTaskSet("RICHpedestals"     ,"RICHpedestals")                         , 12);

    fTaskList->AddAt(new HTaskSet("CTSStatusConfig"   ,"CTSStatusConfig")                       , 14);

    fTaskList->AddAt(new HTaskSet("real"              ,"Main task for all real events")         , 16);
    fTaskList->AddAt(new HTaskSet("calibration"       ,"Main task for all calibration events")  , 17);

    fTaskList->AddAt(new HTaskSet("all"               ,"Main task for all events")              , 18);


    // compatibility
    fTaskList->AddAt(new HTaskSet("special1","sep03")      ,19);
    fTaskList->AddAt(new HTaskSet("offspill","sep03")      ,20);
    fTaskList->AddAt(new HTaskSet("special3","sep03")      ,21);
    fTaskList->AddAt(new HTaskSet("special5","sep03")      ,22);
    fTaskList->AddAt(new HTaskSet("beginrun","sep03")      ,23);
    fTaskList->AddAt(new HTaskSet("endrun"  ,"sep03")      ,24);




}

Int_t Hades::mapId(Int_t id)
{
    if (id >= 0 && id < MAXEVID) return evIdMap[id];
    else                         return -1;
}

Int_t Hades::setAlgorithmLayout(Text_t *fileName)
{
    //This method is used to build the reconstructor's graph. For that purpose
    //the macro in the file "fileName" is executed.
    //
    //Returns 0 if successfull.
    return gROOT->Macro(fileName);
}

Int_t Hades::setEventLayout(Text_t *fileName)
{
    //This method is intended to build the event's structure. For that purpose
    //the macro in the file "fileName" is executed.
    //
    //Returns 0 if succesfull.
    if (fTree) delete fTree;
    fTree = NULL;
    return gROOT->Macro(fileName);
}

Int_t Hades::setConfig(Text_t *fileName)
{
    // This method is used to interpret a "configuration macro". Within this
    // macro all the information to run the analisys is given. This is an
    // alternative way of initialization without using setEventLayout(),
    // setAlgorithmLayout()...
    //
    // For more information on initialization see the initialization section in
    // the HYDRA manual.
    //
    // Within this macro the user is responsible of calling the Hades::init()
    // function before the call to Hades::makeTree();

    if (gROOT->Macro(fileName)) return kTRUE;
    else                        return kFALSE;
}

Bool_t Hades::init(Bool_t externInit)
{
    // This function initializes Hades. This includes initialization of the
    // reconstructors, the data source and the detectors.

    rtdb->initContainers(fDataSource->getCurrentRunId(),
			 fDataSource->getCurrentRefId());
    if(!setup->init()) return kFALSE;


    if(!externInit){
	fDataSource->setEventAddress(&fCurrentEvent);

	if (!fDataSource->init()){
	    Error("init","Error in fDataSource->init()");
	    return kFALSE;
	}
	TString sourcetype = fDataSource->IsA()->GetName();
	if(sourcetype.CompareTo("HldFileSource") == 0)isHldSource = kTRUE;
	else                                          isHldSource = kFALSE;

	if (fSecondDataSource) {
	    fSecondDataSource->setEventAddress(&fCurrentEvent);
	    if (!fSecondDataSource->init()){
		Error("init","Error in fSecondDataSource->init()");
		return kFALSE;
	    }
	}

    }
    Int_t vers = ((fCurrentEvent->getHeader()->getVersion()));
    initTaskSetsIDs(vers);

    if (!initTasks()) return kFALSE;
    else              return kTRUE;
}

Bool_t Hades::isCalibration()
{ // is event a calibration event?
    HEventHeader *head = fCurrentEvent->getHeader();
    if (!head) {
	Error("isCalibration", "No event header found, exiting...");
	exit(1);
    }
    Int_t id = head->getId();
    Int_t version = head->getVersion() & 0xF;
    if (version == 0) {
	if (id == 2 || id == 3 || id == 4 || id == 5 || id == 6 || id == 7 || id == 8 || id == 9){
	    return kTRUE;
	}
    }
    else if (version == 1) {
	if (id == 7 || id == 9) { return kTRUE; }
    }
    else if (version == 2) {
	if (id >= 9 && id <= 12) { return kTRUE; }
    }
    return kFALSE;
}

Bool_t Hades::isReal()
{ // is event a real event?
    // The event with the sequence number == 0 is a very special event
    // which needs special treatment (does not contain any data, it is
    // header only, should be skipped from the analysis!!!). It is only
    // in the real data and has ID == 2 and Version == 0 (between jan04
    // and may06) which points to a calibration event...

    HEventHeader *head = fCurrentEvent->getHeader();
    if (!head) {
	Error("isReal", "No event header found, exiting...");
	exit(1);
    }

    Int_t id = head->getId();
    Int_t version = head->getVersion() & 0xF;

    if (head->getEventSeqNumber() == 0) {
	if (version == 0 && id == 2) { return kTRUE; }
    } else {
	if (version == 0) {
	    if (id == 1) { return kTRUE; }
	}
	else if (version == 1) {
	    if (id == 1 || id == 2 || id == 3 || id == 4 || id == 5) { return kTRUE; }
	}
        else if (version == 2) {
	    if (id >= 1 && id <= 8 ) { return kTRUE; }
	}
    }
    return kFALSE;
}

Bool_t  Hades::initTasks()
{
    HTaskSet* task;
    TIter iter(fTaskList);

    while((task = (HTaskSet*)iter())) {
	if (!task->init()) { Error("init()","Error returned from %s!",task->GetName()); return kFALSE; }
    }
    return kTRUE;
}

Bool_t Hades::reinitTasks()
{
    HTaskSet* task;
    TIter iter(fTaskList);

    while((task = (HTaskSet*)iter())) {
	if (!task->reinit()) { Error("reinit()","Error returned from %s!",task->GetName());return kFALSE; }
    }
    return kTRUE;
}

Bool_t Hades::finalizeTasks()
{
    HTaskSet* task;
    TIter iter(fTaskList);

    while((task = (HTaskSet*)iter())) {
	if (!task->finalize()) { return kFALSE; }
    }
    return kTRUE;
}

Int_t Hades::executeTasks()
{
    HTaskSet* task;
    TIter iter(fTaskList);
    Int_t returnVal = 0;

    UInt_t evtId = fCurrentEvent->getHeader()->getId();

    getTaskSet("all")->next(returnVal);  // allways execute this task set
    if (returnVal < 0 && returnVal != -99) return returnVal;
    while((task = (HTaskSet*)iter())) {
	if(mapId(evtId) !=-1) task->next(returnVal,evtId);  // execute all task sets responsible for given evtId(s),
	if (returnVal < 0 && returnVal != -99) { break; }   // but stop loop on first error/fSkipEvent
    }

    return returnVal;
}

HTaskSet* Hades::getTask()
{  // returns default set (=real events)
    return getTaskSet("real");
}

HTask* Hades::getTask(const Char_t *name)
{   // search task by name in all sets
    HTaskSet* taskSet;
    HTask* task = NULL;
    for (Int_t i = 0; i < fTaskList->GetSize(); i ++) {
	if ( (taskSet = (HTaskSet*)fTaskList->At(i)) ) {
	    if ( (task = taskSet->getTask(name)) ) { return task; } // first occurence
	}
    }
    return NULL;   // not found in any of the sets
}

HTaskSet* Hades::getTaskSet(Int_t nEvtId)
{  // find task set by event id

    Int_t ind = mapId(nEvtId);   // old/new mapping

    if (ind >= 0 && ind < fTaskList->GetSize()) { return (HTaskSet*)fTaskList->At(ind); }
    else                                        { return NULL; }
}

HTaskSet* Hades::getTaskSet(const Char_t *evtTypeName)
{ // find task set by name

    HTaskSet* taskSet;
    for (Int_t i = 0; i < fTaskList->GetSize(); i ++) {
	if ( (taskSet = (HTaskSet*)fTaskList->At(i)) ) {
	    if (strcmp(taskSet->GetName(),evtTypeName) == 0) { return taskSet; }
	}
    }

    return NULL;
}

HEvent *&Hades::getCurrentEvent(void)
{
    //Returns a pointer to the event in reconstruction
    return fCurrentEvent;
}

void Hades::setEvent(HEvent *ev,Bool_t remove)
{
    // This function sets the event layout to that given by "ev". The user first
    // builds the event layout by creating an HEvent object and then call this
    // function; which sets the data member fCurrentEvent.
    //
    // This function is typically called from the macro invoked in
    // setEventLayout()
    if (fCurrentEvent&&remove) delete fCurrentEvent;
    fCurrentEvent = ev;
    if(!remove) fExtEvent = kTRUE;
}

void Hades::setDataSource(HDataSource *dataS)
{
    // Method used to establish the data source where data are taken from. For
    // that purpose an object of a class derived from HDataSource is created and
    // the setDataSource() method is called to pass a pointer to this object
    //
    //  This function should be called typically from the macro invoked with
    //  setConfig()
    fDataSource=dataS;
}

void Hades::setSecondDataSource(HDataSource *dataS)
{
    // Set second data source (needed e.g. for event merging).
    // Must be a Root source!
    if (dataS != NULL) {
	if (dataS->InheritsFrom("HRootSource") ) {
	    fSecondDataSource=dataS;
	} else {
	    Error("setSecondDataSource()","Second Datasource does not inherit from HRootSource! Ignored!");
	    fSecondDataSource = NULL;
	}
    } else { fSecondDataSource = NULL; }
}

Bool_t Hades::setHldOutput(Text_t* filedir,const Text_t* fileSuffix,const Option_t* option)
{
    // Creates an HLD file output
    if (fHldOutput) delete fHldOutput;
    if (fDataSource && fDataSource->InheritsFrom("HldSource")) {
	fHldOutput = new HldFileOutput((HldSource*)fDataSource,filedir,fileSuffix,option);
	return kTRUE;
    } else {
	Error("setHldOutput","No HLD data source!");
	return kFALSE;
    }
}

void Hades::setSplitLevel(Int_t splitLevel)
{
    //Method used to control the shape of the output Root tree for the events..
    //Three split levels are supported:
    //
    //  splitLevel=0 ---> An only branch is created for the event, which is
    //                    stored as a whole (i.e. the whole HEvent is stored as
    //                    one piece).
    //
    //  splitLevel=1 ---> The partial events are stored as a whole, meanwhile the
    //                    top of the event class (tracks, header ...) is stored
    //			creating one TBranch per data member
    //
    //  splitLevel=2 ---> One branch per data member is created (with little
    //			exceptions, see Root automatic split rules). However
    //			the categories (see HCategory) still can decide how the
    //			split is done (by creating their own branches). This
    //                    is the default value set by the Hades constructor
    //
    fSplitLevel = splitLevel;
}

Int_t Hades::getSplitLevel(void)
{
    //Returns the current splitLevel (see setSplitLevel() )
    return fSplitLevel;
}

Bool_t Hades::setOutputFile(Text_t *name,
			    Option_t *opt,
			    Text_t *title,
			    Int_t comp)
{
    //Sets the output file, giving its name, compresion level...
    //For more information on the parameters see the constructor of TFile
    //
    //  This method allocates the file indicated taking care of saving the
    //current file if any. If the file does not exist or the user wants it to be
    //overwritten, then opt="RECREATE"; if the file already exists and is to be
    //updated then opt="UPDATE"...
    //
    fOutputFileName = name;
    fOutputFileName.Remove(fOutputFileName.Length() - 4 - 1);
    closeOutput();
    fOutputFile = new TFile(name,opt,title,comp);
    return kTRUE;
}

HTree *Hades::getTree(void)
{
    //Returns a pointer to the current output Root tree of events
    return fTree;
}

void Hades::activateTree(TTree *tree)
{
    // Sets the right branch address and branch status (=1) for all the branches
    // in tree which correspond to the branches which would eventually be
    // generated for the output Root tree of events if the function makeTree() is
    // called.
    //
    // This mechanism allows to only read those branches in "tree" which are
    // neccesary to fill an event as defined in setEventLayout()
#if DEBUG_LEVEL>2
    gDebuger->enterFunc("Hades::activateTree");
#endif
    Int_t splitLevel = 2;
    TBranch *brEvent = 0;

    Char_t sl = *(strchr(tree->GetTitle(),'.') + 1);
    switch (sl) {
    case '0' : splitLevel = 0;
    break;
    case '1' : splitLevel = 1;
    break;
    case '2' : splitLevel = 2;
    break;
    default : splitLevel  = fSplitLevel;
    }
    if (fCurrentEvent)
    {
	tree->SetBranchStatus("*",1);   // needed since Root 303-04 because of
	// change in TBranchElement::SetAddress()
	if (splitLevel == 0)
	{
	    tree->SetBranchAddress("Event",&fCurrentEvent);
	    tree->SetBranchStatus("Event",1);
	} else {
	    brEvent = tree->GetBranch("Event.");
	    if (brEvent) { //Post ROOT3 splitting
		brEvent->SetAddress(&fCurrentEvent);
		tree->SetBranchStatus("Event.",1);
		tree->SetBranchStatus("Event.*",1);
	    } else { //Pre ROOT3 splitting
		brEvent = tree->GetBranch("Event");
		if (brEvent) {
		    tree->SetBranchAddress("Event",&fCurrentEvent);
		    tree->SetBranchStatus("Event",1);
		    tree->SetBranchStatus("Event.*",1);
		} else {
		    Warning("activateBranch","Event branch not found in tree");
		}
	    }
	    fCurrentEvent->activateBranch(tree,splitLevel);
	}
    }
#if DEBUG_LEVEL>2
    gDebuger->leaveFunc("Hades::activateTree");
#endif
}


Bool_t Hades::makeTree(void)
{
    // Creates an output tree from the information in the event structure
    // and according to the splitLevel (see setSplitLevel() )
    TBranch *b = NULL;
    Bool_t r   = kFALSE;
    Text_t treeTitle[255];

    if (fTree) delete fTree;

    sprintf(treeTitle,"T.%i",fSplitLevel);

    if (fOutputFile) { fOutputFile->cd(); } // Make sure output file is current file

    fTree = new HTree("T",treeTitle);
    gTree = fTree;
    if (fCurrentEvent && fTree)
    {
	if (fSplitLevel==0) {
	    b = fTree->Branch("Event",
			      fCurrentEvent->ClassName(),
			      &fCurrentEvent,64000,0);
	} else {
	    b = fTree->Branch("Event.",
			      fCurrentEvent->ClassName(),
			      &fCurrentEvent,getTreeBufferSize(),99);
	    fCurrentEvent->makeBranch(b,gHades->getTree());
	}
	if (b) {
	    r = kTRUE;
	}
    }
    return r;
}
Int_t Hades::getCurrentRunId(HDataSource* source)
{
    if(source->getCurrentRefId() == -1) return source->getCurrentRunId();
    else                                return source->getCurrentRefId();
}

Int_t Hades::eventLoop(Int_t nEvents, Int_t firstEvent, Double_t timeQuota)
{
    //  Executes the event loop;
    //
    //  For each new event:
    //  First, the current event is cleared.
    //  Second, a new event is read from the data source (see HDataSource)
    //  Third, the reconstruction of this event is launched (see HReconstructor)
    //  Fourth, if a tree was created (see makeTree() ) then it is filled.
    //
    //  This function returns the number of events processed. A negative value
    //  corresponds to an error
    //
    //  timeQuota - time limit for tasks in minutes.
    //  timeQuota <= 0. - no limit
    //  Event loop end condition: evN==nEvents or runing tasks time > timeQuota
#if DEBUG_LEVEL > 2
    gDebuger->enterFunc("Hades::eventLoop");
#endif
    //----------------------------------
    // local event counters
    Int_t evN       = 0;
    Int_t lastEvent = 0;
    //----------------------------------

    //----------------------------------
    // remember error codes from datasource
    // and tasklists (needed to keep sync for second datasource)
    Int_t err                    = 0;
    Int_t errAll                 = 0;
    EDsState dsCode              = kDsOk;
    EDsState dsCode2             = kDsOk;
    //----------------------------------

    //----------------------------------
    // remember the last active run
    // to decide if reinit is needed
    Int_t oldRunId            = -1;
    //----------------------------------

    //----------------------------------
    // remember the init state of rtdb
    Bool_t initOk             = kTRUE;
    //----------------------------------


    UInt_t evtId;
    TDatime dt;
    HTaskSet *taskSet;

    reqEvents = nEvents;
    if (!(fCurrentEvent && fDataSource)) {
	Error("eventLoop","No current event or no data source set!");
	return 0;
    }

    if (fCurrentEvent->InheritsFrom("HRecEvent")) {
	// Ensure we have a monolithic streamer
	( (HRecEvent *)fCurrentEvent)->setExpandedStreamer(kFALSE);
    }

    if(!fExtEvent) fCurrentEvent->Clear();

    //----------------------------------
    // For the first event we have to init parameters
    // and reinit the tasks lists
    if (fFirstEventLoop) {

	if (!rtdb->initContainers(fDataSource->getCurrentRunId(),
				  fDataSource->getCurrentRefId(),
				  fDataSource->getCurrentFileName())) {

	    oldRunId = getCurrentRunId(fDataSource);
	    return 0;
	}

	if(fDataSource->InheritsFrom("HRootSource")){
	    HRootSource* rsrc = (HRootSource*) fDataSource;
            TFile* frsrc = rsrc->getChain()->GetCurrentFile();
	    if(frsrc){
		fgeantMedia = (HGeantMedia*) frsrc ->Get("GeantMedia");
                if(fgeantMedia) fgeantMedia->SetName("GeantMedia");
		if(!fgeantMedia) Warning("eventLoop()","Could not retrieve HGeantMedia from first datasource!");
	    } else Warning("eventLoop()","Could not retrieve file pointer from first datasource!");
	}

	if(!(reinitTasks())) {
	    gDebuger->message("An error occurred in the task list re-init");
	    return evN;
	}
	if(enableCloseInput) rtdb->disconnectInputs();
	fFirstEventLoop = kFALSE;
    }
    //----------------------------------


    //----------------------------------
    // if start event is not 0 we have to
    // skip the events before start event
    dsCode = fDataSource->skipEvents(firstEvent);
    if (dsCode == kDsOk) {
	evN = firstEvent;
    } else {
	evN = firstEvent;
	Warning("eventLoop","Condition %i while skipping events",dsCode);
    }

    if(nEvents != kMaxInt) {
	lastEvent = evN + nEvents;
    } else {
	lastEvent = nEvents;
    }
    //----------------------------------

    //----------------------------------
    // prevent the eventloop from
    // endless waiting for online monitoring
    Bool_t timerFlag = kTRUE;
    fTimer.Reset();
    timeQuota *= 60.;   // minutes -> seconds
    //----------------------------------

    //----------------------------------
    // we need to call the reinit() of the
    // unpackers
    if (!fDataSource->reinit()) {
	Error("eventLoop","An error occurred in fDataSource->reinit()");
    }
    if (fSecondDataSource) {
	if (!fSecondDataSource->reinit()) {
	    Error("eventLoop","An error occurred in fSecondDataSource->reinit()");
	}
	if(!fgeantMedia && fSecondDataSource->InheritsFrom("HRootSource")){
	    HRootSource* rsrc = (HRootSource*) fSecondDataSource;
            TFile* frsrc = rsrc->getChain()->GetCurrentFile();
	    if(frsrc){
		fgeantMedia = (HGeantMedia*) frsrc ->Get("GeantMedia");
                if(fgeantMedia) fgeantMedia->SetName("GeantMedia");
		if(!fgeantMedia) Warning("eventLoop()","Could not retrieve HGeantMedia from second datasource!");
	    } else Warning("eventLoop()","Could not retrieve file pointer from second datasource!");
	}
    }
    //----------------------------------


    //----------------------------------
    if (fHldOutput) {
	TString cf = fDataSource->getCurrentFileName();
	Int_t l = cf.Last('/');
	TString fn = cf(l + 1,cf.Length() - l);
	fHldOutput->open(fn);
    }
    //----------------------------------


    oldRunId = getCurrentRunId(fDataSource);

    while ((evN < lastEvent) && (dsCode != kDsEndData) && (dsCode != kDsError)
	   && timerFlag)
    {
	//----------------------------------
	// here comes now the real event loop
	while ((evN < lastEvent) && timerFlag)
	{

	    EventCounter ++;
	    fTimer.Start(kFALSE);

	    if(!fExtEvent) fCurrentEvent->Clear();

	    //-------------------------------------------
            // save output if file is too big and open a new one
	    if (fOutputFile) {
		if (fOutputFile->GetBytesWritten() > fOutputSizeLimit) {
		    recreateOutput();
		}
	    }
	    //-------------------------------------------


	    //-------------------------------------------
	    // If second data source exists it must be first read.
            // Reading from first data source will overwrite header later
	    if (fSecondDataSource) {
		dsCode2 = fSecondDataSource->getNextEvent();
		if(evN == 0 && isHldSource) { fSecondDataSource->setCursorToPreviousEvent(); }
		if (dsCode2 == kDsError  ) { break; }
		if (dsCode2 == kDsEndData) { dsCode = kDsEndData; break; } // secondinput finished, finish out loop too
	    }
	    //-------------------------------------------



	    //-------------------------------------------
            // now read the new event
	    dsCode = fDataSource->getNextEvent();
 	    //-------------------------------------------

 	    //-------------------------------------------------------
	    // if we reached the end of all data files or recieved an
	    // read error we have to exit the event loop
	    if (dsCode == kDsError || dsCode == kDsEndData) {
		break;
	    }
	    //-------------------------------------------------------




	    //-------------------------------------------
	    // check if reinit is needed (new run)
	    if (dsCode == kDsEndFile || (oldRunId != getCurrentRunId(fDataSource)))
	    {
		if(enableCloseInput) { initOk = rtdb->reconnectInputs(); }
		if (initOk) {
		    initOk = rtdb->initContainers(fDataSource->getCurrentRunId(),
						  fDataSource->getCurrentRefId(),
						  fDataSource->getCurrentFileName());
		}
		if (initOk) {
		    if(!(reinitTasks())) {
			gDebuger->message("An error occurred in the task list re-init");
			return evN;
		    }
		}
		if(enableCloseInput) { rtdb->disconnectInputs(); }

		if (initOk)
		{
		    if (!fDataSource->reinit()) {
			Error("eventLoop","An error occurred in fDataSource->reinit()");
		    }

		    if (fSecondDataSource) {
			if (!fSecondDataSource->reinit()) {
			    Error("eventLoop","An error occurred in fSecondDataSource->reinit()");
			}
		    }

		    if (fHldOutput) {
			TString cf = fDataSource->getCurrentFileName();
			Int_t l = cf.Last('/');
			TString fn = cf(l + 1,cf.Length() - l);
			fHldOutput->open(fn);
			fHldOutput->setHldSource((HldSource*)fDataSource);
		    }
		}
		oldRunId = getCurrentRunId(fDataSource);
	    }
	    //-------------------------------------------

	    //-------------------------------------------------------
	    // For event embbedding we have to take care
	    // about skipped events
	    if (dsCode == kDsSkip)
	    {
		// if the event is skipped the second data source has to
		// be rewind by 1 event
		if(fSecondDataSource)
		{
		    fSecondDataSource->setCursorToPreviousEvent();
		}
		// set all error flags before going to next
		// event
		continue;
	    }
	    //-------------------------------------------------------

	    err    = 99;   // init error
	    errAll = 99;   // init error


	    //-------------------------------------------------------
            // init the tasksset ids and print the definitions
	    UInt_t firstev = fCurrentEvent->getHeader()->getId();

	    if((firstev != 2 && EventCounter == 1) || (EventCounter == 2) )
	    {   // do it only once and
		// if ev is not a begin run ev
		// (kStartEvent=0xd seems to be wrong)
		Int_t vers = ((fCurrentEvent->getHeader()->getVersion()));
		initTaskSetsIDs(vers);
		printDefinedTaskSets();
	    }
	    //-------------------------------------------------------


	    getTaskSet("all")->next(errAll);  // allways execute this task set
            fTaskListStatus = errAll;
	    //-------------------------------------------------------
	    // if no task was returning a skip we have to analyze
            // the data
	    if (errAll != kSkipEvent)
	    {
		evtId = fCurrentEvent->getHeader()->getId();
		if (mapId(evtId) != -1)
		{
		    for (Int_t i = 0; i < fTaskList->GetSize(); i ++) {
			if ( (taskSet = (HTaskSet*)fTaskList->At(i)) ) {
			    taskSet->next(err,evtId); // execute all task sets responsible for given evtId(s),
                            fTaskListStatus = errAll;
			    if (err < 0 && err != -99) { break; }      // but stop loop on first error/fSkipEvent
			}
		    }
		    if(err != 0 )
		    {   // some error code was returned
			if (err != kSkipEvent) {
			    if(!quiet && err != 99) Warning("eventLoop",
							    "Exiting task set with errCode %i at event %i (Id %i)\n",err,evN,evtId);
			    if (fTree)      { fTree->Fill(); }
			    if (fHldOutput) { fHldOutput->writeEvent(); }
			} else {
			    //-------------------------------------------------------
			    // For event embbedding we have to take care
			    // about skipped events
			    if(fSecondDataSource)
			    {
				// if the event is skipped the second data source has to
				// be rewind by 1 event
				fSecondDataSource->setCursorToPreviousEvent();
			    }
			    //-------------------------------------------------------
			}

		    } else { // everything was fine
			if (fTree)      { fTree->Fill(); }
			if (fHldOutput) { fHldOutput->writeEvent(); }
		    }
		} else {
		    Warning("eventLoop","No tasklist defined for event id 0x%x.\n", evtId);
		    if (fHldOutput) { fHldOutput->writeEvent(); }
		}
	    }
	    else {

		//-------------------------------------------------------
		// For event embbedding we have to take care
		// about skipped events
		if(fSecondDataSource)
		{
		    // if the event is skipped the second data source has to
		    // be rewind by 1 event
		    fSecondDataSource->setCursorToPreviousEvent();
		}
		//-------------------------------------------------------
	    }
	    // remember for the next event if the prevoius
	    // event has been skipped

	    evN ++;
	    if(fCounter && (evN % fCounter == 0) && !quiet) {
		dt.Set();
		msgHandler->info(10,HMessageMgr::DET_ALL,GetName()," %s  Events processed: %i current Event: %i SequenceNumber: %i",
				 dt.AsSQLString() + 11, evN - firstEvent,evN,fCurrentEvent->getHeader()->getEventSeqNumber());

	    }
	    timerFlag = fTimer.RealTime() < timeQuota;
	}
    }
    if(dsCode == kDsError) { gDebuger->message("An error occurred in the event loop"); }
#if DEBUG_LEVEL > 2
    gDebuger->leaveFunc("Hades::eventLoop");
#endif
    fDataSource->finalize();
    if (!finalizeTasks()) Error("eventLoop","Unable to finalize");
    if(!timerFlag) msgHandler->info(10,HMessageMgr::DET_ALL,GetName(),"\n%.2f minutes time quota has expired.\n",
				    timeQuota / 60.);
    if(quiet != 2) {
	msgHandler->infoB(10,HMessageMgr::DET_ALL,"Total number of events processed: %i",evN - firstEvent);
	if (fHldOutput) {
	    msgHandler->infoB(10,HMessageMgr::DET_ALL,"\n\nWritten to HLD Output: Total number of events:    %i",
			      fHldOutput->getNumTotalEvt());
	    msgHandler->infoB(10,HMessageMgr::DET_ALL,"                       Number of filtered events: %i",
			      fHldOutput->getNumFilteredEvt());
	}
    }
    return evN - firstEvent;
}

Bool_t Hades::IsFolder(void) const
{
    // Returns true. This tells the Root browser to show Hades as a folder
    // holding other objects
    return kTRUE;
}

void Hades::Browse(TBrowser *b)
{
    // Used to browse the reconstructor's tree, a particular event or the
    // reconstructor's histograms...
    //
    // This function is called by Root when browsing gHades with the Root browser
    //
#if DEBUG_LEVEL>2
    gDebuger->enterFunc("Hades::Browse");
#endif
    if (fTree) { b->Add(fTree,"Tree"); }
    //b->Add(fHistBrowser);
#if DEBUG_LEVEL>2
    gDebuger->message("Adding Task list");
#endif
    if (fTaskList) { b->Add(fTaskList,"Tasks"); }
#if DEBUG_LEVEL>2
    gDebuger->message("Adding current event");
#endif
    if (fCurrentEvent) { b->Add(fCurrentEvent,"Event"); }
#if DEBUG_LEVEL>2
    gDebuger->leaveFunc("Hades::Browse");
#endif
}
void   Hades::addObjectToOutput(TObject* obj)
{
    fObjectsAddedToOutput.AddLast(obj);
}

void Hades::closeOutput(void)
{
    if (fOutputFile)
    {
	fOutputFile->cd();
	this ->Write();
	if(fgeantMedia) fgeantMedia->Write();
	fsrckeeper->Write();
        if(fObjectsAddedToOutput.GetEntries()>0) fObjectsAddedToOutput.Write();
	fOutputFile->Write();
	delete fOutputFile;
	fOutputFile = NULL;
	fTree       = 0;
    }
}

void Hades::recreateOutput(void)
{
    fCycleNumber ++;
    Bool_t createTree = (fTree != 0);
    Char_t name[255];
    TString opt(fOutputFile->GetOption());
    TString title(fOutputFile->GetTitle());
    Int_t comp = fOutputFile->GetCompressionLevel();

    closeOutput();
    sprintf(name,"%s_%i.root",fOutputFileName.Data(),fCycleNumber);

    fOutputFile = new TFile(name,"RECREATE",title.Data(),comp);
    if (createTree) { makeTree(); }

}

void Hades::Streamer(TBuffer &R__b)
{
    if (R__b.IsReading())
    {
	Version_t R__v = R__b.ReadVersion(); if (R__v) { }
	TObject::Streamer(R__b);
	setup->Streamer(R__b);
	rtdb->Streamer(R__b);
	R__b >> fSplitLevel;
	R__b >> fTaskList;
	fDataSource = NULL;
	fOutputFile = NULL;
	fCurrentEvent = (HEvent *)gDirectory->Get("Event");
	fTree = (HTree *)gDirectory->Get("T");
    } else {
	R__b.WriteVersion(Hades::IsA());
	TObject::Streamer(R__b);
        setup->Streamer(R__b);

	if(writeHades)rtdb->Streamer(R__b);
	R__b << fSplitLevel;
	if(writeHades)R__b << fTaskList;
	if (writeEvent&&fCurrentEvent)
	{
	    if (fCurrentEvent->InheritsFrom("HRecEvent")) { //!!!!
		Bool_t expand = ((HRecEvent *)fCurrentEvent)->hasExpandedStreamer();
		( (HRecEvent *)fCurrentEvent)->setExpandedStreamer(kTRUE);
		fCurrentEvent->Clear();
		fCurrentEvent->Write("Event");
		( (HRecEvent *)fCurrentEvent)->setExpandedStreamer(expand);
	    } else {
		fCurrentEvent->Clear();
		fCurrentEvent->Write("Event");
	    }
	}
    }
}

void Hades::printDefinedTaskSets()
{
    HTaskSet* task;
    TIter iter(fTaskList);
    Int_t size = 0;
    Int_t* ids;

    Int_t version = ((fCurrentEvent->getHeader()->getVersion()) & 0xF);
    cout<<"#################### HADES TASKSETS ############################"<<endl;
    if(version == 0) {cout<<"#  Version Nov02"<<endl; }
    if(version == 1) {cout<<"#  Version Sep03"<<endl; }
    if(version == 2) {cout<<"#  Version June 2010"<<endl; }

    while((task = (HTaskSet*)iter()))
    {
	ids = task->getIds(size);
	cout<<"#  "<<setw(15)<<task->GetName()<<" for Ids : "<<flush;
	for(Int_t i = 0; i < size; i ++)
	{
	    if(ids[0] == -1){cout<<"not defined"<<flush;break;}
	    if(ids[i] != -1){cout<<ids[i]<<" "<<flush;}
	}
	cout<<""<<endl;
    }
    cout<<"################################################################"<<endl;
}
void  Hades::initTaskSetsIDs(Int_t version)
{
    // Mapping of event ids into HTaskSet numbers for DAQ type old (version=0),
    // i.e prior to Sep03, and new (version=1). Since June 2010 version = 2
    //
    // This table will go in due time into an rtdb container.  (R.H.)
    //
    Int_t evIdTable[3][MAXEVID] = { { 0,16,17,17,17,17,17,17, /* Nov02  */
                                     17,17,-1,-1,-1,13,14,-1},
				    { 0, 1, 2, 3, 4, 5, 6, 7, /* Sep03  */
				      8, 9,10,-1,-1,13,14,-1},
				    { 0, 1, 2, 3, 4, 5, 6, 7, /* June2010  */
				      8, 9,10,11,12,-1,14,-1}
    };

    for (Int_t i = 0; i < MAXEVID; i ++) { evIdMap[i] = evIdTable[version][i]; }

    if (version == 0) { // Nov02
	getTaskSet("simulation")    ->setIds(0);
	getTaskSet("real")          ->setIds(1);
	getTaskSet("calibration")   ->setIds(2,3,4,5,6,7,8,9);
	getTaskSet("beginrun")      ->setIds(13);
	getTaskSet("endrun")        ->setIds(14);
    }
    else if (version == 1) { // Sep03
	getTaskSet("simulation")    ->setIds(0);
	getTaskSet("real")          ->setIds(1,2,3,4,5);
	getTaskSet("calibration")   ->setIds(7,9);
	getTaskSet("real1")         ->setIds(1);
	getTaskSet("real2")         ->setIds(2);
	getTaskSet("real3")         ->setIds(3);
	getTaskSet("real4")         ->setIds(4);
	getTaskSet("real5")         ->setIds(5);
	getTaskSet("special1")      ->setIds(6);
	getTaskSet("offspill")      ->setIds(7);
	getTaskSet("special3")      ->setIds(8);
	getTaskSet("MDCcalibration")->setIds(9);
	getTaskSet("special5")      ->setIds(10);
	getTaskSet("beginrun")      ->setIds(13);
	getTaskSet("endrun")        ->setIds(14);
    }
    else if (version == 2) { // June 2010
	getTaskSet("simulation")    ->setIds(0);
	getTaskSet("real")          ->setIds(1,2,3,4,5,6,7,8);
	getTaskSet("calibration")   ->setIds(9,10,11,12);
	getTaskSet("real1")         ->setIds(1);
	getTaskSet("real2")         ->setIds(2);
	getTaskSet("real3")         ->setIds(3);
	getTaskSet("real4")         ->setIds(4);
	getTaskSet("real5")         ->setIds(5);
	getTaskSet("real6")         ->setIds(6);
	getTaskSet("real7")         ->setIds(7);
	getTaskSet("real8")         ->setIds(8);
	getTaskSet("MDCcalibration")   ->setIds(9);
	getTaskSet("SHOWERcalibration")->setIds(10);
	getTaskSet("SHOWERpedestals")  ->setIds(11);
	getTaskSet("RICHpedestals")    ->setIds(12);
        getTaskSet("CTSStatusConfig")  ->setIds(14);

	getTaskSet("beginrun") -> setIds(-1,-1,-1,-1,-1,-1,-1,-1) ;
	getTaskSet("endrun")   -> setIds(-1,-1,-1,-1,-1,-1,-1,-1) ;
    }
    else
    {
	Error("initTaskSetsIDs()","Unknown version %i ... exiting!",version);
	exit(EXIT_FAILURE);
    }

}

Hades *gHades;


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