Record changes.
[u/mrichter/AliRoot.git] / SHUTTLE / AliShuttleConfig.cxx
CommitLineData
73abe331 1/**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
16/*
17$Log$
be48e3ea 18Revision 1.11 2006/11/06 14:23:04 jgrosseo
19major update (Alberto)
20o) reading of run parameters from the logbook
21o) online offline naming conversion
22o) standalone DCSclient package
23
eba76848 24Revision 1.10 2006/10/20 15:22:59 jgrosseo
25o) Adding time out to the execution of the preprocessors: The Shuttle forks and the parent process monitors the child
26o) Merging Collect, CollectAll, CollectNew function
27o) Removing implementation of empty copy constructors (declaration still there!)
28
cb343cfd 29Revision 1.9 2006/10/02 16:38:39 jgrosseo
30update (alberto):
31fixed memory leaks
32storing of objects that failed to be stored to the grid before
33interfacing of shuttle status table in daq system
34
2bb7b766 35Revision 1.8 2006/08/15 10:50:00 jgrosseo
36effc++ corrections (alberto)
37
4f0ab988 38Revision 1.7 2006/07/20 09:54:40 jgrosseo
39introducing status management: The processing per subdetector is divided into several steps,
40after each step the status is stored on disk. If the system crashes in any of the steps the Shuttle
41can keep track of the number of failures and skips further processing after a certain threshold is
42exceeded. These thresholds can be configured in LDAP.
43
5164a766 44Revision 1.6 2006/07/19 10:09:55 jgrosseo
45new configuration, accesst to DAQ FES (Alberto)
46
57f50b3c 47Revision 1.5 2006/07/10 13:01:41 jgrosseo
48enhanced storing of last sucessfully processed run (alberto)
49
a7160fe9 50Revision 1.4 2006/06/12 09:11:16 jgrosseo
51coding conventions (Alberto)
52
58bc3020 53Revision 1.3 2006/06/06 14:26:40 jgrosseo
54o) removed files that were moved to STEER
55o) shuttle updated to follow the new interface (Alberto)
56
b948db8d 57Revision 1.7 2006/05/12 09:07:16 colla
5812/05/06
59New configuration complete
60
61Revision 1.2 2006/03/07 07:52:34 hristov
62New version (B.Yordanov)
63
d477ad88 64Revision 1.4 2005/11/19 14:20:31 byordano
65logbook config added to AliShuttleConfig
66
67Revision 1.3 2005/11/17 19:24:25 byordano
68TList changed to TObjArray in AliShuttleConfig
69
70Revision 1.2 2005/11/17 14:43:23 byordano
71import to local CVS
72
73Revision 1.1.1.1 2005/10/28 07:33:58 hristov
74Initial import as subdirectory in AliRoot
75
73abe331 76Revision 1.1.1.1 2005/09/12 22:11:40 byordano
77SHUTTLE package
78
79Revision 1.3 2005/08/30 09:13:02 byordano
80some docs added
81
82*/
83
84
85//
86// This class keeps the AliShuttle configuration.
87// It reads the configuration for LDAP server.
88// For every child entry in basedn which has schema type 'shuttleConfig'
89// it creates a detector configuration. This configuration includes:
90// DCS server host and port and the set of aliases for which data from
91// will be retrieved (used by AliShuttle).
92//
93
94
95#include "AliShuttleConfig.h"
57f50b3c 96#include "AliShuttleInterface.h"
73abe331 97
98#include "AliLog.h"
99
b948db8d 100#include <TSystem.h>
73abe331 101#include <TObjString.h>
102#include <TLDAPResult.h>
103#include <TLDAPEntry.h>
104#include <TLDAPAttribute.h>
105
57f50b3c 106
58bc3020 107AliShuttleConfig::AliShuttleConfigHolder::AliShuttleConfigHolder(const TLDAPEntry* entry):
57f50b3c 108fDetector(""),
109fDCSHost(""),
110fDCSPort(0),
57f50b3c 111fIsValid(kFALSE),
be48e3ea 112fSkipDCSQuery(kFALSE),
113fStrictRunOrder(kFALSE)
73abe331 114{
58bc3020 115// constructor of the shuttle configuration holder
116
73abe331 117 TLDAPAttribute* anAttribute;
2bb7b766 118 fDCSAliases = new TObjArray();
119 fDCSAliases->SetOwner(1);
57f50b3c 120
121 anAttribute = entry->GetAttribute("det"); // MUST
73abe331 122 fDetector = anAttribute->GetValue();
73abe331 123
be48e3ea 124 anAttribute = entry->GetAttribute("StrictRunOrder"); // MAY
125 if (!anAttribute)
126 {
127 AliWarning(Form("%s did not set StrictRunOrder flag - the default is FALSE",
128 fDetector.Data()));
129 } else {
130 TString strictRunStr = anAttribute->GetValue();
131 if (!(strictRunStr == "0" || strictRunStr == "1"))
132 {
133 AliError("Invalid configuration! StrictRunOrder flag must be 0 or 1!");
134 return;
135 }
136 fStrictRunOrder = (Bool_t) strictRunStr.Atoi();
137 }
138
57f50b3c 139 anAttribute = entry->GetAttribute("DCSHost"); // MAY
73abe331 140 if (!anAttribute) {
57f50b3c 141 AliWarning(
142 Form("%s has not DCS host entry - Shuttle will skip DCS data query!",
143 fDetector.Data()));
144 fIsValid = kTRUE;
145 fSkipDCSQuery = kTRUE;
73abe331 146 return;
147 }
57f50b3c 148
b948db8d 149 fDCSHost = anAttribute->GetValue();
73abe331 150
57f50b3c 151 anAttribute = entry->GetAttribute("DCSPort"); // MAY
73abe331 152 if (!anAttribute) {
57f50b3c 153 AliError(Form("Invalid configuration! %s has DCS Host but no port number!",
154 fDetector.Data()));
73abe331 155 return;
156 }
157 TString portStr = anAttribute->GetValue();
b948db8d 158 fDCSPort = portStr.Atoi();
73abe331 159
57f50b3c 160 anAttribute = entry->GetAttribute("DCSAlias"); // MAY
73abe331 161 if (!anAttribute) {
57f50b3c 162 AliError(Form("Invalid configuration! %s has DCS host settings but no DCSAlias entries!",
163 fDetector.Data()));
73abe331 164 return;
165 }
57f50b3c 166
73abe331 167 const char* anAlias;
168 while ((anAlias = anAttribute->GetValue())) {
2bb7b766 169 fDCSAliases->AddLast(new TObjString(anAlias));
b948db8d 170 }
171
73abe331 172 fIsValid = kTRUE;
57f50b3c 173
174
73abe331 175}
176
a7160fe9 177//______________________________________________________________________________________________
178AliShuttleConfig::AliShuttleConfigHolder::~AliShuttleConfigHolder()
58bc3020 179{
180// destructor of the shuttle configuration holder
181
2bb7b766 182 delete fDCSAliases;
73abe331 183}
184
185ClassImp(AliShuttleConfig)
186
a7160fe9 187//______________________________________________________________________________________________
188AliShuttleConfig::AliShuttleConfig(const char* host, Int_t port,
73abe331 189 const char* binddn, const char* password, const char* basedn):
b948db8d 190 fIsValid(kFALSE),
4f0ab988 191 fDAQlbHost(""), fDAQlbUser(""), fDAQlbPass(""),
cb343cfd 192 fMaxRetries(0), fPPTimeOut(0), fDetectorMap(), fDetectorList(),
2bb7b766 193 fShuttleInstanceHost(""), fProcessedDetectors(), fProcessAll(kFALSE)
73abe331 194{
195 //
196 // host: ldap server host
197 // port: ldap server port
198 // binddn: binddn used for ldap binding (simple bind is used!).
199 // password: password for binddn
b948db8d 200 // basedn: this is basedn whose childeren entries which have
73abe331 201 // (objectClass=shuttleConfig) will be used as detector configurations.
202 //
203
2bb7b766 204 fDetectorMap.SetOwner();
205 fDetectorList.SetOwner(0); //fDetectorList and fDetectorMap share the same object!
206 fProcessedDetectors.SetOwner();
207
b948db8d 208 TLDAPServer aServer(host, port, binddn, password, 3);
57f50b3c 209
73abe331 210 if (!aServer.IsConnected()) {
2bb7b766 211 AliError(Form("Can't connect to ldap server %s:%d",
73abe331 212 host, port));
213 return;
214 }
215
b948db8d 216 // reads configuration for the shuttle running on this machine
2bb7b766 217
b948db8d 218 fShuttleInstanceHost = gSystem->HostName();
2bb7b766 219 TString queryFilter = Form("(ShuttleHost=%s)", fShuttleInstanceHost.Data());
220
221 TLDAPResult* aResult = aServer.Search(basedn, LDAP_SCOPE_ONELEVEL, queryFilter.Data());
b948db8d 222
73abe331 223 if (!aResult) {
224 AliError(Form("Can't find configuration with base DN: %s",
225 basedn));
226 return;
227 }
b948db8d 228
229 if (aResult->GetCount() == 0) {
57f50b3c 230 AliError(Form("No Shuttle instance for host = %s!",
231 fShuttleInstanceHost.Data()));
b948db8d 232 AliError(Form("All detectors will be processed."));
233 fProcessAll=kTRUE;
234 }
235
236 if (aResult->GetCount() > 1) {
57f50b3c 237 AliError(Form("More than one Shuttle instance for host %s!",
238 fShuttleInstanceHost.Data()));
2bb7b766 239 delete aResult;
b948db8d 240 return;
241 }
57f50b3c 242
2bb7b766 243 TLDAPEntry* anEntry = 0;
244 TLDAPAttribute* anAttribute = 0;
b948db8d 245
246 if(!fProcessAll){
247 anEntry = aResult->GetNext();
248 anAttribute = anEntry->GetAttribute("detectors");
249 const char *detName;
250 while((detName = anAttribute->GetValue())){
251 TObjString *objDet= new TObjString(detName);
252 fProcessedDetectors.Add(objDet);
253 }
254 }
255
2bb7b766 256 delete anEntry; delete aResult;
257
57f50b3c 258 // Detector configuration (DCS Archive DB settings)
259
2bb7b766 260 aResult = aServer.Search(basedn, LDAP_SCOPE_ONELEVEL, "(objectClass=AliShuttleDetector)");
b948db8d 261 if (!aResult) {
2bb7b766 262 AliError(Form("Can't find configuration with base DN: %s", basedn));
b948db8d 263 return;
264 }
265
57f50b3c 266
73abe331 267 while ((anEntry = aResult->GetNext())) {
58bc3020 268 AliShuttleConfigHolder* aHolder = new AliShuttleConfigHolder(anEntry);
73abe331 269 delete anEntry;
270
271 if (!aHolder->IsValid()) {
57f50b3c 272 AliError("Detector configuration error!");
73abe331 273 delete aHolder;
2bb7b766 274 delete aResult;
57f50b3c 275 return;
73abe331 276 }
277
278 TObjString* detStr = new TObjString(aHolder->GetDetector());
279 fDetectorMap.Add(detStr, aHolder);
d477ad88 280 fDetectorList.AddLast(detStr);
57f50b3c 281 }
282
73abe331 283 delete aResult;
284
57f50b3c 285 // Global configuration (DAQ logbook)
d477ad88 286
287 aResult = aServer.Search(basedn, LDAP_SCOPE_ONELEVEL,
b948db8d 288 "(objectClass=AliShuttleGlobalConfig)");
d477ad88 289 if (!aResult) {
290 AliError(Form("Can't find configuration with base DN: %s",
291 basedn));
292 return;
293 }
294
295 if (aResult->GetCount() == 0) {
b948db8d 296 AliError("Can't find DAQ logbook configuration!");
2bb7b766 297 delete aResult;
d477ad88 298 return;
299 }
300
301 if (aResult->GetCount() > 1) {
b948db8d 302 AliError("More than one DAQ logbook configuration found!");
2bb7b766 303 delete aResult;
d477ad88 304 return;
305 }
306
307 anEntry = aResult->GetNext();
57f50b3c 308
b948db8d 309 anAttribute = anEntry->GetAttribute("DAQLogbookHost");
d477ad88 310 if (!anAttribute) {
b948db8d 311 AliError("Can't find DAQLogbookHost attribute!");
2bb7b766 312 delete anEntry; delete aResult;
d477ad88 313 return;
314 }
57f50b3c 315 fDAQlbHost = anAttribute->GetValue();
d477ad88 316
b948db8d 317 anAttribute = anEntry->GetAttribute("DAQLogbookUser");
d477ad88 318 if (!anAttribute) {
b948db8d 319 AliError("Can't find DAQLogbookUser attribute!");
2bb7b766 320 delete aResult; delete anEntry;
d477ad88 321 return;
322 }
57f50b3c 323 fDAQlbUser = anAttribute->GetValue();
324
b948db8d 325 anAttribute = anEntry->GetAttribute("DAQLogbookPassword");
d477ad88 326 if (!anAttribute) {
b948db8d 327 AliError("Can't find DAQLogbookPassword attribute!");
2bb7b766 328 delete aResult; delete anEntry;
d477ad88 329 return;
330 }
57f50b3c 331 fDAQlbPass = anAttribute->GetValue();
d477ad88 332
cb343cfd 333 anAttribute = anEntry->GetAttribute("MaxRetries");
5164a766 334 if (!anAttribute) {
cb343cfd 335 AliError("Can't find MaxRetries attribute!");
2bb7b766 336 delete aResult; delete anEntry;
5164a766 337 return;
338 }
339 TString tmpStr = anAttribute->GetValue();
cb343cfd 340 fMaxRetries = tmpStr.Atoi();
5164a766 341
cb343cfd 342 anAttribute = anEntry->GetAttribute("PPTimeOut");
5164a766 343 if (!anAttribute) {
cb343cfd 344 AliError("Can't find PPTimeOut attribute!");
2bb7b766 345 delete aResult; delete anEntry;
5164a766 346 return;
347 }
348 tmpStr = anAttribute->GetValue();
cb343cfd 349 fPPTimeOut = tmpStr.Atoi();
5164a766 350
2bb7b766 351 delete aResult; delete anEntry;
57f50b3c 352
353 // FES configuration (FES logbook and hosts)
354
57f50b3c 355 for(int iSys=0;iSys<3;iSys++){
eba76848 356 queryFilter = Form("(system=%s)", AliShuttleInterface::GetSystemName(iSys));
57f50b3c 357 aResult = aServer.Search(basedn, LDAP_SCOPE_ONELEVEL, queryFilter.Data());
358 if (!aResult) {
359 AliError(Form("Can't find configuration for system: %s",
eba76848 360 AliShuttleInterface::GetSystemName(iSys)));
57f50b3c 361 return;
362 }
363
364 if (aResult->GetCount() != 1 ) {
365 AliError("Error in FES configuration!");
2bb7b766 366 delete aResult;
57f50b3c 367 return;
368 }
369
370 anEntry = aResult->GetNext();
371
372 anAttribute = anEntry->GetAttribute("LogbookHost");
373 if (!anAttribute) {
374 AliError(Form ("Can't find LogbookHost attribute for %s!!",
eba76848 375 AliShuttleInterface::GetSystemName(iSys)));
2bb7b766 376 delete aResult; delete anEntry;
57f50b3c 377 return;
378 }
379 fFESlbHost[iSys] = anAttribute->GetValue();
380
381 anAttribute = anEntry->GetAttribute("LogbookUser");
382 if (!anAttribute) {
383 AliError(Form ("Can't find LogbookUser attribute for %s!!",
eba76848 384 AliShuttleInterface::GetSystemName(iSys)));
2bb7b766 385 delete aResult; delete anEntry;
57f50b3c 386 return;
387 }
388 fFESlbUser[iSys] = anAttribute->GetValue();
389
390 anAttribute = anEntry->GetAttribute("LogbookPassword");
391 if (!anAttribute) {
392 AliError(Form ("Can't find LogbookPassword attribute for %s!!",
eba76848 393 AliShuttleInterface::GetSystemName(iSys)));
2bb7b766 394 delete aResult; delete anEntry;
57f50b3c 395 return;
396 }
397 fFESlbPass[iSys] = anAttribute->GetValue();
398
399 anAttribute = anEntry->GetAttribute("FSHost");
400 if (!anAttribute) {
401 AliError(Form ("Can't find FSHost attribute for %s!!",
eba76848 402 AliShuttleInterface::GetSystemName(iSys)));
2bb7b766 403 delete aResult; delete anEntry;
57f50b3c 404 return;
405 }
406 fFESHost[iSys] = anAttribute->GetValue();
407
408 anAttribute = anEntry->GetAttribute("FSUser");
409 if (!anAttribute) {
410 AliError(Form ("Can't find FSUser attribute for %s!!",
eba76848 411 AliShuttleInterface::GetSystemName(iSys)));
2bb7b766 412 delete aResult; delete anEntry;
57f50b3c 413 return;
414 }
415 fFESUser[iSys] = anAttribute->GetValue();
416
417 anAttribute = anEntry->GetAttribute("FSPassword");
418 if (anAttribute) fFESPass[iSys] = anAttribute->GetValue();
419
2bb7b766 420 delete aResult; delete anEntry;
57f50b3c 421 }
422
73abe331 423 fIsValid = kTRUE;
424}
425
a7160fe9 426//______________________________________________________________________________________________
427AliShuttleConfig::~AliShuttleConfig()
58bc3020 428{
429// destructor
430
73abe331 431 fDetectorMap.DeleteAll();
2bb7b766 432 fDetectorList.Clear();
433 fProcessedDetectors.Delete();
73abe331 434}
435
a7160fe9 436//______________________________________________________________________________________________
437const TObjArray* AliShuttleConfig::GetDetectors() const
58bc3020 438{
73abe331 439 //
440 // returns collection of TObjString which contains the name
441 // of every detector which is in the configuration.
442 //
443
444 return &fDetectorList;
445}
446
a7160fe9 447//______________________________________________________________________________________________
448Bool_t AliShuttleConfig::HasDetector(const char* detector) const
58bc3020 449{
73abe331 450 //
451 // checks for paricular detector in the configuration.
452 //
453 return fDetectorMap.GetValue(detector) != NULL;
454}
455
a7160fe9 456//______________________________________________________________________________________________
457const char* AliShuttleConfig::GetDCSHost(const char* detector) const
58bc3020 458{
73abe331 459 //
460 // returns DCS server host used by particular detector
461 //
462
58bc3020 463 AliShuttleConfigHolder* aHolder = (AliShuttleConfigHolder*) fDetectorMap.GetValue(detector);
73abe331 464 if (!aHolder) {
465 AliError(Form("There isn't configuration for detector: %s",
466 detector));
467 return NULL;
468 }
469
b948db8d 470 return aHolder->GetDCSHost();
73abe331 471}
472
a7160fe9 473//______________________________________________________________________________________________
474Int_t AliShuttleConfig::GetDCSPort(const char* detector) const
58bc3020 475{
73abe331 476 //
477 // returns DCS server port used by particular detector
478 //
479
480
58bc3020 481 AliShuttleConfigHolder* aHolder = (AliShuttleConfigHolder*) fDetectorMap.GetValue(detector);
73abe331 482 if (!aHolder) {
483 AliError(Form("There isn't configuration for detector: %s",
484 detector));
485 return 0;
486 }
487
b948db8d 488 return aHolder->GetDCSPort();
73abe331 489}
490
a7160fe9 491//______________________________________________________________________________________________
492const TObjArray* AliShuttleConfig::GetDCSAliases(const char* detector) const
58bc3020 493{
73abe331 494 //
495 // returns collection of TObjString which represents the set of aliases
496 // which used for data retrieval for particular detector
497 //
498
58bc3020 499 AliShuttleConfigHolder* aHolder = (AliShuttleConfigHolder*) fDetectorMap.GetValue(detector);
73abe331 500 if (!aHolder) {
501 AliError(Form("There isn't configuration for detector: %s",
502 detector));
503 return NULL;
504 }
505
b948db8d 506 return aHolder->GetDCSAliases();
507}
508
a7160fe9 509//______________________________________________________________________________________________
a7160fe9 510Bool_t AliShuttleConfig::HostProcessDetector(const char* detector) const
58bc3020 511{
b948db8d 512 // return TRUE if detector is handled by host or if fProcessAll is TRUE
513
514 if(fProcessAll) return kTRUE;
515 TIter iter(&fProcessedDetectors);
516 TObjString* detName;
517 while((detName = (TObjString*) iter.Next())){
518 if(detName->String() == detector) return kTRUE;
519 }
520 return kFALSE;
73abe331 521}
522
a7160fe9 523//______________________________________________________________________________________________
be48e3ea 524Bool_t AliShuttleConfig::StrictRunOrder(const char* detector) const
525{
526 // return TRUE if detector wants strict run ordering of stored data
527
528 AliShuttleConfigHolder* aHolder = (AliShuttleConfigHolder*) fDetectorMap.GetValue(detector);
529 if (!aHolder)
530 {
531 AliError(Form("There isn't configuration for detector: %s",
532 detector));
533 return kTRUE;
534 }
535
536 return aHolder->StrictRunOrder();
537}
538
539//______________________________________________________________________________________________
57f50b3c 540void AliShuttleConfig::Print(Option_t* /*option*/) const
58bc3020 541{
542// print configuration
73abe331 543
544 TString result;
545 result += '\n';
d477ad88 546
57f50b3c 547 result += Form("\nShuttle running on %s \n\n", fShuttleInstanceHost.Data());
548
549 if(fProcessAll) {
550 result += Form("All detectors will be processed! \n\n");
551 } else {
552 result += "Detectors processed by this host: ";
553 TIter it(&fProcessedDetectors);
554 TObjString* aDet;
555 while ((aDet = (TObjString*) it.Next())) {
556 result += Form("%s ", aDet->String().Data());
557 }
558 result += "\n\n";
b948db8d 559 }
b948db8d 560
cb343cfd 561 result += Form("PP time out = %d - Max total retries = %d\n\n", fPPTimeOut, fMaxRetries);
2bb7b766 562
57f50b3c 563 result += Form("DAQ Logbook Configuration \n \tHost: %s - User: %s - ",
564 fDAQlbHost.Data(), fDAQlbUser.Data());
b948db8d 565
57f50b3c 566 result += "Password: ";
567 result.Append('*', fDAQlbPass.Length());
568 result += "\n\n";
569
570 for(int iSys=0;iSys<3;iSys++){
eba76848 571 result += Form("FES Configuration for %s system\n", AliShuttleInterface::GetSystemName(iSys));
57f50b3c 572 result += Form("\tLogbook host: \t%s - \tUser: %s\n",
573 fFESlbHost[iSys].Data(), fFESlbUser[iSys].Data());
574 // result += Form("Logbook Password:",fFESlbPass[iSys].Data());
575 result += Form("\tFES host: \t%s - \tUser: %s\n\n", fFESHost[iSys].Data(), fFESUser[iSys].Data());
576 // result += Form("FES Password:",fFESPass[iSys].Data());
577 }
b948db8d 578
73abe331 579 TIter iter(fDetectorMap.GetTable());
580 TPair* aPair;
581 while ((aPair = (TPair*) iter.Next())) {
58bc3020 582 AliShuttleConfigHolder* aHolder = (AliShuttleConfigHolder*) aPair->Value();
be48e3ea 583 result += Form("Detector-specific configuration: *** %s *** \n", aHolder->GetDetector());
584 result += Form("\tStrict run ordering flag: %s \n", aHolder->StrictRunOrder() ? "TRUE" : "FALSE");
585 if(aHolder->SkipDCSQuery())
586 {
587 result += "\n\n";
588 continue;
589 }
57f50b3c 590 result += Form("\tAmanda server: %s:%d \n", aHolder->GetDCSHost(), aHolder->GetDCSPort());
591
592 result += "\tDCS Aliases: ";
593 const TObjArray* aliases = aHolder->GetDCSAliases();
b948db8d 594 TIter it(aliases);
57f50b3c 595 TObjString* anAlias;
73abe331 596 while ((anAlias = (TObjString*) it.Next())) {
57f50b3c 597 result += Form("%s ", anAlias->String().Data());
598 }
599
600 result += "\n\n";
601
73abe331 602 }
603
57f50b3c 604 if(!fIsValid) result += "\n\n********** !!!!! Configuration is INVALID !!!!! **********\n";
605
73abe331 606 AliInfo(result);
607}