2c75b6ad83bdeb540cc39e14a9385aefbad1d0ed
[u/mrichter/AliRoot.git] / PWGHF / centraltrain / AnalysisTrainPWG3.C
1 //===================== ANALYSIS TRAIN =========================================
2 // To use: copy this macro to your work directory, modify the global part to match
3 // your needs, then run root.
4 //    root[0] .L AnalysisTrain.C
5 // Grid full mode as below (other modes: test, offline, submit, terminate)
6 //    root[1] AnalysisTrainNew("grid", "full")
7 // CAF mode (requires root v5-23-02 + aliroot v4-16-Rev08)
8 //    root[2] AnalysisTrainNew("proof")
9 // Local mode requires AliESds.root or AliAOD.root in ./data directory
10 //    root[3] AnalysisTrainNew("local")
11 // In proof and grid modes, a token is needed and sourcing the produced environment file.
12 //
13 // If 'saveTrain' flag is set, the train will generate a directory name and run
14 // in this directory. A configuration file 'ConfigTrain.C' will be generated. 
15 // One can replay at any time the train via:
16 //    root[1] AnalysisTrainNew(ana_mode, plugin_mode, "train_default_<date>/ConfigTrain.C")
17
18 //==================   TRAIN NAME   ============================================
19 TString     train_name         = "PWG3"; // local folder name
20 TString     train_tag          = "_Pb-Pb_";        // Train special tag appended to 
21                                             // visible name. ("data", "sim", "pp", "highmult", ...)
22                // Name in train page (DON'T CHANGE)
23 TString     visible_name       = Form("PWG3%s$2_$3", train_tag.Data()); //# FIXED #
24                // Add train composition and other comments
25 TString     job_comment        = "PWG3 tasks on AODs (di)muon/vertexing/dielectrons";
26 TString     job_tag            = Form("%s: %s", visible_name.Data(), job_comment.Data());
27 //==============================================================================
28
29 // ### Settings that make sense in PROOF only
30 //==============================================================================
31 TString     proof_cluster      = "alice-caf.cern.ch";
32 Bool_t      useAFPAR           = kFALSE;  // use AF special par file
33 TString     AFversion          = "AF-v4-17";
34 // Change CAF dataset here
35 TString     proof_dataset      = "/COMMON/COMMON/LHC09a4_run8100X#/esdTree";
36 TString     proof_outdir       = "";
37
38 // ### Settings that make sense when using the Alien plugin
39 //==============================================================================
40 Int_t       runOnData          = 1;       // Set to 1 if processing real data
41 Int_t       iCollision         = 1;       // 0=pp, 1=Pb-Pb
42 Bool_t      usePLUGIN          = kTRUE;   // do not change
43 Bool_t      useProductionMode  = kTRUE;   // use the plugin in production mode
44 // Usage of par files ONLY in grid mode and ONLY if the code is not available
45 // in the deployed AliRoot versions. Par file search path: local dir, if not there $ALICE_ROOT.
46 // To refresh par files, remove the ones in the workdir, then do "make <target.par>" in 
47 // AliRoot.
48 Bool_t      usePAR             = kFALSE;  // use par files for extra libs
49 Bool_t      useCPAR            = kFALSE;  // use par files for common libs
50 TString     root_version       = "v5-27-06c";  // *CHANGE ME IF MORE RECENT IN GRID*
51 TString     aliroot_version    = "v4-21-15-AN";  // *CHANGE ME IF MORE RECENT IN GRID*                                          
52 // Change production base directory here (test mode)
53 TString     alien_datadir      = "/alice/data/2010/LHC10h";
54                // Work directory in GRID (DON'T CHANGE)
55 TString     grid_workdir       = "/alice/cern.ch/user/a/alidaq/PWG3/PWG3_$2";
56                // Data pattern - change as needed for test mode
57  TString     data_pattern       = "*ESDs/pass1/AOD033/*AOD.root";
58 //TString     data_pattern       = "*ESDs/pass1/*ESDs.root";
59 // Set the run range
60 Int_t run_numbers[10] = {137844}; // **********************!!!!!!!
61 // AliEn output directory. If blank will become output_<train_name>
62                // Output directory (DON'T CHANGE)
63 TString     alien_outdir       = "$1/PWG3OUT$2";
64                // Input collection (production mode)
65 TString     data_collection    = "$1/input.xml";
66 // Output folder to write delta AOD's. Considered if not null.
67 TString     outputSingleFolder = "";
68 //TString     outputSingleFolder = "deltas";
69 // Number of files merged in a chunk
70 Int_t       maxMergeFiles      = 20;
71 // Files that should not be merged
72 TString     mergeExclude       = "AliAOD.root AliAOD.VertexingHF.root AliAOD.Jets.root deltaAODPartCorr.root AliAOD.Muons.root AliAOD.Dimuons.root AliAOD.Dielectron.root AliAODCentrality.root";
73 TString     mergeDirName       = "PWG3OUT$2";
74 // Make replicas on the storages below
75 TString     outputStorages      = "disk=4";
76 // Number of runs per master job
77 Int_t       nRunsPerMaster     = 10;
78 // Maximum number of files per job (gives size of AOD)
79 Int_t       nFilesPerJob       = 5;
80 // Int_t       nFilesPerJob       = 1; (AOD->delta AOD production case)
81 // ### Settings that make sense only for local analysis
82 //==============================================================================
83 // Change local xml dataset for local interactive analysis
84 TString     local_xmldataset   = "";
85
86 // ### Other flags to steer the analysis
87 //==============================================================================
88 Bool_t      usePhysicsSelection = kFALSE; // use physics selection
89 Bool_t      useBKrejection      = kFALSE; // use BK rejection
90 Bool_t      useCentrality       = kFALSE; // centrality delta AOD
91 Bool_t      useTender           = kFALSE; // use tender wagon
92 Bool_t      useV0tender         = kFALSE;  // use V0 correction in tender
93 Bool_t      useMergeViaJDL      = kTRUE;  // merge via JDL
94 Bool_t      useFastReadOption   = kFALSE;  // use xrootd tweaks
95 Bool_t      useOverwriteMode    = kTRUE;  // overwrite existing collections
96 Bool_t      useDATE             = kFALSE; // use date in train name
97 Bool_t      useDBG              = kTRUE;  // activate debugging
98 Bool_t      useMC               = kFALSE;  // use MC info
99 Bool_t      useTAGS             = kFALSE;  // use ESD tags for selection
100 Bool_t      useKFILTER          = kFALSE;  // use Kinematics filter
101 Bool_t      useTR               = kFALSE;  // use track references
102 Bool_t      useCORRFW           = kTRUE; // do not change
103 Bool_t      useAODTAGS          = kFALSE; // use AOD tags
104 Bool_t      saveTrain           = kTRUE;  // save train configuration as: 
105 Bool_t      saveCanvases        = kFALSE;  // save canvases created in Terminate
106 Bool_t      saveProofToAlien    = kFALSE; // save proof outputs in AliEn
107
108 // ### Analysis modules to be included. Some may not be yet fully implemented.
109 //==============================================================================
110 Int_t       iAODanalysis       = 1;      // Analysis on input AOD's
111 Int_t       iAODhandler        = 0;      // Analysis produces an AOD or dAOD's
112
113 Int_t       iPWG3hfe           = 0;      // Electrons analysis (PWG3)
114 Int_t       iPWG3JPSI          = 0;      // JPSI analysis (PWG3)
115 Int_t       iPWG3d2h           = 1;      // D0->2 hadrons (PWG3)
116 Int_t       iPWG3MuonTrain     = 1;      // Muon analysis train
117
118
119 // Temporaries.
120 TString anaPars = "";
121 TString anaLibs = "";
122 // Function signatures
123 class AliAnalysisAlien;
124
125 //______________________________________________________________________________
126 void AnalysisTrainPWG3(const char *analysis_mode="local", 
127                           const char *plugin_mode="full",
128                           const char *config_file="")
129 {
130 // Main analysis train macro. If a configuration file is provided, all parameters
131 // are taken from there but may be altered by CheckModuleFlags.
132    if (strlen(config_file) && !LoadConfig(config_file)) return;
133    TString smode(analysis_mode);
134    smode.ToUpper();
135    TString spmode(plugin_mode);
136    spmode.ToLower();
137    if (spmode == "test") useProductionMode = kFALSE;
138    // Check compatibility of selected modules
139    CheckModuleFlags(smode);
140    if (saveTrain)              WriteConfig();
141
142    printf("==================================================================\n");
143    printf("===========    RUNNING ANALYSIS TRAIN %s IN %s MODE   ==========\n", train_name.Data(),smode.Data());
144    printf("==================================================================\n");
145    printf("=  Configuring analysis train for:                               =\n");
146    if (iAODanalysis) printf("=  AOD analysis                                                  =\n");
147    else              printf("=  ESD analysis                                                  =\n");
148    if (usePhysicsSelection)   printf("=  Physics selection                                                =\n");
149    if (useTender)    printf("=  TENDER                                                        =\n");
150    if (iPWG3hfe)       printf("=  PWG3 electrons                                                =\n");
151    if (iPWG3JPSI)      printf("=  PWG3 j/psi                                                    =\n");
152    if (iPWG3d2h)     printf("=  PWG3 D -> hadrons tasks                                      =\n");
153    if (iPWG3MuonTrain) printf("=  PWG3 muon train                                               =\n");
154    printf("==================================================================\n");
155    printf(":: use physics selection: %d\n", (UInt_t)usePhysicsSelection);
156    printf(":: use xrootd tweaks:     %d\n", (UInt_t)useFastReadOption);
157    printf(":: use overwrite xml    : %d\n", (UInt_t)useOverwriteMode);
158    printf(":: use merge via JDL:     %d\n", (UInt_t)useMergeViaJDL);
159    printf(":: use MC truth:          %d\n", (UInt_t)useMC);
160    printf(":: use KINE filter:       %d\n", (UInt_t)useKFILTER);
161    printf(":: use track references:  %d\n", (UInt_t)useTR);
162    printf(":: use tags:              %d\n", (UInt_t)useTAGS);
163    printf(":: use AOD tags:          %d\n", (UInt_t)useAODTAGS);
164    printf(":: use debugging:         %d\n", (UInt_t)useDBG);
165    printf(":: use PAR files:         %d\n", (UInt_t)usePAR);
166    printf(":: use AliEn plugin:      %d\n", (UInt_t)usePLUGIN);
167
168    //==========================================================================
169    // Connect to back-end system
170 //   if (!Connect(smode)) {
171 //      ::Error("AnalysisTrain", "Could not connect to %s back-end", analysis_mode);
172 //      return;
173 //   }   
174
175    // Load common libraries and set include path
176    if (!LoadCommonLibraries(smode)) {
177       ::Error("AnalysisTrain", "Could not load common libraries");
178       return;
179    }
180     
181    // Make the analysis manager and connect event handlers
182    AliAnalysisManager *mgr  = new AliAnalysisManager("Analysis Train", "Production train");
183    if (saveProofToAlien) mgr->SetSpecialOutputLocation(proof_outdir);
184    if (!strcmp(plugin_mode, "test")) mgr->SetNSysInfo(1);
185    // Load analysis specific libraries
186    if (!LoadAnalysisLibraries(smode)) {
187       ::Error("AnalysisTrain", "Could not load analysis libraries");
188       return;
189    }   
190
191    // Create input handler (input container created automatically)
192    if (iAODanalysis) {
193    // AOD input handler
194       AliAODInputHandler *aodH = new AliAODInputHandler();
195       if (iPWG3d2h) aodH->AddFriend("AliAOD.VertexingHF.root");
196       mgr->SetInputEventHandler(aodH);
197    } else {   
198    // ESD input handler
199       AliESDInputHandler *esdHandler = new AliESDInputHandler();
200       if (useTAGS) esdHandler->SetReadTags();
201       mgr->SetInputEventHandler(esdHandler);       
202    }
203    // Monte Carlo handler
204    if (useMC && !iAODanalysis) {
205       AliMCEventHandler* mcHandler = new AliMCEventHandler();
206       mgr->SetMCtruthEventHandler(mcHandler);
207       mcHandler->SetReadTR(useTR); 
208    }   
209    // AOD output container, created automatically when setting an AOD handler
210    if (iAODhandler) {
211       // AOD output handler
212       AliAODHandler* aodHandler   = new AliAODHandler();
213       aodHandler->SetOutputFileName("AliAOD.root");
214       mgr->SetOutputEventHandler(aodHandler);
215       if (iAODanalysis) {
216          aodHandler->SetFillAOD(kFALSE);
217          aodHandler->SetCreateNonStandardAOD();
218 //         if (iPWG3vertexing) aodHandler->SetOutputFileName("AliAOD.VertexingHF.root");
219       } 
220    }
221    // Debugging if needed
222    if (useDBG) mgr->SetDebugLevel(3);
223    if (saveCanvases) mgr->SetSaveCanvases(kTRUE);
224
225    //==========================================================================
226    // Create the chain. In this example it is created only from ALIEN files but
227    // can be done to work in batch or grid mode as well.
228    TChain *chain = CreateChain(smode, plugin_mode);
229         
230    //==========================================================================
231    // Load the tasks configuration macros for all wagons. These files are supposed now to be
232    // in the current workdir, but in AliEn they will be in the file catalog, 
233    // mapped from AliRoot and pecified in the jdl input list.
234     
235    // For now connection to top input container and common AOD output container
236    // is done in this macro, but in future these containers will be connected
237    // from each task configuration macro.
238                                                                                                                                            
239    AddAnalysisTasks();                                                                                                                     
240                                                                                                                                            
241    // Run the analysis                                                                                                                     
242    //                                                                                                                                      
243    if (usePLUGIN) {                                                                                                                        
244       AliAnalysisGrid *alienHandler = CreateAlienHandler(plugin_mode);                                                                     
245       AliAnalysisManager::GetAnalysisManager()->SetGridHandler(alienHandler);                                                              
246    }                                                                                                                                       
247                                                                                                                                            
248    if (mgr->InitAnalysis()) {                                                                                                              
249       mgr->PrintStatus();                                                                                                                  
250       if (saveTrain || strlen(config_file)) gSystem->ChangeDirectory(train_name);                                                          
251       StartAnalysis(smode, chain);                                                                                                         
252    }                                                                                                                                       
253 }                                                                                                                                          
254                                                                                                                                             
255 //______________________________________________________________________________                                                           
256 void AddAnalysisTasks()                                                                                                                    
257 {                                                                                                                                          
258 // Add all analysis task wagons to the train                                                                                               
259    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();                                                                    
260
261   //
262   // Tender and supplies. Needs to be called for every event.
263   //
264    if (useTender) {
265       gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/TenderSupplies/AddTaskTender.C");
266       // IF V0 tender needed, put kTRUE below
267       AliAnalysisTaskSE *tender = AddTaskTender(useV0tender);
268 //      tender->SetDebugLevel(2);
269    }
270
271    if (usePhysicsSelection) {
272    // Physics selection task
273       gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
274       mgr->RegisterExtraFile("event_stat.root");
275       AliPhysicsSelectionTask *physSelTask = AddTaskPhysicsSelection(useMC,useBKrejection);
276       mgr->AddStatisticsTask(AliVEvent::kMB);
277    }
278    
279    // AOD tags
280    if (useAODTAGS) {
281       AliAnalysisTaskTagCreator* tagTask = new AliAnalysisTaskTagCreator("AOD Tag Creator");
282       mgr->AddTask(tagTask);
283       AliAnalysisDataContainer *coutTags = mgr->CreateContainer("cTag",  TTree::Class(), 
284                                            AliAnalysisManager::kOutputContainer, "AOD.tag.root");
285       mgr->ConnectInput (tagTask, 0, mgr->GetCommonInputContainer());
286       mgr->ConnectOutput(tagTask, 1, coutTags);
287    }   
288     
289
290 // ********** PWG3 wagons ******************************************************
291    AliAnalysisManager::SetCommonFileName("PWG3histograms.root");
292            
293    // PWG3 electrons
294    if (iPWG3hfe) {
295       gROOT->LoadMacro("$ALICE_ROOT/PWG3/hfe/macros/AddTaskHFE.C");
296       AliAnalysisTaskHFE *taskHFE = AddTaskHFE();
297       if (!taskHFE) ::Warning("AnalysisTrainNew", "AliAnalysisTaskHFE cannot run for this train conditions - EXCLUDED");
298    }  
299     
300    // PWG3 JPSI
301    if (iPWG3JPSI) {
302       gROOT->LoadMacro("$ALICE_ROOT/PWG3/dielectron/macros/AddTaskJPSI.C");
303       AliAnalysisTask *taskJPSI = AddTaskJPSI();
304       if (!taskJPSI) ::Warning("AnalysisTrainNew", "AliAnalysisTaskMultiDielectron cannot run for this train conditions - EXCLUDED");
305    }   
306
307    // PWG3 D2h
308    if (iPWG3d2h) {
309       gROOT->LoadMacro("$ALICE_ROOT/PWG3/vertexingHF/AddD2HTrain.C");
310       Bool_t readMC = (runOnData!=0 ? kTRUE : kFALSE);
311       AddD2HTrain(readMC, 1,1,1,0,0,1,0,0,0,0);
312    }   
313
314    // PWG3 muon
315    if (iPWG3MuonTrain) {
316       gROOT->LoadMacro("$ALICE_ROOT/PWG3/muon/AddPWG3MuonTrain.C");
317       // iESDAnalysis, iAODAnalysis -> flags to select if the train is AOD or ESD based
318       // iMuonDistributions, iSingleMuonANAlysis -> flags to switch on/off analysis wagons
319       Int_t isESDAnalysis = (iAODanalysis)?0:1;
320       Int_t isAODAnalysis = (iAODanalysis)?1:0;
321       Int_t addMuonDistributions = 1;
322       Int_t addSingleMuonAnalysis = 1;
323       Int_t addMuonHFAnalysis = 1;
324       Int_t ntaskmuon = AddPWG3MuonTrain(isESDAnalysis,isAODAnalysis,addMuonDistributions,addSingleMuonAnalysis,addMuonHFAnalysis);
325       printf("Added %d muon tasks\n", ntaskmuon);
326    }   
327       
328 }
329
330 //______________________________________________________________________________
331 void StartAnalysis(const char *mode, TChain *chain) {
332 // Start analysis.
333    Int_t imode = -1;
334    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
335    if (!strcmp(mode, "LOCAL")) imode = 0;
336    if (!strcmp(mode, "PROOF")) imode = 1;
337    if (!strcmp(mode, "GRID"))  imode = 2;
338    switch (imode) {
339       case 0:
340          if (!chain) {
341             ::Error("AnalysisTrainNew.C::StartAnalysis", "Cannot create the chain");
342             return;
343          }   
344          mgr->StartAnalysis(mode, chain);
345          return;
346       case 1:
347          if (!proof_dataset.Length()) {
348             ::Error("AnalysisTrainNew.C::StartAnalysis", "proof_dataset is empty");
349             return;
350          }   
351          mgr->StartAnalysis(mode, proof_dataset, 1000);
352          return;
353       case 2:
354          if (usePLUGIN) {
355             if (!mgr->GetGridHandler()) {
356                ::Error("AnalysisTrainNew.C::StartAnalysis", "Grid plugin not initialized");
357                return;
358             }   
359             mgr->StartAnalysis("grid");
360          } else {
361             if (!chain) {
362                ::Error("AnalysisTrainNew.C::StartAnalysis", "Cannot create the chain");
363                return;
364             }   
365             mgr->StartAnalysis(mode, chain);
366          }   
367          return;
368    }      
369 }          
370     
371 //______________________________________________________________________________
372 void CheckModuleFlags(const char *mode) {
373 // Checks selected modules and insure compatibility
374    Int_t imode = -1;
375    if (!strcmp(mode, "LOCAL")) imode = 0;
376    if (!strcmp(mode, "PROOF")) imode = 1;
377    if (!strcmp(mode, "GRID"))  imode = 2;
378    if (imode==1) {
379       if (!usePAR) {
380          ::Info("AnalysisTrainNew.C::CheckModuleFlags", "PAR files enabled due to PROOF analysis");
381          usePAR = kTRUE;
382       }   
383    }  
384    if (imode != 2) {
385       ::Info("AnalysisTrainNew.C::CheckModuleFlags", "AliEn plugin disabled since not in GRID mode");
386       usePLUGIN = kFALSE; 
387    }   
388    if (iAODanalysis) {
389    // AOD analysis
390       if (useMC)
391          ::Info("AnalysisTrainNew.C::CheckModuleFlags", "MC usage disabled in analysis on AOD's");
392       if (useAODTAGS)
393          ::Info("AnalysisTrainNew.C::CheckModuleFlags", "AOD tags usage disabled in analysis on AOD's");
394       useMC = kFALSE;
395       useTR = kFALSE;
396       useAODTAGS = kFALSE;
397    } else {   
398    // ESD analysis
399       if (!useMC) useTR = kFALSE;
400       if (!useTR) {
401          ::Info("AnalysisTrainNew.C::CheckModuleFlags", "iPWG2evchar disabled if not reading track references");
402          iPWG2evchar = 0;
403       }   
404    }
405    if (useKFILTER && !useMC) useKFILTER = kFALSE;
406    if (useAODTAGS && !iAODhandler) useAODTAGS = kFALSE;
407 }
408
409 //______________________________________________________________________________
410 Bool_t Connect(const char *mode) {
411 // Connect <username> to the back-end system.
412    Int_t imode = -1;
413    if (!strcmp(mode, "LOCAL")) imode = 0;
414    if (!strcmp(mode, "PROOF")) imode = 1;
415    if (!strcmp(mode, "GRID"))  imode = 2;
416    TString username = gSystem->Getenv("alien_API_USER");
417    switch (imode) {
418       case 0:
419          break;
420       case 1:
421          if  (!username.Length()) {
422             ::Error(Form("AnalysisTrainNew.C::Connect <%s>", mode), "Make sure you:\n \
423                            1. Have called: alien-token-init <username>\n \
424                            2. Have called: >source /tmp/gclient_env_$UID");
425             return kFALSE;
426          }
427          ::Info("AnalysisTrainNew.C::Connect", "Connecting user <%s> to PROOF cluster <%s>", 
428                 username.Data(), proof_cluster.Data());
429          gEnv->SetValue("XSec.GSI.DelegProxy", "2");
430 //         TProof::Open(Form("%s@%s:31093", username.Data(), proof_cluster.Data()));       
431          TProof::Open(Form("%s@%s", username.Data(), proof_cluster.Data()));       
432          if (!gProof) {
433             if (strcmp(gSystem->Getenv("XrdSecGSISRVNAMES"), "lxfsrd0506.cern.ch"))
434                ::Error(Form("AnalysisTrainNew.C::Connect <%s>", mode), "Environment XrdSecGSISRVNAMES different from lxfsrd0506.cern.ch");
435             return kFALSE;
436          }
437          TGrid::Connect("alien://");
438          if (gGrid) {
439             TString homedir = gGrid->GetHomeDirectory();
440             TString workdir = homedir + train_name;
441             if (!gGrid->Cd(workdir)) {
442                gGrid->Cd(homedir);
443                if (gGrid->Mkdir(workdir)) {
444                   gGrid->Cd(train_name);
445                   ::Info("AnalysisTrainNew::Connect()", "Directory %s created", gGrid->Pwd());
446                }
447             }
448             gGrid->Mkdir("proof_output");
449             gGrid->Cd("proof_output");
450             proof_outdir = Form("alien://%s", gGrid->Pwd());
451          }   
452          break;
453       case 2:      
454          if (usePLUGIN && !gSystem->Getenv("alien_CLOSE_SE")) {
455             ::Error(Form("AnalysisTrainNew.C::Connect <%s>", mode), 
456                            "When using the AliEn plugin it is preferable to define the \
457                            variable alien_CLOSE_SE in your environment.");
458             return kFALSE;
459          }
460          ::Info("AnalysisTrainNew.C::Connect", "Connecting user <%s> to AliEn ...", 
461                 username.Data());
462          TGrid::Connect("alien://");
463          if (!gGrid || !gGrid->IsConnected()) return kFALSE;
464          break;
465       default:
466          ::Error("AnalysisTrainNew.C::Connect", "Unknown run mode: %s", mode);
467          return kFALSE;
468    }
469    ::Info("AnalysisTrainNew.C::Connect","Connected in %s mode", mode);
470    return kTRUE;
471 }
472
473 //______________________________________________________________________________
474 Bool_t LoadCommonLibraries(const char *mode)
475 {
476 // Load common analysis libraries.
477    Int_t imode = -1;
478    if (!strcmp(mode, "LOCAL")) imode = 0;
479    if (!strcmp(mode, "PROOF")) imode = 1;
480    if (!strcmp(mode, "GRID"))  imode = 2;
481    if (!gSystem->Getenv("ALICE_ROOT")) {
482       ::Error("AnalysisTrainNew.C::LoadCommonLibraries", "Analysis train requires that analysis libraries are compiled with a local AliRoot"); 
483       return kFALSE;
484    }   
485    Bool_t success = kTRUE;
486    // ROOT libraries
487    gSystem->Load("libTree");
488    gSystem->Load("libGeom");
489    gSystem->Load("libVMC");
490    gSystem->Load("libPhysics");
491    gSystem->Load("libMinuit");
492    
493    // Load framework classes. Par option ignored here.
494    switch (imode) {
495       case 0:
496       case 2:
497          if (useCPAR) {
498             success &= LoadLibrary("STEERBase", mode, kTRUE);
499             success &= LoadLibrary("ESD", mode, kTRUE);
500             success &= LoadLibrary("AOD", mode, kTRUE);
501             success &= LoadLibrary("ANALYSIS", mode, kTRUE);
502             success &= LoadLibrary("ANALYSISalice", mode, kTRUE);
503             if (useCORRFW) success &= LoadLibrary("CORRFW", mode, kTRUE);
504          } else {   
505             success &= LoadLibrary("libSTEERBase.so", mode);
506             success &= LoadLibrary("libESD.so", mode);
507             success &= LoadLibrary("libAOD.so", mode);
508             success &= LoadLibrary("libANALYSIS.so", mode);
509             success &= LoadLibrary("libANALYSISalice.so", mode);
510             if (useCORRFW) success &= LoadLibrary("libCORRFW.so", mode);
511             gROOT->ProcessLine(".include $ALICE_ROOT/include");
512          }   
513          break;
514       case 1:
515          Int_t ires = -1;
516          if (useAFPAR && !gSystem->AccessPathName(AFversion)) ires = gProof->UploadPackage(AFversion);
517          if (ires < 0) {
518             success &= LoadLibrary("STEERBase", mode);
519             success &= LoadLibrary("ESD", mode);
520             success &= LoadLibrary("AOD", mode);
521             success &= LoadLibrary("ANALYSIS", mode);
522             success &= LoadLibrary("ANALYSISalice", mode);
523             if (useCORRFW) success &= LoadLibrary("CORRFW", mode);
524          } else { 
525             ires = gProof->EnablePackage(AFversion);
526             if (ires<0) success = kFALSE;
527             if (useCORRFW) success &= LoadLibrary("CORRFW", mode);
528          }
529          break;         
530       default:
531          ::Error("AnalysisTrainNew.C::LoadCommonLibraries", "Unknown run mode: %s", mode);
532          return kFALSE;
533    }
534    if (success) {
535       ::Info("AnalysisTrainNew.C::LoadCommodLibraries", "Load common libraries:    SUCCESS");
536       ::Info("AnalysisTrainNew.C::LoadCommodLibraries", "Include path for Aclic compilation:\n%s",
537               gSystem->GetIncludePath());
538    } else {           
539       ::Info("AnalysisTrainNew.C::LoadCommodLibraries", "Load common libraries:    FAILED");
540    }   
541       
542    return success;
543 }
544
545 //______________________________________________________________________________
546 Bool_t LoadAnalysisLibraries(const char *mode)
547 {
548 // Load common analysis libraries.
549    Bool_t success = kTRUE;
550    if (useTender) {
551       if (!LoadLibrary("TENDER", mode, kTRUE) ||
552           !LoadLibrary("TENDERSupplies", mode, kTRUE)) return kFALSE;
553    }       
554    if (iPWG3MuonTrain) {
555       if (!LoadLibrary("PWG3base", mode, kTRUE) ||
556           !LoadLibrary("PWG3muon", mode, kTRUE)) return kFALSE;
557    }   
558    // PWG3 Vertexing HF
559    if (iPWG3d2h) {
560       if (!LoadLibrary("PWG3base", mode, kTRUE) ||
561           !LoadLibrary("PWG3vertexingHF", mode, kTRUE)) return kFALSE;
562    }   
563    // PWG3 hfe
564    if (iPWG3hfe) {
565       if (!LoadLibrary("PWG3hfe", mode, kTRUE)) return kFALSE;
566    }   
567    // PWG3 dielectron
568    if (iPWG3JPSI) {
569       if (!LoadLibrary("PWG3dielectron", mode, kTRUE)) return kFALSE;
570    }   
571    
572    ::Info("AnalysisTrainNew.C::LoadAnalysisLibraries", "Load other libraries:   SUCCESS");
573    return kTRUE;
574 }
575
576 //______________________________________________________________________________
577 Bool_t LoadLibrary(const char *module, const char *mode, Bool_t rec=kFALSE)
578 {
579 // Load a module library in a given mode. Reports success.
580    Int_t imode = -1;
581    Int_t result;
582    TString smodule(module);
583    if (!strcmp(mode, "LOCAL")) imode = 0;
584    if (!strcmp(mode, "PROOF")) imode = 1;
585    if (!strcmp(mode, "GRID"))  imode = 2;
586    TString mod(module);
587    if (!mod.Length()) {
588       ::Error("AnalysisTrainNew.C::LoadLibrary", "Empty module name");
589       return kFALSE;
590    }   
591    // If a library is specified, just load it
592    if (smodule.EndsWith(".so")) {
593       mod.Remove(mod.Index(".so"));
594       result = gSystem->Load(mod);
595       if (result < 0) {
596          ::Error("AnalysisTrainNew.C::LoadLibrary", "Could not load library %s", module);
597          return kFALSE;
598       }
599       if (rec) anaLibs += Form("%s.so ",mod.Data()); 
600       return kTRUE;
601    } 
602    // Check if the library is already loaded
603    if (strlen(gSystem->GetLibraries(Form("%s.so", module), "", kFALSE)) > 0)
604       return kTRUE;    
605    switch (imode) {
606       case 0:
607       case 2:
608          if (usePAR) {
609             result = SetupPar(module);
610             if (rec) anaPars += Form("%s.par ", module);
611          } else {
612             result = gSystem->Load(Form("lib%s.so", module));
613             if (rec) anaLibs += Form("lib%s.so ", module);
614          }   
615          break;
616       case 1:
617          result = gProof->UploadPackage(module);
618          if (result<0) {
619             result = gProof->UploadPackage(gSystem->ExpandPathName(Form("$ALICE_ROOT/%s.par", module)));
620             if (result<0) {
621                ::Error("AnalysisTrainNew.C::LoadLibrary", "Could not find module %s.par in current directory nor in $ALICE_ROOT", module);
622                return kFALSE;
623             }
624          }   
625          result = gProof->EnablePackage(module);
626          break;
627       default:
628          return kFALSE;
629    }         
630    if (result < 0) {
631       ::Error("AnalysisTrainNew.C::LoadLibrary", "Could not load module %s", module);
632       return kFALSE;
633    }
634    return kTRUE;
635 }           
636
637
638 //______________________________________________________________________________
639 TChain *CreateChain(const char *mode, const char *plugin_mode)
640 {
641 // Create the input chain
642    Int_t imode = -1;
643    if (!strcmp(mode, "LOCAL")) imode = 0;
644    if (!strcmp(mode, "PROOF")) imode = 1;
645    if (!strcmp(mode, "GRID"))  imode = 2;
646    TChain *chain = NULL;
647    // Local chain
648    switch (imode) {
649       case 0:
650          if (iAODanalysis) {
651             if (!local_xmldataset.Length()) {
652                // Local AOD
653                chain = new TChain("aodTree");
654                if (gSystem->AccessPathName("data/AliAOD.root")) 
655                   ::Error("AnalysisTrainNew.C::CreateChain", "File: AliAOD.root not in ./data dir");
656                else {
657                   if (!saveTrain) chain->Add("data/AliAOD.root");
658                   else            chain->Add("../data/AliAOD.root");
659                }   
660             } else {
661                // Interactive AOD
662                chain = CreateChainSingle(local_xmldataset, "aodTree");
663             }
664          } else {      
665             if (!local_xmldataset.Length()) {
666                // Local ESD
667                chain = new TChain("esdTree");
668                if (gSystem->AccessPathName("data/AliESDs.root")) 
669                   ::Error("AnalysisTrainNew.C::CreateChain", "File: AliESDs.root not in ./data dir");
670                else {
671                   if (!saveTrain) chain->Add("data/AliESDs.root");
672                   else            chain->Add("../data/AliESDs.root");
673                }   
674             } else {
675                // Interactive ESD
676                chain = CreateChainSingle(local_xmldataset, "esdTree");
677             }   
678          }
679          break;
680       case 1:
681          break;
682       case 2:
683          if (usePLUGIN) {
684 //            AliAnalysisGrid *alienHandler = CreateAlienHandler(plugin_mode);
685 //            AliAnalysisManager::GetAnalysisManager()->SetGridHandler(alienHandler);
686          } else {
687             TString           treeName = "esdTree";
688             if (iAODanalysis) treeName = "aodTree";
689             chain = CreateChainSingle("wn.xml", treeName);
690          }
691          break;      
692       default:   
693    }
694    if (chain && chain->GetNtrees()) return chain;
695    return NULL;
696 }   
697
698 //______________________________________________________________________________
699 TChain* CreateChainSingle(const char* xmlfile, const char *treeName)
700 {
701    printf("*******************************\n");
702    printf("*** Getting the ESD Chain   ***\n");
703    printf("*******************************\n");
704    TAlienCollection * myCollection  = TAlienCollection::Open(xmlfile);
705
706    if (!myCollection) {
707       ::Error("AnalysisTrainNew.C::CreateChainSingle", "Cannot create an AliEn collection from %s", xmlfile) ;
708       return NULL ;
709    }
710
711    TChain* chain = new TChain(treeName);
712    myCollection->Reset() ;
713    while ( myCollection->Next() ) chain->Add(myCollection->GetTURL("")) ;
714    chain->ls();
715    return chain;
716 }
717
718 //______________________________________________________________________________
719 Int_t SetupPar(char* pararchivename)
720 {
721    if (!pararchivename || !strlen(pararchivename)) return -1;
722    char processline[1024];
723    if (gSystem->AccessPathName(Form("%s.par", pararchivename))) {
724       if (!gSystem->AccessPathName(Form("%s/%s.par", gSystem->Getenv("ALICE_ROOT"),pararchivename))) {
725          ::Info("AnalysisTrainNew.C::SetupPar", "Getting %s.par from $ALICE_ROOT", pararchivename);
726          TFile::Cp(gSystem->ExpandPathName(Form("$ALICE_ROOT/%s.par", pararchivename)), 
727                    Form("%s.par",pararchivename));
728       } else {
729          ::Error("AnalysisTrainNew.C::SetupPar", "Cannot find %s.par", pararchivename);
730          return -1;
731       }   
732    }
733    if (usePLUGIN && saveTrain) gSystem->Exec(Form("ln -s ../%s.par %s",pararchivename, train_name.Data()));
734    gSystem->Exec(Form("tar xvzf %s.par", pararchivename));
735
736    TString ocwd = gSystem->WorkingDirectory();
737    if (!gSystem->ChangeDirectory(pararchivename)) return -1;
738         
739    // check for BUILD.sh and execute
740    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
741       printf("*******************************\n");
742       printf("*** Building PAR archive    ***\n");
743       printf("*******************************\n");          
744       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
745          Error("runProcess","Cannot Build the PAR Archive! - Abort!");
746          return -1;
747       }
748    }
749
750         // check for SETUP.C and execute
751         if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
752             printf("*******************************\n");
753             printf("*** Setup PAR archive       ***\n");
754             printf("*******************************\n");
755             gROOT->Macro("PROOF-INF/SETUP.C");
756         }       
757         if (!gSystem->ChangeDirectory(ocwd.Data())) return -1;
758    return 0;
759 }
760
761 //______________________________________________________________________________
762 AliAnalysisAlien* CreateAlienHandler(const char *plugin_mode)
763 {
764 // Check if user has a valid token, otherwise make one. This has limitations.
765 // One can always follow the standard procedure of calling alien-token-init then
766    AliAnalysisAlien *plugin = new AliAnalysisAlien();
767 // Set the run mode (can be "full", "test", "offline", "submit" or "terminate")
768    plugin->SetRunMode(plugin_mode);
769    if (useProductionMode) {
770       plugin->SetProductionMode();
771       plugin->AddDataFile(data_collection);
772    }   
773       
774    if (!outputSingleFolder.IsNull()) {
775       plugin->SetOutputSingleFolder(outputSingleFolder);
776       plugin->SetOutputToRunNo();
777    } 
778    if (iPWG3d2h) plugin->SetFriendChainName("AliAOD.VertexingHF.root");
779    plugin->SetJobTag(job_tag);
780    plugin->SetNtestFiles(5);
781    plugin->SetCheckCopy(kFALSE);
782    plugin->SetMergeDirName(mergeDirName);
783 // Set versions of used packages
784    plugin->SetAPIVersion("V1.1x");
785    plugin->SetROOTVersion(root_version);
786    plugin->SetAliROOTVersion(aliroot_version);
787 // Declare input data to be processed.
788 // Method 1: Create automatically XML collections using alien 'find' command.
789 // Define production directory LFN
790    plugin->SetGridDataDir(alien_datadir);
791 // Set data search pattern
792    plugin->SetDataPattern(data_pattern);
793    if (!useProductionMode) {
794       if (runOnData) {
795          plugin->SetRunPrefix("%09d");
796       }   
797 //   if (!iAODanalysis) plugin->SetRunRange(run_range[0], run_range[1]);
798       for (Int_t i=0; i<10; i++) {
799          if (run_numbers[i]==0) break;
800          plugin->AddRunNumber(run_numbers[i]);
801       }   
802    }   
803 // Define alien work directory where all files will be copied. Relative to alien $HOME.
804    plugin->SetGridWorkingDir(grid_workdir);
805 // Declare alien output directory. Relative to working directory.
806    if (alien_outdir.IsNull()) alien_outdir = Form("output_%s",train_name.Data());
807    plugin->SetGridOutputDir(alien_outdir);
808
809    TString ana_sources = "";
810    TString ana_add = "";
811    if (usePAR && anaPars.Length()) {
812       printf("%s\n", anaPars.Data());
813       TObjArray *arr;
814       TObjString *objstr;
815       arr = anaPars.Tokenize(" ");
816       TIter next(arr);
817       while ((objstr=(TObjString*)next())) plugin->EnablePackage(objstr->GetString());
818       delete arr;
819    } 
820    
821 // Declare the analysis source files names separated by blancs. To be compiled runtime
822 // using ACLiC on the worker nodes.
823    ana_sources = ana_sources.Strip();
824 // Declare all libraries (other than the default ones for the framework. These will be
825 // loaded by the generated analysis macro. Add all extra files (task .cxx/.h) here.
826    anaLibs     = anaLibs.Strip();   
827    if (ana_sources.Length()) plugin->SetAnalysisSource(ana_sources);
828    if (anaLibs.Length())     plugin->SetAdditionalLibs(anaLibs);
829      
830 // Declare the output file names separated by blancs.
831 // (can be like: file.root or file.root@ALICE::Niham::File)
832    plugin->SetDefaultOutputs();
833    plugin->SetMergeExcludes(mergeExclude);
834    plugin->SetMaxMergeFiles(maxMergeFiles);
835    plugin->SetNrunsPerMaster(nRunsPerMaster);
836 // Optionally define the files to be archived.
837 //   plugin->SetOutputArchive("log_archive.zip:stdout,stderr@ALICE::NIHAM::File root_archive.zip:AliAOD.root,AOD.tag.root@ALICE::NIHAM::File");
838    
839    
840    // Put default output files to archive
841    TString listhists = "";
842    TString listaods  = "";
843    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
844    TIter next(mgr->GetOutputs());
845    AliAnalysisDataContainer *output;
846    while ((output=(AliAnalysisDataContainer*)next())) {
847       const char *filename = output->GetFileName();
848       if (!(strcmp(filename, "default"))) {
849          if (!mgr->GetOutputEventHandler()) continue;
850          filename = mgr->GetOutputEventHandler()->GetOutputFileName();
851          if (listaods.Length()) listaods += ",";
852          listaods += filename;
853          listaods += ",";
854          listaods += "pyxsec_hists.root";
855       } else {
856          if (!strcmp(filename, "pyxsec_hists.root")) continue;
857          if (listhists.Contains(filename)) continue;
858          if (listhists.Length()) listhists += ",";
859          listhists += filename;
860       }
861    }
862    if (mgr->GetExtraFiles().Length()) {
863       if (listaods.Length()) listaods += ",";
864       listaods += mgr->GetExtraFiles();
865       listaods.ReplaceAll(" ", ",");
866    }
867    if (listhists.Length()) listhists = Form("hist_archive.zip:%s@%s", listhists.Data(), outputStorages.Data());
868    if (listaods.Length())  listaods  = Form("aod_archive.zip:%s@%s", listaods.Data(), outputStorages.Data());
869    if (!listhists.Length() && !listaods.Length()) {
870       ::Fatal("AnalysisTrainNew", "No task output !");
871    }
872    TString outputArchive = Form("log_archive.zip:stderr@%s", outputStorages.Data());
873    if (listaods.Length()) {
874       outputArchive += " ";
875       outputArchive += listaods;
876    }   
877    if (listhists.Length()) {
878       outputArchive += " ";
879       outputArchive += listhists;
880    }   
881 // Set friends
882 //   if (iAODanalysis && iPWG3d2h) 
883 //      plugin->SetFriendChainName("AliAOD.VertexingHF.root");
884 //   plugin->SetOutputArchive(outputArchive);
885 // Optionally set a name for the generated analysis macro (default MyAnalysis.C)
886    plugin->SetAnalysisMacro(Form("%s.C", train_name.Data()));
887 // Optionally set a name for the generated validation script
888    plugin->SetValidationScript("PWG3validation.sh");
889 // Optionally set maximum number of input files/subjob (default 100, put 0 to ignore)
890    plugin->SetSplitMaxInputFileNumber(nFilesPerJob);
891 // Optionally set number of failed jobs that will trigger killing waiting sub-jobs.
892 //   plugin->SetMaxInitFailed(5);
893 // Optionally modify the number of replicas
894    plugin->SetNumberOfReplicas(4);
895 // Optionally resubmit threshold.
896 //   plugin->SetMasterResubmitThreshold(90);
897 // Optionally set time to live (default 30000 sec)
898    plugin->SetTTL(70000);
899 // Optionally set input format (default xml-single)
900    plugin->SetInputFormat("xml-single");
901 // Optionally modify the name of the generated JDL (default analysis.jdl)
902    plugin->SetJDLName(Form("%s.jdl", train_name.Data()));
903 // Optionally modify the executable name (default analysis.sh)
904    plugin->SetExecutable(Form("%s.sh", train_name.Data()));
905 // Optionally modify job price (default 1)
906    plugin->SetPrice(1);      
907 // Merge via JDL
908    plugin->SetMergeViaJDL(useMergeViaJDL);
909 // Use fastread option
910    plugin->SetFastReadOption(useFastReadOption);
911 // UseOverwrite mode
912    plugin->SetOverwriteMode(useOverwriteMode);   
913    plugin->SetExecutableCommand("aliroot -b -q");
914 // Optionally modify split mode (default 'se')    
915    plugin->SetSplitMode("se");
916    return plugin;
917 }
918
919 //______________________________________________________________________________
920 void WriteConfig()
921 {
922 // Write train configuration in a file. The file name has the format:
923 // train_[trainName]_ddMonthyyyy_time.C
924    if (useDATE) {
925       gSystem->Exec("date +%d%b%Y_%Hh%M > date.tmp");
926       ifstream fdate("date.tmp");
927       if (!fdate.is_open()) {
928          ::Error("AnalysisTrainNew.C::Export","Could not generate file name");
929          return;
930       }
931       const char date[64];
932       fdate.getline(date,64);
933       fdate.close();
934       gSystem->Exec("rm date.tmp");
935       train_name = Form("%s_%s", train_name.Data(), date);
936    }   
937    TString cdir = gSystem->WorkingDirectory();
938    gSystem->MakeDirectory(train_name);
939    gSystem->ChangeDirectory(train_name);
940    ofstream out;
941    out.open(Form("%sConfig.C",train_name.Data()), ios::out); 
942    if (out.bad()) {
943       ::Error("AnalysisTrainNew.C::Export", "Cannot open ConfigTrain.C for writing");
944       return;
945    }
946    out << "{" << endl;
947    out << "   train_name      = " << "\"" << train_name.Data() << "\";" << endl;
948    out << "   proof_cluster   = " << "\"" << proof_cluster.Data() << "\";" << endl;
949    out << "   useAFPAR        = " << useAFPAR << ";" << endl;
950    if (useAFPAR) 
951       out << "   AFversion       = " << AFversion.Data() << ";" << endl;
952    out << "   proof_dataset   = " << "\"" << proof_dataset.Data() << "\";" << endl;
953    out << "   usePLUGIN       = " << usePLUGIN << ";" << endl;
954    out << "   usePAR          = " << usePAR << ";" << endl;
955    out << "   useCPAR         = " << useCPAR << ";" << endl;
956    out << "   root_version    = " << "\"" << root_version.Data() << "\";" << endl;
957    out << "   aliroot_version = " << "\"" << aliroot_version.Data() << "\";" << endl;
958    out << "   alien_datadir   = " << "\"" << alien_datadir.Data() << "\";" << endl;
959    if (!alien_outdir.Length()) alien_outdir = Form("output_%s",train_name.Data());
960    out << "   alien_outdir    = " << "\"" << alien_outdir.Data() << "\";" << endl;
961    out << "   maxMergeFiles   = " << maxMergeFiles << ";" << endl;
962    out << "   mergeExclude    = " << "\"" << mergeExclude.Data() << "\";" << endl;
963    out << "   nRunsPerMaster  = " << nRunsPerMaster << ";" << endl;
964    out << "   nFilesPerJob    = " << nFilesPerJob << ";" << endl;
965 //   for (Int_t i=0; i<10; i++) {
966 //      if (run_numbers[i]) 
967 //         out << "   run_numbers[" << i << "]  = " << run_numbers[i] << ";" << endl;
968 //   }
969 //   out << "   run_range[0]    = " << run_range[0] << ";" << endl;
970 //   out << "   run_range[1]    = " << run_range[1] << ";" << endl;
971    out << "   usePhysicsSelection = " << usePhysicsSelection << ";" << endl;
972    out << "   useTender       = " << useTender << ";" << endl;
973    out << "   useMergeViaJDL  = " << useMergeViaJDL << ";" << endl;
974    out << "   useOverwriteMode  = " << useOverwriteMode << ";" << endl;
975    out << "   useFastReadOption = " << useFastReadOption << ";" << endl;
976    out << "   useDBG          = " << useDBG << ";" << endl;
977    out << "   useMC           = " << useMC << ";" << endl;
978    out << "   useTAGS         = " << useTAGS << ";" << endl;
979    out << "   useKFILTER      = " << useKFILTER << ";" << endl;
980    out << "   useTR           = " << useTR << ";" << endl;
981    out << "   useCORRFW       = " << useCORRFW << ";" << endl;
982    out << "   useAODTAGS      = " << useAODTAGS << ";" << endl;
983    out << "   saveTrain       = " << "kFALSE;" << endl << endl;
984    out << "   // Analysis modules" << endl;
985    out << "   iAODanalysis    = " << iAODanalysis << ";" << endl;
986    out << "   iAODhandler     = " << iAODhandler << ";" << endl;
987    out << "   iPWG3hfe        = " << iPWG3hfe << ";" << endl;   
988    out << "   iPWG3JPSI       = " << iPWG3JPSI << ";" << endl;   
989    out << "   iPWG3d2h        = " << iPWG3d2h << ";" << endl;   
990    out << "   iPWG3MuonTrain      = " << iPWG3MuonTrain << ";" << endl;   
991    out << "}" << endl;
992    ::Info("AnalysisTrainNew.C::WriteConfig", "Train configuration wrote to file %s", Form("config_%s.C", train_name.Data()));
993    gSystem->ChangeDirectory(cdir);
994 }   
995
996 //______________________________________________________________________________
997 Bool_t LoadConfig(const char *filename)
998 {
999 // Read train configuration from file
1000    if (gSystem->AccessPathName(filename)) {
1001       ::Error("AnalysisTrainNew.C::LoadConfig", "Config file name not found");
1002       return kFALSE;
1003    }   
1004    gROOT->ProcessLine(Form(".x %s", filename));
1005    ::Info("AnalysisTrainNew.C::LoadConfig", "Train configuration loaded from file %s", filename);
1006    return kTRUE;
1007 }