]> git.uio.no Git - u/mrichter/AliRoot.git/blame - MUON/mapping/AliMpMotifMap.cxx
Updated for modifs in AliMpFiles
[u/mrichter/AliRoot.git] / MUON / mapping / AliMpMotifMap.cxx
CommitLineData
dee1d5f1 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
5f91c9e8 16// $Id$
5006ec94 17// $MpId: AliMpMotifMap.cxx,v 1.9 2005/09/26 16:11:20 ivana Exp $
5f91c9e8 18// Category: motif
19//
20// Class AliMpMotifMap
21// -------------------
22// Class describing the motif map container, where motifs are
23// mapped to their string IDs.
dbe945cc 24// Included in AliRoot: 2003/05/02
5f91c9e8 25// Authors: David Guez, Ivana Hrivnacova; IPN Orsay
26
27#include <Riostream.h>
7a854749 28#include <TVector2.h>
5f91c9e8 29
30#include "AliMpMotifMap.h"
31#include "AliMpVMotif.h"
32#include "AliMpMotif.h"
33#include "AliMpMotifSpecial.h"
34#include "AliMpMotifType.h"
35#include "AliMpMotifPosition.h"
36
37ClassImp(AliMpMotifMap)
38
5006ec94 39//_____________________________________________________________________________
40AliMpMotifMap::AliMpMotifMap(Bool_t /*standardConstructor*/)
41 : TObject()
f79c58a5 42#ifdef WITH_ROOT
5006ec94 43 ,fMotifs(true),
44 fMotifTypes(true),
45 fMotifPositions(true),
46 fMotifPositions2(true)
47#endif
48{
49/// Standard constructor
50
51 //fMotifPositions2.SetOwner(false);
52}
f79c58a5 53
5f91c9e8 54//_____________________________________________________________________________
55AliMpMotifMap::AliMpMotifMap()
5006ec94 56 : TObject(),
57 fMotifs(),
58 fMotifTypes(),
59 fMotifPositions(),
60 fMotifPositions2()
5f91c9e8 61{
dee1d5f1 62/// Default constructor
5f91c9e8 63}
64
65//_____________________________________________________________________________
dee1d5f1 66AliMpMotifMap::~AliMpMotifMap()
67{
68/// Destructor
5f91c9e8 69
70 // Delete all registered motifs, motif types, motif positions
71
f79c58a5 72#ifdef WITH_STL
5f91c9e8 73 for (MotifMapIterator im=fMotifs.begin(); im != fMotifs.end(); im++) {
74 delete im->second;
75 }
f79c58a5 76
5f91c9e8 77 for (MotifTypeMapIterator it=fMotifTypes.begin();
78 it != fMotifTypes.end(); it++) {
79 delete it->second;
80 }
f79c58a5 81
5f91c9e8 82 for (MotifPositionMapIterator ip=fMotifPositions.begin();
83 ip != fMotifPositions.end(); ip++) {
84 delete ip->second;
85 }
f79c58a5 86#endif
5f91c9e8 87}
88
89//
90// private methods
91//
92
f79c58a5 93//_____________________________________________________________________________
94void AliMpMotifMap::PrintMotif(const AliMpVMotif* motif) const
95{
dee1d5f1 96/// Print the motif.
f79c58a5 97// ---
98
99 cout << motif->GetID().Data() << " "
100 << motif->GetMotifType()->GetID() << " "
101 << motif->Dimensions().X() << " "
102 << motif->Dimensions().Y();
103}
104
105//_____________________________________________________________________________
106void AliMpMotifMap::PrintMotifType(const AliMpMotifType* motifType) const
107{
dee1d5f1 108/// Print the motif type.
f79c58a5 109
110 cout << motifType->GetID().Data() << " "
111 << motifType->GetNofPadsX() << " "
112 << motifType->GetNofPadsY() << " ";
113}
114
115//_____________________________________________________________________________
116void AliMpMotifMap::PrintMotifPosition(
117 const AliMpMotifPosition* motifPosition) const
118{
dee1d5f1 119/// Print the motif position.
f79c58a5 120
121 cout << motifPosition->GetID() << " "
122 << motifPosition->GetMotif()->GetID() << " "
123 << motifPosition->Position().X() << " "
124 << motifPosition->Position().Y() << " ";
125}
126
127//_____________________________________________________________________________
128void AliMpMotifMap::PrintMotifPosition2(
129 const AliMpMotifPosition* motifPosition) const
130{
dee1d5f1 131/// Print the motif position.
f79c58a5 132
133 cout << setw(3) << motifPosition->GetLowIndicesLimit().GetFirst() << " "
134 << setw(3) << motifPosition->GetLowIndicesLimit().GetSecond() << " "
135 << setw(3) << motifPosition->GetHighIndicesLimit().GetFirst() << " "
136 << setw(3) << motifPosition->GetHighIndicesLimit().GetSecond() << " "
137 << motifPosition->GetID() << " ";
138}
139
5f91c9e8 140//_____________________________________________________________________________
141void AliMpMotifMap::PrintMotifs() const
142{
dee1d5f1 143/// Print all the motifs and their motif types
144/// for all motifs in the motifs map.
5f91c9e8 145
f79c58a5 146#ifdef WITH_STL
5f91c9e8 147 if (fMotifs.size()) {
148 cout << "Dump of Motif Map - " << fMotifs.size() << " entries:" << endl;
149 Int_t counter = 0;
150 for (MotifMapIterator i=fMotifs.begin(); i != fMotifs.end(); i++) {
151 const TString& id = (*i).first;
5f91c9e8 152 cout << "Map element "
153 << setw(3) << counter++ << " "
f79c58a5 154 << id.Data() << " " ;
155 PrintMotif((*i).second);
156 cout << endl;
5f91c9e8 157 }
158 cout << endl;
159 }
f79c58a5 160#endif
161
162#ifdef WITH_ROOT
163 if (fMotifs.GetSize()) {
164 cout << "Dump of Motif Map - " << fMotifs.GetSize() << " entries:" << endl;
165 Int_t counter = 0;
5006ec94 166 TExMapIter i = fMotifs.GetIterator();
f79c58a5 167 Long_t key, value;
168 while ( i.Next(key, value) ) {
5006ec94 169 TString id = fMotifs.AliMpExMap::GetString(key);
f79c58a5 170 AliMpVMotif* motif = (AliMpVMotif*)value;
171 cout << "Map element "
172 << setw(3) << counter++ << " "
173 << id.Data() << " " ;
174 PrintMotif(motif);
175 cout << endl;
176 }
177 cout << endl;
178 }
179#endif
5f91c9e8 180}
181
182//_____________________________________________________________________________
183void AliMpMotifMap::PrintMotifTypes() const
184{
dee1d5f1 185/// Print all the the motifs types and their motif dimensions
186/// for all motif types in the motif types map.
5f91c9e8 187
f79c58a5 188#ifdef WITH_STL
5f91c9e8 189 if (fMotifTypes.size()) {
190 cout << "Dump of Motif Type Map - " << fMotifTypes.size() << " entries:" << endl;
191 Int_t counter = 0;
192 for (MotifTypeMapIterator i=fMotifTypes.begin(); i != fMotifTypes.end(); i++) {
193 const TString& id = (*i).first;
5f91c9e8 194 cout << "Map element "
195 << setw(3) << counter++ << " "
f79c58a5 196 << id.Data() << " ";
197 PrintMotifType((*i).second);
198 cout << endl;
199 }
200 cout << endl;
201 }
202#endif
203
204#ifdef WITH_ROOT
205 if (fMotifTypes.GetSize()) {
206 cout << "Dump of Motif Type Map - " << fMotifTypes.GetSize() << " entries:" << endl;
207 Int_t counter = 0;
5006ec94 208 TExMapIter i = fMotifTypes.GetIterator();
f79c58a5 209 Long_t key, value;
210 while ( i.Next(key, value) ) {
5006ec94 211 TString id = AliMpExMap::GetString(key);
f79c58a5 212 AliMpMotifType* motifType = (AliMpMotifType*)value;
213 cout << "Map element "
214 << setw(3) << counter++ << " "
215 << id.Data() << " " ;
216 PrintMotifType(motifType);
217 cout << endl;
5f91c9e8 218 }
219 cout << endl;
220 }
f79c58a5 221#endif
5f91c9e8 222}
223
224//_____________________________________________________________________________
225void AliMpMotifMap::PrintMotifPositions() const
226{
dee1d5f1 227/// Print all the the motifs positions.
5f91c9e8 228
f79c58a5 229#ifdef WITH_STL
5f91c9e8 230 if (fMotifPositions.size()) {
231 cout << "Dump of Motif Position Map - " << fMotifPositions.size() << " entries:" << endl;
232 Int_t counter = 0;
233 for (MotifPositionMapIterator i=fMotifPositions.begin();
234 i != fMotifPositions.end(); i++) {
235
5f91c9e8 236 cout << "Map element "
f79c58a5 237 << setw(3) << counter++ << " ";
238 PrintMotifPosition((*i).second);
239 cout << endl;
5f91c9e8 240 }
241 cout << endl;
242 }
f79c58a5 243#endif
244
245#ifdef WITH_ROOT
246 if (fMotifPositions.GetSize()) {
dee1d5f1 247 cout << "Dump of Motif Position Map - " << fMotifPositions.GetSize() << " entries:" << endl;
f79c58a5 248 Int_t counter = 0;
5006ec94 249 TExMapIter i = fMotifPositions.GetIterator();
f79c58a5 250 Long_t key, value;
251 while ( i.Next(key, value) ) {
252 AliMpMotifPosition* motifPosition = (AliMpMotifPosition*)value;
253 cout << "Map element "
254 << setw(3) << counter++ << " ";
255 PrintMotifPosition(motifPosition);
256 cout << endl;
257 }
258 cout << endl;
259 }
260#endif
5f91c9e8 261}
262
263//_____________________________________________________________________________
264void AliMpMotifMap::PrintMotifPositions2() const
265{
dee1d5f1 266/// Print all the the motifs positions from the second map
267/// (by global indices)
5f91c9e8 268
f79c58a5 269#ifdef WITH_STL
5f91c9e8 270 if (fMotifPositions2.size()) {
271 cout << "Dump of Motif Position Map 2 - " << fMotifPositions2.size() << " entries:" << endl;
272 Int_t counter = 0;
273 for (MotifPositionMap2Iterator i=fMotifPositions2.begin();
274 i != fMotifPositions2.end(); i++) {
275
5f91c9e8 276 cout << "Map element "
f79c58a5 277 << setw(3) << counter++ << " ";
278 PrintMotifPosition2((*i).second);
279 cout << endl;
280 }
281 cout << endl;
282 }
283#endif
284
285#ifdef WITH_ROOT
286 if (fMotifPositions2.GetSize()) {
287 cout << "Dump of Motif Position Map 2 - " << fMotifPositions2.GetSize() << " entries:" << endl;
288 Int_t counter = 0;
5006ec94 289 TExMapIter i = fMotifPositions2.GetIterator();
f79c58a5 290 Long_t key, value;
291 while ( i.Next(key, value) ) {
292 AliMpMotifPosition* motifPosition = (AliMpMotifPosition*)value;
293 cout << "Map element "
294 << setw(3) << counter++ << " ";
295 PrintMotifPosition2(motifPosition);
296 cout << endl;
5f91c9e8 297 }
298 cout << endl;
299 }
f79c58a5 300#endif
5f91c9e8 301}
302
303//
304// public methods
305//
306
307//_____________________________________________________________________________
308Bool_t AliMpMotifMap::AddMotif(AliMpVMotif* motif, Bool_t warn)
309{
dee1d5f1 310/// Add the specified motif
311/// if the motif with this ID is not yet present.
5f91c9e8 312
313 AliMpVMotif* found = FindMotif(motif->GetID());
314 if (found) {
315 if (warn && found == motif)
316 Warning("AddMotif", "The motif is already in map.");
317 if (warn && found != motif)
318 Warning("AddMotif", "Another motif with the same ID is already in map.");
319 return false;
320 }
321
f79c58a5 322#ifdef WITH_STL
5f91c9e8 323 fMotifs[motif->GetID()] = motif;
f79c58a5 324#endif
325
326#ifdef WITH_ROOT
5006ec94 327 fMotifs.Add(motif->GetID(), motif);
f79c58a5 328#endif
329
5f91c9e8 330 return true;
331}
332
333//_____________________________________________________________________________
334Bool_t AliMpMotifMap::AddMotifType(AliMpMotifType* motifType, Bool_t warn)
335{
dee1d5f1 336/// Add the specified motif type
337/// if the motif with this ID is not yet present.
5f91c9e8 338
339 AliMpMotifType* found = FindMotifType(motifType->GetID());
340 if (found) {
341 if (warn && found == motifType)
342 Warning("AddMotifType", "The motif type is already in map.");
343 if (warn && found != motifType)
344 Warning("AddMotifType",
345 "Another motif type with the same ID is already in map.");
346 return false;
347 }
348
f79c58a5 349#ifdef WITH_STL
5f91c9e8 350 fMotifTypes[motifType->GetID()] = motifType;
f79c58a5 351#endif
352
353#ifdef WITH_ROOT
5006ec94 354 fMotifTypes.Add(motifType->GetID(), motifType);
f79c58a5 355#endif
356
5f91c9e8 357 return true;
358}
359
360//_____________________________________________________________________________
361Bool_t AliMpMotifMap::AddMotifPosition(AliMpMotifPosition* motifPosition, Bool_t warn)
362{
dee1d5f1 363/// Add the specified motif position
364/// if this position is not yet present.
5f91c9e8 365
366 AliMpMotifPosition* found = FindMotifPosition(motifPosition->GetID());
7a854749 367 if (found) {
368 if (warn && found == motifPosition) {
369 cerr << "ID: " << motifPosition->GetID()
370 << " found: " << found
371 << " new: " << motifPosition << endl;
5f91c9e8 372 Warning("AddMotifPosition", "This motif position is already in map.");
7a854749 373 }
374 if (warn && found != motifPosition) {
375 cerr << "ID: " << motifPosition->GetID()
376 << " found: " << found
377 << " new: " << motifPosition << endl;
5f91c9e8 378 Warning("AddMotifposition",
7a854749 379 "Another motif position with the same ID is already in map.");
380 }
5f91c9e8 381 return false;
382 }
383
f79c58a5 384#ifdef WITH_STL
5f91c9e8 385 fMotifPositions[motifPosition->GetID()] = motifPosition;
f79c58a5 386#endif
387
388#ifdef WITH_ROOT
5006ec94 389 fMotifPositions.Add(motifPosition->GetID(), motifPosition);
f79c58a5 390#endif
391
5f91c9e8 392 return true;
393}
394
395//_____________________________________________________________________________
396void AliMpMotifMap::FillMotifPositionMap2()
397{
dee1d5f1 398/// Fill the second map (by global indices) of motif positions.
5f91c9e8 399
f79c58a5 400#ifdef WITH_STL
5f91c9e8 401 if (fMotifPositions2.size() > 0 ) {
402 Warning("FillMotifPositionMap2", "Map has been already filled.");
403 return;
404 }
405
406 for (MotifPositionMapIterator ip=fMotifPositions.begin();
407 ip != fMotifPositions.end(); ip++) {
408
409 fMotifPositions2[(*ip).second->GetLowIndicesLimit()] = (*ip).second;
410 }
f79c58a5 411#endif
412
413#ifdef WITH_ROOT
414 if (fMotifPositions2.GetSize() > 0 ) {
415 Warning("FillMotifPositionMap2", "Map has been already filled.");
416 return;
417 }
418
5006ec94 419 TExMapIter i = fMotifPositions.GetIterator();
f79c58a5 420 Long_t key, value;
421 while ( i.Next(key, value) ) {
422 AliMpMotifPosition* motifPosition = (AliMpMotifPosition*)value;
5006ec94 423 fMotifPositions2.Add(motifPosition->GetLowIndicesLimit(), motifPosition);
f79c58a5 424 }
425#endif
5f91c9e8 426
427}
428
429//_____________________________________________________________________________
7a854749 430void AliMpMotifMap::Print(const char* /*option*/) const
5f91c9e8 431{
dee1d5f1 432/// Print the motifs and motif types maps.
5f91c9e8 433
434 PrintMotifs();
435 PrintMotifTypes();
436 PrintMotifPositions();
437 PrintMotifPositions2();
438}
439
440//_____________________________________________________________________________
441void AliMpMotifMap::PrintGlobalIndices(const char* fileName) const
442{
dee1d5f1 443/// Print all the motifs positions and their global indices.
5f91c9e8 444
445 ofstream out(fileName, ios::out);
446
f79c58a5 447#ifdef WITH_STL
5f91c9e8 448 if (fMotifPositions.size()) {
449 for (MotifPositionMapIterator i=fMotifPositions.begin();
450 i != fMotifPositions.end(); i++) {
451
452 AliMpMotifPosition* motifPosition = (*i).second;
453 out << setw(5) << motifPosition->GetID() << " "
454 << setw(3) << motifPosition->GetLowIndicesLimit().GetFirst() << " "
455 << setw(3) << motifPosition->GetLowIndicesLimit().GetSecond()
456 << endl;
457 }
458 out << endl;
459 }
f79c58a5 460#endif
461
462#ifdef WITH_ROOT
463 if (fMotifPositions.GetSize()) {
5006ec94 464 TExMapIter i = fMotifPositions.GetIterator();
f79c58a5 465 Long_t key, value;
466 while ( i.Next(key, value) ) {
467 AliMpMotifPosition* motifPosition = (AliMpMotifPosition*)value;
468 out << setw(5) << motifPosition->GetID() << " "
469 << setw(3) << motifPosition->GetLowIndicesLimit().GetFirst() << " "
470 << setw(3) << motifPosition->GetLowIndicesLimit().GetSecond()
471 << endl;
472 }
473 out << endl;
474 }
475#endif
5f91c9e8 476}
477
478//_____________________________________________________________________________
479void AliMpMotifMap::UpdateGlobalIndices(const char* fileName)
480{
dee1d5f1 481/// Updates the motifs positions global indices
482/// from the file.
5f91c9e8 483
484 ifstream in(fileName, ios::in);
485
486 Int_t motifPositionId, offx, offy;
487
488 do {
489 in >> motifPositionId >> offx >> offy;
490
491 if (in.eof()) {
492 FillMotifPositionMap2();
493 return;
494 }
495
496 AliMpMotifPosition* motifPosition = FindMotifPosition(motifPositionId);
497
498 if (motifPosition) {
499 cout << "Processing "
500 << motifPosition->GetID() << " " << offx << " " << offy << endl;
501
502 motifPosition->SetLowIndicesLimit(AliMpIntPair(offx, offy));
503
504 Int_t offx2
505 = offx + motifPosition->GetMotif()->GetMotifType()->GetNofPadsX() - 1;
506
507 Int_t offy2
508 = offy + motifPosition->GetMotif()->GetMotifType()->GetNofPadsY() - 1;
509
510 motifPosition->SetHighIndicesLimit(AliMpIntPair(offx2, offy2));
511 }
512 else {
513 cerr <<"Motif position " << motifPositionId << endl;
514 Warning("UpdateGlobalIndices", "Motif position not found !!!");
515 }
516 }
517 while (!in.eof());
518}
519
520
521//_____________________________________________________________________________
522AliMpVMotif* AliMpMotifMap::FindMotif(const TString& motifID) const
523{
dee1d5f1 524/// Finds the motif with the specified ID.
5f91c9e8 525
f79c58a5 526#ifdef WITH_STL
5f91c9e8 527 MotifMapIterator i = fMotifs.find(motifID);
5f91c9e8 528 if (i != fMotifs.end())
529 return (*i).second;
530 else
531 return 0;
f79c58a5 532#endif
533
534#ifdef WITH_ROOT
5006ec94 535 return (AliMpVMotif*)fMotifs.GetValue(motifID);
f79c58a5 536#endif
5f91c9e8 537}
538
539//_____________________________________________________________________________
540AliMpVMotif* AliMpMotifMap::FindMotif(const TString& motifID,
7a854749 541 const TString& motifTypeID,
542 const TVector2& padDimensions ) const
5f91c9e8 543{
dee1d5f1 544/// Finds the motif with the specified ID and returns it
545/// only if its motif type and motif dimensions agree
546/// with the given motifTypeID and motifDimensions.
547/// Disagreement causes fatal error.
548
5f91c9e8 549 AliMpVMotif* motif = FindMotif(motifID);
550
551 if (motif && motif->GetMotifType()->GetID() != motifTypeID) {
552 Fatal("FindMotif",
553 "Motif has been already defined with a different type.");
554 return 0;
555 }
556
557 // check pad dimension in case of a normal motif
558 if (motif &&
559 dynamic_cast<AliMpMotif*>(motif) &&
560 ( motif->GetPadDimensions(0).X() != padDimensions.X() ||
561 motif->GetPadDimensions(0).Y() != padDimensions.Y())) {
562
563 Fatal("FindMotifType",
564 "Motif type has been already defined with different dimensions.");
565 return 0;
566
567 }
568
569 // check case of a special motif
570 if (motif &&
571 (padDimensions.X() == 0. && padDimensions.Y() == 0.) &&
572 !dynamic_cast<AliMpMotifSpecial*>(motif)) {
573
574 Fatal("FindMotifType",
575 "Motif type has been already defined with different dimensions.");
576 return 0;
577
578 }
579
580 return motif;
581}
582
583//_____________________________________________________________________________
584AliMpMotifType* AliMpMotifMap::FindMotifType(const TString& motifTypeID) const
585{
dee1d5f1 586/// Find the motif type with the specified motif type ID.
5f91c9e8 587
f79c58a5 588#ifdef WITH_STL
5f91c9e8 589 MotifTypeMapIterator i = fMotifTypes.find(motifTypeID);
5f91c9e8 590 if (i != fMotifTypes.end())
591 return (*i).second;
592 else
593 return 0;
f79c58a5 594#endif
595
596#ifdef WITH_ROOT
5006ec94 597 return (AliMpMotifType*)fMotifTypes.GetValue(motifTypeID);
f79c58a5 598#endif
5f91c9e8 599}
600
601//_____________________________________________________________________________
7a854749 602AliMpMotifPosition*
603AliMpMotifMap::FindMotifPosition(Int_t motifPositionID) const
5f91c9e8 604{
dee1d5f1 605/// Find the motif position with the specified motif position ID.
5f91c9e8 606
f79c58a5 607#ifdef WITH_STL
5f91c9e8 608 MotifPositionMapIterator i = fMotifPositions.find(motifPositionID);
5f91c9e8 609 if (i != fMotifPositions.end())
610 return (*i).second;
611 else
612 return 0;
f79c58a5 613#endif
614
615#ifdef WITH_ROOT
5006ec94 616 return (AliMpMotifPosition*)fMotifPositions.GetValue(motifPositionID);
f79c58a5 617#endif
5f91c9e8 618}
619
f79c58a5 620/*
5f91c9e8 621//_____________________________________________________________________________
7a854749 622AliMpMotifPosition*
623AliMpMotifMap::FindMotifPosition(const AliMpIntPair& indices) const
5f91c9e8 624{
dee1d5f1 625/// Find the last motif position which has the global indices (low limit)
626/// less then the indices specified.
5f91c9e8 627
f79c58a5 628#ifdef WITH_STL
5f91c9e8 629 MotifPositionMap2Iterator found
630 = fMotifPositions2.lower_bound(indices);
631
632 if (found == fMotifPositions2.end()) found--;
633
634 MotifPositionMap2Iterator i=found;
635 do {
636 AliMpIntPair low = (*i).second->GetLowIndicesLimit();
637 AliMpIntPair up = (*i).second->GetHighIndicesLimit();
638
639 if ( indices.GetFirst() >= low.GetFirst() &&
640 indices.GetSecond() >= low.GetSecond() &&
641 indices.GetFirst() <= up.GetFirst() &&
642 indices.GetSecond() <= up.GetSecond())
643
644 return (*i).second;
645 }
646 while ( i-- != fMotifPositions2.begin());
647
648 return 0;
f79c58a5 649#endif
650
651#ifdef WITH_ROOT
652 // HOW TO DO THIS WITH ROOT ????
653 // Fortunately it seems not to be used anywhere
654 Fatal("FindMotifPosition", "Difficult in Root to do this.");
655 return 0;
656#endif
5f91c9e8 657}
f79c58a5 658*/