clfwrapper/ClientSrc/CCLFServerProxy.cpp
changeset 0 c53acadfccc6
child 1 acef663c1218
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clfwrapper/ClientSrc/CCLFServerProxy.cpp	Mon Jan 18 20:34:07 2010 +0200
@@ -0,0 +1,1291 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+// INCLUDE FILES
+#include <PathInfo.h>
+#include <driveinfo.h>
+#include <s32mem.h>
+#include <bautils.h>
+#include <mdeobjectquery.h>
+#include <mdeconstants.h>
+#include <collate.h>
+#include "CLFConsts.h"
+#include "CLFPanics.h"
+#include "CCLFServerProxy.h"
+#include "mdsutils.h"
+
+// CONSTANTS
+const TInt KCLFDefaultBufferLength( 64 );
+const TInt KCLFDefaultArrayGranularity( 4 );
+const TInt KCLFExtensionArrayGranularity( 49 );
+
+_LIT( KCLFDriveLetterFormatString, ":\\" );
+const TInt KCLFDriveC( 'C' );
+
+const TInt KDelayNotityCLFGetUpdateEventMaxTimes = 30;
+const TInt KCLFWrapperHarvesterEventInterval = 60;
+
+_LIT( KExtensionMp3,    "mp3" );
+_LIT( KExtensionAac,    "aac" );
+_LIT( KExtensionAmr,    "amr" );
+_LIT( KExtensionAwb,    "awb" );
+_LIT( KExtensionMid,    "mid" );
+_LIT( KExtensionMidi,   "midi" );
+_LIT( KExtensionSpMid,  "spmid" );
+_LIT( KExtensionRng,    "rng" );
+_LIT( KExtensionMxmf,   "mxmf" );
+_LIT( KExtensionWav,    "wav" );
+_LIT( KExtensionAu,     "au" );
+_LIT( KExtensionWma,    "wma" );
+_LIT( KExtensionNrt,    "nrt" );
+_LIT( KExtensionRa,    "ra" );
+
+_LIT( KExtJpg, "JPG" );
+_LIT( KExtJpeg, "JPEG" );
+_LIT( KExtJp2, "JP2" );
+_LIT( KExtJ2k, "J2K" ); 
+_LIT( KExtJpx, "JPX" ); 
+_LIT( KExtJpf, "JPF" );
+_LIT( KExtMbm, "MBM" ); 
+_LIT( KExtPng, "PNG" );
+_LIT( KExtGif, "GIF" );
+_LIT( KExtBmp, "BMP" );
+_LIT( KExtTif, "TIF" );
+_LIT( KExtTiff, "TIFF" );
+_LIT( KExtOta, "OTA" );
+_LIT( KExtWbmp, "WBMP" );
+_LIT( KExtWmf, "WMF" ); 
+_LIT( KExtOtb, "OTB" ); 
+
+_LIT(KExtOma1, "dcf");
+_LIT(KExtOma2, "odf");
+_LIT(KExtOma3, "dm");
+_LIT(KExtOma4, "o4a");
+_LIT(KExtOma5, "o4v");
+
+_LIT( KExtensionMp4,   "mp4" );
+_LIT( KExtensionMpg4,  "mpg4" );
+_LIT( KExtensionMpeg4, "mpeg4" );
+_LIT( KExtensionM4v,   "m4v" );
+_LIT( KExtensionM4a,   "m4a" );
+_LIT( KExtension3gp,   "3gp" );
+_LIT( KExtension3gpp,  "3gpp" );
+_LIT( KExtension3g2,   "3g2" );
+_LIT( KExtensionRm,    "rm" );
+_LIT( KExtensionRmvb,  "rmvb" );
+_LIT( KExtensionRam,   "ram" );
+_LIT( KExtensionRv,    "rv" );
+_LIT( KExtensionWmv,    "wmv" );
+_LIT( KExtensionAvi,    "avi" );
+
+// ======== MEMBER FUNCTIONS ========
+
+// -----------------------------------------------------------------------------
+// CItemsDeletedHandler::CUpdateItemsHandler
+// -----------------------------------------------------------------------------
+//
+inline CUpdateItemsHandler::CUpdateItemsHandler()
+    : iWasNotificationHandled( EFalse ), iParentObserver( NULL ),
+      iParentPresentObserver( NULL ), iRemoveObserver( EFalse )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::Start
+// -----------------------------------------------------------------------------
+//
+void CUpdateItemsHandler::StartScheduler()
+    {
+    if( !iScheduler.IsStarted() )
+        {
+        iScheduler.Start();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::AsyncStop
+// -----------------------------------------------------------------------------
+//
+void CUpdateItemsHandler::AsyncStopScheduler()
+    {
+    iScheduler.AsyncStop();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::WasNotificationHandled
+// -----------------------------------------------------------------------------
+//
+TBool CUpdateItemsHandler::WasNotificationHandled() const
+    {
+    return iWasNotificationHandled;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::WasNotificationHandled
+// -----------------------------------------------------------------------------
+//
+void CUpdateItemsHandler::SetRemoveObserverFlag( TBool aRemove )
+    {
+    iRemoveObserver = aRemove;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::NewL
+// -----------------------------------------------------------------------------
+//
+CUpdateIDsHandler* CUpdateIDsHandler::NewL( const TArray< TCLFItemId >& aItemIDArray )
+    {
+    CUpdateIDsHandler* self = new( ELeave ) CUpdateIDsHandler( aItemIDArray );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::~CUpdateIDsHandler
+// -----------------------------------------------------------------------------
+//
+CUpdateIDsHandler::~CUpdateIDsHandler()
+    {
+    iIdsPendingUpdate.Reset();
+
+    if ( iScheduler.IsStarted() )
+        {
+        iScheduler.AsyncStop();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::~CUpdateFoldersHandler
+// -----------------------------------------------------------------------------
+//
+void CUpdateIDsHandler::StartHandlingL()
+    {
+    // Pass through.
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::HandleObjectNotification
+// -----------------------------------------------------------------------------
+//
+void CUpdateIDsHandler::HandleObjectNotification( const TItemId aId, TObserverNotificationType /* aType */ )
+    {
+    iWasNotificationHandled = EFalse;
+
+    TInt index = iIdsPendingUpdate.Find( aId );
+    if ( index != KErrNotFound )
+        {
+        iWasNotificationHandled = ETrue;
+        iIdsPendingUpdate.Remove( index );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::AllDone
+// -----------------------------------------------------------------------------
+//
+TBool CUpdateIDsHandler::AllDone() const
+    {
+    return iIdsPendingUpdate.Count() == 0 ? ETrue : EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::CUpdateIDsHandler
+// -----------------------------------------------------------------------------
+//
+inline CUpdateIDsHandler::CUpdateIDsHandler( const TArray< TCLFItemId >& aItemIDArray )
+    {
+    const TInt idCount( aItemIDArray.Count() );
+    for ( TInt i = 0; i < idCount; ++i )
+        {
+        if ( iIdsPendingUpdate.Find( aItemIDArray[ i ] ) == KErrNotFound )
+            {
+            iIdsPendingUpdate.Append( aItemIDArray[ i ] );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CItemsDeletedHandler::NewL
+// -----------------------------------------------------------------------------
+//
+CItemsDeletedHandler* CItemsDeletedHandler::NewL( CMdESession& aMdESession, 
+                                                                                    const CDesCArray& aUriArray,
+                                                                                    MMdEObjectObserver* aParentObserver,
+                                                                                    MMdEObjectPresentObserver* aParentPresentObserver )
+    {
+    CItemsDeletedHandler* self = new( ELeave ) CItemsDeletedHandler( aMdESession );
+    CleanupStack::PushL( self );
+    self->ConstructL( aUriArray, aParentObserver, aParentPresentObserver );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CItemsDeletedHandler::~CUpdateItemsHandlerWithIDs
+// -----------------------------------------------------------------------------
+//
+CItemsDeletedHandler::~CItemsDeletedHandler()
+    {
+    if( iRemoveObserver )
+        {
+        TRAP_IGNORE( iMdESession.RemoveObjectObserverL( *iParentObserver ) );
+        TRAP_IGNORE( iMdESession.RemoveObjectPresentObserverL( *iParentPresentObserver ) );
+        }
+    iIdsPendingRemoval.Reset();
+    iObjectsPendingRemoval.ResetAndDestroy();
+    
+    if ( iScheduler.IsStarted() )
+        {
+        iScheduler.AsyncStop();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::StartHandlingL
+// -----------------------------------------------------------------------------
+//
+void CItemsDeletedHandler::StartHandlingL()
+    {
+    const TInt count( iObjectsPendingRemoval.Count() );
+    for ( TInt i = 0; i < count; ++i )
+        {
+        // If object for URI to be removed is in MDS, then remove it from MDS. Obviates
+        // the need to rely on unreliable filemonitorplugin.
+        const TItemId id = iMdESession.RemoveObjectL( iObjectsPendingRemoval[ i ]->Id() );
+        
+        if ( id != KNoId )
+            {
+            iIdsPendingRemoval.Append( id );
+            }
+        }
+    iObjectsPendingRemoval.ResetAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// CItemsDeletedHandler::HandleObjectNotification
+// -----------------------------------------------------------------------------
+//
+void CItemsDeletedHandler::HandleObjectNotification( const TItemId aId, TObserverNotificationType aType )
+    {
+    iWasNotificationHandled = EFalse;
+
+    if ( aType == ENotifyRemove )
+        {
+        TInt index = iIdsPendingRemoval.Find( aId );
+        if ( index != KErrNotFound )
+            {
+            iWasNotificationHandled = ETrue;
+            iIdsPendingRemoval.Remove( index );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateIDsHandler::AllDone
+// -----------------------------------------------------------------------------
+//
+TBool CItemsDeletedHandler::AllDone() const
+    {
+    return iIdsPendingRemoval.Count() == 0 ? ETrue : EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CItemsDeletedHandler::CItemsDeletedHandler
+// -----------------------------------------------------------------------------
+//
+inline CItemsDeletedHandler::CItemsDeletedHandler( CMdESession& aMdESession )
+      : iMdESession( aMdESession )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CItemsDeletedHandler::ConstructL
+// -----------------------------------------------------------------------------
+//
+inline void CItemsDeletedHandler::ConstructL( const CDesCArray& aUriArray,
+                                                                            MMdEObjectObserver* aParentObserver,
+                                                                            MMdEObjectPresentObserver* aParentPresentObserver)
+    {
+    iParentObserver = aParentObserver;
+    iParentPresentObserver = aParentPresentObserver;
+    // This leave is needed, if the handler was deleted earlier and the parent observer was removed 
+    TRAP_IGNORE( iMdESession.AddObjectObserverL( *iParentObserver ) );
+    TRAP_IGNORE( iMdESession.AddObjectPresentObserverL( *iParentPresentObserver ) );
+    const TInt uriCount( aUriArray.Count() );
+    for ( TInt i = 0; i < uriCount; ++i )
+        {
+        CMdEObject* object = NULL;
+
+        object = iMdESession.GetObjectL( aUriArray.MdcaPoint( i ));
+        CleanupStack::PushL( object );
+        if ( object )
+            {
+            iObjectsPendingRemoval.AppendL( object );
+            }
+        CleanupStack::Pop( object );
+        }
+    iRemoveObserver = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::NewL
+// -----------------------------------------------------------------------------
+//
+CUpdateFoldersHandler* CUpdateFoldersHandler::NewL( CMdESession& aMdESession, const CDesCArray& aUriArray,
+                                                                                       MMdEObjectObserver* aParentObserver, 
+                                                                                       MMdEObjectPresentObserver* aParentPresentObserver, 
+																					   RFs& aFs,
+																					   RHarvesterClient& aHarvester,
+																					   CDesCArray* aSupportedTypes )
+    {
+    CUpdateFoldersHandler* self = new( ELeave ) CUpdateFoldersHandler( aMdESession, 
+                                                                            aFs, aHarvester, aSupportedTypes );
+    CleanupStack::PushL( self );
+    self->ConstructL( aUriArray, aParentObserver, aParentPresentObserver );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::~CUpdateFoldersHandler
+// -----------------------------------------------------------------------------
+//
+CUpdateFoldersHandler::~CUpdateFoldersHandler()
+    {
+    if( iRemoveObserver )
+        {
+        TRAP_IGNORE( iMdESession.RemoveObjectObserverL( *iParentObserver ) );
+        TRAP_IGNORE( iMdESession.RemoveObjectPresentObserverL( *iParentPresentObserver ) );
+        }
+    iUrisFound.Reset();
+    iFoldersFound.Reset();
+    iIdsPendingRemoval.Reset();
+    iIdsPendingUpdate.Reset();
+    iIdsHandled.Reset();
+    
+    if ( iScheduler.IsStarted() )
+        {
+        iScheduler.AsyncStop();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::StartHandlingL
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::StartHandlingL()
+    {
+    CMdEObjectQuery* query = NULL;
+
+    iIdsPendingRemoval.Reset();
+    iIdsPendingUpdate.Reset();
+    iIdsHandled.Reset();
+    
+    iStartingHandling = ETrue;
+    DoQueryL( query, iFoldersFound );
+    CleanupStack::PushL( query );
+    if( !iScheduler.IsStarted() )
+        {
+        iScheduler.Start();
+        }
+    TRAP_IGNORE( DetermineIdsToRemoveL( *query ) );
+    TRAP_IGNORE( DetermineIdsToUpdateL( iUrisFound ) );
+    CleanupStack::PopAndDestroy( query );
+    iStartingHandling = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::HandleObjectNotification
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::HandleObjectNotification( const TItemId aId, TObserverNotificationType aType )
+    {
+    iWasNotificationHandled = EFalse;
+
+    if ( aType == ENotifyRemove )
+        {
+        const TInt index = iIdsPendingRemoval.Find( aId );
+        
+        if ( index != KErrNotFound )
+            {
+            iIdsPendingRemoval.Remove( index );
+            iWasNotificationHandled = ETrue;
+            }
+        }
+    else if ( aType == ENotifyAdd || aType == ENotifyModify )
+        {
+        const TInt index = iIdsPendingUpdate.Find( aId );
+        
+        if ( index != KErrNotFound )
+            {
+            iIdsPendingUpdate.Remove( index );
+            const TInt handledIndex = iIdsHandled.Find( aId );
+            if( handledIndex != KErrNotFound )
+                {
+                iIdsHandled.Remove( handledIndex );
+                }
+            iWasNotificationHandled = ETrue;
+            }
+        else if( iHarvestingOngoing )
+            { 
+            iIdsHandled.Append( aId );
+            iWasNotificationHandled = ETrue;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::AllDone
+// -----------------------------------------------------------------------------
+//
+TBool CUpdateFoldersHandler::AllDone() const
+    {
+    return ( iIdsPendingRemoval.Count() == 0 &&
+             iIdsPendingUpdate.Count() == 0 &&
+             !iStartingHandling ) ? ETrue : EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::HandleQueryNewResults
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::HandleQueryNewResults( CMdEQuery& /* aQuery */, TInt /* aFirstNewItemIndex */, TInt /* aNewItemCount */ )
+    {
+    // Pass through.
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::HandleQueryCompleted
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::HandleQueryCompleted( CMdEQuery& /* aQuery */, TInt /* aError */ )
+    {
+    iScheduler.AsyncStop();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::CUpdateFoldersHandler
+// -----------------------------------------------------------------------------
+//
+inline CUpdateFoldersHandler::CUpdateFoldersHandler( CMdESession& aMdESession, 
+                                                                                         RFs& aFs,
+                                                                                         RHarvesterClient& aHarvester,
+                                                                                         CDesCArray* aSupportedTypes )
+    : iFs( aFs ),
+      iUrisFound( KCLFDefaultArrayGranularity ),
+      iFoldersFound( KCLFDefaultArrayGranularity ),
+      iMdESession( aMdESession ),
+      iHarvester( aHarvester ),
+      iHarvestError( KErrNone ),
+      iStartingHandling( EFalse ),
+      iExtensionArray( aSupportedTypes ),
+      iHarvestingOngoing( EFalse )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::ConstructL
+// -----------------------------------------------------------------------------
+//
+inline void CUpdateFoldersHandler::ConstructL( const CDesCArray& aUriArray,
+                                                                             MMdEObjectObserver* aParentObserver,
+                                                                             MMdEObjectPresentObserver* aParentPresentObserver )
+    {
+    iParentObserver = aParentObserver;
+    iParentPresentObserver = aParentPresentObserver;
+    // This leave is needed, if the handler was deleted earlier and the parent observer was removed 
+    TRAP_IGNORE( iMdESession.AddObjectObserverL( *iParentObserver ) );
+    TRAP_IGNORE( iMdESession.AddObjectPresentObserverL( *iParentPresentObserver ) );
+
+    for ( TInt i = 0; i < aUriArray.MdcaCount(); ++i )
+        {
+        ScanNodeForUrisL( aUriArray.MdcaPoint( i ), iUrisFound, iFoldersFound );
+        }
+ 
+    iRemoveObserver = ETrue ;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::ScanNodeForUrisL
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::ScanNodeForUrisL( const TDesC16& aNodeName, CDesCArray& aUriArray, CDesCArray& aFolderArray )
+    {
+    TBool isFolder = EFalse;
+
+    BaflUtils::IsFolder( iFs, aNodeName, isFolder );
+    if ( isFolder )
+        {
+        if ( !BaflUtils::FolderExists( iFs, aNodeName ) )
+            {
+            return;
+            }
+        CDirScan* dirscan = CDirScan::NewL( iFs );
+        CDir* dir = NULL;
+
+        CleanupStack::PushL( dirscan );
+        dirscan->SetScanDataL( aNodeName, KEntryAttNormal, EDirsAnyOrder );
+
+        for ( dirscan->NextL( dir ); dir; dirscan->NextL( dir ) )
+            {
+            CleanupStack::PushL( dir );
+
+            for ( TInt i = 0 ; i < dir->Count() ; ++i )
+                {
+                const TEntry& entry = ( *dir )[ i ];
+                const TInt totalLength = entry.iName.Length() + dirscan->FullPath().Length() + 1;
+
+                if (( !entry.IsDir() ) && ( totalLength <= KMaxFileName ))
+                    {
+                    TFileName currentPath( dirscan->FullPath() );
+                    currentPath.Append( ( *dir )[ i ].iName );
+                    aUriArray.AppendL( currentPath );
+                    }
+                }
+            CleanupStack::PopAndDestroy( dir );
+
+            }
+        aFolderArray.AppendL( aNodeName );
+
+        CleanupStack::PopAndDestroy( dirscan );
+        }
+    else
+        {
+        aUriArray.AppendL( aNodeName );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::DetermineIdsToRemove
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::DetermineIdsToRemoveL ( const CMdEObjectQuery& aQuery )
+    {
+    RProcess process( KCurrentProcessHandle );
+    process.Id().Id(); 
+    if( process.HasCapability( ECapabilityWriteDeviceData ) )
+        {
+        const TInt queryCount( aQuery.Count() );
+        for ( TInt i = 0; i < queryCount; ++i )
+            {
+            CMdEObject& object = aQuery.Result( i );
+            TEntry entry;
+            const TInt err = iFs.Entry( object.Uri(), entry );
+
+            if ( err == KErrNotFound )
+                {
+                // Queried metadata object has a URI that does not match a filesystem URI.
+                // It must therefore be removed.
+                TItemId id( KNoId ); 
+                id = iMdESession.RemoveObjectL( object.Id() );
+                if ( id != KNoId )
+                    {
+                    iIdsPendingRemoval.Append( id );
+                    }
+                }
+            }
+        }
+    process.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::DetermineIdsToRemove
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::DetermineIdsToUpdateL ( const CDesCArray& aUriArray )
+    {
+    const TInt uriCount( aUriArray.Count() );
+    for ( TInt i = 0; i < uriCount; ++i )
+        {
+        CMdEObject* object = NULL;
+        const TDesC& uri = aUriArray.MdcaPoint( i );
+        TPtrC ext;
+        const TBool exists( MdsUtils::GetExt( uri, ext ) );
+        if( !exists || !IsSupportedType( ext ) )
+            {
+            return;
+            }
+
+        object = iMdESession.GetObjectL( uri ); 
+        CleanupStack::PushL( object );
+
+        if ( !object )
+            {
+            // If object for given URI is not in MDS, then determine if an ENotifyAdd
+            // or ENotifyModify  is pending by attempting to harvest the file associated
+            // with the URI.
+            DoHarvestL( uri );
+            }
+        CleanupStack::PopAndDestroy( object );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::DoQueryL
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::DoQueryL( CMdEObjectQuery*& aQuery, const CDesCArray& aFolderArray )
+    {
+    CMdENamespaceDef& defaultNamespaceDef = iMdESession.GetDefaultNamespaceDefL();
+    CMdEObjectDef& objDef = defaultNamespaceDef.GetObjectDefL( MdeConstants::Object::KBaseObject );
+    aQuery = iMdESession.NewObjectQueryL( iMdESession.GetDefaultNamespaceDefL(), objDef, this );
+    CleanupStack::PushL( aQuery );
+    CMdELogicCondition& uriLogicCond = aQuery->Conditions().AddLogicConditionL( ELogicConditionOperatorOr );
+
+    const TInt folderCount( aFolderArray.Count() );
+    for ( TInt i = 0; i < folderCount; ++i )
+        {
+        uriLogicCond.AddObjectConditionL( EObjectConditionCompareUriBeginsWith, aFolderArray.MdcaPoint( i ) );
+        }
+    aQuery->FindL();
+
+    CleanupStack::Pop( aQuery ); // Caller takes ownership.
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::DoHarvest
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::DoHarvestL( const TDesC& aUri )
+    {
+    RArray< TItemId > albumIds;
+
+    TUid uid( KNullUid );
+    iHarvester.SetObserver( this );
+    iHarvestingFile = TFileName( aUri );
+    iHarvestingOngoing = ETrue;
+    iHarvester.HarvestFileWithUID( aUri, albumIds, EFalse, uid );
+    if( !iScheduler.IsStarted() )
+        {
+        iScheduler.Start();
+        }
+
+    albumIds.Close();
+    
+    // Wait until harvest complete before trying again.
+    iHarvester.RemoveObserver( this );
+    if ( iHarvestError == KErrNone )
+        {
+        CMdEObject* object = NULL;
+
+        object = iMdESession.GetObjectL( aUri );
+        if( object )
+            {
+            const TInt index = iIdsHandled.Find( object->Id() );
+            if( index != KErrNotFound )
+                {
+                iIdsHandled.Remove( index );
+                }
+            else
+                {
+                iIdsPendingUpdate.Append( object->Id() ); 
+                }
+            }
+        }
+
+    iHarvestError = KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::HarvestingComplete
+// Callback from harvester client after harvesting
+// -----------------------------------------------------------------------------
+//
+void CUpdateFoldersHandler::HarvestingComplete( TDesC& aURI, const TInt aError )
+    {
+    const TFileName uri( aURI );
+    TBool match( EFalse );
+    TCollationMethod m = *Mem::CollationMethodByIndex( 0 );
+
+    iHarvestError = aError;
+    m.iFlags = ( TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase );   
+
+    if ( uri.CompareC( iHarvestingFile, 3, &m ) == 0 )
+        {
+        match = ETrue;
+        iHarvestingOngoing = EFalse;
+        }
+    if ( iScheduler.IsStarted() && match )
+        {
+        iScheduler.AsyncStop();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpdateFoldersHandler::IsSupportedType
+// -----------------------------------------------------------------------------
+//
+TBool CUpdateFoldersHandler::IsSupportedType( const TDesC& aExtension )
+    {
+    TCollationMethod m = *Mem::CollationMethodByIndex( 0 );
+    m.iFlags = ( TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase );   
+    
+    for( TInt i( 0 ); i < iExtensionArray->Count(); i++ )
+        {
+        const TDesC& ext = iExtensionArray->MdcaPoint( i );
+        if ( ext.CompareC( aExtension, 3, &m ) == 0 )
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::~CCLFServerProxy
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CCLFServerProxy::~CCLFServerProxy()
+    {
+    // Reset the arrays this class owns.
+    iStatusArray.Reset();
+    iOpCodeArray.Reset();
+    iUpdatedIds.Reset();
+    TRAP_IGNORE( iMdESession.RemoveObjectObserverL( *this ));
+    TRAP_IGNORE( iMdESession.RemoveObjectPresentObserverL( *this ));
+    iUpdateItemsHandlerArray.ResetAndDestroy();
+    delete iUriArray;
+    delete iExtensionArray;
+    iFs.Close();
+
+    iHC.RemoveHarvesterEventObserver( *this );
+    iHC.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFDbItemProvider::NewL
+// -----------------------------------------------------------------------------
+//
+CCLFServerProxy* CCLFServerProxy::NewL( CMdESession& aMdESession )
+    {
+    CCLFServerProxy* self = new( ELeave ) CCLFServerProxy( aMdESession );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::GetUpdateEndEvent
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::GetUpdateEndEvent( TRequestStatus& aRequestStatus )
+    {
+    GetEvent( aRequestStatus, ECLFGetUpdateEvent );
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::CancelEventGets
+// -----------------------------------------------------------------------------
+//
+TInt CCLFServerProxy::CancelGetEvent()
+    {
+    CancelGetEvent( ECLFGetUpdateEvent );
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::GetUpdateStartEvent
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::GetUpdateStartEvent( TRequestStatus& aRequestStatus )
+    {
+    GetEvent( aRequestStatus, ECLFProcessStartEvent );
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::CancelGetUpdateStartEvent
+// -----------------------------------------------------------------------------
+//
+TInt CCLFServerProxy::CancelGetUpdateStartEvent()
+    {
+    CancelGetEvent( ECLFProcessStartEvent );
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::FetchItemListData
+// -----------------------------------------------------------------------------
+//
+TInt CCLFServerProxy::FetchItemListData( RArray< TCLFItemId >& aItemIDArray )
+    {
+    const TInt count( iUpdatedIds.Count() );
+    for ( TInt i = 0; i < count; ++i )
+        {
+        aItemIDArray.Append( iUpdatedIds[ i ] );
+        }
+
+    iUpdatedIds.Reset();
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::UpdateItems
+// -----------------------------------------------------------------------------
+//
+TInt CCLFServerProxy::UpdateItemsL( const TArray< TCLFItemId >& aItemIDArray )
+    {
+    CUpdateItemsHandler* handler = CUpdateIDsHandler::NewL( aItemIDArray );
+
+    CleanupStack::PushL( handler );
+    StartHandlingL( handler );
+    CleanupStack::Pop( handler );
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::UpdateItems
+// -----------------------------------------------------------------------------
+//
+TInt CCLFServerProxy::UpdateItemsL( const TInt aSemanticId, const TDesC8& aOpaqueData )
+    {
+    CDesCArray* uriArray = new ( ELeave ) CDesCArraySeg( KCLFDefaultArrayGranularity );
+    CleanupStack::PushL( uriArray );
+    DeSerializeL( aOpaqueData, *uriArray );
+
+    if ( uriArray->Count() )
+        {
+        CUpdateItemsHandler* handler = NULL;
+        
+        if ( aSemanticId == KCLFItemsDeletedSemanticId )
+            {
+            handler = CItemsDeletedHandler::NewL( iMdESession, *uriArray, this, this );
+            }
+        else if ( aSemanticId == KCLFUpdateFoldersSemanticId )
+            {
+            handler = CUpdateFoldersHandler::NewL( iMdESession, *uriArray, this, this, 
+                              iFs, iHC, iExtensionArray );
+            }
+        else if ( aSemanticId == KCLFUpdateCollectionsSemanticId )
+            {
+            // Pass through; collections are not supported.
+            CleanupStack::PopAndDestroy( uriArray );
+            return KErrNone;
+            }
+
+        CleanupStack::PushL( handler );
+        StartHandlingL( handler );
+        CleanupStack::Pop( handler );
+        }
+    CleanupStack::PopAndDestroy( uriArray );
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::UpdateAllItems
+// -----------------------------------------------------------------------------
+//
+TInt CCLFServerProxy::UpdateAllItemsL()
+    {
+    CUpdateItemsHandler* handler = CUpdateFoldersHandler::NewL( iMdESession, 
+                                                         *iUriArray, this, this, iFs, iHC, iExtensionArray );
+    CleanupStack::PushL( handler );
+    StartHandlingL( handler );
+    CleanupStack::Pop( handler );
+    
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Default constructor
+// ---------------------------------------------------------------------------
+//
+inline CCLFServerProxy::CCLFServerProxy( CMdESession& aMdESession )
+    : iMdESession( aMdESession ),
+    iUriArray( NULL ),
+    iExtensionArray( NULL ),
+    iHEStateFinished( ETrue ),
+    iNeedNotifyCLFGetUpdateEvent( EFalse ),
+    iDelayNotifyCLFGetUpdateEventCount( 0 )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::ConstructL
+// -----------------------------------------------------------------------------
+//
+inline void CCLFServerProxy::ConstructL()
+    {
+    iUriArray = new ( ELeave ) CDesCArraySeg( KCLFDefaultArrayGranularity );
+    User::LeaveIfError( iFs.Connect() );
+    
+    TDriveList driveList;
+    TChar driveLetter; 
+    TInt numOfElements( 0 );
+    User::LeaveIfError( DriveInfo::GetUserVisibleDrives( iFs, 
+                                                         driveList, 
+                                                         numOfElements, 
+                                                         KDriveAttExclude | KDriveAttRemote | KDriveAttRom ) );
+    
+    for( TInt driveNumber = EDriveA ; driveNumber <= EDriveZ ; driveNumber++ ) 
+        { 
+        if ( driveList[driveNumber] ) 
+            {
+            User::LeaveIfError( iFs.DriveToChar( driveNumber, driveLetter ) );
+            HBufC* letter = HBufC::NewLC( KMaxPath );
+            TPtr letterPtr( letter->Des() );
+
+            if( driveLetter == KCLFDriveC )
+                {
+                letterPtr = PathInfo::PhoneMemoryRootPath();
+                }
+            else
+                {
+                letterPtr.Append( driveLetter );
+                letterPtr.Append( KCLFDriveLetterFormatString ); 
+                }   
+                        
+            if( BaflUtils::PathExists( iFs, letterPtr ) )
+                {
+                iUriArray->AppendL( letterPtr );
+                }
+            CleanupStack::PopAndDestroy( letter );
+            }
+        }
+    
+    PopulateSupportedExtensionL();
+    
+    iMdESession.AddObjectObserverL( *this );
+    iMdESession.AddObjectPresentObserverL( *this );
+
+    User::LeaveIfError( iHC.Connect() );
+    iHC.AddHarvesterEventObserver( *this, EHEObserverTypeOverall, KCLFWrapperHarvesterEventInterval );
+
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::HarvestingUpdated
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::HarvestingUpdated( 
+			HarvesterEventObserverType /*aHEObserverType*/, 
+			HarvesterEventState aHarvesterEventState,
+			TInt /*aItemsLeft*/ )
+    {
+    if( aHarvesterEventState == EHEStateFinished ||
+        aHarvesterEventState == EHEStatePaused )
+        {
+        iHEStateFinished = ETrue;
+        if ( iNeedNotifyCLFGetUpdateEvent )
+            {
+            NotifyUpdateEvent( ECLFGetUpdateEvent );
+            }
+        }
+    else
+        {
+        iHEStateFinished = EFalse;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::StartHandlingL
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::StartHandlingL( CUpdateItemsHandler* aHandler )
+    {
+    if ( aHandler )
+        {
+        // Notify pending active objects about the event.
+        NotifyUpdateEvent( ECLFProcessStartEvent );
+
+        // Now wait until the update is over, then return.
+        iUpdateItemsHandlerArray.Append( aHandler );
+        TRAPD( err, aHandler->StartHandlingL(); );
+        if( err != KErrNone )
+            {
+            // Remove aHandler, because it is in clean up stack.
+            iUpdateItemsHandlerArray.Remove( iUpdateItemsHandlerArray.Count() - 1 );
+            User::LeaveIfError( err );
+            }
+        if ( aHandler->AllDone() )
+            {
+            delete aHandler;
+            iUpdateItemsHandlerArray.Remove( iUpdateItemsHandlerArray.Count() - 1 );
+            }
+        else
+            {
+            aHandler->StartScheduler();
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::HandleObjectNotification
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::HandleObjectNotification( CMdESession& /*aSession*/,
+                                                TObserverNotificationType aType,
+                                                const RArray< TItemId >& aObjectIdArray )
+    {
+    TBool unhandledIds = EFalse;
+
+    const TInt objectCount( aObjectIdArray.Count() );
+    for ( TInt i = 0; i < objectCount; ++i )
+        {
+        TBool handled = EFalse;
+
+        iUpdatedIds.Append( aObjectIdArray[ i ] );
+        for ( TInt j = 0; j < iUpdateItemsHandlerArray.Count(); ++j )
+            {
+            iUpdateItemsHandlerArray[ j ]->HandleObjectNotification( aObjectIdArray[ i ], aType );
+            handled = handled ? ETrue : iUpdateItemsHandlerArray[ j ]->WasNotificationHandled();
+
+            if ( iUpdateItemsHandlerArray[ j ]->AllDone() )
+                {
+                // If we have a pending update, we can now let it continue.
+                iDelayNotifyCLFGetUpdateEventCount = KDelayNotityCLFGetUpdateEventMaxTimes;
+                NotifyUpdateEvent( ECLFGetUpdateEvent );
+                iUpdateItemsHandlerArray[ j ]->AsyncStopScheduler();
+                iUpdateItemsHandlerArray[j]->SetRemoveObserverFlag( EFalse );
+                delete iUpdateItemsHandlerArray[ j ]; 
+                iUpdateItemsHandlerArray.Remove( j );
+                j--; // Compensate for the removed handler
+                }
+            }
+        unhandledIds = ( unhandledIds || !handled ) ? ETrue : EFalse;
+        }
+
+    if ( unhandledIds )
+        {
+        // If we have an ID that doesn't match a pending update, we assume
+        // that the object notification was generated from outside the current
+        // application, and we therefore must simulate a process end event.
+        if( aType == ENotifyRemove )
+            {
+            // Increase the update triggering value more rapidly to provide remove events faster
+            iDelayNotifyCLFGetUpdateEventCount += 12;
+            }
+        NotifyUpdateEvent( ECLFGetUpdateEvent );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::MMdEObjectPresentObserver
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::HandleObjectPresentNotification( CMdESession& /*aSession*/,
+                                                TBool /*aPresent*/,
+                                                const RArray< TItemId >& aObjectIdArray )
+    {
+    TBool unhandledIds = EFalse;
+
+    const TInt objectCount( aObjectIdArray.Count() );
+    for ( TInt i = 0; i < objectCount; ++i )
+        {
+        TBool handled = EFalse;
+
+        iUpdatedIds.Append( aObjectIdArray[ i ] );
+        for ( TInt j = 0; j < iUpdateItemsHandlerArray.Count(); ++j )
+            {
+            iUpdateItemsHandlerArray[ j ]->HandleObjectNotification( aObjectIdArray[ i ], ENotifyModify );
+            handled = handled ? ETrue : iUpdateItemsHandlerArray[ j ]->WasNotificationHandled();
+
+            if ( iUpdateItemsHandlerArray[ j ]->AllDone() )
+                {
+                // If we have a pending update, we can now let it continue.
+                NotifyUpdateEvent( ECLFGetUpdateEvent );
+                iUpdateItemsHandlerArray[ j ]->AsyncStopScheduler();
+                iUpdateItemsHandlerArray[j]->SetRemoveObserverFlag( EFalse );
+                delete iUpdateItemsHandlerArray[ j ]; 
+                iUpdateItemsHandlerArray.Remove( j );
+                j--; // Compensate for the removed handler
+                }
+            }
+        unhandledIds = ( unhandledIds || !handled ) ? ETrue : EFalse;
+        }
+
+    if ( unhandledIds )
+        {
+        // If we have an ID that doesn't match a pending update, we assume
+        // that the object notification was generated from outside the current
+        // application, and we therefore must simulate a process end event.
+        NotifyUpdateEvent( ECLFGetUpdateEvent );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::NotifyUpdateEvent
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::NotifyUpdateEvent( const TCLFServerOpCodes aOpCode )
+    {
+
+    if ( ECLFGetUpdateEvent == aOpCode
+            && !iHEStateFinished
+            && iDelayNotifyCLFGetUpdateEventCount < KDelayNotityCLFGetUpdateEventMaxTimes )
+        {
+        iNeedNotifyCLFGetUpdateEvent = ETrue;
+        iDelayNotifyCLFGetUpdateEventCount++;
+        return;
+        }
+
+    for ( TInt i = 0; i < iOpCodeArray.Count(); ++i )
+        {
+        if ( iOpCodeArray[ i ] == aOpCode )
+            {
+            User::RequestComplete( iStatusArray[ i ], KErrNone );
+            iStatusArray.Remove( i );
+            iOpCodeArray.Remove( i );
+            }
+        }
+    
+    if ( ECLFGetUpdateEvent == aOpCode )
+        {
+        iNeedNotifyCLFGetUpdateEvent = EFalse;
+        iDelayNotifyCLFGetUpdateEventCount = 0;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::DeSerializeL
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::DeSerializeL( const TDesC8& aData, CDesCArray& aDataArray )
+    {
+    // Check if KNullDesC
+    if ( aData.Length() > 0 )
+        {
+        RDesReadStream readStream( aData );
+        CleanupClosePushL( readStream );
+        const TInt count( readStream.ReadInt32L() );
+
+        HBufC* buffer = HBufC::NewLC( KCLFDefaultBufferLength );
+        TPtr ptr( buffer->Des() );
+        for ( TInt i = 0 ; i < count ; ++i )
+            {
+            const TInt length( readStream.ReadInt32L() );
+            const TUint uintLength( length );
+            const TInt maxLength( KMaxTInt / 2 );
+            if (( length < 0 ) || ( uintLength > maxLength ))
+                {
+                User::Leave( KErrNotSupported );
+                }
+            else if ( length > ptr.MaxLength() )
+                {
+                // create new buffer
+                CleanupStack::PopAndDestroy( buffer );
+                buffer = HBufC::NewLC( length );
+                ptr.Set( buffer->Des() );
+                }
+            else
+                {
+                ptr.Zero();
+                }
+            readStream.ReadL( ptr, length );
+            aDataArray.AppendL( ptr );
+            }
+        CleanupStack::PopAndDestroy( 2, &readStream );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::GetEvent
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::GetEvent( TRequestStatus& aRequestStatus, TCLFServerOpCodes aOpcode )
+    {
+    iStatusArray.Append( &aRequestStatus );
+    iOpCodeArray.Append( aOpcode );
+    aRequestStatus = KRequestPending;
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::CancelGetEvent
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::CancelGetEvent( TCLFServerOpCodes aOpcode )
+    {
+    for ( TInt i = 0; i < iStatusArray.Count(); ++i )
+        {
+        if ( iOpCodeArray[ i ] == aOpcode )
+            {
+            User::RequestComplete( iStatusArray[ i ], KErrCancel );
+            iStatusArray.Remove( i );
+            iOpCodeArray.Remove( i );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCLFServerProxy::PopulateSupportedExtensionL
+// -----------------------------------------------------------------------------
+//
+void CCLFServerProxy::PopulateSupportedExtensionL()
+    {
+    iExtensionArray = new ( ELeave ) CDesCArraySeg( KCLFExtensionArrayGranularity );
+    iExtensionArray->AppendL( KExtensionMp3 );
+    iExtensionArray->AppendL( KExtensionAac );
+    iExtensionArray->AppendL( KExtensionAmr );
+    iExtensionArray->AppendL( KExtensionAwb );
+    iExtensionArray->AppendL( KExtensionMid );
+    iExtensionArray->AppendL( KExtensionMidi );
+    iExtensionArray->AppendL( KExtensionSpMid );
+    iExtensionArray->AppendL( KExtensionRng );
+    iExtensionArray->AppendL( KExtensionMxmf );
+    iExtensionArray->AppendL( KExtensionWav );
+    iExtensionArray->AppendL( KExtensionAu );
+    iExtensionArray->AppendL( KExtensionNrt );
+    iExtensionArray->AppendL( KExtensionWma );
+    iExtensionArray->AppendL( KExtensionRa );
+    
+    iExtensionArray->AppendL( KExtJpg );
+    iExtensionArray->AppendL( KExtJpeg );
+    iExtensionArray->AppendL( KExtJp2 );
+    iExtensionArray->AppendL( KExtJ2k );
+    iExtensionArray->AppendL( KExtJpx );
+    iExtensionArray->AppendL( KExtJpf );
+    iExtensionArray->AppendL( KExtMbm );
+    iExtensionArray->AppendL( KExtPng );
+    iExtensionArray->AppendL( KExtGif );
+    iExtensionArray->AppendL( KExtBmp );
+    iExtensionArray->AppendL( KExtTif );
+    iExtensionArray->AppendL( KExtTiff );
+    iExtensionArray->AppendL( KExtOta );
+    iExtensionArray->AppendL( KExtWbmp );
+    iExtensionArray->AppendL( KExtWmf );
+    iExtensionArray->AppendL( KExtOtb );
+    
+    iExtensionArray->AppendL( KExtOma1 );
+    iExtensionArray->AppendL( KExtOma2 );
+    iExtensionArray->AppendL( KExtOma3 );
+    iExtensionArray->AppendL( KExtOma4 );
+    iExtensionArray->AppendL( KExtOma5 );
+    
+    iExtensionArray->AppendL( KExtensionMp4 );
+    iExtensionArray->AppendL( KExtensionMpg4 );
+    iExtensionArray->AppendL( KExtensionMpeg4 );
+    iExtensionArray->AppendL( KExtensionM4v );
+    iExtensionArray->AppendL( KExtensionM4a );
+    iExtensionArray->AppendL( KExtension3gp );
+    iExtensionArray->AppendL( KExtension3gpp );
+    iExtensionArray->AppendL( KExtension3g2 );
+    iExtensionArray->AppendL( KExtensionRm );
+    iExtensionArray->AppendL( KExtensionRmvb );
+    iExtensionArray->AppendL( KExtensionRam );
+    iExtensionArray->AppendL( KExtensionRv );
+    iExtensionArray->AppendL( KExtensionWmv );
+    iExtensionArray->AppendL( KExtensionAvi );
+    }
+
+//  End of File