ROOT logo
// @(#)root/tree:$Id$
// Author: Anna Kreshuk 17/03/2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
// TEntryListFromFile
//
// Manages entry lists from different files, when they are not loaded
// in memory at the same time. 
//
// This entry list should only be used when processing a TChain (see
// TChain::SetEntryList() function). File naming convention:
// - by default, filename_elist.root is used, where filename is the
//   name of the chain element.
// - xxx$xxx.root - $ sign is replaced by the name of the chain element
// If the list name is not specified (by passing filename_elist.root/listname to
// the TChain::SetEntryList() function, the first object of class TEntryList
// in the file is taken.
// It is assumed that there are as many lists, as there are chain elements,
// and they are in the same order.
//
// If one of the list files can't be opened, or there is an error reading a list
// from the file, this list is skipped and the entry loop continues on the next
// list.


#include "TEntryListFromFile.h"
#include "TObjArray.h"
#include "TFile.h"
#include "TKey.h"
#include "TError.h"

ClassImp(TEntryListFromFile)

TEntryListFromFile::TEntryListFromFile(): TEntryList(), 
   fListFileName(""), fListName(""), fNFiles(0), fListOffset(0), fFile(0), fFileNames(0)
{
   // default constructor.
   
}

//______________________________________________________________________________
TEntryListFromFile::TEntryListFromFile(const char *filename, const char *listname, Int_t nfiles) : TEntryList(), 
   fListFileName(filename), fListName(listname), fNFiles(nfiles), fListOffset(0), fFile(0), fFileNames(0)
{
   // File naming convention:
   // - by default, filename_elist.root is used, where filename is the
   //   name of the chain element
   // - xxx$xxx.root - $ sign is replaced by the name of the chain element
   // The TObjArray of chain elements is set by the TEntryListFromFile::SetFileNames()
   // function.
   // If the list name is not specified, the first object of class TEntryList
   // in the file is taken.  
   // nfiles is the total number of files to process
   
   fListOffset = new Long64_t[fNFiles+1];
   fListOffset[0]=0;
   for (Int_t i=1; i<fNFiles+1; i++){
      fListOffset[i]=kBigNumber;
   }
   fN = kBigNumber;
}

//______________________________________________________________________________
TEntryListFromFile::~TEntryListFromFile()
{
   // d-tor
   
   delete [] fListOffset;
   fListOffset = 0;
   delete fFile;
   fFile = 0;
}

//______________________________________________________________________________
Long64_t TEntryListFromFile::GetEntry(Int_t index)
{
   //returns entry #index
   //See also Next() for a faster alternative
   
   if (index<0) return -1;
   
   if (index > fListOffset[fNFiles] && fListOffset[fNFiles]!=kBigNumber){
      Error("GetEntry", "Index value is too large\n");
      return -1;
   }
   
   if (index==fLastIndexQueried+1)
      return Next();
   
   Int_t itree =0;
   while (!fCurrent && itree<fNFiles){
      LoadList(itree);
      itree++;
   }
   if (itree == fNFiles){
      Error("GetEntry", "All lists are empty\n");
      return -1;
   }
   
   if (index < fListOffset[fTreeNumber]) {
      //this entry is in one of previously opened lists
      itree=0;
      for (itree=0; itree<fTreeNumber; itree++){
         if (index >= fListOffset[itree] && fListOffset[itree]!=fListOffset[itree+1])
            break;
      }
      LoadList(itree);
   }
   else if (index >= fListOffset[fTreeNumber+1]){
      //this entry is in one of following lists
      itree = fTreeNumber;
      while (itree < fNFiles){
         itree++;
         if (fListOffset[itree+1]==kBigNumber){
            //this list hasn't been loaded yet
            LoadList(itree);
         }
         if (index < fListOffset[itree+1]){
            //the entry is in this list
            break;
         }
      }
      if (fTreeNumber == fNFiles){
         Error("GetEntry", "Entry number is too big\n");
         return -1;
      }
      if (fTreeNumber!=itree)
         LoadList(itree);
   }
   //now the entry is in the currently opened list
   Long64_t localentry = index - fListOffset[fTreeNumber];
   Long64_t retentry = fCurrent->GetEntry(localentry);
   fLastIndexQueried = index;
   fLastIndexReturned = retentry;
   return retentry;
   
}

