menufw/menufwui/mmextensions/mmfolderuiextension/src/mmfoldercommand.cpp
branchv5backport
changeset 14 1abc632eb502
parent 13 6205fd287e8a
child 20 636d517f67e6
--- a/menufw/menufwui/mmextensions/mmfolderuiextension/src/mmfoldercommand.cpp	Thu Mar 18 14:45:17 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,682 +0,0 @@
-/*
-* Copyright (c) 2007-2008 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:   Interface of the folder command
- *
-*/
-
-#include <liwcommon.h>
-#include <e32base.h>
-#include <eikenv.h>
-#include <StringLoader.h>
-#include <AknQueryDialog.h>
-#include <aknnotewrappers.h>
-#include <s32mem.h>
-
-#include "mmfoldercommand.h"
-#include "mmfoldercommandadd.h"
-#include "mmfoldercommandrename.h"
-#include "mmfoldercommanddelete.h"
-#include "mmmovetofoldercommand.h"
-#include "mmdialogmanager.h"
-#include "hnliwutils.h"
-#include "menudebug.h"
-#include "hnutils.h"
-
-#include "hnmdbasekey.h"
-#include "hnmdkeyfactory.h"
-#include "menudebug.h"
-#include "hnconvutils.h"
-#include "hnservicehandler.h"
-#include "mmfolderuiextpluginconstants.h"
-#include "mmpluginsharedresources.h"
-
-#include <avkon.rsg>
-#include <matrixmenu.rsg>
-#include <mmfolderuiextplugin.rsg>
-
-
-const TInt KCountNotAllowedChars = 9;
-// Unicode character of sign obtained by press '0' key three times. Enter key.
-const TUint16 KIllegalCharEnter = 0x21b2;
-// Unicode line separator character obtained by pressing Shift + Enter keys
-const TUint16 KIllegalCharLineSeparator = 0x2028;
-// Space unicode character.
-// Characters which ascii value is smaller than 32 are not allowed.
-const TUint16 KSpace = ' '; //32;
-
-// ============================ MEMBER FUNCTIONS =============================
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-CMmFolderCommand::~CMmFolderCommand()
-    {
-    iSerializedInputList.Close();
-    iSerializedOutputList.Close();
-    delete iGetListOutParam;
-    delete iGetListInParam;
-    iMcs.Close();
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::BaseConstructL()
-	{
-	// Init MCS session
-	TBuf16<KMaxFileName> buf;
-	buf.Copy(KMatrixMenuData);
-	iMcs.OpenL(buf);
-	iGetListInParam = CLiwGenericParamList::NewL();
-	iGetListOutParam = CLiwGenericParamList::NewL();
-	}
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::MCSQueryExecutionL(
-        const TDesC8& aQueryName,
-        const CHnMdBaseKey* aInputData,
-        const CHnMdBaseKey* aFilter,
-        MLiwNotifyCallback* aCallback )
-    {
-    RPointerArray< CHnMdBaseKey > data;
-    CleanupClosePushL( data );
-    data.AppendL( aInputData );
-    if ( aFilter )
-        {
-        data.AppendL( aFilter );
-        }
-
-    CHnMdBaseKey* serviceData = HnMdKeyFactory::CreateL(
-        KServiceContentName, KKeyTypeString, KMatrixMenuData );
-    CleanupStack::PushL( serviceData );
-
-    RPointerArray< CHnMdBaseKey> constructor;
-    CleanupClosePushL( constructor );
-    constructor.AppendL( serviceData );
-    CLiwGenericParamList* constructorLiw = CLiwGenericParamList::NewLC();
-    CLiwGenericParamList* commandLiw = CLiwGenericParamList::NewLC();
-    HnLiwUtils::SetGenericParamListL( constructor, *constructorLiw );
-    HnLiwUtils::SetGenericParamListL( data, *commandLiw );
-
-    TBuf8< KMaxLength > interface( KMCSDataSourceInterface8 );
-    if ( !aQueryName.Compare( KCmdOrganize8 ) ||
-            !aQueryName.Compare( KCmdExecuteAction8 ) )
-        {
-        interface.Copy( KMCSMenuContentInterface8 );
-        }
-
-    delete iServiceHandler;
-    iServiceHandler = NULL;
-    iServiceHandler = CHnServiceHandler::NewL(
-            KMCSService8, interface, aQueryName,
-            EServiceModeAsynchronous, constructorLiw, commandLiw );
-
-    CleanupStack::Pop( commandLiw );
-    CleanupStack::Pop( constructorLiw );
-
-    iServiceHandler->ExecuteL( aCallback , 0 );
-
-    CleanupStack::PopAndDestroy( &constructor );
-    CleanupStack::PopAndDestroy( serviceData );
-    CleanupStack::PopAndDestroy( &data );
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-CMmFolderCommand* CMmFolderCommand::FactoryL( const TDesC& aCommand )
-    {
-    CMmFolderCommand* ret = NULL;
-    if( !aCommand.Compare( KAddFolderCmd ) )
-		{
-		ret = CMmFolderCommandAdd::NewL();
-		}
-    else if ( !aCommand.Compare( KRenameFolderCmd ) )
-		{
-		ret = CMmFolderCommandRename::NewL();
-		}
-    else if ( !aCommand.Compare( KDeleteFolderCmd ) )
-		{
-		ret = CMmFolderCommandDelete::NewL();
-		}
-    else if ( !aCommand.Compare( KDeleteAppCmd ) )
-		{
-		ret = CMmFolderDeleteApp::NewL();
-		}
-    else if ( !aCommand.Compare( KDeleteSuiteCmd ) )
-		{
-		ret = CMmFolderDeleteSuite::NewL();
-		}
-    else if ( !aCommand.Compare( KMoveToFolderCmd ) )
-        {
-        ret = CMmMoveToFolderCommand::NewL();
-        }
-    return ret;
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-TBool CMmFolderCommand::DoChangeNameL( RBuf& aFolderName, 
-		TInt aDefaultNameLength, RBuf& aNumberInBracket, 
-		CLiwGenericParamList& aFoldersNames, TLiwVariant& aVar,
-		TInt aNumberToAppend )
-    {
-    TBool nameChanged( EFalse );
-    TInt position( KErrNone );
-    TInt count = aFoldersNames.FindFirst( position, KReturnValue8() )
-        ->Value().AsList()->Count();
-    aNumberInBracket.Delete( KOpenBracket().Length(), 
-        aNumberInBracket.Length() - KOpenBracket().Length() );
-    
-    if ( aNumberToAppend < KMaxDigitNumber )
-        {
-        aNumberInBracket.AppendNum( 0 );
-        }
-    
-    for ( TInt i = 0; i < count; i++ )
-        {
-        HnLiwUtils::GetVariantL( aFoldersNames, KLongNamePath8, i, aVar );
-        TPtrC longName;
-        aVar.Get( longName );
-        if ( !aFolderName.Compare( longName ) )
-            {
-            aNumberInBracket.AppendNum( aNumberToAppend );
-            aNumberInBracket.Append( KCloseBracket );
-            aFolderName.Delete( aDefaultNameLength, 
-                aFolderName.Length() - aDefaultNameLength );
-            aFolderName.Append( aNumberInBracket );
-            nameChanged = ETrue;
-            break;
-            }
-        }
-    return nameChanged;
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::ChangeNameIfAlreadyExistsL( RBuf& aFolderName,
-        CLiwGenericParamList* aFoldersNames, TInt aNumberToAppend )
-    {
-    if ( !aFoldersNames )
-        {
-        return;
-        }
-    TLiwVariant var;
-    var.PushL();
-    RBuf numberInBracket;
-    CleanupClosePushL(numberInBracket);
-    numberInBracket.CreateL( KMaxLength );
-    numberInBracket.Append( KOpenBracket );
-    numberInBracket.AppendNum( aNumberToAppend );
-    numberInBracket.Append( KCloseBracket );
-    TInt defaultNameLength = aFolderName.Length();
-    
-    while( DoChangeNameL( aFolderName, defaultNameLength, numberInBracket,
-            *aFoldersNames, var, ++aNumberToAppend ) )
-        ;
-        
-    CleanupStack::PopAndDestroy(&numberInBracket);
-    CleanupStack::PopAndDestroy( &var );
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-TBool CMmFolderCommand::GetFolderNameL( RBuf& aFolderName, 
-        CLiwGenericParamList* aFoldersNames )
-	{
-	TBool res( EFalse );
-	if( aFolderName.Length() == 0 )
-		{
-	    aFolderName.Append( iSharedResources->GetDefaultFolderName() );
-	    ChangeNameIfAlreadyExistsL( aFolderName, aFoldersNames );
-		}
-
-	CAknTextQueryDialog* dialog =
-	    CAknTextQueryDialog::NewL( aFolderName, CAknQueryDialog::ENoTone );
-	
-	dialog->PrepareLC( R_MENU_FILENAME_QUERY );
-	dialog->SetPromptL( iSharedResources->GetEditFolderName() );
-
-	SetDialogL( dialog );
-    res = dialog->RunLD();
-    SetDialogL( NULL );
-
-	return res;
-	}
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::GetFolderListL( TInt aItemId )
-    {
-    // Prepare data for GetList
-    iGetListInParam->Reset();
-    PrepareGetListInputL( aItemId );
-    PrepareGetListFolderFilterL();
-    ExternalizeInputListL();
-    
-    // Get folders list from MCS
-    iMcs.GetListL( iSerializedInputList, iSerializedOutputList );
-    InternalizeOutputListL();
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::GetListL( TInt aItemId )
-    {
-    // Prepare data for GetList
-    iGetListInParam->Reset();
-    PrepareGetListInputL( aItemId );
-    PrepareGetListFilterL();
-    ExternalizeInputListL();
-    
-    // Get folders list from MCS
-    iMcs.GetListL( iSerializedInputList, iSerializedOutputList );
-    InternalizeOutputListL();
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::DisplayErrorInfoL( const TDesC& aFolderName )
-    {
-    CAknNoteDialog* dialog = new (ELeave) CAknNoteDialog(
-            CAknNoteDialog::EConfirmationTone,
-            CAknNoteDialog::ELongTimeout );
-    HBufC* msg = StringLoader::LoadLC(
-            R_FLDR_CANNOT_DELETE_ITEM, aFolderName );
-    dialog->SetTextL( msg->Des() );
-    dialog->ExecuteDlgLD( R_MENU_EDIT_INTERRUPTION_INFO );
-
-    CleanupStack::PopAndDestroy( msg );
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::SetRequestInterface( MMmActionRequest* aActionRequest )
-    {
-    iActionRequest = aActionRequest;
-    }
-
-void CMmFolderCommand::SetSharedResources( CMmPluginSharedResources* aResources )
-	{
-	iSharedResources = aResources;
-	}
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::SetDialogL( CAknQueryDialog* aDialog )
-    {
-    iDialog = aDialog;
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::RemoveDialogL()
-    {
-    iLockDialog = ETrue;
-    if( iDialog )
-        {
-        iDialog->HandleQueryEditorStateEventL( NULL,
-            MAknQueryControlObserver::EEmergencyCallAttempted,
-            MAknQueryControlObserver::EEditorEmpty );
-        iDialog = NULL;
-        }
-    }
-
-// ---------------------------------------------------------------------------
-//
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::AddSubKeyL( CHnMdBaseKey* aInDataKey,
-                                   const TDesC8& aKeyName,
-                                   const TDesC8& aKeyType,
-                                   const TDesC8& aKeyValue )
-    {
-    CHnMdBaseKey* key = HnMdKeyFactory::CreateL(
-    		aKeyName, aKeyType, aKeyValue );
-    CleanupStack::PushL( key );
-    aInDataKey->AddSubKeyL( key );
-    CleanupStack::Pop( key );
-    }
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-// 
-void CMmFolderCommand::AddSubKeyL( CHnMdBaseKey* aInDataKey, 
-                                   const TDesC8& aKeyName, 
-                                   const TDesC8& aKeyType, 
-                                   const TDesC& aKeyValue )
-    {
-    CHnMdBaseKey* key = HnMdKeyFactory::CreateL(
-    		aKeyName, aKeyType, aKeyValue );
-    CleanupStack::PushL( key );
-    aInDataKey->AddSubKeyL( key );
-    CleanupStack::Pop( key );
-    }
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-// 
-TInt CMmFolderCommand::FolderNameValidationL(RBuf& aFolderName,
-        CLiwGenericParamList* aFoldersNames)
-    {
-    TValidation allowed(EValidationOk);
-
-    allowed = (TValidation) IllegalCharacterRemoveL(aFolderName, aFoldersNames);
-    if (allowed != EValidationOk)
-        {
-        return allowed;
-        }
-    allowed = (TValidation) CheckValidFileNameL(aFolderName);
-    if (allowed != EValidationOk)
-        {
-        // §qtn_fldr_bad_file_name§
-        // data entry (for example data query New name: §qtn_fldr_item_name_prmpt§ ) is opened
-        DisplayNameErrorInfoL(iSharedResources->GetMsgBadFileName());
-        return allowed;
-        }
-    allowed = (TValidation) CheckAllowedCharsL(aFolderName);
-    if (allowed != EValidationOk)
-        {
-        // information note "Name cannot contain
-        // the characters < > \\ /"" |:*?" §qtn_fldr_illegal_characters§ is displayed.                 
-        DisplayNameErrorInfoL(iSharedResources->GetMsgIllegalCharacters());
-        }
-    return allowed;
-    }
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-TInt CMmFolderCommand::IllegalCharacterRemoveL(RBuf& aFolderName,
-        CLiwGenericParamList* aFoldersNames)
-    {
-    TValidation allowed( EValidationOk );
-    // illegal characters are removed
-    TInt pos( 0 );
-    while ( pos < aFolderName.Length() )
-        {
-        if ( aFolderName[pos] == KIllegalCharEnter ||
-             aFolderName[pos] == KIllegalCharLineSeparator )
-            {
-            aFolderName.Delete( pos, 1 );
-            }
-        else
-            {
-            ++pos;
-            }
-        }
-    if (aFolderName.Length() == 0)
-        {
-        aFolderName.Append(iSharedResources->GetDefaultFolderName());
-        ChangeNameIfAlreadyExistsL(aFolderName, aFoldersNames);
-        return allowed;
-        }
-    // only space character is not allowed
-    RBuf trimBuf;
-    CleanupClosePushL(trimBuf);
-    trimBuf.CreateL(aFolderName.Length());
-    trimBuf.Copy(aFolderName);
-    trimBuf.Trim();
-    if (!trimBuf.Length())
-        {
-        allowed = EValidationInvalid;
-        }
-    CleanupStack::PopAndDestroy(&trimBuf);
-
-    return allowed;
-    }
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-TInt CMmFolderCommand::CheckValidFileNameL( const TDes& aFolderName )
-    {
-    TValidation allowed(EValidationOk);
-    _LIT( KSingleDot, ".");
-    _LIT( KDoubleDot, "..");
-    
-    if (!aFolderName.Compare( KSingleDot) ||
-            !aFolderName.Compare( KDoubleDot ) ||
-            aFolderName.Length() > KMaxFileName)
-        {
-        allowed = EValidationInvalid;
-        }
-    else
-        {
-        // characters with ascii value less than 32
-        for (TInt index(0); index < aFolderName.Length(); index++)
-            {
-            if (aFolderName[index] < KSpace)
-                {
-                allowed = EValidationInvalid;                
-                }
-            }
-        }    
-    return allowed;
-    }
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-TInt CMmFolderCommand::CheckAllowedCharsL( const TDes& aFolderName )
-    {
-    TValidation allowed(EValidationOk);
-
-    for (TInt index(0); index < aFolderName.Length(); index++)
-        {
-        for (TInt c(0); c < KCountNotAllowedChars; c++)
-            {
-            if (TChar( KNotAllowedChars[c] ) == aFolderName[index])
-                {
-                allowed = EValidationNotAllowed;
-                }
-            }
-        }
-
-    return allowed;
-    }
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::DisplayNameErrorInfoL( const TDesC& aMsg )
-    {
-    CAknNoteDialog* dialog = new (ELeave) CAknNoteDialog(
-            CAknNoteDialog::EConfirmationTone,
-            CAknNoteDialog::ELongTimeout );
-    dialog->SetTextL( aMsg );
-    dialog->ExecuteDlgLD( R_MENU_EDIT_MOVING_ABORT_NOTIFICATION );
-    }
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::PrepareGetListInputL(TInt aItemId)
-	{
-    CLiwDefaultMap* inputMap = CLiwDefaultMap::NewLC();
-    
-    // Specify GetList input data
-    inputMap->InsertL( KIdAttrName8, TLiwVariant( TInt32( aItemId ) ) );         	// Item id
-    inputMap->InsertL( KRecursiveSearch8, TLiwVariant( TBool ( EFalse ) ) );	// Recursive Search
-    inputMap->InsertL( KFlatResult8, TLiwVariant ( TBool ( ETrue ) ) );	   	// Flat GetList
-    inputMap->InsertL( KParentOnly8, TLiwVariant ( TBool ( EFalse ) ) );	   	// Get children
-    
-    // Fill GetList input param list
-    InsertToLiwListL(iGetListInParam, KInData8, inputMap);
-
-    CleanupStack::PopAndDestroy(inputMap);
-	}
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::PrepareGetListFolderFilterL()
-	{
-    // Specify GetList filter
-	CLiwDefaultMap* folderFilter = CLiwDefaultMap::NewLC();
-	folderFilter->InsertL( KTypeAttrName8, TLiwVariant( KMenuFolder ) ); // Folders
-	
-	folderFilter->InsertL( KHidden8, TLiwVariant( TBool(EFalse) ) ); // Not Hidden
-	folderFilter->InsertL( KDeleteLocked8, TLiwVariant( TBool(EFalse) ) ); // Not locked
-	
-	// Fill GetList input param list
-	InsertToLiwListL(iGetListInParam, KFilter8, folderFilter);
-	
-	CleanupStack::PopAndDestroy(folderFilter);
-	}
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::PrepareGetListFilterL()
-    {
-    // Specify GetList filter
-    CLiwDefaultMap* folderFilter = CLiwDefaultMap::NewLC();
-    
-    folderFilter->InsertL( KHidden8, TLiwVariant( TBool(EFalse) ) ); // Not Hidden
-    folderFilter->InsertL( KMissing8, TLiwVariant( TBool(EFalse) ) ); // Not Missing
-    
-    // Fill GetList input param list
-    InsertToLiwListL(iGetListInParam, KFilter8, folderFilter);
-    
-    CleanupStack::PopAndDestroy(folderFilter);
-    }
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::InsertToLiwListL(CLiwGenericParamList* aList, 
-		const TDesC8& aKey, const CLiwDefaultMap* aMap)
-	{
-    TLiwVariant liwVar;    
-    liwVar.Set( aMap );
-    liwVar.PushL();
-    TLiwGenericParam livGenParam( aKey, liwVar );
-    livGenParam.PushL();
-    aList->AppendL ( livGenParam );
-    CleanupStack::PopAndDestroy( &livGenParam );
-    CleanupStack::PopAndDestroy( &liwVar ); 
-	}
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::ExternalizeInputListL()
-	{
-	iSerializedInputList.Close();
-	iSerializedOutputList.Close();
-	iSerializedInputList.CreateL( iGetListInParam->Size() );
-	RDesWriteStream datastrm( iSerializedInputList );
-	CleanupClosePushL(datastrm);
-	iGetListInParam->ExternalizeL(datastrm);
-	datastrm.CommitL();
-	CleanupStack::PopAndDestroy(&datastrm);
-	}
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-void CMmFolderCommand::InternalizeOutputListL()
-	{
-	iGetListOutParam->Reset();
-	if (iSerializedOutputList.Size())
-		{
-		RDesReadStream stream( iSerializedOutputList );
-		CleanupClosePushL( stream );
-		iGetListOutParam->InternalizeL( stream ) ;
-		CleanupStack::PopAndDestroy(&stream);
-		}
-	}
-
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-TInt CMmFolderCommand::GetIntL(
-        const CLiwGenericParamList& aParam, const TDesC8& aPath )
-    {
-    TInt pos( 0 );
-    const TLiwGenericParam* param = aParam.FindFirst( pos, aPath );
-    if( pos != KErrNotFound && param )
-        {
-        return param->Value().AsTInt32();
-        }
-    return KErrNotFound;
-    }
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-TPtrC CMmFolderCommand::GetStringL(
-        const CLiwGenericParamList& aParam, const TDesC8& aPath )
-    {
-    TInt pos( 0 );
-    const TLiwGenericParam* param = aParam.FindFirst( pos, aPath );
-    if( pos != KErrNotFound && param )
-        {
-        return param->Value().AsDes();
-        }
-    TPtrC ret( KNullDesC16 );
-    return ret; 
-    }
-
-// ---------------------------------------------------------------------------
-// 
-// ---------------------------------------------------------------------------
-//
-TBool CMmFolderCommand::GetBoolL(
-        const CLiwGenericParamList& aParam, const TDesC8& aPath )
-    {
-    TInt pos( 0 );
-    const TLiwGenericParam* param = aParam.FindFirst( pos, aPath );
-    if( pos != KErrNotFound && param )
-        {
-        return param->Value().AsTBool();
-        }
-    return EFalse; 
-    }
-
-// end of file