qtinternetradio/ui/src/irsearchchannelsview.cpp
changeset 14 896e9dbc5f19
parent 12 608f67c22514
child 15 065198191975
equal deleted inserted replaced
12:608f67c22514 14:896e9dbc5f19
    24 #include <hbiconitem.h>
    24 #include <hbiconitem.h>
    25 #include <hbiconanimator.h>
    25 #include <hbiconanimator.h>
    26 #include <hblabel.h> 
    26 #include <hblabel.h> 
    27 #include <hbiconanimationmanager.h>
    27 #include <hbiconanimationmanager.h>
    28 #include <HbGroupBox>
    28 #include <HbGroupBox>
       
    29 #include <qinputcontext.h>
       
    30 #include <qapplication.h>
    29 
    31 
    30 #include "irsearchchannelsview.h"
    32 #include "irsearchchannelsview.h"
    31 #include "iruidefines.h"
    33 #include "iruidefines.h"
    32 #include "irqisdsclient.h"
    34 #include "irqisdsclient.h"
    33 #include "irapplication.h"
    35 #include "irapplication.h"
    34 #include "irviewmanager.h"
    36 #include "irviewmanager.h"
    35 #include "irqnetworkcontroller.h"
    37 #include "irqnetworkcontroller.h"
    36 #include "irchannelmodel.h"
    38 #include "irchannelmodel.h"
    37 #include "irqisdsdatastructure.h"
    39 #include "irqisdsdatastructure.h"
    38 #include "irplaycontroller.h"
    40 #include "irplaycontroller.h"
       
    41 #include "irqlogger.h"
       
    42 #include "irqsettings.h"
    39  
    43  
    40 const uint KBitmapSize = 59;
    44 const uint KBitmapSize = 59;
    41 
    45 
    42 IRSearchChannelsView::IRSearchChannelsView(IRApplication* aApplication,
    46 IRSearchChannelsView::IRSearchChannelsView(IRApplication* aApplication,
    43         TIRViewId aViewId): IRBaseView(aApplication, aViewId),
    47         TIRViewId aViewId): IRBaseView(aApplication, aViewId),
    44         iListView(NULL),iSearchPanelWidget(NULL),iSearchState(ESearch_init),
    48         iListView(NULL),iSearchPanelWidget(NULL),iSearchState(ESearch_init),
    45         iChannelModel(NULL),iPreset(NULL),iLogoPreset(NULL),
    49         iChannelModel(NULL),iPreset(NULL),iLogoPreset(NULL),
    46         iConvertTimer(NULL) 
    50         iConvertTimer(NULL) 
    47 {
    51 {
       
    52     LOG_METHOD;
       
    53     iSettings = IRQSettings::openInstance();    
    48     //if this view is not starting view, finish all initialization in constructor
    54     //if this view is not starting view, finish all initialization in constructor
    49     if (getViewManager()->views().count() > 0)
    55     if (getViewManager()->views().count() > 0)
    50     {
    56     {
    51         if (!initCompleted())
    57         if (!initCompleted())
    52         {            
    58         {            
    55     }
    61     }
    56 }
    62 }
    57 
    63 
    58 void IRSearchChannelsView::lazyInit()
    64 void IRSearchChannelsView::lazyInit()
    59 {
    65 {
       
    66     LOG_METHOD;
    60     if (!initCompleted())
    67     if (!initCompleted())
    61     {
    68     {
    62         normalInit();                     
    69         normalInit();                     
    63     }        
    70     }        
    64 }
    71 }
    65 
    72 
    66 void IRSearchChannelsView::normalInit()
    73 void IRSearchChannelsView::normalInit()
    67 {
    74 {
       
    75     LOG_METHOD;
    68     if (!initCompleted())
    76     if (!initCompleted())
    69     { 
    77     { 
    70         IRBaseView::lazyInit();
    78         IRBaseView::lazyInit();
    71         loadLayout();
    79         loadLayout();
    72         connectWidget();  
    80         connectWidget();  
    77     }
    85     }
    78 }
    86 }
    79 
    87 
    80 void IRSearchChannelsView::initMenu()
    88 void IRSearchChannelsView::initMenu()
    81 {
    89 {
       
    90     LOG_METHOD;
    82     HbMenu *viewMenu = menu();
    91     HbMenu *viewMenu = menu();
    83     QObject *exitAction = iLoader.findObject(EXIT_ACTION);
    92     QObject *exitAction = iLoader.findObject(EXIT_ACTION);
    84     connect(exitAction, SIGNAL(triggered()), iApplication, SIGNAL(quit()));
    93     connect(exitAction, SIGNAL(triggered()), iApplication, SIGNAL(quit()));
    85 }
    94 }
    86 
    95 
    87 void IRSearchChannelsView::initTimer()
    96 void IRSearchChannelsView::initTimer()
    88 {     
    97 {     
       
    98     LOG_METHOD;
    89     iConvertTimer = new QTimer(this);
    99     iConvertTimer = new QTimer(this);
    90     iConvertTimer->setInterval(10); 
   100     iConvertTimer->setInterval(10); 
    91     
   101     
    92     connect(iConvertTimer, SIGNAL(timeout()), this, SLOT(convertAnother()));
   102     connect(iConvertTimer, SIGNAL(timeout()), this, SLOT(convertAnother()));
    93 }
   103 }
    94 
   104 
    95  
   105  
    96 
   106 
    97 IRSearchChannelsView::~IRSearchChannelsView()
   107 IRSearchChannelsView::~IRSearchChannelsView()
    98 {   
   108 {   
       
   109     LOG_METHOD;
       
   110     
       
   111     if (iSettings)
       
   112     {
       
   113         iSettings->setSearchText(iKeyText);
       
   114         iSettings->closeInstance();
       
   115     }    
       
   116     
    99     if( iPreset != NULL )
   117     if( iPreset != NULL )
   100     {
   118     {
   101         delete iPreset;
   119         delete iPreset;
   102         iPreset = NULL;
   120         iPreset = NULL;
   103     }
   121     }
   115  
   133  
   116 }
   134 }
   117 
   135 
   118 void IRSearchChannelsView::loadLayout()
   136 void IRSearchChannelsView::loadLayout()
   119 {
   137 {
       
   138     LOG_METHOD;
   120     // Create widget hierarchy
   139     // Create widget hierarchy
   121     setObjectName( SEARCH_CHANNELS_VIEW_OBJECT_VIEW );
   140     setObjectName( SEARCH_CHANNELS_VIEW_OBJECT_VIEW );
   122     // List existing root elements - this allows us to refer to objects in the XML 
   141     // List existing root elements - this allows us to refer to objects in the XML 
   123     // which are created outside the document.
   142     // which are created outside the document.
   124     QObjectList roots;
   143     QObjectList roots;
   125     roots.append( this );
   144     roots.append( this );
   126     iLoader.setObjectTree( roots );
   145     iLoader.setObjectTree( roots );
   127     iLoader.load(SEARCH_CHANNELS_VIEW_LAYOUT_FILENAME);   
   146     iLoader.load(SEARCH_CHANNELS_VIEW_LAYOUT_FILENAME);   
   128     
   147     
   129     iSearchPanelWidget = qobject_cast<HbSearchPanel *>(iLoader.findWidget(SEARCH_CHANNELS_VIEW_SEARCHPANEL_WIDGET));    
   148     iSearchPanelWidget = qobject_cast<HbSearchPanel *>(iLoader.findWidget(SEARCH_CHANNELS_VIEW_SEARCHPANEL_WIDGET));    
   130     
   149     QString searchText;
       
   150     iSettings->getSearchText(searchText);
       
   151     iKeyText = searchText;
       
   152     iSearchPanelWidget->setCriteria(searchText);
       
   153    
   131     iListView = qobject_cast<HbListView *>(iLoader.findWidget(SEARCH_CHANNELS_VIEW_SEARCHLISTVIEW_WIDGET));   
   154     iListView = qobject_cast<HbListView *>(iLoader.findWidget(SEARCH_CHANNELS_VIEW_SEARCHLISTVIEW_WIDGET));   
   132     iListView->setFlag(ItemIsFocusable);
   155     iListView->setFlag(ItemIsFocusable);
   133     HbScrollBar *scrollbar = iListView->verticalScrollBar();
   156     HbScrollBar *scrollbar = iListView->verticalScrollBar();
   134     scrollbar->setVisible(true);
   157     scrollbar->setVisible(true);
   135     scrollbar->setInteractive(true);
   158     scrollbar->setInteractive(true);
   136     iListView->setVerticalScrollBarPolicy(HbScrollArea::ScrollBarAsNeeded);
   159     iListView->setVerticalScrollBarPolicy(HbScrollArea::ScrollBarAsNeeded);
   137     
   160     
   138     iChannelModel = new IrChannelModel(this);
   161     iChannelModel = new IrChannelModel(this);
   139     iChannelModel->initWithCache();
   162     iChannelModel->initWithCache();
   140     iListView->setModel(iChannelModel);     
   163     iListView->setModel(iChannelModel);
       
   164     scrollbar->setValue(0.0);    
       
   165     
       
   166     iListView->installEventFilter(this);
       
   167           
       
   168 #ifdef SUBTITLE_STR_BY_LOCID
       
   169     setTitle(hbTrId("txt_irad_title_internet_radio"));
       
   170          
       
   171 #else
       
   172     setTitle("Internet radio");      
       
   173 #endif
       
   174 
   141 }
   175 }
   142 
   176 
   143 void IRSearchChannelsView::connectWidget()
   177 void IRSearchChannelsView::connectWidget()
   144 {     
   178 {     
       
   179     LOG_METHOD;
   145     connect(iListView, SIGNAL(activated(const QModelIndex&)), this, SLOT(clickItem(const QModelIndex&)));
   180     connect(iListView, SIGNAL(activated(const QModelIndex&)), this, SLOT(clickItem(const QModelIndex&)));
   146     connect(iChannelModel, SIGNAL(dataAvailable()), this, SLOT(dataChanged()));
   181     connect(iChannelModel, SIGNAL(dataAvailable()), this, SLOT(dataChanged()));
   147     connect(iNetworkController, SIGNAL(networkRequestNotified(IRQNetworkEvent)), this, SLOT(networkRequestNotified(IRQNetworkEvent)));     
   182     connect(iNetworkController, SIGNAL(networkRequestNotified(IRQNetworkEvent)), this, SLOT(networkRequestNotified(IRQNetworkEvent)));     
   148     connect(iSearchPanelWidget,SIGNAL(criteriaChanged(const QString&)),this,SLOT(searchTextAlready(const QString&)));
   183     connect(iSearchPanelWidget,SIGNAL(criteriaChanged(const QString&)),this,SLOT(searchTextAlready(const QString&)));
   149     connect(iSearchPanelWidget, SIGNAL(exitClicked()), this, SLOT(minimizeSearchPanel()));
   184     connect(iSearchPanelWidget, SIGNAL(exitClicked()), this, SLOT(minimizeSearchPanel()));
   150 }
   185 }
   151 
   186 
   152 void IRSearchChannelsView::connectIsdsClient()
   187 void IRSearchChannelsView::connectIsdsClient()
   153 {
   188 {
       
   189     LOG_METHOD;
   154     connect(iIsdsClient, SIGNAL(channelItemsChanged(QList<IRQChannelItem *> *)),
   190     connect(iIsdsClient, SIGNAL(channelItemsChanged(QList<IRQChannelItem *> *)),
   155             iChannelModel, SLOT(updateData(QList<IRQChannelItem *> *)));    
   191             iChannelModel, SLOT(updateData(QList<IRQChannelItem *> *)));    
   156     connect(iIsdsClient, SIGNAL(operationException(IRQError)),
   192     connect(iIsdsClient, SIGNAL(operationException(IRQError)),
   157             this, SLOT(operationException(IRQError)));   
   193             this, SLOT(operationException(IRQError)));   
   158     connect(iIsdsClient, SIGNAL(presetResponse(IRQPreset *)),
   194     connect(iIsdsClient, SIGNAL(presetResponse(IRQPreset *)),
   165    
   201    
   166 }
   202 }
   167 
   203 
   168 void IRSearchChannelsView::disconnectIsdsClient()
   204 void IRSearchChannelsView::disconnectIsdsClient()
   169 { 
   205 { 
       
   206     LOG_METHOD;
   170     disconnect(iIsdsClient, SIGNAL(channelItemsChanged(QList<IRQChannelItem *> *)),
   207     disconnect(iIsdsClient, SIGNAL(channelItemsChanged(QList<IRQChannelItem *> *)),
   171             iChannelModel, SLOT(updateData(QList<IRQChannelItem *> *)));
   208             iChannelModel, SLOT(updateData(QList<IRQChannelItem *> *)));
   172     disconnect(iIsdsClient, SIGNAL(operationException(IRQError)), this,
   209     disconnect(iIsdsClient, SIGNAL(operationException(IRQError)), this,
   173             SLOT(operationException(IRQError))); 
   210             SLOT(operationException(IRQError))); 
   174     disconnect(iIsdsClient, SIGNAL(presetResponse(IRQPreset *)),
   211     disconnect(iIsdsClient, SIGNAL(presetResponse(IRQPreset *)),
   179                        this, SLOT(presetLogoDownloadError()));  
   216                        this, SLOT(presetLogoDownloadError()));  
   180 }
   217 }
   181 
   218 
   182 void IRSearchChannelsView::switch2InitState()
   219 void IRSearchChannelsView::switch2InitState()
   183 {    
   220 {    
       
   221     LOG_METHOD;
   184     iSearchState = ESearch_init;     
   222     iSearchState = ESearch_init;     
   185     iApplication->stopLoadingAnimation();
   223     iApplication->stopLoadingAnimation();
   186 } 
   224 } 
   187 
   225 
   188 void IRSearchChannelsView::switch2LoadingState()
   226 void IRSearchChannelsView::switch2LoadingState()
   189 {   
   227 {   
       
   228     LOG_METHOD;
   190     iSearchPanelWidget->clearFocus();
   229     iSearchPanelWidget->clearFocus();
   191     iListView->setFocus();
   230     iListView->setFocus();
   192     iSearchState = ESearch_Loading; 
   231     iSearchState = ESearch_Loading; 
   193     iApplication->startLoadingAnimation(this, SLOT(minimizeSearchPanel()));
   232     iApplication->startLoadingAnimation(this, SLOT(minimizeSearchPanel()));
   194 }
   233 }
   195 
   234 
   196 void IRSearchChannelsView::handleItemSelected()
   235 void IRSearchChannelsView::handleItemSelected()
   197 {
   236 {
       
   237     LOG_METHOD;
   198     if (iListView)
   238     if (iListView)
   199     {
   239     {
   200         int index = iListView->currentIndex().row();
   240         int index = iListView->currentIndex().row();
   201         IRQChannelItem* aItem = iChannelModel->getChannelItemByIndex(index);
   241         IRQChannelItem* aItem = iChannelModel->getChannelItemByIndex(index);
   202         if( NULL != aItem )
   242         if( NULL != aItem )
   206     }
   246     }
   207  
   247  
   208 }
   248 }
   209 
   249 
   210 void IRSearchChannelsView::cancelRequest()
   250 void IRSearchChannelsView::cancelRequest()
   211 {     
   251 {   
       
   252     LOG_METHOD;  
   212     iIsdsClient->isdsCancelRequest();    
   253     iIsdsClient->isdsCancelRequest();    
   213     switch2InitState(); 
   254     switch2InitState(); 
   214 } 
   255 } 
   215 
   256 
   216 void IRSearchChannelsView::networkRequestNotified(IRQNetworkEvent aEvent)
   257 void IRSearchChannelsView::networkRequestNotified(IRQNetworkEvent aEvent)
   217 {        
   258 {       
       
   259     LOG_METHOD;
       
   260     LOG_FORMAT("aEvent = %d", (int)aEvent ); 
   218     if (getViewManager()->currentView() != this)
   261     if (getViewManager()->currentView() != this)
   219     {       
   262     {       
   220         return;
   263         return;
   221     }
   264     }
   222     
   265     
   243     }   
   286     }   
   244 } 
   287 } 
   245 
   288 
   246 void IRSearchChannelsView::searchTextAlready(const QString& aSearchCriteria)
   289 void IRSearchChannelsView::searchTextAlready(const QString& aSearchCriteria)
   247 {
   290 {
       
   291     LOG_METHOD;
   248     iKeyText = aSearchCriteria.trimmed();
   292     iKeyText = aSearchCriteria.trimmed();
   249     
   293     
   250     if( iKeyText.isEmpty() )
   294     if( iKeyText.isEmpty() )
   251     {
   295     {
   252         //show some error info here to let user input some criteria
   296         //show some error info here to let user input some criteria
   274     iIsdsClient->isdsSearchRequest(iKeyText);    
   318     iIsdsClient->isdsSearchRequest(iKeyText);    
   275 }
   319 }
   276 
   320 
   277 void IRSearchChannelsView::operationException(IRQError aError)
   321 void IRSearchChannelsView::operationException(IRQError aError)
   278 {        
   322 {        
       
   323     LOG_METHOD;
   279     switch2InitState();
   324     switch2InitState();
   280     
   325     
   281     QString errStr;    
   326     QString errStr;    
   282     switch(aError)
   327     switch(aError)
   283     {
   328     {
   301     iChannelModel->cleanupDatabase();
   346     iChannelModel->cleanupDatabase();
   302 }
   347 }
   303 
   348 
   304 void IRSearchChannelsView::clickItem(const QModelIndex&)
   349 void IRSearchChannelsView::clickItem(const QModelIndex&)
   305 {
   350 {
       
   351     LOG_METHOD;
   306     setUseNetworkReason(EIR_UseNetwork_SelectItem);
   352     setUseNetworkReason(EIR_UseNetwork_SelectItem);
   307 #ifdef HS_WIDGET_ENABLED	
   353 #ifdef HS_WIDGET_ENABLED	
   308     int index = iListView->currentIndex().row();
   354     int index = iListView->currentIndex().row();
   309     IRQChannelItem* currentItem = iChannelModel->getChannelItemByIndex(index);    
   355     IRQChannelItem* currentItem = iChannelModel->getChannelItemByIndex(index);    
   310     iPlayController->setConnectingStationName(currentItem->channelName,true);
   356     iPlayController->setConnectingStationName(currentItem->channelName,true);
   321 }
   367 }
   322 
   368 
   323 
   369 
   324 void IRSearchChannelsView::presetResponse(IRQPreset *aPreset)
   370 void IRSearchChannelsView::presetResponse(IRQPreset *aPreset)
   325 {    
   371 {    
       
   372     LOG_METHOD;
   326     delete iPreset;
   373     delete iPreset;
   327     iPreset = aPreset;
   374     iPreset = aPreset;
   328     
   375     
   329     if (iPreset)
   376     if (iPreset)
   330     {
   377     {
   332     }
   379     }
   333 }
   380 }
   334 
   381 
   335 void IRSearchChannelsView::convertAnother()
   382 void IRSearchChannelsView::convertAnother()
   336 {
   383 {
       
   384     LOG_METHOD;
   337     iConvertTimer->stop();
   385     iConvertTimer->stop();
   338     int leftCount = iIconIndexArray.count();
   386     int leftCount = iIconIndexArray.count();
   339     
   387     
   340     if( leftCount > 0 )
   388     if( leftCount > 0 )
   341     { 
   389     { 
   343     }
   391     }
   344 }
   392 }
   345  
   393  
   346 void IRSearchChannelsView::dataChanged()
   394 void IRSearchChannelsView::dataChanged()
   347 {
   395 {
       
   396     LOG_METHOD;
   348     switch2InitState();      
   397     switch2InitState();      
   349     iListView->reset();
   398     iListView->reset();
   350     if( iChannelModel->rowCount() )
   399     if( iChannelModel->rowCount() )
   351     {
   400     {
   352         iListView->setCurrentIndex(iChannelModel->index(0));
   401         iListView->setCurrentIndex(iChannelModel->index(0));
   353         iListView->scrollTo(iChannelModel->index(0));         
   402         iListView->verticalScrollBar()->setValue(0.0);
   354     }
   403     }
   355     
   404     
   356     //we move the focus to the listview and the search panel will
   405     //we move the focus to the listview and the search panel will
   357     //hide the virtual keyboard at the same time
   406     //hide the virtual keyboard at the same time
   358     iListView->setFocus();            
   407     iListView->setFocus();            
   373     }   
   422     }   
   374 }
   423 }
   375 
   424 
   376 void IRSearchChannelsView::startConvert(int aIndex)
   425 void IRSearchChannelsView::startConvert(int aIndex)
   377 {
   426 {
       
   427     LOG_METHOD;
   378     QString url = iChannelModel->imageUrl(aIndex);
   428     QString url = iChannelModel->imageUrl(aIndex);
   379  
   429  
   380     IRQPreset tempPreset;
   430     IRQPreset tempPreset;
   381     tempPreset.imgUrl = url;
   431     tempPreset.imgUrl = url;
   382     tempPreset.type = IRQPreset::EIsds;
   432     tempPreset.type = IRQPreset::EIsds;
   398 }
   448 }
   399 
   449 
   400 //if the logo is downloaded ok
   450 //if the logo is downloaded ok
   401 void IRSearchChannelsView::presetLogoDownload(IRQPreset* aPreset)
   451 void IRSearchChannelsView::presetLogoDownload(IRQPreset* aPreset)
   402 {
   452 {
       
   453     LOG_METHOD;
   403     if( NULL == aPreset )
   454     if( NULL == aPreset )
   404     {
   455     {
   405         presetLogoDownloadError();
   456         presetLogoDownloadError();
   406         return;
   457         return;
   407     } 
   458     } 
   436 }
   487 }
   437 
   488 
   438 //if the logo download fails
   489 //if the logo download fails
   439 void IRSearchChannelsView::presetLogoDownloadError()
   490 void IRSearchChannelsView::presetLogoDownloadError()
   440 {
   491 {
       
   492     LOG_METHOD;
   441     // if the logo download fails, try to download the next
   493     // if the logo download fails, try to download the next
   442     iIconIndexArray.removeAt(0);
   494     iIconIndexArray.removeAt(0);
   443     int leftCount = iIconIndexArray.count();
   495     int leftCount = iIconIndexArray.count();
   444     if( leftCount > 0 )
   496     if( leftCount > 0 )
   445     {
   497     {
   447     }     
   499     }     
   448 }
   500 }
   449 
   501 
   450 void IRSearchChannelsView::minimizeSearchPanel()
   502 void IRSearchChannelsView::minimizeSearchPanel()
   451 {
   503 {
       
   504     LOG_METHOD;
   452     if( ESearch_Loading == iSearchState )
   505     if( ESearch_Loading == iSearchState )
   453     {
   506     {
   454         iPlayController->cancelBuffering(); 
   507         iPlayController->cancelBuffering(); 
   455         iIsdsClient->isdsCancelRequest();
   508         iIsdsClient->isdsCancelRequest();
   456         iConvertTimer->stop();
   509         iConvertTimer->stop();
   468     else
   521     else
   469     {
   522     {
   470         iSearchPanelWidget->clearFocus();
   523         iSearchPanelWidget->clearFocus();
   471         iListView->setFocus();        
   524         iListView->setFocus();        
   472     }
   525     }
       
   526 
       
   527     hideVkb();
   473 }
   528 }
   474  
   529  
   475 
   530 
   476 TIRHandleResult IRSearchChannelsView::handleCommand(TIRViewCommand aCommand,
   531 TIRHandleResult IRSearchChannelsView::handleCommand(TIRViewCommand aCommand,
   477         TIRViewCommandReason aReason)
   532         TIRViewCommandReason aReason)
   478 {
   533 {
       
   534     LOG_METHOD;
       
   535     LOG_FORMAT("aCommand = %d", (int)aCommand);
   479     TIRHandleResult ret = IRBaseView::handleCommand(aCommand, aReason);
   536     TIRHandleResult ret = IRBaseView::handleCommand(aCommand, aReason);
   480     
   537     
   481     switch (aCommand)
   538     switch (aCommand)
   482     {   
   539     {   
   483     case EIR_ViewCommand_ACTIVATED:         
   540     case EIR_ViewCommand_ACTIVATED:         
   500     }
   557     }
   501     
   558     
   502     return ret;
   559     return ret;
   503 }
   560 }
   504 
   561 
   505 
   562 bool IRSearchChannelsView::eventFilter(QObject *object, QEvent *event)
   506  
   563 {
   507 
   564     if( object == iListView
   508 
   565         && event->type() == QEvent::FocusOut )
       
   566     {
       
   567         hideVkb();
       
   568     }
       
   569   
       
   570     return false;
       
   571 }
       
   572 void IRSearchChannelsView::hideVkb()
       
   573 {
       
   574     QInputContext *ic = qApp->inputContext(); 
       
   575     if (ic)
       
   576     {
       
   577         QEvent *event = new QEvent(QEvent::CloseSoftwareInputPanel);
       
   578         ic->filterEvent(event);
       
   579         delete event;
       
   580     }
       
   581 }
       
   582 
       
   583