//______________________________________________________________________________
Long64_t TEntryListFromFile::GetEntryAndTree(Int_t index, Int_t &treenum)
{
   //return the entry corresponding to the index parameter and the
   //number of the tree, where this entry is
   
   Long64_t result = GetEntry(index);
   treenum = fTreeNumber;
   return result;
}

//______________________________________________________________________________
Long64_t TEntryListFromFile::GetEntries()
{
   //Returns the total number of entries in the list.
   //If some lists have not been loaded, loads them.
   
   if (fN==kBigNumber){
      for (Int_t i=0; i<fNFiles; i++){
         if (fListOffset[i+1]==kBigNumber){
            LoadList(i);
         }
      }
   }
   fN = fListOffset[fNFiles];
   fLastIndexQueried = -3;
   return fN;
}

//______________________________________________________________________________
Long64_t TEntryListFromFile::Next()
{
   //Returns the next entry in the list.
   //Faster than GetEntry()   
   
   Int_t itree =0;
   while (!fCurrent && itree<fNFiles){
      LoadList(itree);
      itree++;
   }
   if (itree == fNFiles){
      Error("Next", "All lists are empty\n");
      return -1;
   }
   
   Long64_t retentry = fCurrent->Next();
   if (retentry<0){
      if (fLastIndexQueried == fListOffset[fTreeNumber+1]-1){
         //requested entry is in the next list
         if (fTreeNumber == fNFiles -1){
            // Error("Next", "No more entries, last list\n");
            return -1;
         }
         do{
            //load the next non-empty list. fTreeNumber is changed by LoadList()
            fTreeNumber++;
            LoadList(fTreeNumber);
         } while (fListOffset[fTreeNumber+1]==fListOffset[fTreeNumber] && fTreeNumber<fNFiles-1);
         if (fTreeNumber == fNFiles -1 && fListOffset[fTreeNumber+1]==fListOffset[fTreeNumber]){
            //no more lists
            return -1;
         }
         retentry = fCurrent->Next();
      } else {
         Error("Next", "Something wrong with reading the current list, even though thefile #%d and the list exist\n", fTreeNumber);
         return -1;
      }
      
   }
   
   fLastIndexQueried++;
   fLastIndexReturned = retentry;
   return retentry;
   
}

//______________________________________________________________________________
Int_t TEntryListFromFile::LoadList(Int_t listnumber)
{
   //Loads the list #listnumber
   //This is the only function that can modify fCurrent and fFile data members
   
   //first close the current list
   if (fCurrent){
      if (fFile) {
         delete fFile;
         fFile = 0;
         fCurrent = 0;
      }
   }
   
   R__ASSERT(fFileNames);
   
   //find the right name
   //get the name of the corresponding chain element (with the treenumber=listnumber)
   TNamed *nametitle = (TNamed*)fFileNames->At(listnumber);
   TString filename_short = nametitle->GetTitle();
   if (filename_short.Contains(".root")){
      filename_short.Remove(filename_short.Length()-5, 5);
   }
   if (!strcmp(fListFileName.Data(), "")){
      //no name supplied, use the one of the chain file
      filename_short.Append("_elist.root");
      //printf("filename: %s\n", filename_short.Data());
      fFile = TFile::Open(filename_short.Data());
   } else {
      TString filename = fListFileName;
      filename.ReplaceAll("$", filename_short);
      //printf("filename: %s\n", filename.Data());
      fFile = TFile::Open(filename.Data());
   }
   
   if (!fFile || fFile->IsZombie()){
      if (fFile) {
         delete fFile;
         fFile = 0;
      }
      fCurrent = 0;
      fListOffset[listnumber+1] = fListOffset[listnumber];
      return -1;
   }
   
   if (!strcmp(fListName.Data(), "")){
      TKey *key;
      TIter nextkey(fFile->GetListOfKeys());
      while ((key=(TKey*)nextkey())){
         if (strcmp("TEntryList", key->GetClassName())==0){
            //found an object of class TEntryList
            fCurrent = (TEntryList*)key->ReadObj();
         }
      }
   } else {
      fCurrent = (TEntryList*)fFile->Get(fListName.Data());
   }
   
   if (!fCurrent){
      Error("LoadList", "List %s not found in the file\n", fListName.Data());
      fCurrent = 0;
      fListOffset[listnumber+1]=fListOffset[listnumber];
      return -1;
   }
   fTreeNumber = listnumber;
   Long64_t nentries = fCurrent->GetN();
   if (fListOffset[fTreeNumber+1] != (fListOffset[fTreeNumber] + nentries)) {
      fListOffset[fTreeNumber+1] = fListOffset[fTreeNumber] + nentries;
      fN = fListOffset[fNFiles];
   }
   
   return 1;
}

