size_t GetMinUnused(const set_size_t& used, const set_size_t& unused, const vector_2d_size_t& diff, size_t& minDiff, size_t& minIndex)
{
    LOCAL_ASSERT(!used.empty());
    LOCAL_ASSERT(!unused.empty());

    minDiff = 1UL << 30;
    size_t minUnused = 0;

    for (auto pu = used.begin(); pu != used.end(); ++pu)
    {
        for (auto pn = unused.begin(); pn != unused.end(); ++pn)
        {
            const size_t usedIndex = *pu;
            const size_t unusedIndex = *pn;
            const size_t d = diff[usedIndex][unusedIndex];
            if (d < minDiff)
            {
                minDiff = d;
                minUnused = unusedIndex;
                minIndex = usedIndex;
            }
        }
    }

    return minUnused;
}
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_RegisterServiceDescriptionLL_noContractL(TTestResult& aResult)
    {
	SetupL(); 

    TInt error = KErrNone;
    
    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
	error = iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription);
    RDebug::Print( _L( "WSModTester: CSenServiceManager_RegisterServiceDescriptionLL_noContract status %d" ), error);
    
    //not set
    iSenXmlServiceDescription->SetEndPointL(KText);
    error = iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription);
    RDebug::Print( _L( "WSModTester: CSenServiceManager_RegisterServiceDescriptionLL_noContract status %d" ), error);
    LOCAL_ASSERT(error == KErrSenNoContract);
    
    //null
    iSenXmlServiceDescription->SetContractL(KNullDesC8);
    error = iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription);
    RDebug::Print( _L( "WSModTester: CSenServiceManager_RegisterServiceDescriptionLL_noContract status %d" ), error);
    LOCAL_ASSERT(error == KErrSenNoContract);

    Teardown();
    return KErrNone;
    
}
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_ServiceDescriptionsL_1L_notFoundL(TTestResult& aResult)
{
	SetupL(); 

    RServiceDescriptionArray arr;
    LOCAL_ASSERT(iServiceManager->ServiceDescriptionsL(KText, arr) == KErrNotFound);
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
}
TInt CsenservicemanagerTester::UT_CSenServiceManager_UnregisterServiceDescriptionLL_normalL(CStifItemParser& aItem)
    {
	SetupL(); 

    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
    LOCAL_ASSERT((iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);

    Teardown();
    return KErrNone;
    }
TInt CsenservicemanagerTester::UT_CSenServiceManager_ServiceDescriptionsL_1L_notFoundL(CStifItemParser& aItem)
{
	SetupL(); 

    RServiceDescriptionArray arr;
    LOCAL_ASSERT(iServiceManager->ServiceDescriptionsL(KText, arr) == KErrNotFound);
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
}
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_UnregisterServiceDescriptionLL_normalL(TTestResult& aResult)
    {
	SetupL(); 

    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
    LOCAL_ASSERT((iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);

    Teardown();
    return KErrNone;
    }
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_NewLL( TTestResult& aResult )
    {
    Empty();
    
    CSenServiceManager*     serviceManager = NULL;
    CSenServiceManager*     serviceManager2 = NULL;
    serviceManager = CSenServiceManager::NewL();
    TL(serviceManager != (CSenServiceManager*)NULL);

    __ASSERT_ALWAYS_NO_LEAVE(delete serviceManager );
    
    serviceManager = NULL;

    serviceManager = CSenServiceManager::NewL();
    TRAPD(error, serviceManager2 = CSenServiceManager::NewL());
    RDebug::Print( _L( "WSModTester: CSenServiceManager_NewL 2nd try with status %d" ), error);
    LOCAL_ASSERT(error==KErrNone);

    if (serviceManager != NULL){
        __ASSERT_ALWAYS_NO_LEAVE(delete serviceManager );
        serviceManager = NULL;
    }

    if (serviceManager2 != NULL){
        __ASSERT_ALWAYS_NO_LEAVE(delete serviceManager2 );
        serviceManager2 = NULL;
    }

    Empty();
    return KErrNone;
    }
size_t GetAns(const size_t fieldSize, const size_t w, const vector_2d_size_t& diff, const size_t firstLevel, vector_move_t& sequence)
{
    const size_t k = diff.size();   

    size_t ans = fieldSize;
    sequence.clear();
    sequence.push_back(move_t(firstLevel, 0));

    set_size_t used;
    used.insert(firstLevel);

    set_size_t unused;
    for (size_t i = 0; i < k; i++)
    {
        if (i != firstLevel)
            unused.insert(i);
    }

    for (size_t i = 1; i < k; i++)
    {
        size_t minDiff = 0;
        size_t minIndex = 0;
        const size_t minUnused = GetMinUnused(used, unused, diff, minDiff, minIndex);
        LOCAL_ASSERT(used.find(minUnused) == used.end());
        LOCAL_ASSERT(unused.find(minUnused) != unused.end());
        if (minDiff * w < fieldSize)
        {
            sequence.push_back(move_t(minUnused, minIndex + 1));
            ans += minDiff * w;
        }
        else
        {
            sequence.push_back(move_t(minUnused, 0));
            ans += fieldSize;
        }
        used.insert(minUnused);
        unused.erase(minUnused);
    }

    LOCAL_ASSERT(unused.empty());
    return ans;
}
//-------------------------------------------
//              SEARCHING
//-------------------------------------------
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_ServiceDescriptionsLL_normalL(TTestResult& aResult)
    {
	SetupL(); 
	   
    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
 
    RServiceDescriptionArray arr;
    LOCAL_ASSERT(iServiceManager->ServiceDescriptionsL(*iSenXmlServiceDescription, arr) == KErrNone);
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 1);
    arr.ResetAndDestroy();
    
    //Added Vaibhav
    iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription);
    
    Teardown();
    return KErrNone;
    }
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_ServiceDescriptionsLL_badDescriptorL(TTestResult& aResult)
    {
	SetupL(); 

    iSenXmlServiceDescription->SetEndPointL(KNullDesC8);
    RServiceDescriptionArray arr;
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
    }
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_ServiceDescriptionsL_1L_badDescriptorL(TTestResult& aResult)
{
	SetupL(); 

    RServiceDescriptionArray arr;
    //LOCAL_ASSERT(iServiceManager->ServiceDescriptionsL(KNullDesC8, arr) == KErrBadDescriptor);
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
}
TInt CsenservicemanagerTester::UT_CSenServiceManager_RegisterServiceDescriptionLL_badFrameworkL(CStifItemParser& aItem)
    {
	SetupL(); 

    _LIT8(KBadFramework,"bla");
    iSenXmlServiceDescription->SetFrameworkIdL(KBadFramework);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNotFound);

    Teardown();
    return KErrNone;
}
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_RegisterServiceDescriptionLL_badFrameworkL(TTestResult& aResult)
    {
	SetupL(); 

    _LIT8(KBadFramework,"bla");
    iSenXmlServiceDescription->SetFrameworkIdL(KBadFramework);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNotFound);

    Teardown();
    return KErrNone;
}
TInt CsenservicemanagerTester::UT_CSenServiceManager_ServiceDescriptionsLL_badDescriptorL(CStifItemParser& aItem)
    {
	SetupL(); 

    iSenXmlServiceDescription->SetEndPointL(KNullDesC8);
    RServiceDescriptionArray arr;
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
    }
