]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTriggerElectronics.cxx
Comments for Doxygen
[u/mrichter/AliRoot.git] / MUON / AliMUONTriggerElectronics.cxx
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 /* $Id$ */
17
18 //*-- Author: Rachid Guernane (LPCCFd)
19 //*   Manager class for muon trigger electronics
20 //*   Client of trigger board classes
21 //*
22 //*
23
24 #include "AliMUONTriggerElectronics.h"
25 #include "AliMUONTriggerCrate.h"
26 #include "AliMUONTriggerCrateStore.h"
27 #include "AliMUONConstants.h"
28 #include "AliMUONLocalTriggerBoard.h"
29 #include "AliMUONRegionalTriggerBoard.h"
30 #include "AliMUONGlobalTriggerBoard.h"
31 #include "AliMUONLocalTrigger.h"
32 #include "AliMUONRegionalTrigger.h"
33 #include "AliMUONGlobalTrigger.h"
34 #include "AliMUON.h" 
35 #include "AliMUONData.h" 
36 #include "AliMUONDigit.h"
37 #include "AliMUONSegmentation.h"
38 #include "AliMUONCalibrationData.h"
39 #include "AliMUONVCalibParam.h"
40
41 #include "AliMpSegmentation.h"
42 #include "AliMpVSegmentation.h"
43
44 #include "AliLog.h"
45 #include "AliLoader.h"
46 #include "AliRun.h"
47
48 //#include "Riostream.h"
49 #include "TBits.h"
50 #include "TSystem.h"
51
52 /// \cond CLASSIMP
53 ClassImp(AliMUONTriggerElectronics)
54 /// \endcond
55
56 //___________________________________________
57 AliMUONTriggerElectronics::AliMUONTriggerElectronics(AliMUONData *Data, AliMUONCalibrationData* calibData) 
58 : TTask("AliMUONTriggerElectronics",
59         "From trigger digits to Local and Global Trigger objects"),
60   fSourceFileName(),
61   fCrates(new AliMUONTriggerCrateStore),
62   fGlobalTriggerBoard(new AliMUONGlobalTriggerBoard),
63   fMUONData(Data),
64   fLocalTrigger(new AliMUONLocalTrigger()),
65   fGlobalTrigger(new AliMUONGlobalTrigger())
66
67 {
68 /// CONSTRUCTOR
69 ///
70   if (!fMUONData)
71   {  
72     AliFatal("NO MUON TRIGGER DATA");
73   }
74     
75   SetDataSource();
76   Factory(calibData);
77   LoadMasks(calibData);
78 }
79
80 //___________________________________________
81 AliMUONTriggerElectronics::~AliMUONTriggerElectronics()
82 {
83 /// DESTRUCTOR
84 ///
85   delete fGlobalTriggerBoard;
86   delete fCrates;
87   delete fLocalTrigger;
88   delete fGlobalTrigger;
89
90 }
91
92 //___________________________________________
93 void AliMUONTriggerElectronics::Factory(AliMUONCalibrationData* calibData)
94 {  
95  /// BUILD ALL ELECTRONICS
96  ///
97
98 // get coinc44 from AliMUON (added 12/09/06)
99   AliMUON *pMUON  = (AliMUON*)gAlice->GetModule("MUON");
100   Int_t coinc44 = pMUON->GetTriggerCoinc44();
101   if (coinc44 != 0 && coinc44 != 1) {
102       AliFatal("Coinc 44 should be equal to 0 or 1");
103       return;
104   }
105
106   fCrates->ReadFromFile(gSystem->ExpandPathName(fSourceFileName.Data()));
107   
108   if ( !calibData ) return;
109   
110   AliMUONTriggerLut* lut = calibData->TriggerLut();
111   
112   if (!lut) return;
113   
114   AliMUONLocalTriggerBoard* localBoard;
115   
116   fCrates->FirstLocalBoard();
117   
118   while ( (localBoard=fCrates->NextLocalBoard()) )
119   {
120     localBoard->SetLUT(lut);
121     localBoard->SetCoinc44(coinc44);
122   }
123 }
124
125 //___________________________________________
126 void AliMUONTriggerElectronics::FeedM()
127 {
128 /// FILL INPUTS
129 ///
130     for (Int_t ichamber=10; ichamber<14; ichamber++) 
131     {
132       TClonesArray *muonDigits = fMUONData->Digits(ichamber);
133       Int_t ndigits = muonDigits->GetEntriesFast();
134
135       for (Int_t digit=0; digit<ndigits; digit++)
136       {
137           AliMUONDigit *mdig = static_cast<AliMUONDigit*>(muonDigits->UncheckedAt(digit));
138
139           //       CHECKME ! The TrackCharge is not ok with new digitizerV3 !
140           //                    for (Int_t ichg=0; ichg<10; ichg++) schg += mdig->TrackCharge(ichg);
141           //       assert(schg==mdig->Signal());
142           Int_t schg = (Int_t)(mdig->Signal() + 0.5);
143          
144           //       APPLY CONDITION ON SOFT BACKGROUND   
145           Int_t tchg = schg - (Int_t(schg/10))*10;      
146
147           if (schg<=10 || tchg>0) 
148           {
149               //                                mdig->Print();
150
151               Int_t digitindex = digit;
152               Int_t detElemId  = mdig->DetElemId();
153               Int_t cathode    = mdig->Cathode();
154
155               const AliMpVSegmentation *seg = 
156                 AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,cathode);
157
158               Int_t ix = mdig->PadX(), iy = mdig->PadY();
159                                 
160               AliDebug(3,Form("cathode %d ix %d iy %d ",cathode,ix,iy));
161
162               AliMpPad pad = seg->PadByIndices(AliMpIntPair(ix,iy),kTRUE);
163                                 
164               for (Int_t i=0; i<pad.GetNofLocations(); i++) 
165               {
166                   AliMpIntPair location = pad.GetLocation(i);
167                                         
168                   Int_t nboard = location.GetFirst();
169
170                   Int_t ibitxy = location.GetSecond();
171
172                   AliMUONLocalTriggerBoard *b = fCrates->LocalBoard(nboard);
173
174                   if (b) 
175                   {
176                       if (cathode && b->GetSwitch(6)) ibitxy += 8;
177                                                 
178                       b->SetbitM(ibitxy,cathode,ichamber-10);
179                                                 
180                       DigitFiredCircuit(b->GetI(), cathode, ichamber, digitindex);
181                   }
182                   else
183                   {
184                       AliError(Form("Could not get local board number %d",b->GetNumber()));
185                  }
186               }
187           }             
188       }
189     }
190
191   // Particular case of the columns with 22 local boards (2R(L) 3R(L))   
192   AliMUONTriggerCrate *crate = 0x0; TObjArray *bs = 0x0;
193
194   char *scratess[4] = {  "2R",   "2L",   "3L",   "3R"}; 
195   char *scratesd[4] = {"2-3R", "2-3L", "2-3L", "2-3R"}; 
196   Int_t    slotf[4] = {     2,      2,     10,     10}; 
197   Int_t    slotd[4] = {     1,      1,      9,      9}; 
198
199   for (Int_t i = 0; i < 4; i++)
200   {
201       crate = fCrates->Crate(scratess[i]); 
202       bs = crate->Boards();
203       AliMUONLocalTriggerBoard *desybb = (AliMUONLocalTriggerBoard*)bs->At(14);
204       AliMUONLocalTriggerBoard *fromcb = (AliMUONLocalTriggerBoard*)bs->At(15);
205       AliMUONLocalTriggerBoard *desxbb = (AliMUONLocalTriggerBoard*)bs->At(16);
206
207       crate = fCrates->Crate(scratesd[i]); 
208       bs = crate->Boards();
209       AliMUONLocalTriggerBoard *frombb = (AliMUONLocalTriggerBoard*)bs->At(slotf[i]);
210       AliMUONLocalTriggerBoard *desycb = (AliMUONLocalTriggerBoard*)bs->At(slotd[i]);
211
212       UShort_t cX[2];
213
214       //    COPY X3-4 FROM BOARD  2 OF CRATE 2-3 TO BOARD 16 OF CRATE 2
215       //    COPY X3-4 FROM BOARD 10 OF CRATE 2-3 TO BOARD 16 OF CRATE 3
216       frombb->GetX34(cX); desxbb->SetX34(cX);
217
218       //    COPY X3-4 FROM BOARD 15 OF CRATE 2 TO BOARD 1 OF CRATE 2-3
219       //    COPY X3-4 FROM BOARD 15 OF CRATE 3 TO BOARD 9 OF CRATE 2-3
220       fromcb->GetX34(cX); desycb->SetX34(cX);
221
222       UShort_t cY[4];
223
224       desybb->GetY(cY); frombb->SetY(cY);
225
226       frombb->GetY(cY); desxbb->SetY(cY);
227       fromcb->GetY(cY); desycb->SetY(cY);
228   }
229
230   // FILL UP/DOWN OF CURRENT BOARD (DONE VIA J3 BUS IN REAL LIFE)
231   AliMUONTriggerCrate* cr;
232  
233   fCrates->FirstCrate();
234  
235   while ( ( cr = fCrates->NextCrate() ) )
236   {            
237       TObjArray *boards = cr->Boards();
238                 
239       for (Int_t j = 1; j < boards->GetEntries()-1; j++)
240       {
241           TObject *o = boards->At(j);
242                         
243           if (!o) break;
244                         
245           AliMUONLocalTriggerBoard *currboard = (AliMUONLocalTriggerBoard*)o;
246                         
247           AliMUONLocalTriggerBoard *neighbour = (AliMUONLocalTriggerBoard*)boards->At(j+1);
248                         
249           UShort_t cXY[2][4];
250                         
251           if (j==1) {neighbour->GetXY(cXY); currboard->SetXYU(cXY);}
252                         
253           //       LAST BOARD IN THE CRATE HAS NO UP EXCEPT FOR CRATES 2 & 3
254           if (j < boards->GetEntries()-2)  
255           {
256               AliMUONLocalTriggerBoard *nextboard = (AliMUONLocalTriggerBoard*)boards->At(j+2);
257                                 
258               currboard->GetXY(cXY); neighbour->SetXYD(cXY);
259               nextboard->GetXY(cXY); neighbour->SetXYU(cXY);
260                                 
261               if (j==boards->GetEntries()-3) {neighbour->GetXY(cXY); nextboard->SetXYD(cXY);}
262           }
263       }
264   }
265 }
266
267 //___________________________________________
268 void AliMUONTriggerElectronics::Feed(UShort_t pattern[2][4])
269 {
270   /// FILL INPUTS
271   ///
272   AliMUONTriggerCrate* cr;
273    
274    fCrates->FirstCrate();
275    
276    while ( ( cr = fCrates->NextCrate() ) )
277    {                 
278      TObjArray *boards = cr->Boards();
279      
280      for (Int_t j = 1; j < boards->GetEntries(); j++)
281      {
282        TObject *o = boards->At(j);
283        
284        if (!o) break;
285        
286        AliMUONLocalTriggerBoard *board = (AliMUONLocalTriggerBoard*)o;
287        
288        board->SetXY(pattern);
289      }
290    }
291 }
292
293 //___________________________________________
294 void AliMUONTriggerElectronics::DumpOS()
295 {
296 /// DUMP IN THE OLD WAY
297 ///
298    for (Int_t i= 0; i < 234;i++)
299    {
300       AliMUONLocalTriggerBoard *board = fCrates->LocalBoard(i);
301
302       if (board) board->Scan("ALL");
303    }
304 }
305
306 //___________________________________________
307 void AliMUONTriggerElectronics::Scan(Option_t *option)
308 {
309   /// SCAN
310   ///
311
312   AliMUONTriggerCrate* cr;
313   
314   fCrates->FirstCrate();
315   
316   while ( ( cr = fCrates->NextCrate() ) )
317   {                
318     TObjArray *boards = cr->Boards();
319     
320     for (Int_t j = 0; j < boards->GetEntries(); j++)
321     {
322       TObject *o = boards->At(j);
323       
324       TString op = option;
325       
326       Bool_t cdtion = kFALSE;
327       
328       if (op.Contains("LOCAL"))    cdtion = o->IsA() == AliMUONLocalTriggerBoard::Class();
329       if (op.Contains("REGIONAL")) cdtion = o->IsA() == AliMUONRegionalTriggerBoard::Class();
330       if (op.Contains("GLOBAL"))   cdtion = o->IsA() == AliMUONGlobalTriggerBoard::Class();
331       
332       if (!o || !cdtion) continue;
333       
334       AliMUONLocalTriggerBoard *board = (AliMUONLocalTriggerBoard*)o;
335       
336       board->Scan();
337     }
338   }
339 }
340
341 //___________________________________________
342 void AliMUONTriggerElectronics::Reset()
343 {
344   /// RESET
345   ///
346   
347    AliMUONTriggerCrate* cr;
348    
349    fCrates->FirstCrate();
350    
351    while ( ( cr = fCrates->NextCrate() ) )
352    {            
353       TObjArray *boards = cr->Boards();
354             
355       for (Int_t j=0; j<boards->GetEntries(); j++)
356       {     
357          AliMUONTriggerBoard *b = (AliMUONTriggerBoard*)boards->At(j);
358
359          if (b) b->Reset();
360       }
361    }
362 }
363
364 //_______________________________________________________________________
365 void AliMUONTriggerElectronics::LoadMasks(AliMUONCalibrationData* calibData)
366 {
367   // LOAD MASKS FROM CDB
368   
369
370   // SET MASKS
371   
372   AliMUONTriggerCrate* cr;
373   
374   fCrates->FirstCrate();
375   
376   Int_t irb(0);
377   
378   while ( ( cr = fCrates->NextCrate() ) )
379   {            
380     TObjArray *boards = cr->Boards();
381     
382     AliMUONRegionalTriggerBoard *regb =
383       (AliMUONRegionalTriggerBoard*)boards->At(0);
384
385     AliMUONVCalibParam* regionalBoardMasks = calibData->RegionalTriggerBoardMasks(irb);
386     
387     for ( Int_t i = 0; i < regionalBoardMasks->Size(); ++i )
388     {
389       UShort_t rmask = static_cast<UShort_t>(regionalBoardMasks->ValueAsInt(i) & 0x3F);
390       regb->Mask(i,rmask);
391     }
392     
393     for (Int_t j = 1; j < boards->GetEntries(); j++)
394     {
395       AliMUONLocalTriggerBoard *b = (AliMUONLocalTriggerBoard*)boards->At(j);
396       
397       Int_t cardNumber = b->GetNumber();
398       
399       if (cardNumber) // interface board are not interested
400       {
401         AliMUONVCalibParam* localBoardMasks = calibData->LocalTriggerBoardMasks(cardNumber);
402         for ( Int_t i = 0; i < localBoardMasks->Size(); ++i )
403         {
404           UShort_t lmask = static_cast<UShort_t>(localBoardMasks->ValueAsInt(i) & 0xFFFF);
405           b->Mask(i,lmask);
406         }
407       }
408     }
409     ++irb;
410   }
411   
412   AliMUONVCalibParam* globalBoardMasks = calibData->GlobalTriggerBoardMasks();
413   for ( Int_t i = 0; i < globalBoardMasks->Size(); ++i )
414   {
415     UShort_t gmask = static_cast<UShort_t>(globalBoardMasks->ValueAsInt(i) & 0xFFF);
416     fGlobalTriggerBoard->Mask(i,gmask);
417   }
418 }
419
420
421 //___________________________________________
422 void AliMUONTriggerElectronics::LocalResponse()
423 {
424 /// \todo add comment
425         
426   AliMUONTriggerCrate* cr;
427   
428   fCrates->FirstCrate();
429   
430   while ( ( cr = fCrates->NextCrate() ) )
431   {            
432     
433     TObjArray *boards = cr->Boards();
434     
435     AliMUONRegionalTriggerBoard *regb = (AliMUONRegionalTriggerBoard*)boards->At(0);
436     
437     UShort_t thisl[16]; for (Int_t j=0; j<16; j++) thisl[j] = 0;
438   
439     for (Int_t j = 1; j < boards->GetEntries(); j++)
440     {     
441         TObject *o = boards->At(j);
442       
443         if (!o) break;
444       
445         AliMUONLocalTriggerBoard *board = (AliMUONLocalTriggerBoard*)o;
446       
447         if (board) // check if empty slot
448         {
449           board->Response();
450                                 
451           UShort_t response = board->GetResponse();            
452         
453           // CRATE CONTAINING INTERFACE BOARD
454           if (board->GetNumber() == 0) // copy boards
455           {
456             if ( response != 0 ) 
457               AliWarning(Form("Interface board %s in slot %d of crate %s has a non zero response",
458                                           board->GetName(),j,cr->GetName()));
459             AliDebug(1, Form("local slot %d, number %d in crate %s\n", j, board->GetNumber(), cr->GetName()));
460
461           }
462         
463           thisl[j-1] = response;
464         }
465       }
466     
467     regb->SetLocalResponse(thisl);
468   }
469 }
470
471 //___________________________________________
472 void AliMUONTriggerElectronics::RegionalResponse()
473 {
474   /// Compute the response for all regional cards.
475   AliMUONTriggerCrate* cr;
476   
477   fCrates->FirstCrate();
478   
479   while ( ( cr = fCrates->NextCrate() ) )
480   {            
481       TObjArray *boards = cr->Boards();
482
483       AliMUONRegionalTriggerBoard *regb = (AliMUONRegionalTriggerBoard*)boards->At(0);
484       
485       if (regb) 
486       {
487          regb->Response();
488       }  
489    }
490 }
491
492 //___________________________________________
493 void AliMUONTriggerElectronics::GlobalResponse()
494 {
495   /// Compute the global response
496
497   UShort_t regional[16];
498   
499   AliMUONTriggerCrate* cr;
500   
501   fCrates->FirstCrate();
502   Int_t irb(0);
503   
504   if ( !fCrates->NumberOfCrates() >= 16 ) 
505   {
506     AliFatal(Form("Something is wrong : too many crates %d",
507                   fCrates->NumberOfCrates()));
508   }
509   
510   while ( ( cr = fCrates->NextCrate() ) )
511   {            
512     AliMUONTriggerBoard* rb = 
513       static_cast<AliMUONTriggerBoard*>(cr->Boards()->At(0));
514     regional[irb] = rb->GetResponse();
515     ++irb;
516   }
517   
518   fGlobalTriggerBoard->SetRegionalResponse(regional);
519   fGlobalTriggerBoard->Response();
520 }
521
522 //_______________________________________________________________________
523 void 
524 AliMUONTriggerElectronics::Exec(Option_t*)
525 {
526 /// \todo add comment
527 ///
528   Digits2Trigger();
529 }
530
531 //_______________________________________________________________________
532 void AliMUONTriggerElectronics::Trigger()
533 {
534 /// \todo add comment
535 ///
536    FeedM();
537    LocalResponse();
538    RegionalResponse();      
539    GlobalResponse();
540 }
541
542 //_______________________________________________________________________
543 void AliMUONTriggerElectronics::Digits2Trigger()
544 {
545   /// Main method to go from digits to trigger decision
546   AliMUONRegionalTrigger *pRegTrig = new AliMUONRegionalTrigger();
547   ClearDigitNumbers();
548   fMUONData->ResetTrigger(); 
549   // RUN THE FULL BEE CHAIN
550   Trigger();
551 //    DumpOS();
552         
553   AliMUONTriggerCrate* cr;
554   fCrates->FirstCrate();
555
556   while ( ( cr = fCrates->NextCrate() ) )
557   {            
558     TObjArray *boards = cr->Boards();
559
560     UInt_t regInpLpt = 0;
561     UInt_t regInpHpt = 0;
562     UShort_t localMask = 0x0;
563
564     AliMUONRegionalTriggerBoard *regBoard = (AliMUONRegionalTriggerBoard*)boards->At(0);
565
566     for (Int_t j = 1; j < boards->GetEntries(); j++)
567     {     
568       TObject *o = boards->At(j);
569       
570       if (!o) break;
571       
572       AliMUONLocalTriggerBoard *board = (AliMUONLocalTriggerBoard*)o;
573       
574       if (board) 
575       {
576         //          L0 TRIGGER
577         if (board->Triggered())
578         {
579           
580           Int_t icirc = board->GetNumber();
581
582           fLocalTrigger->SetLoCircuit(icirc);
583           fLocalTrigger->SetLoStripX(board->GetStripX11());
584           fLocalTrigger->SetLoDev(board->GetDev());
585           fLocalTrigger->SetLoStripY(board->GetStripY11());
586           
587           //             SAVE LUT OUTPUT 
588           UShort_t response = board->GetResponse();
589           fLocalTrigger->SetLoHpt((response & 12) >> 2);
590           fLocalTrigger->SetLoLpt(response &  3);
591
592           // calculates regional inputs from local for the moment
593           UInt_t hPt = (response >> 4) & 0x3;
594           UInt_t lPt = (response >> 2) & 0x3;
595             
596           regInpHpt |= hPt << (30 - (j-1)*2);
597           regInpLpt |= lPt << (30 - (j-1)*2);
598           localMask |= (0x1 << (j-1)); // local mask
599
600           TBits rrr;
601           rrr.Set(6,&response);   
602           
603           //             SAVE BIT PATTERN
604           fLocalTrigger->SetX1Pattern(board->GetXY(0,0));
605           fLocalTrigger->SetX2Pattern(board->GetXY(0,1));
606           fLocalTrigger->SetX3Pattern(board->GetXY(0,2));
607           fLocalTrigger->SetX4Pattern(board->GetXY(0,3));
608           
609           fLocalTrigger->SetY1Pattern(board->GetXY(1,0));
610           fLocalTrigger->SetY2Pattern(board->GetXY(1,1));
611           fLocalTrigger->SetY3Pattern(board->GetXY(1,2));
612           fLocalTrigger->SetY4Pattern(board->GetXY(1,3));
613           
614           fLocalTrigger->SetDigits(fDigitNumbers[icirc]);
615
616           //             ADD A NEW LOCAL TRIGGER          
617           fMUONData->AddLocalTrigger(*fLocalTrigger);  
618           
619         }
620       }
621     }
622     pRegTrig->SetLocalOutput(regInpLpt, 0);
623     pRegTrig->SetLocalOutput(regInpHpt, 1);
624     pRegTrig->SetLocalMask(localMask);
625     pRegTrig->SetOutput((regBoard->GetResponse() >> 4) & 0xF); // to be uniformized (oct06 ?)
626
627     fMUONData->AddRegionalTrigger(*pRegTrig);  
628     
629   }
630   delete pRegTrig;
631   
632   // GLOBAL TRIGGER INFORMATION
633   UShort_t global = fGlobalTriggerBoard->GetResponse();
634   fGlobalTrigger->SetFromGlobalResponse(global);
635
636   
637   // ADD A LOCAL TRIGGER IN THE LIST 
638   fMUONData->AddGlobalTrigger(*fGlobalTrigger);
639
640   // NOW RESET ELECTRONICS
641   Reset();
642 }
643
644 //_______________________________________________________________________
645 void AliMUONTriggerElectronics::ClearDigitNumbers()
646 {
647 // RESET fDigitNumbers
648         for (Int_t i=0; i<AliMUONConstants::NTriggerCircuit(); i++) fDigitNumbers[i].Set(0);
649 }
650
651 //_______________________________________________________________________
652 void AliMUONTriggerElectronics::DigitFiredCircuit(Int_t circuit, Int_t cathode,
653                                                   Int_t chamber, Int_t digit)
654 {
655 // REGISTERS THAT THE SPECIFIED DIGIT FIRED THE SPECIFIED CIRCUIT
656 // THIS DIGIT GETS ADDED TO AN ARRAY WHICH WILL BE COPIED TO
657 // AliMUONLocalTrigger WHEN SUCH AN OBJECT IS CREATED FOR EACH CIRCUIT
658         Int_t digitnumber = AliMUONLocalTrigger::EncodeDigitNumber(chamber, cathode, digit);
659         Int_t last = fDigitNumbers[circuit].GetSize();
660         fDigitNumbers[circuit].Set(last + 1);
661         fDigitNumbers[circuit][last] = digitnumber;
662 }
663