]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - FMD/AliFMDParameters.cxx
Added the offline trigger functions for use with the first physics.
[u/mrichter/AliRoot.git] / FMD / AliFMDParameters.cxx
index 5eb6e1dec694c9985b085a559726f66dba6ec0f0..d5b8eb1366a0db3b7886b236eb2b74840e9321fe 100644 (file)
@@ -86,6 +86,9 @@ AliFMDParameters::AliFMDParameters()
     fAltroChannelSize(0),
     fChannelsPerAltro(0),
     fPedestalFactor(0),
+    fZSPre(0),
+    fZSPost(0),
+    fZSPedSubtract(kFALSE),
     fFixedPedestal(0),
     fFixedPedestalWidth(0),
     fFixedZeroSuppression(0),
@@ -102,7 +105,9 @@ AliFMDParameters::AliFMDParameters()
     fPulseGain(0), 
     fDeadMap(0), 
     fAltroMap(0), 
-    fStripRange(0)
+    fStripRange(0),
+    fOfflineTriggerLowCut(0.1),
+    fOfflineTriggerHitCut(0.6)
 {
   // Default constructor 
   SetVA1MipRange();
@@ -132,6 +137,7 @@ AliFMDParameters::Init(Bool_t forceReInit, UInt_t what)
   if (what & kSampleRate)      InitSampleRate();
   if (what & kZeroSuppression) InitZeroSuppression();
   if (what & kAltroMap)        InitAltroMap();
+  if (what & kStripRange)      InitStripRange();
   fIsInit = kTRUE;
 }
 //__________________________________________________________________
@@ -148,9 +154,91 @@ AliFMDParameters::Init(AliFMDPreprocessor* pp, Bool_t forceReInit, UInt_t what)
   if (what & kSampleRate)      InitSampleRate(pp);
   if (what & kZeroSuppression) InitZeroSuppression(pp);
   if (what & kAltroMap)        InitAltroMap(pp);
+  if (what & kStripRange)      InitStripRange(pp);
   fIsInit = kTRUE;
 }
 