TInt CsenservicemanagerTester::UT_CSenServiceManager_RegisterIdentityProviderLL_normalL(CStifItemParser& aItem)
    {
	SetupL(); 

    iProvider->SetProviderID(KText);
    iProvider->SetUserInfoL(KText, KText, KText);
    LOCAL_ASSERT((iServiceManager->RegisterIdentityProviderL(*iProvider)) == KErrNone); 

	//Added Vaibhav
	iServiceManager->UnregisterIdentityProviderL(*iProvider);
	
    Teardown();
    return KErrNone;
    }
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_RegisterIdentityProviderLL_normalL(TTestResult& aResult)
    {
	SetupL(); 

    iProvider->SetProviderID(KText);
    iProvider->SetUserInfoL(KText, KText, KText);
    LOCAL_ASSERT((iServiceManager->RegisterIdentityProviderL(*iProvider)) == KErrNone); 

	//Added Vaibhav
	iServiceManager->UnregisterIdentityProviderL(*iProvider);
	
    Teardown();
    return KErrNone;
    }
TInt CsenservicemanagerTester::UT_CSenServiceManager_ServiceDescriptionsL_1L_normalL(CStifItemParser& aItem)
    {
    
	SetupL(); 

    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
 
    RServiceDescriptionArray arr;
    LOCAL_ASSERT(iServiceManager->ServiceDescriptionsL(KText, arr) == KErrNone);
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 1);
    LOCAL_ASSERT((iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
    
    arr.ResetAndDestroy();

	//Added Vaibhav
	//iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription);

    Teardown();
    return KErrNone;
    }
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_UnregisterServiceDescriptionLL_randomPtrL(TTestResult& aResult)
    {
	SetupL(); 

    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
    iSenXmlServiceDescription = (CSenXmlServiceDescription *)0xeaeaea;
   	#ifdef __WINS__
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcAccessViolation) ;
	#else
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcPageFault) ;
	#endif      
	iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription);

    Teardown();
    return KErrNone;
    }
