]>
Commit | Line | Data |
---|---|---|
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$ |
13985652 | 17 | // $MpId: AliMpMotifType.cxx,v 1.10 2006/05/24 13:58:41 ivana Exp $ |
5f91c9e8 | 18 | // Category: motif |
3d1463c8 | 19 | |
20 | //----------------------------------------------------------------------------- | |
5f91c9e8 | 21 | // Class AliMpMotifType |
22 | // -------------------- | |
23 | // Class that defines the motif properties. | |
dbe945cc | 24 | // Included in AliRoot: 2003/05/02 |
5f91c9e8 | 25 | // Authors: David Guez, Ivana Hrivnacova; IPN Orsay |
3d1463c8 | 26 | //----------------------------------------------------------------------------- |
5f91c9e8 | 27 | |
5f91c9e8 | 28 | #include "AliMpMotifType.h" |
630711ed | 29 | #include "AliMpExMapIterator.h" |
5f91c9e8 | 30 | #include "AliMpMotifTypePadIterator.h" |
31 | #include "AliMpConnection.h" | |
3635f34f | 32 | #include "AliMpConstants.h" |
da635033 | 33 | #include "AliMpFiles.h" |
168e9c4d | 34 | #include "AliMpEncodePair.h" |
63ed9c6b | 35 | |
168e9c4d | 36 | #include "AliLog.h" |
37 | ||
38 | #include <TSystem.h> | |
da635033 | 39 | #include <Riostream.h> |
5f91c9e8 | 40 | |
168e9c4d | 41 | #include <cstdlib> |
42 | ||
13985652 | 43 | /// \cond CLASSIMP |
63ed9c6b | 44 | ClassImp(AliMpMotifType) |
13985652 | 45 | /// \endcond |
46 | ||
47 | const Int_t AliMpMotifType::fgkPadNumForA = 65; | |
63ed9c6b | 48 | |
5f91c9e8 | 49 | //______________________________________________________________________________ |
50 | AliMpMotifType::AliMpMotifType(const TString &id) | |
3635f34f | 51 | : TObject(), |
52 | fID(id), | |
53 | fNofPadsX(0), | |
54 | fNofPadsY(0), | |
55 | fNofPads(0), | |
56 | fMaxNofPads(AliMpConstants::ManuNofChannels()), | |
57 | fConnectionsByLocalIndices(fMaxNofPads*fMaxNofPads), | |
58 | fConnectionsByManuChannel(fMaxNofPads) | |
5f91c9e8 | 59 | { |
f5671fc3 | 60 | /// Standard constructor \n |
61 | /// Please note that id should be of the form %s for station 1,2, | |
62 | // %s-%e-%e for station345 and %sx%e for stationTrigger | |
3635f34f | 63 | |
64 | fConnectionsByLocalIndices.SetOwner(kTRUE); | |
65 | fConnectionsByManuChannel.SetOwner(kFALSE); | |
66 | AliDebug(1,Form("this=%p id=%s",this,id.Data())); | |
5f91c9e8 | 67 | } |
68 | ||
69 | //______________________________________________________________________________ | |
3635f34f | 70 | AliMpMotifType::AliMpMotifType(TRootIOCtor*) |
71 | : TObject(), | |
72 | fID(""), | |
73 | fNofPadsX(0), | |
74 | fNofPadsY(0), | |
75 | fNofPads(0), | |
76 | fMaxNofPads(0), | |
77 | fConnectionsByLocalIndices(), | |
78 | fConnectionsByManuChannel() | |
5f91c9e8 | 79 | { |
dee1d5f1 | 80 | /// Default constructor |
3635f34f | 81 | AliDebug(1,Form("this=%p",this)); |
da635033 | 82 | } |
83 | ||
84 | //______________________________________________________________________________ | |
85 | AliMpMotifType::AliMpMotifType(const AliMpMotifType& rhs) | |
86 | : TObject(), | |
3635f34f | 87 | fID(""), |
88 | fNofPadsX(0), | |
89 | fNofPadsY(0), | |
90 | fNofPads(0), | |
91 | fMaxNofPads(0), | |
92 | fConnectionsByLocalIndices(), | |
93 | fConnectionsByManuChannel() | |
da635033 | 94 | { |
144129ae | 95 | /// Copy constructor |
3635f34f | 96 | AliDebug(1,Form("this=%p (copy ctor)",this)); |
97 | rhs.Copy(*this); | |
da635033 | 98 | } |
99 | ||
100 | //______________________________________________________________________________ | |
101 | AliMpMotifType& | |
102 | AliMpMotifType::operator=(const AliMpMotifType& rhs) | |
103 | { | |
144129ae | 104 | /// Assignment operator |
3635f34f | 105 | |
da635033 | 106 | TObject::operator=(rhs); |
107 | rhs.Copy(*this); | |
108 | return *this; | |
109 | } | |
110 | ||
111 | //______________________________________________________________________________ | |
112 | TObject* | |
113 | AliMpMotifType::Clone(const char* /*newname*/) const | |
114 | { | |
115 | /// Returns a full copy of this object | |
116 | return new AliMpMotifType(*this); | |
117 | } | |
118 | ||
119 | //______________________________________________________________________________ | |
120 | void | |
121 | AliMpMotifType::Copy(TObject& object) const | |
122 | { | |
144129ae | 123 | /// Copy object |
124 | ||
da635033 | 125 | TObject::Copy(object); |
126 | AliMpMotifType& mt = static_cast<AliMpMotifType&>(object); | |
127 | mt.fID = fID; | |
128 | mt.fNofPadsX = fNofPadsX; | |
129 | mt.fNofPadsY = fNofPadsY; | |
3635f34f | 130 | mt.fNofPads = fNofPads; |
131 | mt.fMaxNofPads = fMaxNofPads; | |
132 | mt.fConnectionsByLocalIndices = fConnectionsByLocalIndices; | |
133 | mt.fConnectionsByManuChannel = fConnectionsByManuChannel; | |
5f91c9e8 | 134 | } |
135 | ||
136 | //______________________________________________________________________________ | |
dee1d5f1 | 137 | AliMpMotifType::~AliMpMotifType() |
138 | { | |
3635f34f | 139 | /// Destructor |
5f91c9e8 | 140 | |
da635033 | 141 | AliDebug(1,Form("this=%p",this)); |
5f91c9e8 | 142 | } |
143 | ||
144 | //______________________________________________________________________________ | |
145 | AliMpVPadIterator* AliMpMotifType::CreateIterator() const | |
146 | { | |
dee1d5f1 | 147 | /// Create new motif type iterator |
148 | ||
5f91c9e8 | 149 | return new AliMpMotifTypePadIterator(this); |
150 | } | |
151 | ||
152 | //______________________________________________________________________________ | |
153 | void AliMpMotifType::SetNofPads(Int_t nofPadsX, Int_t nofPadsY) | |
154 | { | |
dee1d5f1 | 155 | /// Change the number of pads in this motif |
5f91c9e8 | 156 | |
157 | fNofPadsX = nofPadsX; | |
158 | fNofPadsY = nofPadsY; | |
159 | } | |
160 | ||
161 | ||
162 | //______________________________________________________________________________ | |
163 | Int_t AliMpMotifType::PadNum(const TString &padName) const | |
164 | { | |
dee1d5f1 | 165 | /// Transform a pad name into the equivalent pad number |
166 | ||
5f91c9e8 | 167 | if ( (padName[0]>='A') && (padName[0]<='Z') ) |
168 | return fgkPadNumForA+padName[0]-'A'; | |
169 | else | |
170 | return atoi(padName.Data()); | |
171 | } | |
172 | ||
173 | //______________________________________________________________________________ | |
174 | TString AliMpMotifType::PadName(Int_t padNum) const | |
175 | { | |
dee1d5f1 | 176 | /// Transform a pad number into its equivalent pad name |
177 | ||
5f91c9e8 | 178 | if (padNum<fgkPadNumForA) |
179 | return Form("%d",padNum); | |
180 | else | |
181 | return char('A'+padNum-fgkPadNumForA); | |
182 | } | |
183 | ||
184 | //______________________________________________________________________________ | |
3635f34f | 185 | Bool_t |
186 | AliMpMotifType::AddConnection(AliMpConnection* connection) | |
5f91c9e8 | 187 | { |
dee1d5f1 | 188 | /// Add the connection to the map |
5f91c9e8 | 189 | |
3635f34f | 190 | if (!connection) return kFALSE; |
191 | ||
168e9c4d | 192 | Int_t ix = connection->GetLocalIx(); |
193 | Int_t iy = connection->GetLocalIy(); | |
3635f34f | 194 | |
34ee05d7 | 195 | Int_t manuChannel = connection->GetManuChannel(); |
3635f34f | 196 | |
197 | if ( ix >=0 && ix < fMaxNofPads && | |
198 | iy >=0 && iy < fMaxNofPads && | |
199 | manuChannel >= 0 && manuChannel < AliMpConstants::ManuNofChannels()) | |
200 | { | |
201 | ||
202 | Int_t index = ix + iy*AliMpConstants::ManuNofChannels(); | |
203 | ||
168e9c4d | 204 | AliMpConnection* c = FindConnectionByLocalIndices( |
205 | connection->GetLocalIndices()); | |
3635f34f | 206 | |
207 | if (c) | |
208 | { | |
209 | AliError(Form("Connection already exists for ix=%d iy=%d",ix,iy)); | |
210 | return kFALSE; | |
211 | } | |
212 | ||
213 | ++fNofPads; | |
214 | ||
215 | fConnectionsByLocalIndices[index] = connection; | |
216 | fConnectionsByManuChannel[manuChannel] = connection; | |
217 | ||
218 | connection->SetOwner(this); | |
219 | ||
220 | return kTRUE; | |
221 | ||
222 | } | |
223 | return kFALSE; | |
5f91c9e8 | 224 | } |
f79c58a5 | 225 | |
5f91c9e8 | 226 | //______________________________________________________________________________ |
3635f34f | 227 | AliMpConnection* |
228 | AliMpMotifType::FindConnectionByPadNum(Int_t padNum) const | |
5f91c9e8 | 229 | { |
dee1d5f1 | 230 | /// Retrieve the AliMpConnection pointer from its pad num |
3635f34f | 231 | /// This method is quite inefficient as we're looping over all connections |
232 | ||
233 | TIter next(&fConnectionsByManuChannel); | |
234 | AliMpConnection* connection; | |
dee1d5f1 | 235 | |
3635f34f | 236 | while ( ( connection = static_cast<AliMpConnection*>(next()) ) ) |
237 | { | |
238 | if (connection->GetPadNum()==padNum) return connection; | |
239 | } | |
240 | return 0x0; | |
5f91c9e8 | 241 | } |
242 | ||
243 | //______________________________________________________________________________ | |
3635f34f | 244 | AliMpConnection* |
168e9c4d | 245 | AliMpMotifType::FindConnectionByLocalIndices(MpPair_t localIndices) const |
246 | { | |
247 | /// Retrieve the AliMpConnection pointer from its position (in pad unit) | |
248 | ||
249 | return FindConnectionByLocalIndices(AliMp::PairFirst(localIndices), | |
250 | AliMp::PairSecond(localIndices)); | |
251 | } | |
252 | ||
253 | //______________________________________________________________________________ | |
254 | AliMpConnection* | |
255 | AliMpMotifType::FindConnectionByLocalIndices(Int_t ix, Int_t iy) const | |
5f91c9e8 | 256 | { |
dee1d5f1 | 257 | /// Retrieve the AliMpConnection pointer from its position (in pad unit) |
3635f34f | 258 | |
3635f34f | 259 | if ( ix < fNofPadsX && iy < fNofPadsY && ix >= 0 && iy >= 0 ) |
260 | { | |
261 | Int_t index = ix + iy*fMaxNofPads; | |
262 | ||
263 | return static_cast<AliMpConnection*>(fConnectionsByLocalIndices.UncheckedAt(index)); | |
264 | } | |
265 | else | |
266 | { | |
267 | return 0x0; | |
268 | } | |
5f91c9e8 | 269 | } |
270 | ||
271 | //______________________________________________________________________________ | |
3635f34f | 272 | AliMpConnection* |
273 | AliMpMotifType::FindConnectionByGassiNum(Int_t gassiNum) const | |
5f91c9e8 | 274 | { |
dee1d5f1 | 275 | /// Return the connection for the given gassiplex number |
276 | ||
3635f34f | 277 | if ( gassiNum >=0 && gassiNum < fMaxNofPads ) |
278 | { | |
279 | return static_cast<AliMpConnection*>(fConnectionsByManuChannel.UncheckedAt(gassiNum)); | |
280 | } | |
281 | ||
282 | return 0x0; | |
5f91c9e8 | 283 | } |
f79c58a5 | 284 | |
5f91c9e8 | 285 | //______________________________________________________________________________ |
3635f34f | 286 | AliMpConnection* |
287 | AliMpMotifType::FindConnectionByKaptonNum(Int_t kaptonNum) const | |
5f91c9e8 | 288 | { |
dee1d5f1 | 289 | /// Give the connection related to the given kapton number |
3635f34f | 290 | /// Inefficient method as we loop over connections to find the right one |
291 | ||
292 | TIter next(&fConnectionsByManuChannel); | |
293 | AliMpConnection* connection; | |
dee1d5f1 | 294 | |
3635f34f | 295 | while ( ( connection = static_cast<AliMpConnection*>(next()) ) ) |
296 | { | |
297 | if ( connection && connection->GetKaptonNum()==kaptonNum) return connection; | |
298 | } | |
299 | return 0x0; | |
5f91c9e8 | 300 | } |
3635f34f | 301 | |
5f91c9e8 | 302 | //______________________________________________________________________________ |
3635f34f | 303 | AliMpConnection* |
304 | AliMpMotifType::FindConnectionByBergNum(Int_t bergNum) const | |
5f91c9e8 | 305 | { |
dee1d5f1 | 306 | /// Retrieve the connection from a Berg connector number |
3635f34f | 307 | /// Inefficient method as we loop over connections to find the right one |
dee1d5f1 | 308 | |
3635f34f | 309 | TIter next(&fConnectionsByManuChannel); |
310 | AliMpConnection* connection; | |
311 | ||
312 | while ( ( connection = static_cast<AliMpConnection*>(next()) ) ) | |
313 | { | |
314 | if ( connection && connection->GetBergNum()==bergNum) return connection; | |
315 | } | |
316 | return 0x0; | |
5f91c9e8 | 317 | } |
318 | ||
319 | ||
320 | //______________________________________________________________________________ | |
168e9c4d | 321 | MpPair_t AliMpMotifType::FindLocalIndicesByConnection(const AliMpConnection* connection) const |
5f91c9e8 | 322 | { |
630711ed | 323 | /// Reurn the pad position from the connection pointer. |
5f91c9e8 | 324 | |
168e9c4d | 325 | return connection->GetLocalIndices(); |
5f91c9e8 | 326 | } |
327 | ||
328 | //______________________________________________________________________________ | |
168e9c4d | 329 | MpPair_t AliMpMotifType::FindLocalIndicesByPadNum(Int_t padNum) const |
5f91c9e8 | 330 | { |
dee1d5f1 | 331 | /// Retrieve the AliMpConnection pointer from its pad num |
332 | ||
3635f34f | 333 | AliMpConnection* connection = FindConnectionByPadNum(padNum); |
630711ed | 334 | |
168e9c4d | 335 | if ( ! connection) return -1; |
336 | ||
337 | return connection->GetLocalIndices(); | |
5f91c9e8 | 338 | } |
339 | ||
340 | //______________________________________________________________________________ | |
168e9c4d | 341 | MpPair_t AliMpMotifType::FindLocalIndicesByGassiNum(Int_t gassiNum) const |
5f91c9e8 | 342 | { |
dee1d5f1 | 343 | /// Return the connection for the given gassiplex number |
344 | ||
3635f34f | 345 | AliMpConnection* connection = FindConnectionByGassiNum(gassiNum); |
630711ed | 346 | |
168e9c4d | 347 | if ( ! connection) return -1; |
348 | ||
349 | return connection->GetLocalIndices(); | |
5f91c9e8 | 350 | } |
351 | ||
352 | //______________________________________________________________________________ | |
168e9c4d | 353 | MpPair_t AliMpMotifType::FindLocalIndicesByKaptonNum(Int_t kaptonNum) const |
5f91c9e8 | 354 | { |
dee1d5f1 | 355 | /// Give the connection related to the given kapton number |
3635f34f | 356 | |
357 | AliMpConnection* connection = FindConnectionByKaptonNum(kaptonNum); | |
dee1d5f1 | 358 | |
168e9c4d | 359 | if ( ! connection) return -1; |
360 | ||
361 | return connection->GetLocalIndices(); | |
5f91c9e8 | 362 | } |
363 | ||
364 | //______________________________________________________________________________ | |
168e9c4d | 365 | MpPair_t AliMpMotifType::FindLocalIndicesByBergNum(Int_t bergNum) const |
5f91c9e8 | 366 | { |
dee1d5f1 | 367 | /// Retrieve the connection from a Berg connector number |
368 | ||
3635f34f | 369 | AliMpConnection* connection = FindConnectionByBergNum(bergNum); |
630711ed | 370 | |
168e9c4d | 371 | if ( ! connection) return -1; |
372 | ||
373 | return connection->GetLocalIndices(); | |
5f91c9e8 | 374 | } |
375 | ||
f79c58a5 | 376 | //______________________________________________________________________________ |
3635f34f | 377 | Bool_t |
168e9c4d | 378 | AliMpMotifType::HasPadByLocalIndices(MpPair_t localIndices) const |
f79c58a5 | 379 | { |
3635f34f | 380 | /// Return true if the pad indexed by \a localIndices has a connection |
381 | ||
382 | return ( FindConnectionByLocalIndices(localIndices) != 0x0 ); | |
f79c58a5 | 383 | } |
384 | ||
168e9c4d | 385 | //______________________________________________________________________________ |
386 | Bool_t | |
387 | AliMpMotifType::HasPadByLocalIndices(Int_t localIx, Int_t localIy) const | |
388 | { | |
389 | /// Return true if the pad indexed by \a localIndices has a connection | |
390 | ||
391 | return ( FindConnectionByLocalIndices(localIx, localIy) != 0x0 ); | |
392 | } | |
393 | ||
5f91c9e8 | 394 | //______________________________________________________________________________ |
3635f34f | 395 | Bool_t |
396 | AliMpMotifType::HasPadByManuChannel(Int_t manuChannel) const | |
5f91c9e8 | 397 | { |
13985652 | 398 | /// Return true if the pad indexed by \a localIndices has a connection |
dee1d5f1 | 399 | |
7a170a5c | 400 | // if ( manuChannel >= fNofPads ) return kFALSE; |
3635f34f | 401 | |
402 | return ( FindConnectionByGassiNum(manuChannel) != 0x0 ); | |
5f91c9e8 | 403 | } |
404 | ||
405 | //______________________________________________________________________________ | |
406 | void AliMpMotifType::Print(Option_t *option) const | |
407 | { | |
dee1d5f1 | 408 | /// Print the map of the motif. In each cell, the value |
409 | /// printed depends of option, as the following: | |
410 | /// - option="N" the "name" of the pad is written | |
411 | /// - option="K" the Kapton connect. number attached to the pad is written | |
412 | /// - option="B" the Berg connect. number attached to the pad is written | |
413 | /// - option="G" the Gassiplex channel number attached to the pad is written | |
414 | /// otherwise the number of the pad is written | |
415 | /// | |
416 | /// NOTE : this method is really not optimized, in case 'N' or '', | |
417 | /// but the Print() this should not be very important in a Print() method | |
5f91c9e8 | 418 | |
419 | switch (option[0]){ | |
420 | case 'N':cout<<"Name mapping"; | |
421 | break; | |
422 | case 'K':cout<<"Kapton mapping"; | |
423 | break; | |
424 | case 'B':cout<<"Berg mapping"; | |
425 | break; | |
426 | case 'G':cout<<"Gassiplex number mapping"; | |
427 | break; | |
428 | default:cout<<"Pad mapping"; | |
429 | } | |
430 | cout<<" in the motif "<<fID<<endl; | |
431 | cout<<"-----------------------------------"<<endl; | |
432 | ||
433 | for (Int_t j=fNofPadsY-1;j>=0;j--){ | |
434 | for (Int_t i=0;i<fNofPadsX;i++){ | |
168e9c4d | 435 | AliMpConnection *connexion = FindConnectionByLocalIndices(i,j); |
5f91c9e8 | 436 | TString str; |
437 | if (connexion){ | |
da635033 | 438 | AliDebug(1,Form("i,j=%2d,%2d connexion=%p",i,j,connexion)); |
439 | ||
440 | switch (option[0]){ | |
441 | case 'N':str=PadName(connexion->GetPadNum()); | |
442 | break; | |
443 | case 'K':str=Form("%d",connexion->GetKaptonNum()); | |
444 | break; | |
445 | case 'B':str=Form("%d",connexion->GetBergNum()); | |
446 | break; | |
34ee05d7 | 447 | case 'G':str=Form("%d",connexion->GetManuChannel()); |
da635033 | 448 | break; |
449 | default:str= Form("%d",connexion->GetPadNum()); | |
450 | } | |
451 | cout<<setw(2)<<str; | |
5f91c9e8 | 452 | } else cout<<setw(2)<<"--"; |
453 | cout<<" "; | |
454 | } | |
455 | cout<<endl; | |
456 | } | |
457 | } | |
da635033 | 458 | |
459 | //_____________________________________________________________________________ | |
460 | Bool_t | |
461 | AliMpMotifType::Save() const | |
462 | { | |
71a2d3aa | 463 | /// Save this motif type |
464 | ||
da635033 | 465 | return Save(fID.Data()); |
466 | } | |
467 | ||
468 | //_____________________________________________________________________________ | |
469 | Bool_t | |
470 | AliMpMotifType::Save(const char* motifName) const | |
471 | { | |
472 | /// Generate the 2 files needed to describe the motif | |
473 | ||
474 | TString padPosFileName(AliMpFiles::PadPosFileName(motifName)); | |
475 | ||
476 | TString motifTypeFileName(AliMpFiles::MotifFileName(motifName)); | |
477 | ||
478 | // first a protection : do not allow overwriting existing files... | |
479 | Bool_t test = gSystem->AccessPathName(padPosFileName.Data()); | |
480 | if (test==kFALSE) // AccessPathName has a strange return value convention... | |
481 | { | |
482 | AliError("Cannot overwrite existing padPos file"); | |
483 | return kFALSE; | |
484 | } | |
485 | test = gSystem->AccessPathName(motifTypeFileName.Data()); | |
486 | if (test==kFALSE) | |
487 | { | |
488 | AliError("Cannot overwrite existing motifType file"); | |
489 | return kFALSE; | |
490 | } | |
491 | ||
492 | ofstream padPosFile(padPosFileName.Data()); | |
493 | ofstream motifFile(motifTypeFileName.Data()); | |
494 | ||
495 | motifFile << "# Motif " << motifName << endl | |
496 | << "#" << endl | |
497 | << "#connecteur_berg kapton padname not_used" << endl | |
498 | << "#for slats there's no kapton connector, so it's always 1" | |
499 | << " (zero make the reader" << endl | |
500 | << "#abort, so it's not a valid value here)." << endl | |
501 | << "#" << endl; | |
502 | ||
503 | for ( Int_t ix = 0; ix < GetNofPadsX(); ++ix ) | |
504 | { | |
505 | for ( Int_t iy = 0; iy < GetNofPadsY(); ++iy ) | |
506 | { | |
168e9c4d | 507 | AliMpConnection* con = FindConnectionByLocalIndices(ix,iy); |
da635033 | 508 | if (con) |
509 | { | |
510 | motifFile << con->GetBergNum() << "\t1\t" << con->GetPadNum() << "\t-" << endl; | |
511 | padPosFile << con->GetPadNum() << "\t" << ix << "\t" << iy << endl; | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
516 | padPosFile.close(); | |
517 | motifFile.close(); | |
518 | ||
519 | return kTRUE; | |
520 | } | |
521 | ||
522 | ||
523 |