mpdata/src/mpmpxcollectiondata_p.cpp
changeset 54 c5b304f4d89b
parent 48 af3740e3753f
equal deleted inserted replaced
48:af3740e3753f 54:c5b304f4d89b
    36 
    36 
    37 /*!
    37 /*!
    38  \internal
    38  \internal
    39  */
    39  */
    40 MpMpxCollectionDataPrivate::MpMpxCollectionDataPrivate( MpMpxCollectionData *wrapper )
    40 MpMpxCollectionDataPrivate::MpMpxCollectionDataPrivate( MpMpxCollectionData *wrapper )
    41     : q_ptr( wrapper ),
    41     : q_ptr(wrapper),
    42       iContext( ECollectionContextUnknown ),
    42       iContext(ECollectionContextUnknown),
    43       iContainerMedia(0),
    43       iContainerMedia(0),
    44       iMediaArray(0),
    44       iMediaArray(0),
    45       iCachedRemovedItem(0),
    45       iCachedRemovedItem(0),
    46       iCurrentAlbumIndex(-1),
    46       iCurrentAlbumIndex(-1),
    47       iAlbumSongCount(0)
    47       iAlbumSongCount(0),
       
    48       iReloadAlbumContent(false),
       
    49 	  iNeedReload(false)
    48 {
    50 {
    49     TX_LOG
    51     TX_LOG
    50 }
    52 }
    51 
    53 
    52 /*!
    54 /*!
    97 }
    99 }
    98 
   100 
    99 /*!
   101 /*!
   100  \internal
   102  \internal
   101  */
   103  */
   102 QString MpMpxCollectionDataPrivate::itemData( int index, MpMpxCollectionData::DataType type ) const
   104 QString MpMpxCollectionDataPrivate::itemData( int index, MpMpxCollectionData::DataType type )
   103 {
   105 {
   104     TX_ENTRY_ARGS("index=" << index << ", type=" << type);
   106     TX_ENTRY_ARGS("index=" << index << ", type=" << type);
   105     QString data;
   107     QString data;
   106     TRAPD(err, DoGetDataL(index, type, data));
   108     TRAPD(err, DoGetDataL(index, type, data));
   107     if ( err != KErrNone ) {
   109     if ( err != KErrNone ) {
   312     if ( err != KErrNone ) {
   314     if ( err != KErrNone ) {
   313         TX_LOG_ARGS("Error: " << err << "; should never get here.");
   315         TX_LOG_ARGS("Error: " << err << "; should never get here.");
   314     }
   316     }
   315     TX_EXIT
   317     TX_EXIT
   316     return data;
   318     return data;
       
   319 }
       
   320 
       
   321 /*!
       
   322  \internal
       
   323  */
       
   324 bool MpMpxCollectionDataPrivate::hasItemProperty( int index, MpMpxCollectionData:: DataProperty type ) const
       
   325 {
       
   326     TX_ENTRY_ARGS("index=" << index << ", type=" << type);
       
   327     bool available = false;
       
   328     TRAPD(err, available = DoHasItemPropertyL(index, type));
       
   329     if ( err != KErrNone ) {
       
   330         TX_LOG_ARGS("Error: " << err << "; should never get here.");
       
   331     }
       
   332     TX_EXIT
       
   333     return available;
       
   334 }
       
   335 
       
   336 /*!
       
   337  \internal
       
   338  */
       
   339 bool MpMpxCollectionDataPrivate::hasAlbumSongProperty( int index, MpMpxCollectionData:: DataProperty type ) const
       
   340 {
       
   341     TX_ENTRY_ARGS("index=" << index << ", type=" << type);
       
   342     bool available = false;
       
   343     TRAPD(err, available = DoHasAlbumSongPropertyL(index, type));
       
   344     if ( err != KErrNone ) {
       
   345         TX_LOG_ARGS("Error: " << err << "; should never get here.");
       
   346     }
       
   347     TX_EXIT
       
   348     return available;
   317 }
   349 }
   318 
   350 
   319 /*!
   351 /*!
   320  \internal
   352  \internal
   321  New data from MPX collection. This could be due to Open operation, in which case
   353  New data from MPX collection. This could be due to Open operation, in which case
   411     TX_EXIT
   443     TX_EXIT
   412 }
   444 }
   413 
   445 
   414 /*!
   446 /*!
   415  \internal
   447  \internal
       
   448  This indicates data update during incremental open operation. This indicates
       
   449  that media received in setMpxMedia() has updates.
       
   450  */
       
   451 void MpMpxCollectionDataPrivate::incrementalOpenUpdate()
       
   452 {
       
   453     TX_ENTRY_ARGS( "iNeedReload=" << iNeedReload);
       
   454     if ( iNeedReload ) {
       
   455         if ( itemId(iReloadRange.second) != -1 ) {
       
   456             iNeedReload = false;
       
   457             emit q_ptr->dataChanged(iReloadRange.first, iReloadRange.second);
       
   458         }
       
   459     }
       
   460     TX_EXIT
       
   461 }
       
   462 
       
   463 /*!
       
   464  \internal
   416  */
   465  */
   417 const CMPXMedia& MpMpxCollectionDataPrivate::containerMedia()
   466 const CMPXMedia& MpMpxCollectionDataPrivate::containerMedia()
   418 {
   467 {
   419     return *iContainerMedia;
   468     return *iContainerMedia;
   420 }
   469 }
   453    Currently only used to lookup playing song album id to index of albums on 
   502    Currently only used to lookup playing song album id to index of albums on 
   454    media wall.
   503    media wall.
   455  */
   504  */
   456 int MpMpxCollectionDataPrivate::itemIndex( int itemUniqueId )
   505 int MpMpxCollectionDataPrivate::itemIndex( int itemUniqueId )
   457 {
   506 {
   458     return albumIdIndexMapping.value( itemUniqueId, -1 );
   507     return iAlbumIdIndexMapping.value( itemUniqueId, -1 );
   459 }
   508 }
   460 
   509 
   461 /*!
   510 /*!
   462  \internal
   511  \internal
   463    Currently only used to lookup playing song id to index of song in the 
   512    Currently only used to lookup playing song id to index of song in the 
   464    current album on media wall.
   513    current album on media wall.
   465  */
   514  */
   466 int MpMpxCollectionDataPrivate::albumSongIndex( int songUniqueId )
   515 int MpMpxCollectionDataPrivate::albumSongIndex( int songUniqueId )
   467 {
   516 {
   468     return albumSongIdIndexMapping.value( songUniqueId, -1 );
   517     return iAlbumSongIdIndexMapping.value( songUniqueId, -1 );
   469 }
   518 }
   470 
   519 
       
   520 /*!
       
   521  \internal
       
   522    Use to lookup playing song id to index of song in collection and playlist
       
   523    view 
       
   524  */
       
   525 QList<int>  MpMpxCollectionDataPrivate::songIndex( int songUniqueId )
       
   526 {
       
   527     TX_ENTRY
       
   528     if(iSongIdIndexMapping.empty()){
       
   529         for ( int i = count() - 1 ; i >= 0 ; i-- ) {
       
   530             iSongIdIndexMapping.insertMulti( itemId2( i ) , i );
       
   531         }
       
   532     }
       
   533     TX_EXIT
       
   534     return iSongIdIndexMapping.values( songUniqueId );
       
   535 }
       
   536 
       
   537 /*!
       
   538  \internal
       
   539    Set item at index to corrupted depends on if viewing TBone
       
   540  */
       
   541 void MpMpxCollectionDataPrivate::setCorruptValue( QModelIndex index, bool tBone)
       
   542 {
       
   543     TX_ENTRY
       
   544     TRAPD(err, DoSetCorruptValueL(index, tBone));
       
   545     if ( err != KErrNone ) {
       
   546         TX_LOG_ARGS("Error: " << err << "; should never get here.");
       
   547     }
       
   548     TX_EXIT
       
   549 }
       
   550 
       
   551 /*!
       
   552  \internal
       
   553  */
       
   554 void MpMpxCollectionDataPrivate::setReloadAlbumContent( bool reloadAlbum )
       
   555 {
       
   556     iReloadAlbumContent = reloadAlbum;
       
   557 }
   471 
   558 
   472 /*!
   559 /*!
   473  \internal
   560  \internal
   474  */
   561  */
   475 void MpMpxCollectionDataPrivate::loadAlbumsLookup()
   562 void MpMpxCollectionDataPrivate::loadAlbumsLookup()
   476 {
   563 {
   477     //Clearing all the album ids.
   564     //Clearing all the album ids.
   478     albumIdIndexMapping.clear();
   565     iAlbumIdIndexMapping.clear();
   479     if ( iContext == ECollectionContextAlbumsMediaWall) {
   566     if ( iContext == ECollectionContextAlbumsMediaWall) {
   480         //Adding album ids and indixes to the hash, for itemIndex lookup.
   567         //Adding album ids and indixes to the hash, for itemIndex lookup.
   481         //This is disabled for other containers to save resources.
   568         //This is disabled for other containers to save resources.
   482         for ( int i = count() - 1 ; i >= 0 ; i-- ) {
   569         for ( int i = count() - 1 ; i >= 0 ; i-- ) {
   483             albumIdIndexMapping.insert( itemId( i ) , i );
   570             iAlbumIdIndexMapping.insert( itemId( i ) , i );
   484         }
   571         }
   485     }
   572     }
   486 }
   573 }
   487 
   574 
   488 /*!
   575 /*!
   489  \internal
   576  \internal
   490  */
   577  */
   491 void MpMpxCollectionDataPrivate::loadAlbumSongsLookup()
   578 void MpMpxCollectionDataPrivate::loadAlbumSongsLookup()
   492 {
   579 {
   493     //Clearing all the song ids.
   580     //Clearing all the song ids.
   494     albumSongIdIndexMapping.clear();
   581     iAlbumSongIdIndexMapping.clear();
   495     if ( iContext == ECollectionContextAlbumsMediaWall) {
   582     //Adding album song ids and indixes to the hash, for albumSongIndex lookup.
   496         //Adding album song ids and indixes to the hash, for albumSongIndex lookup.
   583     //This is disabled for other containers to save resources.
   497         //This is disabled for other containers to save resources.
   584     for ( int i = albumSongsCount() - 1 ; i >= 0 ; i-- ) {
   498         for ( int i = albumSongsCount() - 1 ; i >= 0 ; i-- ) {
   585         iAlbumSongIdIndexMapping.insert( albumSongId( i ) , i );
   499             albumSongIdIndexMapping.insert( albumSongId( i ) , i );
   586     }
   500         }
   587 }
   501     }
   588 
   502 }
   589 /*!
   503 
   590  \internal
   504 /*!
   591  */
   505  \internal
   592 void MpMpxCollectionDataPrivate::setReloadRange( int index )
   506  */
   593 {
   507 void MpMpxCollectionDataPrivate::DoGetDataL( int index, MpMpxCollectionData::DataType type, QString& data ) const
   594     TX_ENTRY_ARGS( "index=" << index);
       
   595     if ( !iNeedReload ) {
       
   596         iNeedReload = true;
       
   597         iReloadRange.first = index;
       
   598         iReloadRange.second = index;
       
   599     }
       
   600     else if ( index < iReloadRange.first ) {
       
   601         iReloadRange.first = index;
       
   602     }
       
   603     else if ( index > iReloadRange.second ) {
       
   604         iReloadRange.second = index;
       
   605     }
       
   606     TX_EXIT
       
   607 }
       
   608 
       
   609 /*!
       
   610  \internal
       
   611  */
       
   612 int MpMpxCollectionDataPrivate::itemId2( int index )
       
   613 {
       
   614     TX_ENTRY_ARGS( "index=" << index );
       
   615     int id = -1;
       
   616     TRAPD( err, id = DoGetItemId2L( index ) );
       
   617     if ( err == KErrNone ) {
       
   618         TX_LOG_ARGS( "id=" << id );
       
   619     }
       
   620     else {
       
   621         TX_LOG_ARGS( "Error: " << err << "; should never get here." );
       
   622     }
       
   623     TX_EXIT
       
   624     return id;
       
   625 }
       
   626 
       
   627 /*!
       
   628  \internal
       
   629  */
       
   630 void MpMpxCollectionDataPrivate::DoGetDataL( int index, MpMpxCollectionData::DataType type, QString& data )
   508 {
   631 {
   509     TX_ENTRY
   632     TX_ENTRY
   510     CMPXMedia* currentMedia( iMediaArray->AtL( index ) );
   633     CMPXMedia* currentMedia( iMediaArray->AtL( index ) );
       
   634 
       
   635     if ( currentMedia->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId) == KMPXInvalidItemId ) {
       
   636         // Accessing a data that hasn't been fully fetched from the collection.
       
   637         // This can happen during incremental open. Set the index as reload candidate.
       
   638         setReloadRange(index);
       
   639     }
   511 
   640 
   512     TBuf<10> countBuf;
   641     TBuf<10> countBuf;
   513     TInt count = 0;
   642     TInt count = 0;
   514     switch ( type ) {
   643     switch ( type ) {
   515         case MpMpxCollectionData::Title:
   644         case MpMpxCollectionData::Title:
   629  \internal
   758  \internal
   630  */
   759  */
   631 int MpMpxCollectionDataPrivate::DoGetItemIdL( int index )
   760 int MpMpxCollectionDataPrivate::DoGetItemIdL( int index )
   632 {
   761 {
   633     CMPXMedia* currentMedia( iMediaArray->AtL( index ) );
   762     CMPXMedia* currentMedia( iMediaArray->AtL( index ) );
   634     if ( !currentMedia->IsSupported( KMPXMediaGeneralId ) ) {
   763     if ( currentMedia->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId) == KMPXInvalidItemId ) {
   635         User::Leave(KErrNotFound);
   764         return -1;
   636     }
   765     }
   637     return currentMedia->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId );
   766     else {
       
   767         int id1 = (currentMedia->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId )).iId1;
       
   768         int id2 = (currentMedia->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId )).iId2;
       
   769         TX_LOG_ARGS( "id1=" << id1 << ", id2=" << id2 );
       
   770         return (currentMedia->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId )).iId1;
       
   771     }
       
   772 }
       
   773 
       
   774 /*!
       
   775  \internal
       
   776  */
       
   777 int MpMpxCollectionDataPrivate::DoGetItemId2L( int index )
       
   778 {
       
   779     CMPXMedia* currentMedia( iMediaArray->AtL( index ) );
       
   780     if ( currentMedia->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId) == KMPXInvalidItemId ) {
       
   781         return -1;
       
   782     }
       
   783     else {
       
   784         return (currentMedia->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId )).iId2;
       
   785     }
   638 }
   786 }
   639 
   787 
   640 /*!
   788 /*!
   641  \internal
   789  \internal
   642  */
   790  */
   644 {
   792 {
   645     CMPXMedia* album( iMediaArray->AtL( iCurrentAlbumIndex ) );
   793     CMPXMedia* album( iMediaArray->AtL( iCurrentAlbumIndex ) );
   646     const CMPXMediaArray* songs = album->Value<CMPXMediaArray>(KMPXMediaArrayContents);
   794     const CMPXMediaArray* songs = album->Value<CMPXMediaArray>(KMPXMediaArrayContents);
   647     User::LeaveIfNull(const_cast<CMPXMediaArray*>(songs));
   795     User::LeaveIfNull(const_cast<CMPXMediaArray*>(songs));
   648     CMPXMedia* song = songs->AtL(index);
   796     CMPXMedia* song = songs->AtL(index);
   649     if ( !song->IsSupported( KMPXMediaGeneralId ) ) {
   797     if ( song->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId) == KMPXInvalidItemId ) {
   650         User::Leave(KErrNotFound);
   798         return -1;
   651     }
   799     }
   652     return song->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId );
   800     else {
       
   801         return song->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId );
       
   802     }
   653 }
   803 }
   654 
   804 
   655 /*!
   805 /*!
   656  \internal
   806  \internal
   657  */
   807  */
   681 {
   831 {
   682     TX_ENTRY_ARGS( "index=" << index);
   832     TX_ENTRY_ARGS( "index=" << index);
   683     iCurrentAlbumIndex = index;
   833     iCurrentAlbumIndex = index;
   684 
   834 
   685     bool songsAvailable = false;
   835     bool songsAvailable = false;
   686     CMPXMedia* album( iMediaArray->AtL( index ) );
   836     if (!iReloadAlbumContent){    
   687     if ( album->IsSupported(KMPXMediaArrayContents) ) {
   837         CMPXMedia* album( iMediaArray->AtL( index ) );
   688         // We've previously fetched the songs for this album so
   838         if ( album->IsSupported(KMPXMediaArrayContents) ) {
   689         // all we do now is populate the list with the song titles.
   839             // We've previously fetched the songs for this album so
   690         const CMPXMediaArray* songs = album->Value<CMPXMediaArray>(KMPXMediaArrayContents);
   840             // all we do now is populate the list with the song titles.
   691         iAlbumSongCount = songs->Count();
   841             const CMPXMediaArray* songs = album->Value<CMPXMediaArray>(KMPXMediaArrayContents);
   692         songsAvailable = true;
   842             iAlbumSongCount = songs->Count();
   693         TX_LOG_ARGS("Songs available.");
   843             songsAvailable = true;
   694         loadAlbumSongsLookup();
   844             TX_LOG_ARGS("Songs available.");
   695         emit q_ptr->refreshAlbumSongs();
   845             loadAlbumSongsLookup();
       
   846             emit q_ptr->refreshAlbumSongs();
       
   847         }
   696     }
   848     }
   697     TX_EXIT
   849     TX_EXIT
   698     return songsAvailable;
   850     return songsAvailable;
   699 }
   851 }
   700 
   852 
   735 }
   887 }
   736 
   888 
   737 /*!
   889 /*!
   738  \internal
   890  \internal
   739  */
   891  */
       
   892 bool MpMpxCollectionDataPrivate::DoHasItemPropertyL( int index, MpMpxCollectionData:: DataProperty type ) const
       
   893 {
       
   894     TX_ENTRY
       
   895     CMPXMedia* currentMedia( iMediaArray->AtL( index ) );
       
   896 
       
   897     TInt flags(0);
       
   898     if ( currentMedia->IsSupported( KMPXMediaGeneralFlags ) ) {
       
   899         flags = currentMedia->ValueTObjectL<TUint>( KMPXMediaGeneralFlags );
       
   900     }
       
   901     switch ( type ) {
       
   902         case MpMpxCollectionData::Corrupted:
       
   903             if ( ( flags ) & ( KMPXMediaGeneralFlagsIsCorrupted ) ){
       
   904                 return true;
       
   905             }
       
   906             break;
       
   907         case MpMpxCollectionData::DrmExpired:
       
   908             if ( ( flags ) & ( KMPXMediaGeneralFlagsIsDrmLicenceInvalid ) ){
       
   909                 return true;
       
   910             }
       
   911             break;
       
   912         default:
       
   913             break;
       
   914     }
       
   915     TX_EXIT
       
   916     return false;    
       
   917 }
       
   918 
       
   919 /*!
       
   920  \internal
       
   921  */
       
   922 bool MpMpxCollectionDataPrivate::DoHasAlbumSongPropertyL( int index, MpMpxCollectionData:: DataProperty type ) const
       
   923 {
       
   924     TX_ENTRY
       
   925     CMPXMedia* album( iMediaArray->AtL( iCurrentAlbumIndex ) );
       
   926     if ( album->IsSupported(KMPXMediaArrayContents) ) {
       
   927         const CMPXMediaArray* songs = album->Value<CMPXMediaArray>(KMPXMediaArrayContents);
       
   928         User::LeaveIfNull(const_cast<CMPXMediaArray*>(songs));
       
   929         CMPXMedia* song = songs->AtL(index);
       
   930         TInt flags(0);
       
   931         if ( song->IsSupported( KMPXMediaGeneralFlags ) ) {
       
   932             flags = song->ValueTObjectL<TUint>( KMPXMediaGeneralFlags );
       
   933         }
       
   934         switch ( type ) {
       
   935             case MpMpxCollectionData::Corrupted:
       
   936                 if ( ( flags ) & ( KMPXMediaGeneralFlagsIsCorrupted ) ){
       
   937                     return true;
       
   938                 }
       
   939                 break;
       
   940             case MpMpxCollectionData::DrmExpired:
       
   941                 if ( ( flags ) & ( KMPXMediaGeneralFlagsIsDrmLicenceInvalid ) ){
       
   942                     return true;
       
   943                 }
       
   944                 break;
       
   945             default:
       
   946                 break;
       
   947         }
       
   948         
       
   949     }
       
   950     TX_EXIT
       
   951     return false;    
       
   952 }
       
   953 /*!
       
   954  \internal
       
   955  */
   740 void MpMpxCollectionDataPrivate::SetCollectionContextL()
   956 void MpMpxCollectionDataPrivate::SetCollectionContextL()
   741 {
   957 {
   742     TX_ENTRY
   958     TX_ENTRY
       
   959 	// Clear Song Index Hash when context switched
       
   960     iSongIdIndexMapping.clear();
   743     TMPXGeneralType containerType( EMPXNoType );
   961     TMPXGeneralType containerType( EMPXNoType );
   744     if ( iContainerMedia->IsSupported( KMPXMediaGeneralType ) ) {
   962     if ( iContainerMedia->IsSupported( KMPXMediaGeneralType ) ) {
   745         containerType = iContainerMedia->ValueTObjectL<TMPXGeneralType>( KMPXMediaGeneralType );
   963         containerType = iContainerMedia->ValueTObjectL<TMPXGeneralType>( KMPXMediaGeneralType );
   746     }
   964     }
   747 
   965 
   800     delete iContainerMedia;
  1018     delete iContainerMedia;
   801     iContainerMedia = 0;
  1019     iContainerMedia = 0;
   802     iContainerMedia = CMPXMedia::NewL(entries);
  1020     iContainerMedia = CMPXMedia::NewL(entries);
   803     iMediaArray = const_cast<CMPXMediaArray*>(iContainerMedia->Value<CMPXMediaArray>( KMPXMediaArrayContents ) );
  1021     iMediaArray = const_cast<CMPXMediaArray*>(iContainerMedia->Value<CMPXMediaArray>( KMPXMediaArrayContents ) );
   804     TX_LOG_ARGS("media count=" << iMediaArray->Count() );
  1022     TX_LOG_ARGS("media count=" << iMediaArray->Count() );
   805 
  1023     iReloadAlbumContent = false;
   806     SetCollectionContextL();
  1024     SetCollectionContextL();
   807     TX_EXIT
  1025     TX_EXIT
   808 }
  1026 }
   809 
  1027 
   810 /*!
  1028 /*!
   827         albumMedia->SetTObjectValueL<TInt>(KMPXMediaArrayCount, iAlbumSongCount);
  1045         albumMedia->SetTObjectValueL<TInt>(KMPXMediaArrayCount, iAlbumSongCount);
   828     }
  1046     }
   829     TX_EXIT
  1047     TX_EXIT
   830 }
  1048 }
   831 
  1049 
   832 
  1050 /*!
       
  1051  \internal
       
  1052  */
       
  1053 void MpMpxCollectionDataPrivate::DoSetCorruptValueL(QModelIndex index, bool tBone)
       
  1054 {
       
  1055     TX_ENTRY
       
  1056     if (tBone){
       
  1057         CMPXMedia* album( iMediaArray->AtL( iCurrentAlbumIndex ) );
       
  1058         if ( album->IsSupported(KMPXMediaArrayContents) ) {
       
  1059             const CMPXMediaArray* songs = album->Value<CMPXMediaArray>(KMPXMediaArrayContents);
       
  1060             User::LeaveIfNull(const_cast<CMPXMediaArray*>(songs));
       
  1061             CMPXMedia* song = songs->AtL( index.row() );
       
  1062             song->SetTObjectValueL<TUint>( KMPXMediaGeneralFlags,KMPXMediaGeneralFlagsIsCorrupted );
       
  1063         }
       
  1064     }
       
  1065     else {
       
  1066         CMPXMedia* song( iMediaArray->AtL( index.row() ) );
       
  1067         song->SetTObjectValueL<TUint>( KMPXMediaGeneralFlags,KMPXMediaGeneralFlagsIsCorrupted );        
       
  1068     }
       
  1069     TX_EXIT  
       
  1070 }
       
  1071