TInt CsenservicemanagerTester::UT_CSenServiceManager_UnregisterServiceDescriptionLL_nullL(CStifItemParser& aItem)
    {
	SetupL(); 

    iSenXmlServiceDescription->SetFrameworkIdL(KDefaultIdWsfFrameworkID);
    iSenXmlServiceDescription->SetEndPointL(KText);
    iSenXmlServiceDescription->SetContractL(KText);
    LOCAL_ASSERT((iServiceManager->RegisterServiceDescriptionL( *iSenXmlServiceDescription)) == KErrNone);
    iSenXmlServiceDescription = NULL;
   	#ifdef __WINS__
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcAccessViolation) ;
	#else
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcPageFault) ;
	#endif      
	iServiceManager->UnregisterServiceDescriptionL( *iSenXmlServiceDescription);

    Teardown();
    return KErrNone;
    
    }
TInt CsenservicemanagerTester::UT_CSenServiceManager_ServiceDescriptionsLL_nullL(CStifItemParser& aItem)
    {
	SetupL(); 

    delete iSenXmlServiceDescription;
    iSenXmlServiceDescription = NULL;
    RServiceDescriptionArray arr;
	
	#ifdef __WINS__
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcAccessViolation) ;
	#else
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcPageFault) ;
	#endif     
	iServiceManager->ServiceDescriptionsL(*iSenXmlServiceDescription, arr);
	
  	TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
    }
TInt CSenServiceManagerBCTest::UT_CSenServiceManager_ServiceDescriptionsLL_randomPtrL(TTestResult& aResult)
    {
	SetupL(); 

    delete iSenXmlServiceDescription;
    iSenXmlServiceDescription = (CSenXmlServiceDescription *)0xeaeaea;
    RServiceDescriptionArray arr;

	#ifdef __WINS__
		TestModuleIf().SetExitReason (TestModuleIf(). EException, EExcAccessViolation) ;
	#else
		TestModuleIf().SetExitReason (TestModuleIf(). EException,EExcPageFault);
	#endif      
	iServiceManager->ServiceDescriptionsL(*iSenXmlServiceDescription, arr);
    
    TInt SDs = arr.Count();
    LOCAL_ASSERT(SDs == 0);
    arr.ResetAndDestroy();

    Teardown();
    return KErrNone;
    }
