Changeset 7981 for trunk


Ignore:
Timestamp:
09/28/06 10:29:56 (18 years ago)
Author:
tbretz
Message:
*** empty log message ***
Location:
trunk/MagicSoft/Mars
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/MagicSoft/Mars/Changelog

    r7979 r7981  
    2626     - fixed abug introduced 14.7.2005 which caused the M3Long of the
    2727       anti source to be not properly evaluated in case of optimization.
     28
     29   * ganymed_onoff.rc, ganymed_wobble.rc:
     30     - updated with comments how to use random forest
    2831
    2932
  • trunk/MagicSoft/Mars/NEWS

    r7979 r7981  
    126126     of optimization with anti-theta cut switched on. This might have
    127127     lead to improper, but not necessarily wrong, optimization results.
     128
     129   - ganzmed: ganymed_onoff.rc, ganymed_wobble.rc - updated with comments
     130     how to use random forest
     131
    128132
    129133
  • trunk/MagicSoft/Mars/datacenter/macros/buildsequenceentries.C

    r7813 r7981  
    8181#include <fstream>
    8282
    83 #include <MSQLServer.h>
    8483#include <TSQLRow.h>
    8584#include <TSQLResult.h>
    8685
    8786#include <TEnv.h>
     87#include <TMap.h>
    8888#include <TMath.h>
    8989#include <TExMap.h>
    9090#include <TArrayI.h>
    91 #include <TRegexp.h>
     91#include <TArrayD.h>
     92#include <TPRegexp.h>
    9293#include <TSystem.h>
    9394#include <TObjString.h>
    9495#include <TObjArray.h>
    9596
    96 #include <MTime.h>
    97 #include <MDirIter.h>
     97#include "MTime.h"
     98#include "MDirIter.h"
     99
     100#include "MSQLMagic.h"
    98101
    99102using namespace std;
    100103
    101 int debug = 0;
    102 
    103 Bool_t DeleteSequence(MSQLServer &serv, TString datapath, TString sequpath, Int_t sequ, Bool_t dummy)
     104
     105class Rule : public TObject
    104106{
    105     //queries to delete information from the database
    106     TString query1(Form("DELETE FROM Calibration WHERE fSequenceFirst=%d", sequ));
    107     TString query2(Form("DELETE FROM Star WHERE fSequenceFirst=%d", sequ));
    108     TString query3(Form("DELETE FROM SequenceProcessStatus WHERE fSequenceFirst=%d", sequ));
    109     TString query4(Form("UPDATE RunData SET fSequenceFirst=0 WHERE fSequenceFirst=%d", sequ));
    110     TString query5(Form("DELETE FROM Sequences WHERE fSequenceFirst=%d AND fManuallyChangedKEY=1", sequ));
    111 
    112     //commands to delete files from the disk
    113     TString fname(Form("%s/%04d/sequence%08d.txt", sequpath.Data(),sequ/10000, sequ));
    114     TString command(Form("rm -r %s/callisto/%04d/%08d/", datapath.Data(), sequ/10000, sequ));
    115     TString command2(Form("rm -r %s/star/%04d/%08d/", datapath.Data(), sequ/10000, sequ));
    116 
    117     if (dummy)
    118     {
    119         cout << "not using dummy=kTRUE the following commands would be executed: " << endl;
    120         cout << "queries: " << endl;
    121         cout << query1 << endl;
    122         cout << query2 << endl;
    123         cout << query3 << endl;
    124         cout << query4 << endl;
    125         cout << query5 << endl;
    126         cout << "removing files:" << endl;
    127         cout << "unlink " << fname << endl;
    128         cout << command << endl;
    129         cout << command2 << endl;
     107private:
     108    TPRegexp fRegexp;
     109
     110    UInt_t fMin;
     111    UInt_t fMax;
     112
     113public:
     114    Rule(const char *regexp, UInt_t min=0, UInt_t max=(UInt_t)-1) :
     115        fRegexp(Form("^%s", regexp)), fMin(min), fMax(max)
     116    {
     117    }
     118
     119    Rule(TObjArray &arr) :
     120        fRegexp(arr.GetEntries()>0?Form("^%s", arr[0]->GetName()):""),
     121            fMin(0), fMax((UInt_t)-1)
     122    {
     123        if (arr.GetEntries()>1)
     124            fMin = atoi(arr[1]->GetName());
     125        if (arr.GetEntries()>2)
     126            fMax = atoi(arr[2]->GetName());
     127
     128        //cout << "Regexp: " << (arr.GetEntries()>0?Form("^%s", arr[0]->GetName()):"") << " " << fMin << " " << fMax << endl;
     129    }
     130
     131    Ssiz_t Match(const TString &str, Int_t idx, Int_t run=-1)
     132    {
     133        if (!IsValid(run))
     134            return 0;
     135
     136        TString mods;
     137        TArrayI pos;
     138        fRegexp.Match(str.Data()+idx, mods, 0, str.Length()*10, &pos);
     139
     140        return pos.GetSize()<2 ? 0 : pos[1]-pos[0];
     141    }
     142
     143    Bool_t IsValid(UInt_t run) const { return run<0 || (run>=fMin && run<=fMax); }
     144    ClassDef(Rule, 0)
     145};
     146ClassImp(Rule);
     147
     148class CheckMatch : public TObject
     149{
     150private:
     151    TPRegexp fRunType1;
     152    TPRegexp fRunType2;
     153
     154    TPRegexp fRegexp1;
     155    TPRegexp fRegexp2;
     156
     157    UInt_t fMin;
     158    UInt_t fMax;
     159
     160    void Init(const TObjArray &arr, Int_t idx=0)
     161    {
     162        const Int_t n = arr.GetEntries();
     163
     164        const Bool_t isminus = n>idx && TString(arr[idx]->GetName())=="-";
     165
     166        for (int i=0; i<n-idx; i++)
     167        {
     168            //cout << arr[i+idx]->GetName() << " ";
     169
     170            TString str(arr[i+idx]->GetName());
     171            if (str=="*")
     172                str = ".*";
     173
     174            switch (isminus && i>1 ? i+1 : i)
     175            {
     176            case 0: fRunType1 = TPRegexp(Form(isminus?"-":"^%s$", str.Data())); break;
     177            case 1: fRunType2 = TPRegexp(Form("^%s$", str.Data())); break;
     178            case 2: fRegexp1  = TPRegexp(Form("^%s$", str.Data())); break;
     179            case 3: fRegexp2  = TPRegexp(Form("^%s$", str.Data())); break;
     180            case 4: fMin      = str.Atoi();               break;
     181            case 5: fMax      = str.Atoi();               break;
     182            }
     183        }
     184        //cout << endl;
     185    }
     186
     187public:
     188    CheckMatch() : fRunType1(""), fRunType2(""), fRegexp1(""), fRegexp2("") {}
     189
     190    CheckMatch(const TString &txt) : fRunType1(""), fRunType2(""), fRegexp1(""), fRegexp2(""), fMin(0), fMax((UInt_t)-1)
     191    {
     192        TObjArray *arr = txt.Tokenize(" ");
     193        Init(*arr);
     194        delete arr;
     195    }
     196
     197    CheckMatch(TObjArray &arr, Int_t idx=0) : fRunType1(""), fRunType2(""), fRegexp1(""), fRegexp2(""), fMin(0), fMax((UInt_t)-1)
     198    {
     199        Init(arr, idx);
     200    }
     201
     202    CheckMatch(const char *from, const char *to, Int_t min=0, Int_t max=-1)
     203        : fRunType1(".*"), fRunType2(".*"), fRegexp1(Form("^%s$", from)), fRegexp2(Form("^%s$", to)), fMin(min), fMax(max)
     204    {
     205    }
     206
     207    Int_t Matches(const TString &rt1, const TString &rt2, const TString &lc1, const TString &lc2, UInt_t run=0)
     208    {
     209        if (run>0)
     210        {
     211            if (run<fMin || run>fMax)
     212                return kFALSE;
     213        }
     214
     215        const TString test("X-"); // FIXME:STUPID!
     216
     217        //if (test.Index(fRunType2)==1)
     218         //   return -(!rt1(fRunType1).IsNull() && !lc1(fRegexp1).IsNull());
     219
     220        if (test.Index(fRunType1,0)==1)
     221            return -(!rt2(fRunType2).IsNull() && !lc2(fRegexp2).IsNull());
     222
     223        return !rt1(fRunType1).IsNull() && !rt2(fRunType2).IsNull() && !lc1(fRegexp1).IsNull() && !lc2(fRegexp2).IsNull();
     224    }
     225    ClassDef(CheckMatch,0)
     226};
     227ClassImp(CheckMatch);
     228
     229class CheckList : public TList
     230{
     231public:
     232    CheckList() { SetOwner(); }
     233    Int_t Matches(const TString &rt1, const TString &rt2, const TString &lc1, const TString &lc2, Int_t run=-1) const
     234    {
     235        TIter Next(this);
     236
     237        CheckMatch *check = 0;
     238
     239        while ((check=(CheckMatch*)Next()))
     240        {
     241            const Int_t rc = check->Matches(rt1, rt2, lc1, lc2, run);
     242            if (rc)
     243                return rc;
     244        }
     245
     246        return kFALSE;
     247    }
     248    ClassDef(CheckList,0)
     249};
     250ClassImp(CheckList);
     251
     252class SequenceBuild : public MSQLMagic
     253{
     254private:
     255    TString fPathRawData;
     256    TString fPathSequences;
     257
     258    TMap  fMap;
     259    TList fListRegexp;
     260
     261    /*
     262    TString GetKeyName(TString col, TString key)
     263    {
     264        col(TRegexp("^Elt")) = "";
     265        return QueryNameOfKey(col, key, kFALSE);
     266    }*/
     267
     268    Int_t CheckTransition(TSQLResult &res, const TString *keys, TSQLRow &row, Int_t i)
     269    {
     270        // Get the name of the column from result table
     271        const TString key = res.GetFieldName(i);
     272
     273        // Get the list with the allowed attributed from the map
     274        CheckList *list = dynamic_cast<CheckList*>(fMap.GetValue(key));
     275        if (!list)
     276            return kFALSE;
     277
     278        // Check whether the current run (row[0]) with the current attribute
     279        // (row[i]) and the current run-type (row[1]) matches the attribute
     280        // of the last run (keys[i] with run-type row[i])
     281        return list->Matches(keys[1], row[1], keys[i], row[i], atoi(row[0]));
     282    }
     283
     284    Bool_t InsertSequence(Int_t from, Int_t to)
     285    {
     286        cout << "     - Inserting Sequence into database." << endl;
     287
     288        // ========== Request number of events ==========
     289
     290        const TString runtime =
     291            "SUM(if(TIME_TO_SEC(fRunStop)-TIME_TO_SEC(fRunStart)<0,"
     292            " TIME_TO_SEC(fRunStop)-TIME_TO_SEC(fRunStart)+24*60*60,"
     293            " TIME_TO_SEC(fRunStop)-TIME_TO_SEC(fRunStart))), ";
     294
     295        const TString where = Form("(fRunNumber BETWEEN %d AND %d) AND fExcludedFDAKEY=1",
     296                                   from, to);
     297
     298        TString query;
     299        query  = "SELECT SUM(fNumEvents), ";
     300        query += runtime;
     301        query += " MIN(fZenithDistance), MAX(fZenithDistance), ";
     302        query += " MIN(fAzimuth), MAX(fAzimuth), ";
     303        query += " MIN(fRunStart), MAX(fRunStop), ";
     304        query += " ELT(MAX(FIELD(fLightConditionsKEY, 1, 2, 7, 5, 8)), 1, 2, 7, 5, 8) ";
     305        query += " FROM RunData WHERE ";
     306        query += where;
     307        query += " AND fRunTypeKEY=2";
     308
     309        TSQLResult *res = Query(query);
     310        if (!res)
     311            return kFALSE;
     312
     313        TSQLRow *row = res->Next();
     314        if (!row || res->GetFieldCount()!=9)
     315        {
     316            cout << "ERROR - Wrong result from query: " << query << endl;
     317            return kFALSE;
     318        }
     319
     320        const TString nevts = (*row)[0];
     321        const TString secs  = (*row)[1];
     322        const TString zdmin = (*row)[2];
     323        const TString zdmax = (*row)[3];
     324        const TString azmin = (*row)[4];
     325        const TString azmax = (*row)[5];
     326        const TString start = (*row)[6];
     327        const TString stop  = (*row)[7];
     328        const TString light = (*row)[8];
     329
     330        delete res;
     331
     332        // ========== Request data of sequence ==========
     333        query = Form("SELECT fSourceKEY, fProjectKEY, "
     334                     " fL1TriggerTableKEY, fL2TriggerTableKEY,"
     335                     " fHvSettingsKEY, fDiscriminatorThresholdTableKEY,"
     336                     " fTriggerDelayTableKEY, fObservationModeKEY "
     337                     " FROM RunData WHERE fRunTypeKEY=2 AND %s"
     338                     " LIMIT 1", where.Data());
     339
     340        res = Query(query);
     341        if (!res)
     342            return kFALSE;
     343
     344        row = res->Next();
     345        if (!row || res->GetFieldCount()!=8)
     346        {
     347            cout << "ERROR - No result from query: " << query << endl;
     348            return kFALSE;
     349        }
     350
     351        const TString set = Form("fSequenceFirst=%d ", from);
     352
     353        TString query1;
     354        query1 += set;
     355        query1 += Form(",fSequenceLast=%d,",                   to);
     356        query1 += Form(" fSourceKEY=%s,",                      (*row)[0]);
     357        query1 += Form(" fProjectKEY=%s,",                     (*row)[1]);
     358        query1 += Form(" fNumEvents=%s,",                      nevts.Data());
     359        query1 += Form(" fRunTime=%s,",                        secs.Data());
     360        query1 += Form(" fRunStart=\"%s\",",                   start.Data());
     361        query1 += Form(" fRunStop=\"%s\",",                    stop.Data());
     362        query1 += Form(" fZenithDistanceMin=%s,",              zdmin.Data());
     363        query1 += Form(" fZenithDistanceMax=%s,",              zdmax.Data());
     364        query1 += Form(" fAzimuthMin=%s,",                     azmin.Data());
     365        query1 += Form(" fAzimuthMax=%s,",                     azmax.Data());
     366        query1 += Form(" fL1TriggerTableKEY=%s,",              (*row)[2]);
     367        query1 += Form(" fL2TriggerTableKEY=%s,",              (*row)[3]);
     368        query1 += Form(" fHvSettingsKEY=%s,",                  (*row)[4]);
     369        query1 += Form(" fDiscriminatorThresholdTableKEY=%s,", (*row)[5]);
     370        query1 += Form(" fTriggerDelayTableKEY=%s,",           (*row)[6]);
     371        query1 += Form(" fLightConditionsKEY=%s,",             light.Data());
     372        query1 += Form(" fObservationModeKEY=%s, ",            (*row)[7]);
     373        query1 += "fManuallyChangedKEY=1";
     374
     375        delete res;
     376
     377        const TString where2 = Form("(fRunTypeKEY BETWEEN 2 AND 4) AND %s",
     378                                    where.Data());
     379
     380        if (!Insert("Sequences", query1))
     381        {
     382            cout << "ERROR - Could not insert Sequence into Sequences." << endl;
     383            return kFALSE;
     384        }
     385
     386        if (!Update("RunData", set, where))
     387        {
     388            cout << "ERROR - Could not update RunData." << endl;
     389            return kFALSE;
     390        }
     391
     392        if (!Insert("SequenceProcessStatus", set))
     393        {
     394            cout << "ERROR - Could not insert Sequence into SequenceProcessStatus." << endl;
     395            return kFALSE;
     396        }
     397
    130398        return kTRUE;
    131399    }
    132400
    133     TSQLResult *res = serv.Query(query1);
    134     if (!res)
     401    Bool_t DeleteSequence(Int_t sequ)
     402    {
     403        if (fPathRawData.IsNull() || fPathSequences.IsNull())
     404        {
     405            cout << "       + Deletion " << sequ << " skipped due to missing path." << endl;
     406            return kTRUE;
     407        }
     408
     409        //queries to delete information from the database
     410        const TString query(Form("fSequenceFirst=%d", sequ));
     411
     412        //commands to delete files from the disk
     413        const TString fname(Form("%s/%04d/sequence%08d.txt", fPathSequences.Data(),sequ/10000, sequ));
     414        const TString cmd1(Form("rm -rf %s/callisto/%04d/%08d/", fPathRawData.Data(), sequ/10000, sequ));
     415        const TString cmd2(Form("rm -rf %s/star/%04d/%08d/", fPathRawData.Data(), sequ/10000, sequ));
     416
     417        if (!Delete("Calibration", query))
     418            return 2;
     419
     420        if (!Delete("Star", query))
     421            return 2;
     422
     423        if (!Delete("SequenceProcessStatus", query))
     424            return 2;
     425
     426        if (!Delete("Sequences", query))
     427            return 2;
     428
     429        if (!Update("RunData", "fSequenceFirst=0", query))
     430            return 2;
     431
     432        if (IsDummy())
     433        {
     434            cout << "       + unlink " << fname << endl;
     435            cout << "       + " << cmd1 << endl;
     436            cout << "       + " << cmd2 << endl;
     437            return kTRUE;
     438        }
     439
     440        gSystem->Unlink(fname);
     441
     442        gSystem->Exec(cmd1);
     443        gSystem->Exec(cmd2);
     444
     445        return kTRUE;
     446    }
     447
     448    Int_t CheckSequence(Int_t runstart, Int_t runstop)
     449    {
     450        const char *fmt1 = "SELECT fRunNumber FROM RunData WHERE";
     451        const char *fmt2 = "AND fExcludedFDAKEY=1 AND (fRunTypeKEY BETWEEN 2 AND 4) ORDER BY fRunNumber";
     452
     453        const TString query1 = Form("%s fSequenceFirst=%d %s",            fmt1, runstart, fmt2);
     454        const TString query2 = Form("%s fRunNumber BETWEEN %d AND %d %s", fmt1, runstart, runstop, fmt2);
     455
     456        TSQLResult *res1 = Query(query1);
     457        if (!res1)
     458            return 2;
     459
     460        TSQLResult *res2 = Query(query2);
     461        if (!res2)
     462        {
     463            delete res1;
     464            return 2;
     465        }
     466
     467        while (1)
     468        {
     469            TSQLRow *row1 = res1->Next();
     470            TSQLRow *row2 = res2->Next();
     471
     472            if (!row1 && !row2)
     473                return kTRUE;
     474
     475            if (!row1 || !row2)
     476                return kFALSE;
     477
     478            if (atoi((*row1)[0])!=atoi((*row2)[0]))
     479                return kFALSE;
     480        }
     481
    135482        return kFALSE;
    136     delete res;
    137 
    138     res = serv.Query(query2);
    139     if (!res)
    140         return kFALSE;
    141     delete res;
    142 
    143     res = serv.Query(query3);
    144     if (!res)
    145         return kFALSE;
    146     delete res;
    147 
    148     res = serv.Query(query4);
    149     if (!res)
    150         return kFALSE;
    151     delete res;
    152 
    153     res = serv.Query(query5);
    154     if (!res)
    155         return kFALSE;
    156     delete res;
    157 
    158     gSystem->Unlink(fname);
    159 
    160     gSystem->Exec(command);
    161     gSystem->Exec(command2);
    162 
    163     return kTRUE;
    164 }
    165 
    166 Int_t DoCheck(TSQLResult &res)
    167 {
    168     TArrayI data(5);
    169     Int_t n = 0;
    170 
    171     TSQLRow *row=0;
    172     while ((row=res.Next()))
    173     {
    174         n++;
    175 
    176         if (data[0]==0)
    177         {
    178             for (int i=0; i<data.GetSize(); i++)
    179                 data[i] = atoi((*row)[i]);
    180             continue;
    181         }
    182 
    183         for (int i=1; i<data.GetSize(); i++)
    184         {
    185             if (data[i] != atoi((*row)[i]))
    186                 return i+1;
    187         }
    188     }
    189     return n==0 ? 0 : -1;
    190 }
    191 
    192 
    193 //check values, that can be different for different runtypes
    194 Bool_t CheckRuns(MSQLServer &serv, Int_t from, Int_t to, Int_t type)
    195 {
    196     TString query("SELECT fRunNumber, fL1TriggerTableKEY, fL2TriggerTableKEY,"
    197                   " fCalibrationScriptKEY, fProjectKEY FROM RunData");
    198     query += Form(" WHERE fRunTypeKEY=%d AND fExcludedFDAKEY=1 AND "
    199                   " (fRunNumber BETWEEN %d AND %d)"
    200                   " ORDER BY fRunNumber", type, from, to);
    201 
    202     TSQLResult *res = serv.Query(query);
    203     if (!res)
    204         return kFALSE;
    205 
    206     Int_t rc = DoCheck(*res);
    207     delete res;
    208 
    209     switch (rc)
    210     {
    211     case 0: cout << "ERROR - No runs found for check!"             << endl; break;
    212     case 1: cout << "ERROR - fRunNumber doesn't match!"            << endl; break;
    213     case 2: cout << "ERROR - fL1TriggerTableKEY doesn't match!"    << endl; break;
    214     case 3: cout << "ERROR - fL2TriggerTableKEY doesn't match!"    << endl; break;
    215     case 4: cout << "ERROR - fCalibrationScriptKEY doesn't match!" << endl; break;
    216     case 5: cout << "ERROR - fProjectKEY doesn't match!"           << endl; break;
    217     }
    218 
    219     return rc<0;
    220 }
    221 
    222 Int_t CheckSequence(MSQLServer &serv, TString datapath, TString sequpath, Int_t from, Int_t to, Bool_t dummy)
    223 {
    224     Int_t rc=0;
    225     //rc=0 means sequence not found -> insert
    226     //rc=1 means deleting sequence(s) worked -> insert
    227     //rc=2 means sequence is still the same -> insert not neccessary
    228     //if deleting sequence doesn't work -> return -1
    229 
    230 
    231     //getting # of sequence (in sequDB) between from and to
    232     TString query("SELECT fSequenceFirst FROM Sequences WHERE (fSequenceFirst ");
    233     query += Form("BETWEEN %d and %d OR fSequenceLast BETWEEN %d and %d) AND "
    234                   "fManuallyChangedKEY=1 ", from, to, from, to);
    235 
    236     TSQLResult *res = serv.Query(query);
    237     if (!res)
    238         return -1;
    239 
    240     TArrayI sequences;
    241     Int_t numsequ=0;
    242 
    243     TSQLRow *row=0;
    244     while ((row=res->Next()))
    245     {
    246         numsequ++;
    247         sequences.Set(numsequ);
    248         sequences.AddAt(atoi((*row)[0]), numsequ-1);
    249     }
    250     delete res;
    251 
    252     //if there's no sequence in the table Sequences -> check other tables
    253     //if there's one sequence -> check if the sequence is identical
    254     //if there are more sequences -> delete them
    255     switch (numsequ)
    256     {
    257     case 0:
    258         //FIXME: like this the check is of no use, but when doing it
    259         //       without the check for manuallychanged, all manually
    260         //       changed sequences would be deleted
    261         cout << "   + found no sequence in Sequ-DB -> check other tables" << endl;
    262         cout << "     deleting every sequence found in Calibration, Star or" << endl;
    263         cout << "     SequenceProcessStatus between " << from << " and " << to << endl;
    264 
    265         //calibration table
    266         query=Form("SELECT Calibration.fSequenceFirst FROM Calibration "
    267                    " LEFT JOIN Sequences ON Calibration.fSequenceFirst=Sequences.fSequenceFirst "
    268                    " WHERE fManuallyChangedKEY=1 AND Calibration.fSequenceFirst BETWEEN %d and %d",
    269                    from, to);
    270         res = serv.Query(query);
     483    }
     484
     485    Int_t CreateSequence(Int_t runstart, Int_t runstop)
     486    {
     487        cout << "   * Creating Sequence " << runstart << "-" << runstop << ":" << endl;
     488
     489        TString query=
     490            Form("SELECT fSequenceFirst FROM RunData "
     491                 " WHERE fRunNumber BETWEEN %d AND %d AND "
     492                 " fSequenceFirst>0 AND "
     493                 " fExcludedFDAKEY=1 AND (fRunTypeKEY BETWEEN 2 AND 4)"
     494                 " GROUP BY fSequenceFirst", runstart, runstop);
     495
     496        TSQLResult *res = Query(query);
    271497        if (!res)
    272             return -1;
    273         row=0;
    274         while ((row=res->Next()))
    275         {
    276             if (!DeleteSequence(serv, datapath, sequpath, atoi((*row)[0]), dummy))
    277                 return -1;
    278             rc=1;
    279         }
    280         delete res;
    281 
    282         //Star table
    283         query=Form("SELECT Star.fSequenceFirst FROM Star "
    284                    " LEFT JOIN Sequences ON Star.fSequenceFirst=Sequences.fSequenceFirst "
    285                    " WHERE fManuallyChangedKEY=1 AND  Star.fSequenceFirst BETWEEN %d and %d",
    286                    from, to);
    287         res = serv.Query(query);
    288         if (!res)
    289             return -1;
    290         row=0;
    291         while ((row=res->Next()))
    292         {
    293             if (!DeleteSequence(serv, datapath, sequpath, atoi((*row)[0]), dummy))
    294                 return -1;
    295             rc=1;
    296         }
    297         delete res;
    298 
    299         //SequenceProcessStatus table
    300         query=Form("SELECT SequenceProcessStatus.fSequenceFirst FROM SequenceProcessStatus "
    301                    " LEFT JOIN Sequences ON SequenceProcessStatus.fSequenceFirst=Sequences.fSequenceFirst "
    302                    " WHERE fManuallyChangedKEY=1 AND  SequenceProcessStatus.fSequenceFirst BETWEEN %d and %d",
    303                    from, to);
    304         res = serv.Query(query);
    305         if (!res)
    306             return -1;
    307         row=0;
    308         while ((row=res->Next()))
    309         {
    310             if (!DeleteSequence(serv, datapath, sequpath, atoi((*row)[0]), dummy))
    311                 return -1;
    312             rc=1;
    313         }
    314         delete res;
    315         break;
    316 
    317     case 1:
    318         cout << "   + found one sequence: " << sequences.At(0) << " -> check sequence." << endl;
    319         if (sequences.At(0)!=from)
    320         {
    321             if (!DeleteSequence(serv, datapath, sequpath, sequences.At(0), dummy))
    322                 return -1;
    323             rc=1;
     498            return 2;
     499
     500        const Int_t cnt = res->GetRowCount();
     501
     502        Int_t rc = kTRUE;
     503        if (cnt==1)
     504        {
     505            TSQLRow *row=res->Next();
     506            const Int_t check = CheckSequence(runstart, runstop);
     507            if (check==kFALSE)
     508            {
     509                cout << "     - Identical sequence already existing." << endl;
     510                delete res;
     511                return kTRUE;
     512            }
     513            if (check==2)
     514                rc=2;
     515            else
     516            {
     517                cout << "     - Deleting quasi-identical sequence " << atoi((*row)[0]) << endl;
     518                if (DeleteSequence(atoi((*row)[0]))==2)
     519                    rc = 2;
     520            }
    324521        }
    325522        else
    326523        {
    327             cout << "     * sequence is the same -> checking the runs." << endl;
    328 
    329             //getting olf runs
    330             query=Form("SELECT fRunNumber FROM RunData WHERE fSequenceFirst=%d ", from);
    331             res = serv.Query(query);
    332             if (!res)
    333                 return -1;
    334 
    335             TArrayI oldruns;
    336             Int_t count=0;
    337             row=0;
     524            TSQLRow *row=0;
    338525            while ((row=res->Next()))
    339526            {
    340                 count++;
    341                 oldruns.Set(count);
    342                 oldruns.AddAt(atoi((*row)[0]), count-1);
     527                cout << "     - Deleting overlapping sequence " << atoi((*row)[0]) << endl;
     528                if (DeleteSequence(atoi((*row)[0]))==2)
     529                    rc = 2;
    343530            }
    344             delete res;
    345 
    346             //getting new runs
    347             query=Form("SELECT fRunNumber FROM RunData WHERE fRunNumber BETWEEN %d and %d AND fExcludedFDAKEY=1", from, to);
    348             res = serv.Query(query);
    349             if (!res)
    350                 return -1;
    351             TArrayI newruns;
    352             count=0;
    353             row=0;
    354             while ((row=res->Next()))
     531        }
     532
     533        delete res;
     534
     535        if (rc==2)
     536            return 2;
     537
     538        if (!InsertSequence(runstart, runstop))
     539            return 2;
     540
     541        return kTRUE;
     542    }
     543
     544    Bool_t ReadResources(const char *fname)
     545    {
     546        TPRegexp regexp("^\\[.*\\]$");
     547
     548        ifstream fin(fname);
     549        if (!fin)
     550        {
     551            cout << "Cannot open file " << fname << ": ";
     552            cout << strerror(errno) << endl;
     553            return kFALSE;
     554        }
     555
     556        Int_t section = 0;
     557
     558        TString key;
     559        while (1)
     560        {
     561            TString txt;
     562            txt.ReadLine(fin);
     563            if (!fin)
     564                break;
     565
     566            txt = txt.Strip(TString::kBoth);
     567
     568            if (txt[0]=='#' || txt.IsNull())
     569                continue;
     570
     571            if (txt[0]=='[' && section!=2)
    355572            {
    356                 count++;
    357                 newruns.Set(count);
    358                 newruns.AddAt(atoi((*row)[0]), count-1);
     573                //cout << txt << endl;
     574                section = 0;
     575                if (txt(regexp)=="[Transition]")
     576                    section = 1;
     577                if (txt(regexp)=="[Regexp]")
     578                    section = 2;
     579                continue;
    359580            }
    360             delete res;
    361 
    362             //comparing old and new runs (first the # of runs, if it is the same, also the single runnumbers
    363             if (oldruns.GetSize()!=newruns.GetSize())
     581
     582            TObjArray *arr = txt.Tokenize(" ");
     583
     584            if (arr->GetEntries()>0)
     585                switch (section)
     586                {
     587                case 1:
     588                    {
     589                        TString key = arr->At(0)->GetName();
     590                        key.Prepend("f");
     591                        key.Append("KEY");
     592
     593                        CheckList *list = dynamic_cast<CheckList*>(fMap.GetValue(key));
     594                        if (!list)
     595                        {
     596                            //cout << key << endl;
     597                            list = new CheckList;
     598                            fMap.Add(new TObjString(key), list);
     599                        }
     600
     601                        if (arr->GetEntries()>1)
     602                        {
     603                            //cout << key << " ";
     604                            list->Add(new CheckMatch(*arr, 1));
     605                        }
     606                    }
     607                    break;
     608                case 2:
     609                    fListRegexp.Add(new Rule(*arr));
     610                    break;
     611                }
     612
     613            delete arr;
     614        }
     615
     616        return kTRUE;
     617    }
     618
     619    TString GetELT(const char *col, TSQLResult *res, TList &regexp)
     620    {
     621        TObjArray names; // array with old names (including regexp)
     622
     623        // Add to array and expand the array if necessary
     624        TSQLRow *row=0;
     625        while ((row=res->Next()))
     626            names.AddAtAndExpand(new TObjString((*row)[1]), atoi((*row)[0]));
     627
     628        // Now a LUT is build which converts the keys for
     629        // the names including the regexp into keys for
     630        // the names excluding the regexp
     631        TString elt(Form("ELT(RunData.f%sKEY+1", col));
     632
     633        // loop over all entries in the list
     634        const Int_t n = names.GetSize();
     635        for (int i=0; i<n; i++)
     636        {
     637            // For all entries which are not in the list
     638            // write an undefined value into the LUT
     639            TObject *o = names.UncheckedAt(i);
     640            if (!o)
    364641            {
    365 //                cout << " number of runs (" << oldruns.GetSize() << " - " << newruns.GetSize()
    366 //                    << ") is not the same -> deleting sequence " << sequences.At(0) << endl;
    367                 if (!DeleteSequence(serv, datapath, sequpath, sequences.At(0), dummy))
    368                     return -1;
    369                 rc=1;
     642                elt += ",0";
     643                continue;
    370644            }
    371             else
     645
     646            // Remove the regexp from the string which includes it
     647            TString name = o->GetName();
     648
     649            TIter NextR(&regexp);
     650            TObject *reg=0;
     651            while ((reg=NextR()))
    372652            {
    373                 cout << "       · number of runs is the same -> checking the single runnumbers." << endl;
    374 
    375                 for (Int_t i=0;i<newruns.GetSize();i++)
     653                TPRegexp reg(reg->GetName());
     654                const Ssiz_t pos = name.Index(reg, 0);
     655                if (pos>0)
    376656                {
    377 //                    cout << "i: " << i << " - new: " << newruns.At(i) << " - old: " << oldruns.At(i) << endl;
    378                     if (newruns.At(i)==oldruns.At(i))
    379                         continue;
    380 
    381                     cout << "       · " << i << ". run is not the same ( " << oldruns.At(i) << " -- " << newruns.At(i)
    382                         << ") -> deleting sequence " << sequences.At(0) << endl;
    383                     if (!DeleteSequence(serv, datapath, sequpath, sequences.At(0), dummy))
    384                         return -1;
    385                     return 1;
     657                    name.Remove(pos);
     658                    name += "-W";
     659                    break;
    386660                }
    387661            }
    388         }
    389         return 2;
    390 
    391     default:
    392         cout << " - found " << numsequ << " sequences -> deleting them " << endl;
    393 
    394         for (Int_t i=0;i<sequences.GetSize();i++)
    395         {
    396                 cout << "   + deleting sequence " << sequences.At(i) << "... <" << i << ">" << endl;
    397                 if (!DeleteSequence(serv, datapath, sequpath, sequences.At(i), dummy))
    398                     return -1;
    399                 rc=1;
    400         }
    401     }
    402 
    403     return rc;
    404 }
    405 
    406 Bool_t InsertSequence(MSQLServer &serv, Int_t from, Int_t to)
    407 {
    408     cout << "       · Inserting sequence " << from << " ... " << endl;
    409 
    410     // ========== Request number of events ==========
    411     TString query("SELECT SUM(fNumEvents), "
    412                   " SUM(if(TIME_TO_SEC(fRunStop)-TIME_TO_SEC(fRunStart)<0,"
    413                   "  TIME_TO_SEC(fRunStop)-TIME_TO_SEC(fRunStart)+24*60*60,"
    414                   "  TIME_TO_SEC(fRunStop)-TIME_TO_SEC(fRunStart))), ");
    415     query +=      " MIN(fZenithDistance), MAX(fZenithDistance), ";
    416     query +=      " MIN(fAzimuth), MAX(fAzimuth) ";
    417     query += Form(" FROM RunData WHERE fRunTypeKEY=2 AND "
    418                   " (fRunNumber BETWEEN %d AND %d) AND fExcludedFDAKEY=1",
    419                   from, to);
    420 
    421     TSQLResult *res = serv.Query(query);
    422     if (!res)
    423         return kFALSE;
    424 
    425     TSQLRow *row = res->Next();
    426     if (!row || !(*row)[0])
    427     {
    428         cout << "ERROR - No result from query: " << query << endl;
    429         return kFALSE;
    430     }
    431 
    432     TString nevts = (*row)[0];
    433     TString secs  = (*row)[1];
    434     TString zdmin = (*row)[2];
    435     TString zdmax = (*row)[3];
    436     TString azmin = (*row)[4];
    437     TString azmax = (*row)[5];
    438 
    439     delete res;
    440 
    441     // ========== Request start time of sequence ==========
    442     query = Form("SELECT fRunStart FROM RunData WHERE fRunNumber=%d AND fExcludedFDAKEY=1", from);
    443 
    444     res = serv.Query(query);
    445     if (!res)
    446         return kFALSE;
    447 
    448     row = res->Next();
    449     if (!row || !(*row)[0])
    450     {
    451         cout << "ERROR - No result from query: " << query << endl;
    452         return kFALSE;
    453     }
    454 
    455     TString start((*row)[0]);
    456 
    457     delete res;
    458 
    459     // ========== Request data of sequence ==========
    460     query = Form("SELECT fSourceKEY, fProjectKEY, "
    461                  " fL1TriggerTableKEY, fL2TriggerTableKEY,"
    462                  " fHvSettingsKEY, fDiscriminatorThresholdTableKEY,"
    463                  " fTriggerDelayTableKEY, fLightConditionsKEY, "
    464                  " fTestFlagKEY, fObservationModeKEY "
    465                  " FROM RunData"
    466                  " WHERE fRunTypeKEY=2 AND fExcludedFDAKEY=1 AND (fRunNumber BETWEEN %d AND %d)"
    467                  " LIMIT 1", from, to);
    468 
    469     res = serv.Query(query);
    470     if (!res)
    471         return kFALSE;
    472 
    473     row = res->Next();
    474     if (!row)
    475     {
    476         cout << "ERROR - No result from query: " << query << endl;
    477         return kFALSE;
    478     }
    479 
    480     TString query1("INSERT Sequences SET");
    481     query1 += Form(" fSequenceFirst=%d,  fSequenceLast=%d,", from, to);
    482     query1 += Form(" fSourceKEY=%s,",                      (*row)[0]);
    483     query1 += Form(" fProjectKEY=%s,",                     (*row)[1]);
    484     query1 += Form(" fNumEvents=%s,",                      nevts.Data());
    485     query1 += Form(" fRunTime=%s,",                        secs.Data());
    486     query1 += Form(" fRunStart=\"%s\",",                   start.Data());
    487     query1 += Form(" fZenithDistanceMin=%s,",              zdmin.Data());
    488     query1 += Form(" fZenithDistanceMax=%s,",              zdmax.Data());
    489     query1 += Form(" fAzimuthMin=%s,",                     azmin.Data());
    490     query1 += Form(" fAzimuthMax=%s,",                     azmax.Data());
    491     query1 += Form(" fL1TriggerTableKEY=%s,",              (*row)[2]);
    492     query1 += Form(" fL2TriggerTableKEY=%s,",              (*row)[3]);
    493     query1 += Form(" fHvSettingsKEY=%s,",                  (*row)[4]);
    494     query1 += Form(" fDiscriminatorThresholdTableKEY=%s,", (*row)[5]);
    495     query1 += Form(" fTriggerDelayTableKEY=%s,",           (*row)[6]);
    496     query1 += Form(" fLightConditionsKEY=%s,",             (*row)[7]);
    497     query1 += Form(" fTestFlagKEY=%s,",                    (*row)[8]);
    498     query1 += Form(" fObservationModeKEY=%s, ",            (*row)[9]);
    499     query1+="fManuallyChangedKEY=1";
    500 
    501 
    502     TString query2 = Form("UPDATE RunData SET fSequenceFirst=%d WHERE"
    503                           "  (fRunNumber  BETWEEN %d AND %d) AND"
    504                           "  (fRunTypeKEY BETWEEN  2 AND  4) AND"
    505                           "  fSourceKEY=%s AND fHvSettingsKEY=%s AND fExcludedFDAKEY=1",
    506                           from, from, to, (*row)[0], (*row)[4]);
    507 
    508     TString query3 = Form("INSERT SequenceProcessStatus SET fSequenceFirst=%d ", from);
    509 
    510     delete res;
    511 
    512     /*
    513      cout << "q1: " << query1 << endl;
    514      cout << "q2: " << query2 << endl;
    515      cout << "q3: " << query3 << endl;
    516      */
    517 
    518     res = serv.Query(query1);
    519     if (!res)
    520     {
    521         cout << "ERROR - Could not insert Sequence into Sequences." << endl;
    522         return kFALSE;
    523     }
    524     delete res;
    525 
    526     res = serv.Query(query2);
    527     if (!res)
    528     {
    529         cout << "ERROR - Could not update RunData." << endl;
    530         return kFALSE;
    531     }
    532     delete res;
    533 
    534     res = serv.Query(query3);
    535     if (!res)
    536     {
    537         cout << "ERROR - Could not insert Sequence into SequenceProcessStatus." << endl;
    538         return kFALSE;
    539     }
    540     delete res;
    541 
    542     return kTRUE;
    543 }
    544 
    545 //
    546 // Handling new sequence (checking runs; checking for old sequence; inserting sequence, if everything is okay)
    547 //
    548 Bool_t NewSequence(MSQLServer &serv, TString datapath, TString sequpath, Int_t from, Int_t to, TList &sequlist, Bool_t dummy)
    549 {
    550     cout << " - Found Sequence (" << from << ", " << to << ") ... checking runs..." << flush;
    551 
    552     if (!CheckRuns(serv, from, to, 2))
    553     {
    554         cout << "Warning - Found inconsistency in data-runs (" << from << ", " << to << ")" << endl;
    555         //sequence is not built, but kTRUE is returned, to allow
    556         //the automatic processing of the other sequences of this day
     662
     663            // Check if such a Key exists, if not insert it
     664            const Int_t key = QueryKeyOfName(col, name);
     665
     666            // RESOLVE return code!!!
     667            //if (key<0)
     668            //     return "";
     669
     670            // add index to the LUT
     671            elt += Form(",%d", key);
     672        }
     673
     674        // close LUT expression
     675        //    elt += ") AS Elt";
     676        //    elt += col;
     677
     678        elt += ") AS f";
     679        elt += col;
     680        elt += "KEY";
     681
     682        // return result
     683        return elt;
     684    }
     685
     686    TString GetELT(const char *col, TSQLResult *res, TString regexp)
     687    {
     688        TList list;
     689        list.SetOwner();
     690        list.Add(new TObjString(regexp));
     691        return GetELT(col, res, list);
     692    }
     693
     694    Bool_t HasAtLeastOne(TString src, TString chk) const
     695    {
     696        src.ToLower();
     697        chk.ToLower();
     698
     699        for (int i=0; i<chk.Length(); i++)
     700            if (src.First(chk[i])<0)
     701                return kFALSE;
     702
    557703        return kTRUE;
    558704    }
    559     if (!CheckRuns(serv, from, to, 3))
    560     {
    561         cout << "Warning - Found inconsistency in ped-runs (" << from << ", " << to << ")" << endl;
    562         //sequence is not built, but kTRUE is returned, to allow
    563         //the automatic processing of the other sequences of this day
    564         return kTRUE;
    565     }
    566 
    567     cout << "ok." << endl;
    568 
    569 
    570     cout << "   + checking sequence..." << endl;
    571 
    572     TObject *sequ;
    573     Bool_t rc=kFALSE;
    574     switch (CheckSequence(serv, datapath, sequpath, from, to, dummy))
    575     {
    576     case 0:
    577         cout << "       · sequence not found -> inserting " << from << flush;
    578         if (dummy)
    579         {
    580             cout << " <dummy> " << endl;
     705
     706    TString PrepareString(TSQLResult &res, TArrayI &runs)
     707    {
     708        // Number of result rows
     709        const Int_t rows = res.GetRowCount();
     710
     711        runs.Set(rows);       // initialize size of array for run numbers
     712
     713        TArrayD start(rows);  // instantiate array for start times
     714        TArrayD stop(rows);   // instantiate array for stop times
     715
     716        TString str;          // result string
     717
     718        Int_t idx=0;
     719        TSQLRow *row=0;
     720        while ((row=res.Next()))
     721        {
     722            runs[idx] = atoi((*row)[0]);          // run number
     723
     724            const TString tstart = ((*row)[2]);   // start time
     725            const TString tstop  = ((*row)[3]);   // stop time
     726
     727            start[idx] = MTime(tstart).GetMjd();  // convert to double
     728            stop[idx]  = MTime(tstop).GetMjd();   // convert to double
     729
     730            // This is a workaround for broken start-times
     731            if (tstart=="0000-00-00 00:00:00")
     732                start[idx] = stop[idx];
     733
     734            // Add a run-type character for this run to the string
     735            str += RunType((*row)[1]);
     736
     737            // Increase index
     738            idx++;
     739        }
     740
     741        // Now the P- and D- runs are classified by the time-distance
     742        // to the next or previous C-Run
     743        Double_t lastc = -1;
     744        Double_t nextc = -1;
     745        for (int i=0; i<str.Length(); i++)
     746        {
     747            if (str[i]=='C')
     748            {
     749                // Remember stop time of C-Run as time of last C-run
     750                lastc = stop[i];
     751
     752                // Calculate start time of next C-Run
     753                const TString residual = str(i+1, str.Length());
     754                const Int_t pos = residual.First('C');
     755
     756                // No C-Run found anymore. Finished...
     757                if (pos<0)
     758                    break;
     759
     760                // Remember start  time of C-Run as time of next C-run
     761                nextc = start[i+1+pos];
     762                continue;
     763            }
     764
     765            // Check whether the identifying character should
     766            // be converted to lower case
     767            if (start[i]-lastc>nextc-stop[i])
     768                str[i] = tolower(str[i]);
     769        }
     770        //cout << str << endl;
     771        return str;
     772    }
     773
     774    void PrintResidual(Int_t runstart, Int_t runstop, TString residual, const char *descr)
     775    {
     776        residual.ToLower();
     777
     778        // Count number of unsequences "characters"
     779        const Int_t nump = residual.CountChar('p');
     780        const Int_t numd = residual.CountChar('d');
     781        const Int_t numc = residual.CountChar('c');
     782
     783        // Print some information to the output steram
     784        if (nump+numc+numd==0)
     785            return;
     786
     787        cout << "   ! " << runstart << "-" << runstop << " [" << setw(3) << 100*residual.Length()/(runstop-runstart+1) << "%]: " << descr << " not sequenced:  P=" << nump << "  C=" << numc << "  D=" << numd;
     788        if (numd>0)
     789            cout << "  (DATA!)";
     790
     791        if (nump==0 || numc==0 || numd==0)
     792            cout << "  Missing";
     793        if (numd==0)
     794            cout << " D";
     795        if (nump==0)
     796            cout << " P";
     797        if (numc==0)
     798            cout << " C";
     799
     800        cout << endl;
     801    }
     802
     803    Int_t SplitBlock(Int_t runstart, Int_t runstop)
     804    {
     805        // Request data necessary to split block into sequences
     806        const TString query=
     807            Form("SELECT fRunNumber, fRunTypeKEY, fRunStart, fRunStop"
     808                 " FROM RunData "
     809                 " WHERE fRunNumber BETWEEN %d AND %d AND "
     810                 " fExcludedFDAKEY=1 AND (fRunTypeKEY BETWEEN 2 AND 4)"
     811                 " ORDER BY fRunNumber", runstart, runstop);
     812
     813        // Send query
     814        TSQLResult *res = Query(query);
     815        if (!res)
     816            return 2;
     817
     818        // Get String containing the sequence of P-,C- and D-Runs
     819        // and an array with the corresponding run-numbers
     820        TArrayI runs;
     821        const TString str = PrepareString(*res, runs);
     822
     823        delete res;
     824
     825        // Check if the prepared string at least contains one run of each type
     826        if (!HasAtLeastOne(str, "PCD"))
     827        {
     828            PrintResidual(runstart, runstop, str, "Block");
    581829            return kTRUE;
    582830        }
    583         cout << endl;
    584         if ((sequ=sequlist.Remove(sequlist.FindObject(Form("%d", from)))))
    585             delete sequ;
    586         return InsertSequence(serv, from, to);
    587 
    588     case 1:
    589         cout << "       · deleting successfully finished -> inserting sequence " << from << flush;
    590         if (dummy)
    591         {
    592             cout << " <dummy> " << endl;
    593             return kTRUE;
    594         }
    595         cout << endl;
    596         if ((sequ=sequlist.Remove(sequlist.FindObject(Form("%d", from)))))
    597             delete sequ;
    598         return InsertSequence(serv, from, to);
    599 
    600     case 2:
    601         cout << "       · sequence " << from << " is already existing -> inserting not necessary" << endl;
    602         if ((sequ=sequlist.Remove(sequlist.FindObject(Form("%d", from)))))
    603             delete sequ;
    604         return kTRUE;
    605 
    606     case -1:
    607         cout << "       · deleting went wrong " << endl;
    608         return kFALSE;
    609     }
    610 
    611 
    612     return rc;
    613 }
    614 
    615 //
    616 // Build Sequences in range of runs
    617 //
    618 Bool_t Process(MSQLServer &serv, TString datapath, TString sequpath, Int_t from, Int_t to,  TList &sequlist, Bool_t dummy)
    619 {
    620 
    621     TString query(Form("SELECT fRunNumber, fRunTypeKEY, fRunStart, fRunStop"
    622                        " FROM RunData"
    623                        " WHERE fRunNumber BETWEEN %d AND %d AND "
    624                        " fExcludedFDAKEY=1 AND (fRunTypeKEY BETWEEN 2 AND 4)"
    625                        " ORDER BY fRunNumber", from, to));
    626 
    627     TSQLResult *res = serv.Query(query);
    628     if (!res)
    629         return kFALSE;
    630 
    631     TExMap map;
    632 
    633     Int_t start=0;
    634     Int_t stop=0;
    635     Int_t last=0;
    636     Int_t first=0;
    637 
    638     MTime lasttime;
    639 
    640     TSQLRow *row=0;
    641 
    642     enum { UNKNOWN, PED=3, CAL=4, DATA=2 };
    643     Char_t status = UNKNOWN;
    644 
    645     Int_t nblocks = 0;
    646 
    647     while ((row=res->Next()))
    648     {
    649         if (!(*row)[1])
    650             continue;
    651 
    652         if (start==0)
    653         {
    654             first = atoi((*row)[0]);
    655             if (debug)
    656                 cout << "First Run: " << first << endl;
    657         }
    658 
    659         switch (atoi((*row)[1]))
    660         {
    661         case CAL: // ---------- CALIBRATION ----------
    662             if (status!=CAL)
     831
     832        // Start the sequence building
     833        // ---------------------------
     834
     835        Int_t   pos = 0;   // Position in the string
     836        TExMap  map;       // Map for resulting sequences
     837        TString residual;  // Unsequences "characters"
     838
     839        // Step through the string one character by one
     840        cout << "   ";
     841        while (pos<str.Length())
     842        {
     843            Bool_t found = kFALSE;
     844
     845            // Loop over the predefined regular expressions
     846            TIter Next(&fListRegexp);
     847            Rule *obj = 0;
     848            while ((obj=(Rule*)Next()))
    663849            {
    664                 start = stop = atoi((*row)[0]);
    665                 if (!(*row)[2])
    666                     cout << "No time available... skipped." << endl;
    667                 else
     850                // Check if regular expressions matchs
     851                const Ssiz_t len = obj->Match(str, pos, runs[pos]);
     852                if (len>0)
    668853                {
    669                     MTime *tm = new MTime;
    670                     tm->SetSqlDateTime((*row)[2]);
    671                     map.Add((ULong_t)map.GetSize(), (Long_t)tm, (Long_t)nblocks);
     854                    // In case of match get the substring which
     855                    // defines the sequence and print it
     856                    TString sub = str(pos, len);
     857                    sub.ToUpper();
     858                    cout << runs[pos]<<":"<< sub << "|";
     859
     860                    // Add the first and last run of the sequence to the map
     861                    map.Add(runs[pos], runs[pos+len-1]);
     862
     863                    // A sequence was found...
     864                    found = kTRUE;
     865
     866                    // step forward in the string by the length of the sequence
     867                    pos += len;
     868                    break;
    672869                }
    673870            }
    674             status = CAL;
    675             break;
    676         default:
    677             if (status==CAL)
     871
     872            // If a sequence was found go on...
     873            if (found)
     874                continue;
     875
     876            // print unsequenced characters
     877            cout << (char)tolower(str[pos]);
     878
     879            // Count the number of "characters" not sequenced
     880            residual += str[pos];
     881
     882            // step one character forward
     883            pos++;
     884        }
     885        cout << endl;
     886
     887        PrintResidual(runstart, runstop, residual, "Runs ");
     888
     889        // Create all sequences which were previously found
     890        Long_t first, last;
     891        TExMapIter iter(&map);
     892        while (iter.Next(first, last))
     893            if (CreateSequence(first, last)==2)
     894                return 2;
     895
     896        return kTRUE;
     897    }
     898
     899    Char_t RunType(Int_t n) const
     900    {
     901        switch (n)
     902        {
     903        case 2: return 'D';
     904        case 3: return 'P';
     905        case 4: return 'C';
     906        }
     907        return '-';
     908    }
     909    Char_t RunType(const char *str) const
     910    {
     911        return RunType(atoi(str));
     912    }
     913
     914    Int_t BuildBlocks(TSQLResult *res, TExMap &blocks)
     915    {
     916        // col key content
     917        // -----------------------------
     918        //  0   -  runnumber
     919        //  1   0  RunTypeKEY
     920        //  2   1  source
     921        //  3   2  project
     922        //  .   .
     923        //  .   .
     924        //  .   .  from transition.txt
     925        //
     926
     927        //build blocks of runs, which have the same values
     928        //for each block the first and the last run are stored in a TExMap
     929        //the values are checked with the help of an array of TStrings
     930        Long_t runstart = -1;
     931        Long_t runstop  = -1;
     932
     933        const UInt_t ncols = res->GetFieldCount();
     934
     935        TString keys[ncols]; // Index 0 is not used (Index 1: RunType)
     936
     937        // Loop over runs
     938        TSQLRow *row=0;
     939        while ((row=res->Next()))
     940        {
     941            // This is the runnumber of the first run in the new block
     942            if (runstart<0)
     943                runstart=atoi((*row)[0]);
     944
     945            // Check which transitions might be allowed for this run and
     946            // which are not. Check also which attributes should be ignored
     947            // for this run. The information about it is stored in the map.
     948            Int_t rc[ncols];
     949            for (UInt_t i=2; i<ncols; i++)
     950                rc[i] = CheckTransition(*res, keys, *row, i);
     951
     952            for (UInt_t i=2; i<ncols; i++)
    678953            {
    679                 MTime *tm = new MTime(lasttime);
    680                 map.Add((ULong_t)map.GetSize(), (Long_t)tm, (Long_t)nblocks);
    681 
    682                 stop = last;
    683                 nblocks++;
    684                 if (debug)
    685                     cout << "Cal Block #" << nblocks << " from " << start << " to " << last << endl;
     954                switch (rc[i])
     955                {
     956                case kTRUE:    // Transition allowed, switch to new attribute
     957                    keys[i] = (*row)[i];
     958                    continue;
     959
     960                case -1:       // Ignore attribute, continue with next one
     961                    //if (keys[i] == (*row)[i])
     962                    //    break; // Only ignore it if it is really different
     963                    continue;
     964
     965                case kFALSE:   // No decision (nothing matching found in map)
     966                    break;     //  go on checking
     967
     968                }
     969
     970                // If past-attribute is not yet initialized, do it now.
     971                if (keys[i].IsNull())
     972                    keys[i] = (*row)[i];
     973
     974                // Check whether key has changed for this run
     975                // (this condition is never true for the first run)
     976                // This condition in only reached if keys[i] was initialized
     977                if (keys[i] == (*row)[i])
     978                    continue;
     979
     980                // Found one block with unique keys, fill values into TExMap
     981                // (except if this is the first run processed)
     982                cout << endl;
     983                cout << " - Identical conditions from " << runstart << " to " << runstop << endl;
     984                blocks.Add((ULong_t)blocks.GetSize(), runstart, runstop);
     985                if (SplitBlock(runstart, runstop)==2)
     986                    return 2;
     987                cout << " - Transition from " << RunType(keys[1]) << ":";
     988                cout << QueryNameOfKey(res->GetFieldName(i), keys[i]) << " <" << keys[i] << "> to " << RunType((*row)[1]) << ":";
     989                cout << QueryNameOfKey(res->GetFieldName(i), (*row)[i]) << " <" << (*row)[i] << ">";
     990                cout << " in " << res->GetFieldName(i) << " of " << (*row)[0] << endl;
     991
     992                // This is already the first run of the new block
     993                runstart=atoi((*row)[0]);
     994
     995                // These are the keys corresponding to the first run
     996                // in the new block. All following runs should have
     997                // identical keys. Do not set the attribute if for
     998                // this attribute the transition check evaluated
     999                // to "ignore".
     1000                for (UInt_t j=2; j<ncols; j++)
     1001                    keys[j] = rc[j]==-1 ? "" : (*row)[j];
     1002
     1003                break;
    6861004            }
    687             status = UNKNOWN;
    688             break;
    689         }
    690         last = atoi((*row)[0]);
    691         lasttime.SetSqlDateTime((*row)[3]);
    692     }
    693     if (status==CAL)
    694     {
    695         stop = last;
    696         nblocks++;
    697         if (debug)
    698             cout << "Cal Block #" << nblocks << " from " << start << " to " << stop << endl;
    699     }
    700 
    701     if (debug)
    702         cout << "Last Run: " << last << endl;
    703     delete res;
    704 
    705     if (debug)
    706         cout << "Found " << nblocks << " calibration blocks" << endl;
    707 
    708     res = serv.Query(query);
    709     if (!res)
    710         return kFALSE;
    711 
    712     Int_t n = -1;
    713 
    714     Bool_t rc = kTRUE;
    715 
    716     start = first;
    717     while ((row=res->Next()))
    718     {
    719         if (!(*row)[1])
    720             continue;
    721 
    722         MTime tstart, tstop;
    723         tstart.SetSqlDateTime((*row)[2]);
    724         tstop.SetSqlDateTime((*row)[3]);
    725 
    726         MTime    min;
    727         Int_t    nmin = -1;
    728         Double_t dmin = 1e35;
    729 
    730         Long_t key, val;
    731         TExMapIter nmap(&map);
    732         while (nmap.Next(key, val))
    733         {
    734             MTime *t = (MTime*)key;
    735 
    736             if (nmin==-1)
     1005
     1006            keys[1] = (*row)[1]; // Remember run type for next run
     1007
     1008            // This is the new runnumber of the last run in this block
     1009            runstop=atoi((*row)[0]);
     1010        }
     1011
     1012        // If runstart==-1 a possible block would contain a single run...
     1013        if (runstart>0 && runstart!=runstop)
     1014        {
     1015            cout << " - Identical conditions from " << runstart << " to " << runstop << " (last run)" << endl;
     1016            //fill values into TExMap (last value)
     1017            blocks.Add((ULong_t)blocks.GetSize(), runstart, runstop);
     1018            if (SplitBlock(runstart, runstop)==2)
     1019                return 2;
     1020        }
     1021        cout << "Done." << endl << endl;
     1022
     1023        return kTRUE;
     1024    }
     1025
     1026public:
     1027    SequenceBuild(TEnv &env) : MSQLMagic(env)
     1028    {
     1029        cout << "buildsequences" << endl;
     1030        cout << "--------------" << endl;
     1031        cout << endl;
     1032        cout << "Connected to " << GetName() << endl;
     1033
     1034        fListRegexp.SetOwner();
     1035
     1036        // FIXME: THIS IS NOT YET HANDLED
     1037        if (ReadResources("resources/sequences.rc"))
     1038            return;
     1039    }
     1040    SequenceBuild()
     1041    {
     1042        fMap.DeleteAll();
     1043    }
     1044    /*
     1045     SequenceBuild(SequenceBuild &sb) : MSQLServer(sb)
     1046     {
     1047        fPathRawData = sb.fPathRawData;
     1048        fPathSequences = sb.fPathSequences;
     1049    }*/
     1050    void SetPathRawData(const char *path) { fPathRawData=path; }
     1051    void SetPathSequences(const char *path) { fPathSequences=path; }
     1052
     1053    int Build(TString day)
     1054    {
     1055        cout << endl;
     1056        cout << "Night of sunrise at " << day << ":" << endl;
     1057
     1058        day += " 13:00:00";
     1059        const TString cond =
     1060            Form("(fRunStart>ADDDATE(\"%s\", INTERVAL -1 DAY) AND fRunStart<\"%s\") "
     1061                 "AND fExcludedFDAKEY=1 AND fRunTypeKEY BETWEEN 2 AND 4 "
     1062                 "ORDER BY fRunNumber",
     1063                 day.Data(), day.Data());
     1064
     1065
     1066
     1067        //query all sources observed in this night
     1068        TString querys(Form("SELECT RunData.fSourceKEY, fSourceName FROM RunData "
     1069                            "LEFT JOIN Source ON RunData.fSourceKEY=Source.fSourceKEY "
     1070                            "WHERE %s", cond.Data()));
     1071        TSQLResult *resx = Query(querys);
     1072        if (!resx)
     1073            return 2;
     1074        TString elts = GetELT("Source", resx, "\\-*W[1-9][ abc]*$");
     1075        delete resx;
     1076
     1077        //query all project names observed in this night
     1078        TString queryp(Form("SELECT RunData.fProjectKEY, fProjectName FROM RunData "
     1079                            "LEFT JOIN Project ON RunData.fProjectKEY=Project.fProjectKEY "
     1080                            "WHERE %s", cond.Data()));
     1081        resx = Query(queryp);
     1082        if (!resx)
     1083            return 2;
     1084
     1085        TList regexp;
     1086        regexp.Add(new TObjString("\\-*W[1-9][abc]?$"));
     1087        regexp.Add(new TObjString("\\-W[0-9]\\.[0-9][0-9]\\+[0-9][0-9][0-9]$"));
     1088        TString eltp2 = GetELT("Project", resx, regexp);
     1089        delete resx;
     1090        regexp.Delete();
     1091
     1092        // Setup query to get all values from the database,
     1093        // that are relevant for building sequences
     1094        TString query("SELECT fRunNumber, fRunTypeKEY, ");
     1095        query += elts;
     1096        query += ", ";
     1097        query += eltp2;
     1098
     1099        // Now add all entries from the transition table to the query
     1100        TIter NextPair(&fMap);
     1101        TObject *mapkey = 0;
     1102        while ((mapkey=(TPair*)NextPair()))
     1103            if (!query.Contains(mapkey->GetName()))
    7371104            {
    738                 nmin = val;
    739                 min  = *(MTime*)key;
    740                 dmin = fabs((Double_t)*t-(Double_t)tstart);
     1105                query += ", ";
     1106                query += mapkey->GetName();
    7411107            }
    742 
    743             if (fabs((Double_t)*t-(Double_t)tstart) < dmin)
    744             {
    745                 nmin = val;
    746                 dmin = fabs((Double_t)*t-(Double_t)tstart);
    747                 min = *t;
    748             }
    749             if (fabs((Double_t)*t-(Double_t)tstop) < dmin)
    750             {
    751                 nmin = val;
    752                 dmin = fabs((Double_t)*t-(Double_t)tstop);
    753                 min = *t;
    754             }
    755         }
    756 
    757         if (n!=nmin)
    758         {
    759             if (n!=-1)
    760             {
    761                 if (!NewSequence(serv, datapath, sequpath, start, last, sequlist, dummy))
    762                 {
    763                     rc = kFALSE;
    764                     //continue;
    765                 }
    766             }
    767             n = nmin;
    768             start = atoi((*row)[0]);
    769         }
    770         last = atoi((*row)[0]);
    771     }
    772 
    773     delete res;
    774 
    775     if (n!=-1 && start!=last)
    776     {
    777         if (!NewSequence(serv, datapath, sequpath, start, last, sequlist, dummy))
    778             rc = kFALSE;
    779     }
    780 
    781     if (debug)
    782         cout << endl;
    783 
    784     return rc;
    785 }
    786 
    787 void buildblocks(TSQLResult *res, TExMap &blocks)
    788 {
    789     //build blocks of runs, which have the same values
    790     //for each block the first and the last run are stored in a TExMap
    791     //the values are checked with the help of an array of TStrings
    792     TString keys[7];
    793 
    794     Long_t runstart = -1;
    795     Long_t runstop  = -1;
    796 
    797     // "Result set closed" means "Result set empty"
    798 
    799     // Loop over runs
    800     TSQLRow *row=0;
    801     while ((row=res->Next()))
    802     {
    803         // Check whether all keys for this run fit
    804         for (Int_t i=1; i<8; i++)
    805         {
    806             // Do not check project key for this runs
    807             // (this condition is never true for the first run)
    808             if (i==2 && runstart>20100 && runstop<45100)
    809                 continue;
    810 
    811             // Check whether key has changed for this run
    812             // (this condition is never true for the first run)
    813             if (keys[i-1] == (*row)[i])
    814                 continue;
    815 
    816             // Found one block with unique keys, fill values into TExMap
    817             // (except if this is the first run processed)
    818             if (runstart>0)
    819                 blocks.Add((ULong_t)blocks.GetSize(), runstart, runstop);
    820 
    821             // This is the runnumber of the first run in the new block
    822             runstart=atoi((*row)[0]);
    823 
    824             // These are the keys corresponding to the first run in the new block
    825             for (int i=1; i<8; i++)
    826                 keys[i-1] = (*row)[i];
    827 
    828             break;
    829         }
    830 
    831         // This is the new runnumber of the last run in this block
    832         runstop=atoi((*row)[0]);
    833     }
    834 
    835     if (runstart!=runstop)
    836     {
    837         //fill values into TExMap (last value)
    838         blocks.Add((ULong_t)blocks.GetSize(), runstart, runstop);
    839     }
    840 }
    841 
    842 //
    843 // Build Sequences for the night given by TString day
    844 //
     1108        query += Form(" FROM RunData WHERE %s", cond.Data());
     1109
     1110        TSQLResult *res = Query(query);
     1111        if (!res)
     1112            return 2;
     1113
     1114        TExMap blocks;
     1115        const Int_t rc = BuildBlocks(res, blocks);
     1116        delete res;
     1117
     1118        return rc;
     1119    }
     1120
     1121    Int_t Build()
     1122    {
     1123        //get all dates from the database
     1124        TSQLResult *res = Query("SELECT fDate FROM SequenceBuildStatus ORDER BY fDate DESC");
     1125        if (!res)
     1126            return 2;
     1127
     1128        //execute buildsequenceentries for all dates
     1129        TSQLRow *row=0;
     1130        while ((row=res->Next()))
     1131            Build((*row)[0]);
     1132
     1133        delete res;
     1134
     1135        return 1;
     1136    }
     1137    ClassDef(SequenceBuild, 0)
     1138};
     1139
     1140ClassImp(SequenceBuild);
     1141
    8451142int buildsequenceentries(TString day, TString datapath, TString sequpath, Bool_t dummy=kTRUE)
    8461143{
    8471144    TEnv env("sql.rc");
    8481145
    849     MSQLServer serv(env);
     1146    SequenceBuild serv(env);
    8501147    if (!serv.IsConnected())
    8511148    {
     
    8541151    }
    8551152
    856     cout << "buildsequences" << endl;
    857     cout << "--------------" << endl;
    858     cout << endl;
    859     cout << "Connected to " << serv.GetName() << endl;
    860     cout << "Night of sunrise at: " << day << endl;
    861     cout << endl;
    862 
    863     day += " 13:00:00";
    864     const TString cond(Form("(fRunStart>ADDDATE(\"%s\", INTERVAL -1 DAY) AND fRunStart<\"%s\")",
    865                             day.Data(), day.Data()));
    866 
    867     TString elts  = "fSourceKEY";
    868     TString eltp2 = "fProjectKEY";
    869 
    870     //get all values from the database, that are relevant for building sequences
    871     TString query("SELECT fRunNumber, ");
    872     query += elts;
    873     query += ", ";
    874     query += eltp2;
    875     query += Form(", fHvSettingsKEY, fLightConditionsKEY, fDiscriminatorThresholdTableKEY, "
    876                   "fTriggerDelayTableKEY, fObservationModeKEY FROM RunData "
    877                   "WHERE %s AND fExcludedFDAKEY=1 order by fRunNumber", cond.Data());
    878 
    879     TSQLResult *res = serv.Query(query);
    880     if (!res)
    881         return 2;
    882 
    883     TExMap blocks;
    884     buildblocks(res, blocks);
    885     delete res;
    886 
    887     // ---
    888     // Now the blocks containing the same observation conditions
    889     // are created...
    890     // ---
    891 
    892     //get list of current sequence of this night from the database and store it in sequlist
    893     TList sequlist;
    894     query=Form("SELECT fSequenceFirst FROM Sequences WHERE fManuallyChangedKEY=1 AND %s order by fSequenceFirst",
    895                cond.Data());
    896 
    897     res = serv.Query(query);
    898     if (!res)
    899         return 2;
    900 
    901     cout << "Old sequences: " << flush;
    902     TSQLRow *row=0;
    903     while ((row=res->Next()))
    904     {
    905         const char *str =  (*row)[0];
    906         cout << str << " " << flush;
    907         sequlist.Add(new TObjString(str));
    908     }
    909     cout << endl;
    910 
    911     delete res;
    912 
    913     Bool_t rc = kTRUE;
    914 
    915     //build sequences in each block of runs
    916     Long_t key, val;
    917     TExMapIter nblocks(&blocks);
    918     while (nblocks.Next(key, val))
    919     {
    920         const Int_t runstart = (Int_t)key;
    921         const Int_t runstop  = (Int_t)val;
    922 
    923         cout << endl << "Datablock from " << runstart << " to " << runstop << ":" << endl;
    924 
    925         if (!Process(serv, datapath, sequpath, runstart, runstop, sequlist, dummy))
    926             rc = kFALSE;
    927 
    928     }
    929 
    930     //newly build or remaining sequences are removed from sequlist while building sequences
    931     //delete sequences that remained in the list
    932     //this is necessary if e.g. all runs of one old sequence have been excluded in the meantime
    933     TIter Next(&sequlist);
    934     TObject *obj = 0;
    935     while ((obj=Next()))
    936     {
    937         cout << " - Sequence " << obj->GetName() << " deleting... " << endl;
    938         if (!DeleteSequence(serv, datapath, sequpath, atoi(obj->GetName()), dummy))
    939             return 2;
    940     }
    941 
    942     return rc ? 1 : 2;
     1153    serv.SetIsDummy(dummy);
     1154    serv.SetPathRawData(datapath);
     1155    serv.SetPathSequences(sequpath);
     1156    return serv.Build(day);
    9431157}
    9441158
     
    9501164    TEnv env("sql.rc");
    9511165
    952     MSQLServer serv(env);
     1166    SequenceBuild serv(env);
    9531167    if (!serv.IsConnected())
    9541168    {
     
    9571171    }
    9581172
    959     //get all dates from the database
    960     TString query="SELECT fDate FROM SequenceBuildStatus";
    961 
    962     TSQLResult *res = serv.Query(query);
    963     if (!res)
    964         return 2;
    965 
    966     //execute buildsequenceentries for all dates
    967     TString date;
    968     TSQLRow *row=0;
    969     while ((row=res->Next()))
    970     {
    971         date=(*row)[0];
    972         buildsequenceentries(date, datapath, sequpath, dummy);
    973     }
    974 
    975     delete res;
    976 
    977     return 1;
     1173    serv.SetIsDummy(dummy);
     1174    serv.SetPathRawData(datapath);
     1175    serv.SetPathSequences(sequpath);
     1176    return serv.Build();
    9781177}
     1178
     1179int buildsequenceentries(Bool_t dummy=kTRUE)
     1180{
     1181    return buildsequenceentries("", "", dummy);
     1182}
     1183
     1184int buildsequenceentries(TString day, Bool_t dummy=kTRUE)
     1185{
     1186    return buildsequenceentries(day, "", "", dummy);
     1187}
  • trunk/MagicSoft/Mars/ganymed_onoff.rc

    r7980 r7981  
    4949#MPointingDevCalc.NsbMin:      30
    5050#MPointingDevCalc.NsbMax:      60
     51#MPointingDevCalc.MaxAbsDev:   15
    5152#MPointingDevCalc.Dx           -7
    5253#MPointingDevCalc.Dy           16
     
    112113
    113114# Get rid of triangular events...
    114 #Cut0.Condition: log10(MNewImagePar.fConc1) < (-0.467)*log10(MHillas.fSize) + 0.75
    115115Cut0.Condition: ({0} || {1}) && {2} && {3} && {4} && {5} && {6}
    116116Cut0.0: MImagePar.fNumSatPixelsHG < 1
  • trunk/MagicSoft/Mars/ganymed_wobble.rc

    r7744 r7981  
    5555
    5656# -------------------------------------------------------------------------
     57# Setup the misfocussing correction
     58# -------------------------------------------------------------------------
     59#MSrcPosCorrect.Dx: 0
     60#MSrcPosCorrect.Dy: 0
     61
     62# -------------------------------------------------------------------------
    5763# Setup fit mode and ranges
    5864# -------------------------------------------------------------------------
     
    7177# -------------------------------------------------------------------------
    7278#MJCut.NameHist: MHAlpha
     79
     80# Be carefull: The spectrum might be done with a different binning
     81# This might change the scale factor
     82#MHThetaSq.NumBinsSignal:   3
     83#MHThetaSq.NumBinsTotal:   75
    7384
    7485# -------------------------------------------------------------------------
     
    120131MAlphaFitter.SignalFunction: ThetaSq
    121132
     133# For more details on the magic cuts see its class reference
    122134Cut1.Condition: MFMagicCuts
    123135Cut1.ThetaCut: Off
     136# Parametrization of Disp
    124137Cut1.Param0:  1.221
     138Cut1.Param6:  13.425
     139Cut1.Param7:  1.04343
     140# Parametrization for sign of disp (m3long)
     141Cut1.Param5: -0.07
     142# ThetaSq-Cut
    125143Cut1.Param1:  0.22
     144# Area-Cut
    126145Cut1.Param2:  0.222
    127146Cut1.Param3:  5.524
    128147Cut1.Param4:  0.0878
    129 Cut1.Param5: -0.07
    130 Cut1.Param6:  13.425
    131 Cut1.Param7:  1.04343
    132148
    133 # Be carefull: The spectrum might be done with a different binning
    134 # This might change the scale factor
    135 #MHThetaSq.NumBinsSignal:   3
    136 #MHThetaSq.NumBinsTotal:   75
     149# To switch on random forest uncomment the following lines
     150#Cut1.HadronnessCut: Hadronness
     151#Cut1.Param8: 0.5
     152#Cut1.Param9: 100
    137153
    138 # -------------------------------------------------------------------------
    139 # Setup cuts in false source plot
    140 # -------------------------------------------------------------------------
    141 #MHFalseSource.DistMin: 0.55
    142 #MHFalseSource.DistMax: 0.55
    143 #MHFalseSource.DWMin:   0.55
    144 #MHFalseSource.DWMax:   0.55
     154# To use both, hadronness and area cut do
     155#Cut1.HadronnessCut: All
    145156
    146157# -------------------------------------------------------------------------
Note: See TracChangeset for help on using the changeset viewer.