//______________________________________________________________________________
void TEntryListFromFile::Print(const Option_t* option) const
{
   //Print info about this list  
   printf("total number of files: %d\n", fNFiles);
   TFile *f;
   TEntryList *el=0;
   if (fFileNames==0) {
      Error("Print","fFileNames was not set properly.");
   } else {
      for (Int_t listnumber=0; listnumber<fNFiles; listnumber++){
         TNamed *nametitle = (TNamed*)fFileNames->At(listnumber);
         TString filename_short = nametitle->GetTitle();
         if (filename_short.Contains(".root")){
            filename_short.Remove(filename_short.Length()-5, 5);
         }
         if (!strcmp(fListFileName.Data(), "")){
            //no name supplied, use the one of the chain file
            filename_short.Append("_elist.root");
            //printf("filename: %s\n", filename_short.Data());
            f = TFile::Open(filename_short.Data());
         } else {
            TString filename = fListFileName;
            filename.ReplaceAll("$", filename_short);
            //printf("filename: %s\n", filename.Data());
            f = TFile::Open(filename.Data());
         }
         if (f && !f->IsZombie()){
            if (!strcmp(fListName.Data(), "")){
               TKey *key;
               TIter nextkey(f->GetListOfKeys());
               while ((key=(TKey*)nextkey())){
                  if (strcmp("TEntryList", key->GetClassName())==0){
                     //found an object of class TEntryList
                     el = (TEntryList*)key->ReadObj();
                  }
               }
            } else {
               el = (TEntryList*)f->Get(fListName.Data());
            }
            if (el) 
               el->Print(option);
         }
      }
   }
   
}
 TEntryListFromFile.cxx:1
 TEntryListFromFile.cxx:2
 TEntryListFromFile.cxx:3
 TEntryListFromFile.cxx:4
 TEntryListFromFile.cxx:5
 TEntryListFromFile.cxx:6
 TEntryListFromFile.cxx:7
 TEntryListFromFile.cxx:8
 TEntryListFromFile.cxx:9
 TEntryListFromFile.cxx:10
 TEntryListFromFile.cxx:11
 TEntryListFromFile.cxx:12
 TEntryListFromFile.cxx:13
 TEntryListFromFile.cxx:14
 TEntryListFromFile.cxx:15
 TEntryListFromFile.cxx:16
 TEntryListFromFile.cxx:17
 TEntryListFromFile.cxx:18
 TEntryListFromFile.cxx:19
 TEntryListFromFile.cxx:20
 TEntryListFromFile.cxx:21
 TEntryListFromFile.cxx:22
 TEntryListFromFile.cxx:23
 TEntryListFromFile.cxx:24
 TEntryListFromFile.cxx:25
 TEntryListFromFile.cxx:26
 TEntryListFromFile.cxx:27
 TEntryListFromFile.cxx:28
 TEntryListFromFile.cxx:29
 TEntryListFromFile.cxx:30
 TEntryListFromFile.cxx:31
 TEntryListFromFile.cxx:32
 TEntryListFromFile.cxx:33
 TEntryListFromFile.cxx:34
 TEntryListFromFile.cxx:35
 TEntryListFromFile.cxx:36
 TEntryListFromFile.cxx:37
 TEntryListFromFile.cxx:38
 TEntryListFromFile.cxx:39
 TEntryListFromFile.cxx:40
 TEntryListFromFile.cxx:41
 TEntryListFromFile.cxx:42
 TEntryListFromFile.cxx:43
 TEntryListFromFile.cxx:44
 TEntryListFromFile.cxx:45
 TEntryListFromFile.cxx:46
 TEntryListFromFile.cxx:47
 TEntryListFromFile.cxx:48
 TEntryListFromFile.cxx:49
 TEntryListFromFile.cxx:50
 TEntryListFromFile.cxx:51
 TEntryListFromFile.cxx:52
 TEntryListFromFile.cxx:53
 TEntryListFromFile.cxx:54
 TEntryListFromFile.cxx:55
 TEntryListFromFile.cxx:56
 TEntryListFromFile.cxx:57
 TEntryListFromFile.cxx:58
 TEntryListFromFile.cxx:59
 TEntryListFromFile.cxx:60
 TEntryListFromFile.cxx:61
 TEntryListFromFile.cxx:62
 TEntryListFromFile.cxx:63
 TEntryListFromFile.cxx:64
 TEntryListFromFile.cxx:65
 TEntryListFromFile.cxx:66
 TEntryListFromFile.cxx:67
 TEntryListFromFile.cxx:68
 TEntryListFromFile.cxx:69
 TEntryListFromFile.cxx:70
 TEntryListFromFile.cxx:71
 TEntryListFromFile.cxx:72
 TEntryListFromFile.cxx:73
 TEntryListFromFile.cxx:74
 TEntryListFromFile.cxx:75
 TEntryListFromFile.cxx:76
 TEntryListFromFile.cxx:77
 TEntryListFromFile.cxx:78
 TEntryListFromFile.cxx:79
 TEntryListFromFile.cxx:80
 TEntryListFromFile.cxx:81
 TEntryListFromFile.cxx:82
 TEntryListFromFile.cxx:83
 TEntryListFromFile.cxx:84
 TEntryListFromFile.cxx:85
 TEntryListFromFile.cxx:86
 TEntryListFromFile.cxx:87
 TEntryListFromFile.cxx:88
 TEntryListFromFile.cxx:89
 TEntryListFromFile.cxx:90
 TEntryListFromFile.cxx:91
 TEntryListFromFile.cxx:92
 TEntryListFromFile.cxx:93
 TEntryListFromFile.cxx:94
 TEntryListFromFile.cxx:95
 TEntryListFromFile.cxx:96
 TEntryListFromFile.cxx:97
 TEntryListFromFile.cxx:98
 TEntryListFromFile.cxx:99
 TEntryListFromFile.cxx:100
 TEntryListFromFile.cxx:101
 TEntryListFromFile.cxx:102
 TEntryListFromFile.cxx:103
 TEntryListFromFile.cxx:104
 TEntryListFromFile.cxx:105
 TEntryListFromFile.cxx:106
 TEntryListFromFile.cxx:107
 TEntryListFromFile.cxx:108
 TEntryListFromFile.cxx:109
 TEntryListFromFile.cxx:110
 TEntryListFromFile.cxx:111
 TEntryListFromFile.cxx:112
 TEntryListFromFile.cxx:113
 TEntryListFromFile.cxx:114
 TEntryListFromFile.cxx:115
 TEntryListFromFile.cxx:116
 TEntryListFromFile.cxx:117
 TEntryListFromFile.cxx:118
 TEntryListFromFile.cxx:119
 TEntryListFromFile.cxx:120
 TEntryListFromFile.cxx:121
 TEntryListFromFile.cxx:122
 TEntryListFromFile.cxx:123
 TEntryListFromFile.cxx:124
 TEntryListFromFile.cxx:125
 TEntryListFromFile.cxx:126
 TEntryListFromFile.cxx:127
 TEntryListFromFile.cxx:128
 TEntryListFromFile.cxx:129
 TEntryListFromFile.cxx:130
 TEntryListFromFile.cxx:131
 TEntryListFromFile.cxx:132
 TEntryListFromFile.cxx:133
 TEntryListFromFile.cxx:134
 TEntryListFromFile.cxx:135
 TEntryListFromFile.cxx:136
 TEntryListFromFile.cxx:137
 TEntryListFromFile.cxx:138
 TEntryListFromFile.cxx:139
 TEntryListFromFile.cxx:140
 TEntryListFromFile.cxx:141
 TEntryListFromFile.cxx:142
 TEntryListFromFile.cxx:143
 TEntryListFromFile.cxx:144
 TEntryListFromFile.cxx:145
 TEntryListFromFile.cxx:146
 TEntryListFromFile.cxx:147
 TEntryListFromFile.cxx:148
 TEntryListFromFile.cxx:149
 TEntryListFromFile.cxx:150
 TEntryListFromFile.cxx:151
 TEntryListFromFile.cxx:152
 TEntryListFromFile.cxx:153
 TEntryListFromFile.cxx:154
 TEntryListFromFile.cxx:155
 TEntryListFromFile.cxx:156
 TEntryListFromFile.cxx:157
 TEntryListFromFile.cxx:158
 TEntryListFromFile.cxx:159
 TEntryListFromFile.cxx:160
 TEntryListFromFile.cxx:161
 TEntryListFromFile.cxx:162
 TEntryListFromFile.cxx:163
 TEntryListFromFile.cxx:164
 TEntryListFromFile.cxx:165
 TEntryListFromFile.cxx:166
 TEntryListFromFile.cxx:167
 TEntryListFromFile.cxx:168
 TEntryListFromFile.cxx:169
 TEntryListFromFile.cxx:170
 TEntryListFromFile.cxx:171
 TEntryListFromFile.cxx:172
 TEntryListFromFile.cxx:173
 TEntryListFromFile.cxx:174
 TEntryListFromFile.cxx:175
 TEntryListFromFile.cxx:176
 TEntryListFromFile.cxx:177
 TEntryListFromFile.cxx:178
 TEntryListFromFile.cxx:179
 TEntryListFromFile.cxx:180
 TEntryListFromFile.cxx:181
 TEntryListFromFile.cxx:182
 TEntryListFromFile.cxx:183
 TEntryListFromFile.cxx:184
 TEntryListFromFile.cxx:185
 TEntryListFromFile.cxx:186
 TEntryListFromFile.cxx:187
 TEntryListFromFile.cxx:188
 TEntryListFromFile.cxx:189
 TEntryListFromFile.cxx:190
 TEntryListFromFile.cxx:191
 TEntryListFromFile.cxx:192
 TEntryListFromFile.cxx:193
 TEntryListFromFile.cxx:194
 TEntryListFromFile.cxx:195
 TEntryListFromFile.cxx:196
 TEntryListFromFile.cxx:197
 TEntryListFromFile.cxx:198
 TEntryListFromFile.cxx:199
 TEntryListFromFile.cxx:200
 TEntryListFromFile.cxx:201
 TEntryListFromFile.cxx:202
 TEntryListFromFile.cxx:203
 TEntryListFromFile.cxx:204
 TEntryListFromFile.cxx:205
 TEntryListFromFile.cxx:206
 TEntryListFromFile.cxx:207
 TEntryListFromFile.cxx:208
 TEntryListFromFile.cxx:209
 TEntryListFromFile.cxx:210
 TEntryListFromFile.cxx:211
 TEntryListFromFile.cxx:212
 TEntryListFromFile.cxx:213
 TEntryListFromFile.cxx:214
 TEntryListFromFile.cxx:215
 TEntryListFromFile.cxx:216
 TEntryListFromFile.cxx:217
 TEntryListFromFile.cxx:218
 TEntryListFromFile.cxx:219
 TEntryListFromFile.cxx:220
 TEntryListFromFile.cxx:221
 TEntryListFromFile.cxx:222
 TEntryListFromFile.cxx:223
 TEntryListFromFile.cxx:224
 TEntryListFromFile.cxx:225
 TEntryListFromFile.cxx:226
 TEntryListFromFile.cxx:227
 TEntryListFromFile.cxx:228
 TEntryListFromFile.cxx:229
 TEntryListFromFile.cxx:230
 TEntryListFromFile.cxx:231
 TEntryListFromFile.cxx:232
 TEntryListFromFile.cxx:233
 TEntryListFromFile.cxx:234
 TEntryListFromFile.cxx:235
 TEntryListFromFile.cxx:236
 TEntryListFromFile.cxx:237
 TEntryListFromFile.cxx:238
 TEntryListFromFile.cxx:239
 TEntryListFromFile.cxx:240
 TEntryListFromFile.cxx:241
 TEntryListFromFile.cxx:242
 TEntryListFromFile.cxx:243
 TEntryListFromFile.cxx:244
 TEntryListFromFile.cxx:245
 TEntryListFromFile.cxx:246
 TEntryListFromFile.cxx:247
 TEntryListFromFile.cxx:248
 TEntryListFromFile.cxx:249
 TEntryListFromFile.cxx:250
 TEntryListFromFile.cxx:251
 TEntryListFromFile.cxx:252
 TEntryListFromFile.cxx:253
 TEntryListFromFile.cxx:254
 TEntryListFromFile.cxx:255
 TEntryListFromFile.cxx:256
 TEntryListFromFile.cxx:257
 TEntryListFromFile.cxx:258
 TEntryListFromFile.cxx:259
 TEntryListFromFile.cxx:260
 TEntryListFromFile.cxx:261
 TEntryListFromFile.cxx:262
 TEntryListFromFile.cxx:263
 TEntryListFromFile.cxx:264
 TEntryListFromFile.cxx:265
 TEntryListFromFile.cxx:266
 TEntryListFromFile.cxx:267
 TEntryListFromFile.cxx:268
 TEntryListFromFile.cxx:269
 TEntryListFromFile.cxx:270
 TEntryListFromFile.cxx:271
 TEntryListFromFile.cxx:272
 TEntryListFromFile.cxx:273
 TEntryListFromFile.cxx:274
 TEntryListFromFile.cxx:275
 TEntryListFromFile.cxx:276
 TEntryListFromFile.cxx:277
 TEntryListFromFile.cxx:278
 TEntryListFromFile.cxx:279
 TEntryListFromFile.cxx:280
 TEntryListFromFile.cxx:281
 TEntryListFromFile.cxx:282
 TEntryListFromFile.cxx:283
 TEntryListFromFile.cxx:284
 TEntryListFromFile.cxx:285
 TEntryListFromFile.cxx:286
 TEntryListFromFile.cxx:287
 TEntryListFromFile.cxx:288
 TEntryListFromFile.cxx:289
 TEntryListFromFile.cxx:290
 TEntryListFromFile.cxx:291
 TEntryListFromFile.cxx:292
 TEntryListFromFile.cxx:293
 TEntryListFromFile.cxx:294
 TEntryListFromFile.cxx:295
 TEntryListFromFile.cxx:296
 TEntryListFromFile.cxx:297
 TEntryListFromFile.cxx:298
 TEntryListFromFile.cxx:299
 TEntryListFromFile.cxx:300
 TEntryListFromFile.cxx:301
 TEntryListFromFile.cxx:302
 TEntryListFromFile.cxx:303
 TEntryListFromFile.cxx:304
 TEntryListFromFile.cxx:305
 TEntryListFromFile.cxx:306
 TEntryListFromFile.cxx:307
 TEntryListFromFile.cxx:308
 TEntryListFromFile.cxx:309
 TEntryListFromFile.cxx:310
 TEntryListFromFile.cxx:311
 TEntryListFromFile.cxx:312
 TEntryListFromFile.cxx:313
 TEntryListFromFile.cxx:314
 TEntryListFromFile.cxx:315
 TEntryListFromFile.cxx:316
 TEntryListFromFile.cxx:317
 TEntryListFromFile.cxx:318
 TEntryListFromFile.cxx:319
 TEntryListFromFile.cxx:320
 TEntryListFromFile.cxx:321
 TEntryListFromFile.cxx:322
 TEntryListFromFile.cxx:323
 TEntryListFromFile.cxx:324
 TEntryListFromFile.cxx:325
 TEntryListFromFile.cxx:326
 TEntryListFromFile.cxx:327
 TEntryListFromFile.cxx:328
 TEntryListFromFile.cxx:329
 TEntryListFromFile.cxx:330
 TEntryListFromFile.cxx:331
 TEntryListFromFile.cxx:332
 TEntryListFromFile.cxx:333
 TEntryListFromFile.cxx:334
 TEntryListFromFile.cxx:335
 TEntryListFromFile.cxx:336
 TEntryListFromFile.cxx:337
 TEntryListFromFile.cxx:338
 TEntryListFromFile.cxx:339
 TEntryListFromFile.cxx:340
 TEntryListFromFile.cxx:341
 TEntryListFromFile.cxx:342
 TEntryListFromFile.cxx:343
 TEntryListFromFile.cxx:344