Exemple #22
0
/****************************************************************************
* MagicInit *
*-----------*
*   Description:  
*       Initializes the symbol loading code. Currently called (if necessary)
*       at the beginning of each method that might need ImageHelp to be
*       loaded.
****************************************************************************/
void MagicInit()
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
    
    if (g_fLoadedImageHlp || g_fLoadedImageHlpFailed)
    {
        return;
    }

    g_hProcess = GetCurrentProcess();

    if (g_hinstDbgHelp == NULL)
    {
        g_hinstDbgHelp = LoadDbgHelp();
    }
    if (NULL == g_hinstDbgHelp)
    {
        // Imagehlp.dll has dependency on dbghelp.dll through delay load.
        // If dbghelp.dll is not available, Imagehlp.dll initializes API's like ImageApiVersionEx to
        // some dummy function.  Then we AV when we use data from _ImagehlpApiVersionEx
        g_fLoadedImageHlpFailed = TRUE;
        return;
    }

    //
    // Try to load imagehlp.dll
    //
    if (g_hinstImageHlp == NULL) {
        g_hinstImageHlp = LoadImageHlp();
    }
    LOCAL_ASSERT(g_hinstImageHlp);

    if (NULL == g_hinstImageHlp)
    {
        g_fLoadedImageHlpFailed = TRUE;
        return;
    }

    //
    // Try to get the API entrypoints in imagehlp.dll
    //
    for (int i = 0; i < COUNT_OF(ailFuncList); i++)
    {
        *(ailFuncList[i].ppvfn) = GetProcAddress(
                g_hinstImageHlp, 
                ailFuncList[i].pszFnName);
        LOCAL_ASSERT(*(ailFuncList[i].ppvfn));
        
        if (!*(ailFuncList[i].ppvfn))
        {
            g_fLoadedImageHlpFailed = TRUE;
            return;
        }
    }

    API_VERSION AppVersion = { 4, 0, API_VERSION_NUMBER, 0 };
    LPAPI_VERSION papiver = _ImagehlpApiVersionEx(&AppVersion);

    //
    // We assume any version 4 or greater is OK.
    //
    LOCAL_ASSERT(papiver->Revision >= 4);
    if (papiver->Revision < 4)
    {
        g_fLoadedImageHlpFailed = TRUE;
        return;
    }

    g_fLoadedImageHlp = TRUE;
    
    //
    // Initialize imagehlp.dll.  A NULL search path is supposed to resolve
    // symbols but never works.  So pull in everything and put some additional
    // hints that might help out a dev box.
    //

    _SymSetOptions(_SymGetOptions() | SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
#ifndef _WIN64
    _SymRegisterCallback(g_hProcess, SymCallback, 0);
#endif

    CQuickBytes qbSearchPath;
    LPSTR szSearchPath = FillSymbolSearchPath(qbSearchPath);
    _SymInitialize(g_hProcess, szSearchPath, TRUE);

    return;
}
Exemple #23
0
UINT GetStackBacktrace
(
UINT ifrStart,          // How many stack elements to skip before starting. 
UINT cfrTotal,          // How many elements to trace after starting.
DWORD_PTR* pdwEip,      // Array to be filled with stack addresses.
SYM_INFO* psiSymbols,   // This array is filled with symbol information.
                        // It should be big enough to hold cfrTotal elts.
                        // If NULL, no symbol information is stored.
CONTEXT * pContext      // Context to use (or NULL to use current)
)
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
    
    UINT        nElements   = 0;
    DWORD_PTR*  pdw         = pdwEip;
    SYM_INFO*   psi         = psiSymbols;

    MagicInit();

    memset(pdwEip, 0, cfrTotal*sizeof(DWORD_PTR));

    if (psiSymbols)
    {
        memset(psiSymbols, 0, cfrTotal * sizeof(SYM_INFO));
    }

    if (!g_fLoadedImageHlp)
    {
        return 0;
    }

    CONTEXT context;
    if (pContext == NULL)
    {
        ClrCaptureContext(&context);
    }
    else
    {   
        memcpy(&context, pContext, sizeof(CONTEXT));
    }

#ifdef _WIN64
    STACKFRAME64 stkfrm;
    memset(&stkfrm, 0, sizeof(STACKFRAME64));
#else
    STACKFRAME stkfrm;
    memset(&stkfrm, 0, sizeof(STACKFRAME));
#endif

    stkfrm.AddrPC.Mode      = AddrModeFlat;
    stkfrm.AddrStack.Mode   = AddrModeFlat;
    stkfrm.AddrFrame.Mode   = AddrModeFlat;
#if defined(_M_IX86)
    stkfrm.AddrPC.Offset    = context.Eip;
    stkfrm.AddrStack.Offset = context.Esp;
    stkfrm.AddrFrame.Offset = context.Ebp;  // Frame Pointer
#endif

#ifndef _TARGET_X86_
    // If we don't have a user-supplied context, then don't skip any frames.
    // So ignore this function (GetStackBackTrace)
    // ClrCaptureContext on x86 gives us the ESP/EBP/EIP of its caller's caller
    // so we don't need to do this.
    if (pContext == NULL)
    {
        ifrStart += 1;        
    }
