1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: CMSFillView class implementation |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <mediaservant.rsg> |
|
20 #include <StringLoader.h> |
|
21 #include <aknlistquerydialog.h> |
|
22 #include <hlplch.h> |
|
23 #include <utf.h> |
|
24 |
|
25 #include "cmfillrule.h" |
|
26 #include "msfillview.h" |
|
27 #include "msengine.h" |
|
28 #include "msfillcontainer.h" |
|
29 #include "msappui.h" |
|
30 #include "msconstants.h" |
|
31 #include "mediaservant.hrh" |
|
32 #include "msparameteragent.h" |
|
33 #include "msdebug.h" |
|
34 |
|
35 |
|
36 // CONSTANTS |
|
37 _LIT( KWildCard, "*" ); |
|
38 _LIT( KSpace, " "); |
|
39 |
|
40 const TInt KImageListTemplate = 1; |
|
41 const TInt KVideoListTemplate = 2; |
|
42 const TInt KMusicListTemplate = 3; |
|
43 |
|
44 |
|
45 // -------------------------------------------------------------------------- |
|
46 // CMSFillView::CMSFillView() |
|
47 // -------------------------------------------------------------------------- |
|
48 // |
|
49 CMSFillView::CMSFillView( CMSAppUi& aAppUi ) |
|
50 { |
|
51 LOG(_L("[MediaServant]\t CMSFillView::CMSFillView")); |
|
52 |
|
53 iAppUi = &aAppUi; |
|
54 } |
|
55 |
|
56 // -------------------------------------------------------------------------- |
|
57 // CMSFillView::ConstructL() |
|
58 // -------------------------------------------------------------------------- |
|
59 // |
|
60 void CMSFillView::ConstructL() |
|
61 { |
|
62 LOG(_L("[MediaServant]\t CMSFillView::ConstructL")); |
|
63 |
|
64 BaseConstructL( R_MS_FILL_VIEW ); |
|
65 } |
|
66 |
|
67 // -------------------------------------------------------------------------- |
|
68 // CMSFillView::~CMSFillView() |
|
69 // -------------------------------------------------------------------------- |
|
70 // |
|
71 CMSFillView::~CMSFillView() |
|
72 { |
|
73 LOG(_L("[MediaServant]\t CMSFillView::~CMSFillView")); |
|
74 DoDeactivate(); |
|
75 } |
|
76 |
|
77 // -------------------------------------------------------------------------- |
|
78 // TUid CMSFillView::Id() |
|
79 // -------------------------------------------------------------------------- |
|
80 // |
|
81 TUid CMSFillView::Id() const |
|
82 { |
|
83 LOG(_L("[MediaServant]\t CMSFillView::Id")); |
|
84 |
|
85 return KMSFillViewId; |
|
86 } |
|
87 |
|
88 |
|
89 // -------------------------------------------------------------------------- |
|
90 // CMSFillView::HandleCommandL(TInt aCommand) |
|
91 // -------------------------------------------------------------------------- |
|
92 // |
|
93 void CMSFillView::HandleCommandL(TInt aCommand) |
|
94 { |
|
95 LOG(_L("[MediaServant]\t CMSFillView::HandleCommandL")); |
|
96 |
|
97 CEikButtonGroupContainer* cba = Cba(); |
|
98 |
|
99 switch (aCommand) |
|
100 { |
|
101 case EAknSoftkeyBack: |
|
102 { |
|
103 CancelAsyncOperation( iAppUi ); |
|
104 iNextView = KMSMainViewId; |
|
105 |
|
106 CheckAndHandleChangesL(); |
|
107 |
|
108 break; |
|
109 } |
|
110 |
|
111 case EAknSoftkeyDone: |
|
112 { |
|
113 CancelAsyncOperation( iAppUi ); |
|
114 iContainer->SetReorderStateL( EMSFillNormal ); |
|
115 cba->SetCommandSetL( R_AVKON_SOFTKEYS_OPTIONS_BACK ); |
|
116 cba->DrawNow(); |
|
117 |
|
118 // Set title pane text |
|
119 SetTitlePaneTextL( R_MS_FILL_VIEW_TITLE ); |
|
120 break; |
|
121 } |
|
122 |
|
123 case EMSCmdActivate: // fall through |
|
124 case EMSCmdDeActivate: |
|
125 { |
|
126 iContainer->ChangeListActivityL(); |
|
127 SetListUnselected(); |
|
128 break; |
|
129 } |
|
130 // Edit fill rule |
|
131 case EMSCmdEditRule: |
|
132 { |
|
133 CancelAsyncOperation( iAppUi ); |
|
134 TMSTemplate ruleTemplate; |
|
135 ruleTemplate.templateType = aCommand; |
|
136 ruleTemplate.selectedTemplate = EMSNoTemplate; |
|
137 iAppUi->ParameterAgent()->SetRuleTemplate( ruleTemplate ); |
|
138 |
|
139 iNextView = KMSFillEditViewId; |
|
140 CheckAndHandleChangesL(); |
|
141 |
|
142 break; |
|
143 } |
|
144 |
|
145 case EMSCmdBrowse: |
|
146 { |
|
147 CancelAsyncOperation( iAppUi ); |
|
148 iNextView = KMSFillBrowseViewId; |
|
149 CheckAndHandleChangesL(); |
|
150 |
|
151 break; |
|
152 } |
|
153 |
|
154 case EMSCmdNewImageList: // fall through |
|
155 case EMSCmdNewVideoList: // fall through |
|
156 case EMSCmdNewMusicList: |
|
157 { |
|
158 CancelAsyncOperation( iAppUi ); |
|
159 ShowTemplateQueryL( aCommand ); |
|
160 iNextView = KMSFillEditViewId; |
|
161 CheckAndHandleChangesL(); |
|
162 break; |
|
163 } |
|
164 |
|
165 // Reorder fill rule |
|
166 case EMSCmdReorder: |
|
167 { |
|
168 iContainer->SetReorderStateL( EMSFillReorderActive ); |
|
169 cba->SetCommandSetL( R_SOFTKEYS_DROP_EMPTY ); |
|
170 cba->DrawNow(); |
|
171 // Set title pane text |
|
172 SetTitlePaneTextL( R_MS_FILL_VIEW_TITLE_REORDER_MODE ); |
|
173 break; |
|
174 } |
|
175 |
|
176 // Drop rule to new location |
|
177 case EMSCmdDrop: |
|
178 { |
|
179 iContainer->SetReorderStateL( EMSFillGrabActive ); |
|
180 cba->SetCommandSetL( R_SOFTKEYS_GRAB_DONE ); |
|
181 cba->DrawNow(); |
|
182 break; |
|
183 } |
|
184 // Reorder mode active - grab item |
|
185 case EMSCmdGrab: |
|
186 { |
|
187 iContainer->SetReorderStateL( EMSFillReorderActive ); |
|
188 cba->SetCommandSetL( R_SOFTKEYS_DROP_EMPTY ); |
|
189 cba->DrawNow(); |
|
190 break; |
|
191 } |
|
192 // Delete fill rule |
|
193 case EMSCmdDelete: |
|
194 { |
|
195 iContainer->DeleteRuleL(); |
|
196 break; |
|
197 } |
|
198 case EAknCmdHelp : |
|
199 { |
|
200 TRAP_IGNORE( HlpLauncher::LaunchHelpApplicationL( |
|
201 iEikonEnv->WsSession(), |
|
202 iEikonEnv->EikAppUi()->AppHelpContextL() )); |
|
203 break; |
|
204 } |
|
205 default: |
|
206 { |
|
207 CancelAsyncOperation( iAppUi ); |
|
208 AppUi()->HandleCommandL(aCommand); |
|
209 break; |
|
210 } |
|
211 } |
|
212 } |
|
213 |
|
214 |
|
215 // -------------------------------------------------------------------------- |
|
216 // CMSFillView::DoActivateL() |
|
217 // -------------------------------------------------------------------------- |
|
218 // |
|
219 void CMSFillView::DoActivateL( |
|
220 const TVwsViewId& /*aPrevViewId*/,TUid /*aCustomMessageId*/, |
|
221 const TDesC8& /*aCustomMessage*/) |
|
222 { |
|
223 LOG(_L("[MediaServant]\t CMSFillView::DoActivateL")); |
|
224 |
|
225 // Set engine observer |
|
226 iAppUi->MSEngine()->SetObserver( this ); |
|
227 |
|
228 // Set title pane text |
|
229 SetTitlePaneTextL( R_MS_FILL_VIEW_TITLE ); |
|
230 |
|
231 if ( !iContainer ) |
|
232 { |
|
233 iContainer = new (ELeave) CMSFillContainer( *iAppUi, *this ); |
|
234 iContainer->ConstructL( ClientRect() ); |
|
235 iContainer->SetMopParent( this ); |
|
236 AppUi()->AddToViewStackL( *this, iContainer ); |
|
237 } |
|
238 SetListUnselected(); |
|
239 } |
|
240 |
|
241 // -------------------------------------------------------------------------- |
|
242 // CMSFillView::DoDeactivate() |
|
243 // -------------------------------------------------------------------------- |
|
244 // |
|
245 void CMSFillView::DoDeactivate() |
|
246 { |
|
247 LOG(_L("[MediaServant]\t CMSFillView::DoDeactivate")); |
|
248 |
|
249 if ( iContainer ) |
|
250 { |
|
251 AppUi()->RemoveFromStack( iContainer ); |
|
252 } |
|
253 |
|
254 delete iContainer; // Deletes the container class object. |
|
255 iContainer = NULL; |
|
256 SetListUnselected(); |
|
257 } |
|
258 |
|
259 // -------------------------------------------------------------------------- |
|
260 // CMSFillView::FocusIndex() |
|
261 // -------------------------------------------------------------------------- |
|
262 // |
|
263 TInt CMSFillView::FocusIndex() const |
|
264 { |
|
265 return iContainer->SelectedItemIndex(); |
|
266 } |
|
267 |
|
268 // -------------------------------------------------------------------------- |
|
269 // CMSFillView::DynInitMenuPaneL(TInt aResourceId,CEikMenuPane* aMenuPane) |
|
270 // -------------------------------------------------------------------------- |
|
271 // |
|
272 void CMSFillView::DynInitMenuPaneL( TInt aResourceId, |
|
273 CEikMenuPane* aMenuPane ) |
|
274 { |
|
275 LOG(_L("[MediaServant]\t CMSFillView::DynInitMenuPaneL")); |
|
276 |
|
277 if ( aResourceId == R_FILL_VIEW_MENU && iContainer ) |
|
278 { |
|
279 // check if the list is empty |
|
280 if ( iContainer->ListItemCount() <= 0 ) |
|
281 { |
|
282 // Hide commands |
|
283 aMenuPane->SetItemDimmed(EMSCmdEditRule, ETrue); |
|
284 aMenuPane->SetItemDimmed(EMSCmdReorder, ETrue); |
|
285 aMenuPane->SetItemDimmed(EMSCmdDelete, ETrue); |
|
286 aMenuPane->SetItemDimmed(EMSCmdBrowse, ETrue); |
|
287 aMenuPane->SetItemDimmed(EMSCmdActivate, ETrue); |
|
288 aMenuPane->SetItemDimmed(EMSCmdDeActivate, ETrue); |
|
289 } |
|
290 |
|
291 if ( iContainer->IsCurrentListItemActive() ) |
|
292 { |
|
293 aMenuPane->SetItemDimmed(EMSCmdActivate, ETrue); |
|
294 } |
|
295 else |
|
296 { |
|
297 aMenuPane->SetItemDimmed(EMSCmdDeActivate, ETrue); |
|
298 } |
|
299 } |
|
300 } |
|
301 |
|
302 // -------------------------------------------------------------------------- |
|
303 // CMSFillView::ShowTemplateQueryL |
|
304 // shows template query |
|
305 // -------------------------------------------------------------------------- |
|
306 // |
|
307 void CMSFillView::ShowTemplateQueryL( TInt aCommand ) |
|
308 { |
|
309 LOG(_L("[MediaServant]\t CMSFillView::ShowTemplateQueryL")); |
|
310 |
|
311 HBufC* defaultListName = NULL;; |
|
312 |
|
313 TMSTemplate ruleTemplate; |
|
314 // set template info |
|
315 ruleTemplate.templateType = aCommand; |
|
316 |
|
317 switch ( aCommand ) |
|
318 { |
|
319 case EMSCmdNewImageList: |
|
320 { |
|
321 defaultListName = StringLoader::LoadLC( |
|
322 R_MS_CUSTOM_LIST_IMAGE_NAME ); |
|
323 ruleTemplate.selectedTemplate = KImageListTemplate; |
|
324 break; |
|
325 } |
|
326 case EMSCmdNewVideoList: |
|
327 { |
|
328 defaultListName = StringLoader::LoadLC( |
|
329 R_MS_CUSTOM_LIST_VIDEO_NAME ); |
|
330 ruleTemplate.selectedTemplate = KVideoListTemplate; |
|
331 break; |
|
332 } |
|
333 case EMSCmdNewMusicList: |
|
334 { |
|
335 defaultListName = StringLoader::LoadLC( |
|
336 R_MS_CUSTOM_LIST_MUSIC_NAME ); |
|
337 ruleTemplate.selectedTemplate = KMusicListTemplate; |
|
338 break; |
|
339 } |
|
340 default: |
|
341 { |
|
342 defaultListName = StringLoader::LoadLC( |
|
343 R_MS_CUSTOM_LIST_IMAGE_NAME ); |
|
344 ruleTemplate.selectedTemplate = KImageListTemplate; |
|
345 // command not found |
|
346 break; |
|
347 } |
|
348 } |
|
349 |
|
350 // Create search string with wildcards |
|
351 HBufC* searchStr = HBufC::NewLC( KMaxFileName ); |
|
352 searchStr->Des().Copy( KWildCard ); |
|
353 searchStr->Des().Append( defaultListName->Des() ); |
|
354 searchStr->Des().Append( KWildCard ); |
|
355 |
|
356 // Check if fill list have dublicate names |
|
357 TInt count = iContainer->CheckIfDublicateNames( *searchStr ); |
|
358 |
|
359 CleanupStack::PopAndDestroy( searchStr ); |
|
360 // keep template name safe |
|
361 ruleTemplate.templateName.Copy( defaultListName->Des() ); |
|
362 |
|
363 // if existing items... |
|
364 searchStr = HBufC::NewLC( KMaxFileName ); |
|
365 searchStr->Des().Append( defaultListName->Des() ); |
|
366 |
|
367 TBool same = EFalse; |
|
368 |
|
369 RPointerArray<CMSFillList>* iFillListArray = |
|
370 iAppUi->FillRuleController()->FillListArray(); |
|
371 |
|
372 // if there are same name items |
|
373 for ( TInt index = 0; index < iFillListArray->Count(); ++index ) |
|
374 { |
|
375 CCmFillRule* rule = (*iFillListArray)[index]->List(); |
|
376 HBufC* listName = |
|
377 CnvUtfConverter::ConvertToUnicodeFromUtf8L( rule->Name() ); |
|
378 CleanupStack::PushL( listName ); |
|
379 if ( *searchStr == *listName ) |
|
380 { |
|
381 same = ETrue; |
|
382 } |
|
383 CleanupStack::PopAndDestroy( listName ); |
|
384 } |
|
385 |
|
386 CleanupStack::PopAndDestroy( searchStr ); |
|
387 // exist same name items |
|
388 if ( count > 0 && same ) |
|
389 { |
|
390 TInt postfix; |
|
391 // calculate a postfix number to add the end of the name |
|
392 for ( postfix = 1; ; ++postfix ) |
|
393 { |
|
394 HBufC* sameStr = HBufC::NewL( KMaxFileName ); |
|
395 CleanupStack::PushL( sameStr ); |
|
396 sameStr->Des().Copy( KWildCard ); |
|
397 sameStr->Des().Append( defaultListName->Des() ); |
|
398 sameStr->Des().Append( KSpace ); |
|
399 sameStr->Des().AppendNum( postfix ); |
|
400 sameStr->Des().Append( KWildCard ); |
|
401 |
|
402 // do number conversion |
|
403 TPtr ptr = sameStr->Des(); |
|
404 AknTextUtils:: |
|
405 DisplayTextLanguageSpecificNumberConversion( ptr ); |
|
406 |
|
407 if ( 0 == iContainer->CheckIfDublicateNames( *sameStr ) ) |
|
408 { |
|
409 // after append the current number, there are not |
|
410 //same name items, so jump out the code block |
|
411 CleanupStack::PopAndDestroy( sameStr ); |
|
412 break; |
|
413 } |
|
414 CleanupStack::PopAndDestroy( sameStr ); |
|
415 } |
|
416 |
|
417 // append order number to name |
|
418 ruleTemplate.templateName.Append( KSpace ); |
|
419 ruleTemplate.templateName.AppendNum( postfix ); |
|
420 |
|
421 // do number conversion |
|
422 AknTextUtils:: |
|
423 DisplayTextLanguageSpecificNumberConversion( |
|
424 ruleTemplate.templateName ); |
|
425 } |
|
426 |
|
427 // store template info to parameter agent |
|
428 iAppUi->ParameterAgent()->SetRuleTemplate( ruleTemplate ); |
|
429 |
|
430 CleanupStack::PopAndDestroy( defaultListName ); |
|
431 } |
|
432 |
|
433 // --------------------------------------------------------------------------- |
|
434 // CMSFillView::ShowNaviTextL |
|
435 // --------------------------------------------------------------------------- |
|
436 // |
|
437 void CMSFillView::ShowNaviTextL() |
|
438 { |
|
439 LOG(_L("[MediaServant]\t CMSFillView::ShowNaviTextL")); |
|
440 |
|
441 HBufC* naviText = StringLoader::LoadLC( R_MS_PREPROCESSING_TEXT ); |
|
442 SetNavigationPaneTextL( *naviText ); |
|
443 CleanupStack::PopAndDestroy( naviText ); |
|
444 } |
|
445 |
|
446 // --------------------------------------------------------------------------- |
|
447 // CMSFillView::SetListUnselected |
|
448 // --------------------------------------------------------------------------- |
|
449 // |
|
450 void CMSFillView::SetListUnselected( ) |
|
451 { |
|
452 LOG(_L("[MediaServant]\t CMSFillView::SetListUnselected")); |
|
453 |
|
454 iListUnSelected = iAppUi->FillRuleController()-> |
|
455 HasSelectionsChanged( ECmUnSelected ); |
|
456 } |
|
457 |
|
458 // --------------------------------------------------------------------------- |
|
459 // CMSFillView::CheckAndHandleChangesL |
|
460 // --------------------------------------------------------------------------- |
|
461 // |
|
462 void CMSFillView::CheckAndHandleChangesL() |
|
463 { |
|
464 LOG(_L("[MediaServant]\t CMSFillView::CheckAndHandleChangesL")); |
|
465 |
|
466 TBool priorityChanged( EFalse ); |
|
467 |
|
468 // Check if priorities has been changed |
|
469 priorityChanged = iAppUi->FillRuleController()-> |
|
470 HasPriorityChangedL(); |
|
471 |
|
472 iNewListSelected = iAppUi->FillRuleController()-> |
|
473 HasSelectionsChanged( ECmSelected ); |
|
474 // check if there is deleted lists |
|
475 TBool listDeleted = iContainer->IsListDeleted(); |
|
476 |
|
477 // set activity for all rules |
|
478 iContainer->SetFillRules(); |
|
479 |
|
480 if ( iListUnSelected ) |
|
481 { |
|
482 // unselected list(s) - show query |
|
483 DoDeleteQueryL(); |
|
484 } |
|
485 |
|
486 // send rules to server |
|
487 iAppUi->FillRuleController()->SaveRulesL(); |
|
488 |
|
489 // update lists if list(s) have been deleted, created or their selection |
|
490 // statuses or priorities have been changed |
|
491 if ( listDeleted || |
|
492 priorityChanged || |
|
493 iListUnSelected || |
|
494 iNewListSelected ) |
|
495 { |
|
496 // disable right softkey |
|
497 CEikButtonGroupContainer* cba = CEikButtonGroupContainer::Current(); |
|
498 cba->SetCommandSetL( R_MS_SOFTKEYS_OPTIONS_EMPTY ); |
|
499 cba->DrawDeferred(); |
|
500 |
|
501 ShowNaviTextL(); |
|
502 iAppUi->MSEngine()->UpdateFillListsL(); |
|
503 } |
|
504 else // no list update needed |
|
505 { |
|
506 // retrieve new information |
|
507 iAppUi->FillRuleController()->UpdateArrayL(); |
|
508 iAppUi->ChangeViewL( KMSFillViewId, iNextView ); |
|
509 } |
|
510 } |
|
511 |
|
512 // --------------------------------------------------------------------------- |
|
513 // CMSFillView::DoDeleteQueryL |
|
514 // --------------------------------------------------------------------------- |
|
515 // |
|
516 void CMSFillView::DoDeleteQueryL() |
|
517 { |
|
518 LOG(_L("[MediaServant]\t CMSFillView::DoDeleteQueryL")); |
|
519 |
|
520 // Show delete files query |
|
521 CAknQueryDialog* query= CAknQueryDialog::NewL( |
|
522 CAknQueryDialog::ENoTone ); |
|
523 |
|
524 if ( query->ExecuteLD( R_MSERV_DELETE_FILES_QUERY ) ) |
|
525 { |
|
526 // do nothing |
|
527 } |
|
528 else // canceled |
|
529 { |
|
530 iAppUi->FillRuleController()->RestoreOriginalSelections(); |
|
531 } |
|
532 } |
|
533 |
|
534 // -------------------------------------------------------------------------- |
|
535 // CMSFillView::ReadyL() |
|
536 // engine observer callback |
|
537 // -------------------------------------------------------------------------- |
|
538 // |
|
539 void CMSFillView::ReadyL( TCmService aService, TInt /*aError*/ ) |
|
540 { |
|
541 LOG(_L("[MediaServant]\t CMSFillView::ReadyL")); |
|
542 |
|
543 switch ( aService ) |
|
544 { |
|
545 case ECmServiceUpdateFillLists: |
|
546 { |
|
547 // set original softkeys back |
|
548 CEikButtonGroupContainer* cba = |
|
549 CEikButtonGroupContainer::Current(); |
|
550 cba->SetCommandSetL( R_AVKON_SOFTKEYS_OPTIONS_BACK ); |
|
551 cba->DrawDeferred(); |
|
552 |
|
553 // retrieve new information |
|
554 iAppUi->FillRuleController()->UpdateArrayL(); |
|
555 |
|
556 ClearCurrentNaviPaneText(); |
|
557 iAppUi->ChangeViewL( KMSFillViewId, iNextView ); |
|
558 break; |
|
559 } |
|
560 case ECmServiceDeleteFilledFiles: |
|
561 { |
|
562 LOG(_L("[MediaServant]\t CMSFillView::ReadyL delete complete")); |
|
563 ClearCurrentNaviPaneText(); |
|
564 // Set context pane icon |
|
565 iContainer->SetDefaultContextPaneIconL(); |
|
566 |
|
567 iContainer->UpdateListBoxDataL(); |
|
568 break; |
|
569 } |
|
570 |
|
571 default: |
|
572 { |
|
573 LOG(_L("[MediaServant]\t CMSFillView::ReadyL \ |
|
574 service not found")); |
|
575 } |
|
576 |
|
577 } |
|
578 } |
|
579 |
|
580 // -------------------------------------------------------------------------- |
|
581 // CMSFillView::SetCbaL() |
|
582 // Changes softkeys |
|
583 // -------------------------------------------------------------------------- |
|
584 // |
|
585 void CMSFillView::SetCbaL( TBool aSelected ) |
|
586 { |
|
587 LOG(_L("[MediaServant]\t CMSFillView::SetCbaL")); |
|
588 |
|
589 CEikButtonGroupContainer* cba = Cba(); |
|
590 |
|
591 if ( aSelected ) |
|
592 { |
|
593 cba->SetCommandSetL( R_MS_SOFTKEYS_OPTIONS_BACK__DEACTIVATE ); |
|
594 } |
|
595 else |
|
596 { |
|
597 cba->SetCommandSetL( R_MS_SOFTKEYS_OPTIONS_BACK__ACTIVATE ); |
|
598 } |
|
599 cba->DrawDeferred(); |
|
600 } |
|
601 |
|
602 // End of File |
|
603 |
|