+//__________________________________________________________________
+Bool_t
+AliFMDParameters::CheckFile(const char* prefix, 
+                           const char* path, 
+                           int         number, 
+                           TString&    f) const
+{
+  f = (Form("%s%d.csv", prefix, number));
+  AliFMDDebug(5, ("Checking if %s exists in %s ...", f.Data(), path));
+  f = gSystem->Which(path, f.Data());
+  AliFMDDebug(5, ("Got back '%s'", f.Data()));
+  return !f.IsNull();
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::Init(const char* path, Bool_t forceReInit, UInt_t what)
+{
+  // Initialize the parameters manager.  Pedestals, gains, strip
+  // range, and sample rate is read from local comma separated value
+  // files if available.  Otherwise, the calibrations are obtained
+  // from OCDB.
+  if (forceReInit) fIsInit = kFALSE;
+  if (fIsInit) return;
+
+  AliFMDCalibStripRange*  range = 0;
+  AliFMDCalibSampleRate*  rate  = 0;
+  AliFMDCalibPedestal*    peds  = 0;
+  AliFMDCalibGain*        gains = 0;
+
+  for (Int_t i = 1; i <= 3; i++) { 
+    TString f;
+    if (((what & kSampleRate) || (what & kStripRange)) && 
+       CheckFile("conditions", path, i, f)) {
+      if (!rate  && (what & kSampleRate)) rate  = new AliFMDCalibSampleRate;
+      if (!range && (what & kStripRange)) range = new AliFMDCalibStripRange;
+      std::ifstream in(f.Data());
+      if (range) range->ReadFromFile(in);
+      if (rate)  rate->ReadFromFile(in);
+      in.close();
+    }
+    if ((what & kPedestal) && CheckFile("peds", path, i, f)) {
+      if (!peds) peds  = new AliFMDCalibPedestal;
+      std::ifstream in(f.Data());
+      peds->ReadFromFile(in);
+      in.close();
+    }
+    if ((what & kPulseGain) && CheckFile("gains", path, i, f)) { 
+      if (!gains) gains = new AliFMDCalibGain;
+      std::ifstream in(f.Data());
+      gains->ReadFromFile(in);
+      in.close();
+    }
+  }
+
+  if (range) what &= ~kStripRange;
+  if (rate)  what &= ~kSampleRate;
+  if (peds)  what &= ~kPedestal;
+  if (gains) what &= ~kPulseGain;
+
+  Init(kFALSE, what);
+  
+  if (range) SetStripRange(range);
+  if (rate)  SetSampleRate(rate);
+  if (peds)  SetPedestal(peds);
+  if (gains) SetGain(gains);
+
+  fIsInit = kTRUE;
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::MakeDeadMap(Float_t maxNoise, 
+                             Float_t minGain, 
+                             Float_t maxGain)
+{
+  if (fPedestal)  
+    fDeadMap = fPedestal->MakeDeadMap(maxNoise, fDeadMap);
+  if (fPulseGain) 
+    fDeadMap = fPulseGain->MakeDeadMap(minGain, maxGain, fDeadMap);
+}
 //__________________________________________________________________
 #define DET2IDX(det,ring,sec,str) \
   (det * 1000 + (ring == 'I' ? 0 : 512) + str)  
@@ -161,39 +249,38 @@ AliFMDParameters::Draw(Option_t* option)
 {
   TString opt(option);
   enum {
-    kPulseGain,       // Path to PulseGain calib object
-    kThreshold,       // Path to PulseGain calib object
-    kPedestal,        // Path to Pedestal calib object
-    kPedestalWidth,   // Path to Pedestal calib object
-    kDead,            // Path to Dead calib object
-    kSampleRate,      // Path to SampleRate calib object
-    kAltroMap,        // Path to AltroMap calib object
-    kZeroSuppression, // Path to ZeroSuppression cal object
-    kMinStripRange,   // Path to strip range cal object
-    kMaxStripRange    // Path to strip range cal object
+    kLocalPulseGain,       // Path to PulseGain calib object
+    kLocalThreshold,       // Path to PulseGain calib object
+    kLocalPedestal,        // Path to Pedestal calib object
+    kLocalPedestalWidth,   // Path to Pedestal calib object
+    kLocalDead,            // Path to Dead calib object
+    kLocalSampleRate,      // Path to SampleRate calib object
+    kLocalAltroMap,        // Path to AltroMap calib object
+    kLocalZeroSuppression, // Path to ZeroSuppression cal object
+    kLocalMinStripRange,   // Path to strip range cal object
+    kLocalMaxStripRange    // Path to strip range cal object
   } what;
-  
     
   if      (opt.Contains("dead", TString::kIgnoreCase)) 
-    what = kDead;
+    what = kLocalDead;
   else if (opt.Contains("threshold",TString::kIgnoreCase)) 
-    what = kThreshold;
+    what = kLocalThreshold;
   else if (opt.Contains("gain",TString::kIgnoreCase)) 
-    what = kPulseGain;
+    what = kLocalPulseGain;
   else if (opt.Contains("pedestal",TString::kIgnoreCase)) 
-    what = kPedestal;
+    what = kLocalPedestal;
   else if (opt.Contains("noise",TString::kIgnoreCase)) 
-    what = kPedestalWidth;
+    what = kLocalPedestalWidth;
   else if (opt.Contains("zero",TString::kIgnoreCase)) 
-    what = kZeroSuppression;
+    what = kLocalZeroSuppression;
   else if (opt.Contains("rate",TString::kIgnoreCase)) 
-    what = kSampleRate;
+    what = kLocalSampleRate;
   else if (opt.Contains("min",TString::kIgnoreCase)) 
-    what = kMinStripRange;
+    what = kLocalMinStripRange;
   else if (opt.Contains("max",TString::kIgnoreCase)) 
-    what = kMaxStripRange;
+    what = kLocalMaxStripRange;
   else if (opt.Contains("map",TString::kIgnoreCase)) 
-    what = kAltroMap;
+    what = kLocalAltroMap;
   else {
     Warning("Draw", "unknown parameter: %s\n\tShould be one of\n\t"
            "dead, threshold, gain, pedestal, noise, zero, rate, "
@@ -228,7 +315,7 @@ AliFMDParameters::Draw(Option_t* option)
     }
   }
   TArrayD ybins(41);
-  for (Int_t i = 0; i < ybins.fN; i++) ybins[i] = Float_t(i - .5);
+  for (/*Int_t*/ i = 0; i < ybins.fN; i++) ybins[i] = Float_t(i - .5);
   TH2D* hist = new TH2D("calib", Form("Calibration %s", option), 
                        xbins.fN-1, xbins.fArray,  
                        ybins.fN-1, ybins.fArray);
@@ -247,29 +334,29 @@ AliFMDParameters::Draw(Option_t* option)
       for (UShort_t sec = 0; sec < nSector; sec++) {
        for (UShort_t str = 0; str < nStrip; str++) {
          Int_t idx = DET2IDX(det, ring, sec, str);
-         UInt_t ddl, addr;
+         UShort_t ddl, addr, time, sam=0;
          Double_t val = 0;
          switch (what) {
-         case kPulseGain:       // Path to PulseGain calib object
+         case kLocalPulseGain:       // Path to PulseGain calib object
             val = GetPulseGain(det,ring,sec,str); break;
-         case kThreshold:       // Path to PulseGain calib object
+         case kLocalThreshold:       // Path to PulseGain calib object
             val = GetThreshold(); break;
-         case kPedestal:        // Path to Pedestal calib object
+         case kLocalPedestal:        // Path to Pedestal calib object
             val = GetPedestal(det,ring,sec,str); break;
-         case kPedestalWidth:   // Path to Pedestal calib object
+         case kLocalPedestalWidth:   // Path to Pedestal calib object
             val = GetPedestalWidth(det,ring,sec,str); break;
-         case kDead:            // Path to Dead calib object
+         case kLocalDead:            // Path to Dead calib object
             val = IsDead(det,ring,sec,str); break;
-         case kSampleRate:      // Path to SampleRate calib object
+         case kLocalSampleRate:      // Path to SampleRate calib object
             val = GetSampleRate(det,ring,sec,str); break;
-         case kAltroMap:        // Path to AltroMap calib object
-           Detector2Hardware(det,ring,sec,str, ddl, addr); 
+         case kLocalAltroMap:        // Path to AltroMap calib object
+           Detector2Hardware(det,ring,sec,str,sam,ddl,addr,time); 
             val = addr; break;
-         case kZeroSuppression: // Path to ZeroSuppression cal object
+         case kLocalZeroSuppression: // Path to ZeroSuppression cal object
             val = GetZeroSuppression(det,ring,sec,str); break;
-         case kMinStripRange:   // Path to strip range cal object
+         case kLocalMinStripRange:   // Path to strip range cal object
             val = GetMinStrip(det,ring,sec,str); break;
-         case kMaxStripRange:    // Path to strip range cal object
+         case kLocalMaxStripRange:    // Path to strip range cal object
             val = GetMaxStrip(det,ring,sec,str); break;
          }
          hist->Fill(idx,sec,val);
@@ -306,9 +393,12 @@ AliFMDParameters::Print(Option_t* option) const
   
   
   if (opt.Contains("fmd",TString::kIgnoreCase)) {
-    showStrips    = kTRUE;
-    size_t   i    = opt.Index("fmd",TString::kIgnoreCase);
-    size_t   j    = opt.Index("]",TString::kIgnoreCase);
+    Int_t   i    = opt.Index("fmd",TString::kIgnoreCase);
+    Int_t   j    = opt.Index("]",TString::kIgnoreCase);
+    if (j != kNPOS)
+      showStrips    = kTRUE;
+    else 
+      j = opt.Length();
     enum {
       kReadDet, 
       kReadRing, 
@@ -402,17 +492,20 @@ AliFMDParameters::Print(Option_t* option) const
       if (det == 1 && ring == 'O') continue;
       UShort_t min  = GetMinStrip(det, ring, 0, 0);
       UShort_t max  = GetMaxStrip(det, ring, 0, 0);
-      UShort_t rate = GetSampleRate(det, ring, 0, 0);
       std::cout << "FMD" << det << ring 
                << "  Strip range: " 
                << std::setw(3) << min << "," 
-               << std::setw(3) << max << "  Rate: " 
-               << std::setw(2) << rate << std::endl;
+               << std::setw(3) << max << std::endl;
 
-      if (!showStrips) continue;
       UShort_t nSec = ( ring == 'I' ? 20  :  40 );
       UShort_t nStr = ( ring == 'I' ? 512 : 256 );
       for (UShort_t sec = minSector; sec < maxSector && sec < nSec; sec++) {
+
+       UShort_t rate = GetSampleRate(det, ring, sec, 0);
+       std::cout << "FMD" << det << ring << "[" << std::setw(2) << sec 
+                 << "] sample rate: " << rate << std::endl;
+
+       if (!showStrips) continue;
        std::cout 
          << "  Strip |     Pedestal      |    Gain    | ZS thr. | Address\n" 
          << "--------+-------------------+------------+---------+---------" 
@@ -425,8 +518,8 @@ AliFMDParameters::Print(Option_t* option) const
            std::cout << "dead" << std::endl;
            continue;
          }
-         UInt_t ddl, addr;
-         Detector2Hardware(det, ring, sec, str, ddl, addr);
+         UShort_t ddl, addr, time, sam=0;
+         Detector2Hardware(det, ring, sec, str, sam, ddl, addr, time);
          std::cout << std::setw(7) << GetPedestal(det, ring, sec, str) 
                    << "+/-" << std::setw(7) 
                    << GetPedestalWidth(det, ring, sec, str) 
@@ -493,7 +586,7 @@ AliFMDParameters::InitPulseGain(AliFMDPreprocessor* pp)
   AliCDBEntry*   gain     = GetEntry(fgkPulseGain, pp);
   if (!gain) return;
   
-  AliFMDDebug(1, ("Got gain from CDB"));
+  AliFMDDebug(5, ("Got gain from CDB"));
   fPulseGain = dynamic_cast<AliFMDCalibGain*>(gain->GetObject());
   if (!fPulseGain) AliFatal("Invalid pulser gain object from CDB");
 }
@@ -505,7 +598,7 @@ AliFMDParameters::InitPedestal(AliFMDPreprocessor* pp)
   AliCDBEntry*   pedestal = GetEntry(fgkPedestal, pp);
   if (!pedestal) return;
 
-  AliFMDDebug(1, ("Got pedestal from CDB"));
+  AliFMDDebug(5, ("Got pedestal from CDB"));
   fPedestal = dynamic_cast<AliFMDCalibPedestal*>(pedestal->GetObject());
   if (!fPedestal) AliFatal("Invalid pedestal object from CDB");
 }
@@ -518,7 +611,7 @@ AliFMDParameters::InitDeadMap(AliFMDPreprocessor* pp)
   AliCDBEntry*   deadMap  = GetEntry(fgkDead, pp);
   if (!deadMap) return;
   
-  AliFMDDebug(1, ("Got dead map from CDB"));
+  AliFMDDebug(5, ("Got dead map from CDB"));
   fDeadMap = dynamic_cast<AliFMDCalibDeadMap*>(deadMap->GetObject());
   if (!fDeadMap) AliFatal("Invalid dead map object from CDB");
 }
@@ -530,7 +623,7 @@ AliFMDParameters::InitZeroSuppression(AliFMDPreprocessor* pp)
   // Get 0-suppression from CDB 
   AliCDBEntry*   zeroSup  = GetEntry(fgkZeroSuppression, pp);
   if (!zeroSup) return;
-  AliFMDDebug(1, ("Got zero suppression from CDB"));
+  AliFMDDebug(5, ("Got zero suppression from CDB"));
   fZeroSuppression = 
     dynamic_cast<AliFMDCalibZeroSuppression*>(zeroSup->GetObject());
   if (!fZeroSuppression)AliFatal("Invalid zero suppression object from CDB");
@@ -543,7 +636,7 @@ AliFMDParameters::InitSampleRate(AliFMDPreprocessor* pp)
   // get Sample rate from CDB
   AliCDBEntry*   sampRat  = GetEntry(fgkSampleRate, pp);
   if (!sampRat) return;
-  AliFMDDebug(1, ("Got zero suppression from CDB"));
+  AliFMDDebug(5, ("Got zero suppression from CDB"));
   fSampleRate = dynamic_cast<AliFMDCalibSampleRate*>(sampRat->GetObject());
   if (!fSampleRate) AliFatal("Invalid zero suppression object from CDB");
 }
@@ -557,10 +650,10 @@ AliFMDParameters::InitAltroMap(AliFMDPreprocessor* pp)
     delete fAltroMap;
     fAltroMap = 0;
   }
-  AliCDBEntry*   hwMap    = GetEntry(fgkAltroMap, pp);       
+  AliCDBEntry*   hwMap    = GetEntry(fgkAltroMap, pp, kFALSE);       
   if (!hwMap) return;
 
-  AliFMDDebug(1, ("Got ALTRO map from CDB"));
+  AliFMDDebug(5, ("Got ALTRO map from CDB"));
   fAltroMap = dynamic_cast<AliFMDAltroMapping*>(hwMap->GetObject());
   if (!fAltroMap) {
     AliFatal("Invalid ALTRO map object from CDB");
@@ -575,7 +668,7 @@ AliFMDParameters::InitStripRange(AliFMDPreprocessor* pp)
   // Get strips read-out from CDB
   AliCDBEntry*   range    = GetEntry(fgkStripRange, pp);
   if (!range) return;
-  AliFMDDebug(1, ("Got strip range from CDB"));
+  AliFMDDebug(5, ("Got strip range from CDB"));
   fStripRange = dynamic_cast<AliFMDCalibStripRange*>(range->GetObject());
   if (!fStripRange) AliFatal("Invalid strip range object from CDB");
 }
@@ -721,12 +814,58 @@ AliFMDParameters::GetAltroMap() const
 }
 
 
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Hardware2Detector(UShort_t  ddl,       UShort_t addr,
+                                   UShort_t  timebin,   
+                                   UShort_t& det,       Char_t&  ring, 
+                                   UShort_t& sec,       Short_t& str,
+                                   UShort_t& sam) const
+{
+  // Translate a hardware address to detector coordinates. 
+  // 
+  // See also Hardware2Detector that accepts 4 inputs 
+  if (!fAltroMap) return kFALSE;
+  UShort_t board, chip, chan;
+  fAltroMap->ChannelAddress(addr, board, chip, chan);
+  return Hardware2Detector(ddl,board,chip,chan,timebin,det,ring,sec,str,sam);
+}
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Hardware2Detector(UShort_t    ddl,       UShort_t   board,
+                                   UShort_t    chip,      UShort_t   chan,
+                                   UShort_t  timebin,   
+                                   UShort_t& det,       Char_t&   ring, 
+                                   UShort_t& sec,       Short_t& str,
+                                   UShort_t& sam) const
+{
+  // Translate a hardware address to detector coordinates. 
+  // 
+  // See also Hardware2Detector that accepts 4 inputs 
+  if (!fAltroMap) return kFALSE;
+  if (fAltroMap->DDL2Detector(ddl) < 0) return kFALSE;
+  Short_t stripBase = 0;
+  if (!fAltroMap->Channel2StripBase(board,chip,chan, ring, sec, stripBase)) 
+    return kFALSE;
+  UShort_t preSamples = GetPreSamples(det, ring, sec, stripBase);
+  UShort_t sampleRate = GetSampleRate(det, ring, sec, stripBase);
+  Short_t stripOff = 0;
+  fAltroMap->Timebin2Strip(sec, timebin, preSamples, sampleRate, stripOff, sam);
+  str = stripBase + stripOff;
+  AliFMDDebug(50, ("%d/0x%02x/0x%x/0x%x/%04d -> FMD%d%c[%02d,%03d]-%d"
+                 " (pre=%2d, rate=%d)", 
+                  ddl, board, chip, chan, timebin, 
+                  det, ring, sec, str, sam, preSamples, sampleRate));
+  return kTRUE;
+}
+
+#if 0
 //__________________________________________________________________
 Bool_t
-AliFMDParameters::Hardware2Detector(UInt_t    ddl,  UInt_t    board, 
-                                   UInt_t    chip, UInt_t    chan,
+AliFMDParameters::Hardware2Detector(UShort_t    ddl,  UShort_t    board, 
+                                   UShort_t    chip, UShort_t    chan,
                                    UShort_t& det,  Char_t&   ring, 
-                                   UShort_t& sec,  UShort_t& str) const
+                                   UShort_t& sec,  Short_t& str) const
 {
   // Map hardware address to detector index
   if (!fAltroMap) return kFALSE;
@@ -734,21 +873,60 @@ AliFMDParameters::Hardware2Detector(UInt_t    ddl,  UInt_t    board,
 }
 //__________________________________________________________________
 Bool_t
-AliFMDParameters::Hardware2Detector(UInt_t    ddl,  UInt_t    addr, 
+AliFMDParameters::Hardware2Detector(UShort_t    ddl,  UShort_t    addr, 
                                    UShort_t& det,  Char_t&   ring, 
-                                   UShort_t& sec,  UShort_t& str) const
+                                   UShort_t& sec,  Short_t& str) const
 {
   // Map hardware address to detector index
   if (!fAltroMap) return kFALSE;
   return fAltroMap->Hardware2Detector(ddl, addr, det, ring, sec, str);
 }
+#endif
+
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Detector2Hardware(UShort_t  det,        Char_t    ring, 
+                                   UShort_t  sec,        UShort_t  str,
+                                   UShort_t  sam, 
+                                   UShort_t& ddl,        UShort_t& board, 
+                                   UShort_t& altro,      UShort_t& channel, 
+                                   UShort_t& timebin) const
+{
+  if (!fAltroMap) return kFALSE;
+  UShort_t preSamples = GetPreSamples(det, ring, sec, str);
+  UShort_t sampleRate = GetSampleRate(det, ring, sec, str);
+  UShort_t strip      = str - GetMinStrip(det,ring,sec,str);
+  return fAltroMap->Detector2Hardware(det, ring, sec, strip, sam,
+                                     preSamples, sampleRate,
+                                     ddl, board, altro, channel, timebin);
+}
 
+  
+
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Detector2Hardware(UShort_t  det,        Char_t    ring, 
+                                   UShort_t  sec,        UShort_t  str,
+                                   UShort_t  sam, 
+                                   UShort_t&   ddl,        UShort_t&   addr,
+                                   UShort_t& timebin) const
+{
+  if (!fAltroMap) return kFALSE;
+  UShort_t preSamples = GetPreSamples(det, ring, sec, str);
+  UShort_t sampleRate = GetSampleRate(det, ring, sec, str);
+  UShort_t strip      = str - GetMinStrip(det,ring,sec,str);
+  return fAltroMap->Detector2Hardware(det, ring, sec, strip, sam,
+                                     preSamples, sampleRate,
+                                     ddl, addr, timebin);
+}
+
+#if 0
 //__________________________________________________________________
 Bool_t
 AliFMDParameters::Detector2Hardware(UShort_t det,  Char_t   ring, 
                                    UShort_t sec,  UShort_t str, 
-                                   UInt_t&  ddl,  UInt_t&  board, 
-                                   UInt_t&  chip, UInt_t&  chan) const
+                                   UShort_t&  ddl,  UShort_t&  board, 
+                                   UShort_t&  chip, UShort_t&  chan) const
 {
   // Map detector index to hardware address
   if (!fAltroMap) return kFALSE;
@@ -759,13 +937,13 @@ AliFMDParameters::Detector2Hardware(UShort_t det,  Char_t   ring,
 Bool_t
 AliFMDParameters::Detector2Hardware(UShort_t det, Char_t   ring, 
                                    UShort_t sec, UShort_t str, 
-                                   UInt_t&  ddl, UInt_t&  addr) const
+                                   UShort_t&  ddl, UShort_t&  addr) const
 {
   // Map detector index to hardware address
   if (!fAltroMap) return kFALSE;
   return fAltroMap->Detector2Hardware(det, ring, sec, str, ddl, addr);
 }
-
+#endif
 
 //__________________________________________________________________
 Float_t
@@ -780,11 +958,18 @@ AliFMDParameters::GetEdepMip() const
   }
   return fEdepMip;
 }
-
-
-  
+//____________________________________________________________________
+Float_t  
+AliFMDParameters::GetDACPerMIP() const
+{
+  //This is the conversion from the Digital-to-Analog-Converter setting
+  // to the number of MIPs. The number was measured in the NBI lab during
+  // August 2008.
   
+  return 29.67;
   
+}
 //____________________________________________________________________
 //
 // EOF