#endif // !_TARGET_X86_

    for (UINT i = 0; i < ifrStart + cfrTotal; i++)
    {
        if (!_StackWalk(IMAGE_FILE_MACHINE_NATIVE,
                        g_hProcess,
                        GetCurrentThread(),
                        &stkfrm,
                        &context,
                        NULL,
                        (PFUNCTION_TABLE_ACCESS_ROUTINE)FunctionTableAccess,
                        (PGET_MODULE_BASE_ROUTINE)GetModuleBase,
                        NULL))
        {
            break;
        }

        if (i >= ifrStart)
        {
            *pdw++ = stkfrm.AddrPC.Offset;
            nElements++;

            if (psi)
            {
                FillSymbolInfo(psi++, stkfrm.AddrPC.Offset);
            }   
        }
    }

    LOCAL_ASSERT(nElements == (UINT)(pdw - pdwEip));
    return nElements;
}
Exemple #24
0
/****************************************************************************
* FillSymbolInfo *
*----------------*
*   Description:  
*       Fills in a SYM_INFO structure
****************************************************************************/
void FillSymbolInfo
(
SYM_INFO *psi,
DWORD_PTR dwAddr
)
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
    
    if (!g_fLoadedImageHlp)
    {
        return;
    }

    LOCAL_ASSERT(psi);
    memset(psi, 0, sizeof(SYM_INFO));

    PLAT_IMAGEHLP_MODULE  mi;
    mi.SizeOfStruct = sizeof(mi);
    
    if (!_SymGetModuleInfo(g_hProcess, dwAddr, &mi))
    {
        strcpy_s(psi->achModule, _countof(psi->achModule), "<no module>");
    }
    else
    {
        strcpy_s(psi->achModule, _countof(psi->achModule), mi.ModuleName);
        _strupr_s(psi->achModule, _countof(psi->achModule));
    }

    CHAR rgchUndec[256];
    const CHAR * pszSymbol = NULL;

    // Name field of IMAGEHLP_SYMBOL is dynamically sized.
    // Pad with space for 255 characters.
    union
    {
        CHAR rgchSymbol[sizeof(PLAT_IMAGEHLP_SYMBOL) + 255];
        PLAT_IMAGEHLP_SYMBOL  sym;
    };

    __try
    {
        sym.SizeOfStruct = sizeof(PLAT_IMAGEHLP_SYMBOL);
        sym.Address = dwAddr;
        sym.MaxNameLength = 255;

        if (_SymGetSymFromAddr(g_hProcess, dwAddr, &psi->dwOffset, &sym))
        {
            pszSymbol = sym.Name;

            if (_SymUnDName(&sym, rgchUndec, COUNT_OF(rgchUndec)-1))
            {
                pszSymbol = rgchUndec;
            }
        }
        else
        {
            pszSymbol = "<no symbol>";
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        pszSymbol = "<EX: no symbol>";
        psi->dwOffset = dwAddr - mi.BaseOfImage;
    }

    strcpy_s(psi->achSymbol, _countof(psi->achSymbol), pszSymbol);
}
bool Solve(std::istream& ist, std::ostream& ost, const bool multipleTestMode)
{
    StopWatch<1> sw; sw;

    // 
    size_t n, m, k;
    size_t w;
    ist >> n >> m >> k >> w;

    if (multipleTestMode && !ist)
        return false;

    vector_2d_string8_t levels(k, vector_string8_t(n));

    for (size_t l = 0; l < k; l++)
    {
        for (size_t i = 0; i < n; i++)
        {
            ist >> levels[l][i];
        }
    }

    // 
    vector_2d_size_t diff(k, vector_size_t(k));
    for (size_t a1 = 0; a1 < k; a1++)
    {
        for (size_t a2 = a1 + 1; a2 < k; a2++)
        {
            for (size_t i = 0; i < n; i++)
            {
                for (size_t j = 0; j < m; j++)
                {
                    if (levels[a1][i][j] != levels[a2][i][j])
                    {
                        diff[a1][a2] += 1;
                        diff[a2][a1] += 1;
                    }
                }
            }
        }
    }

    size_t minDiff = 1UL << 31;
    size_t minA1 = 0;
    size_t minA2 = 0;
    for (size_t a1 = 0; a1 < k; a1++)
    {
        for (size_t a2 = a1 + 1; a2 < k; a2++)
        {
            const size_t d = diff[a1][a2];
            if (minDiff > d)
            {
                minDiff = d;
                minA1 = a1;
                minA2 = a2;
            }
        }
    }
    const size_t fieldSize = n * m;
    LOCAL_ASSERT(minA1 != minA2);

    vector_move_t minSequence;
    const size_t ans = GetAns(fieldSize, w, diff, minA1, minSequence);

    ost << ans << std::endl;
    for (size_t i = 0; i < k; i++)
    {
        ost << (minSequence[i].index + 1) << ' ' << minSequence[i].way << std::endl;
    }
    
    return multipleTestMode;
}