HRESULT CFoundationExemplars::TMchInstall(IModule* pModule)
{
	// Array of methods for transaction machine
	CMethodInfo rgMethod[] =
	{
		{ METHOD_SERVER,	"OnCreate",					"TMchOnCreate",					PSBIT_NONE, PS_EXEMPLARDEFAULTMETHOD },
		{ METHOD_CLIENT,	"UpdateCurrentIndex",		"TMchUpdateCurrentIndex",		PSBIT_NONE, PS_ALLEXECUTEMETHOD },
		{ METHOD_CLIENT,	"SetCurrentIndex",			"TMchSetCurrentIndex",			PSBIT_NONE, PS_ALLEXECUTEMETHOD },
		{ METHOD_CLIENT,	"OnCurrentIndexChanged",	"TMchOnCurrentIndexChanged",	PSBIT_NONE, PS_ALLEXECUTEMETHOD },
		{ METHOD_CLIENT,	"GetCurrentItem",			"TMchGetCurrentItem",			PSBIT_NONE, PS_ALLEXECUTEMETHOD },
		{ METHOD_SERVER,	"CreateAndDispenseObject",	"TMchCreateAndDispenseObject",	PSBIT_NONE, PS_ALLEXECUTEMETHOD }
	};
	int cMethod = sizeof(rgMethod)/sizeof(rgMethod[0]);
    int iMethod;

	HRESULT hr = S_OK;
	CComPtr<IThing> pTransMachineEx;
	CComPtr<IVector> pVector;
	CComPtr<IPropertyList> pItemList;

	CComPtr<IPropertyList> pMenu;
	CComPtr<IPropertyList> pMenuEx;
	CComPtr<IMenuItem> pMenuItem;
	CComPtr<IThing> pPrevBtnEx;
	CComPtr<IThing> pNextBtnEx;
	CComPtr<IThing> pSelectBtnEx;
	CComPtr<IThing> pDisplayEx;
	CComBSTR bstrName;
	CComBSTR bstrNameInternal;

	static CComBSTR bstrGeometryName("GeometryName");

	// Create the transaction machine exemplar
	if (FAILED(hr = m_pWorld->CreateExemplarEx(CComBSTR("Transaction Machine Exemplar"),
												CComBSTR("TransactionMachine"),
												CComVariant(CComBSTR("Artifact")), &pTransMachineEx)))
		goto ERROR_ENCOUNTERED;

	// Set the description string
	if (FAILED(hr = pTransMachineEx->put_Description(CComBSTR("A transaction machine which dispenses goods"))))
		goto ERROR_ENCOUNTERED;

	// Create a geometry for it
	if (FAILED(hr = pTransMachineEx->put_String(bstrGeometryName, CComBSTR("Client/Exemplar/Vending/Hvend.x"))))
		goto ERROR_ENCOUNTERED;

	// Set contents (buttons, display) to be visible
	if (FAILED(hr = pTransMachineEx->put_BOOL(CComBSTR("IsContentsVisible"), VARIANT_TRUE)))
		goto ERROR_ENCOUNTERED;

	// Add properties
	if (FAILED(hr = pTransMachineEx->AddPropertyExt(CComBSTR("Display"),
												CComVariant((IDispatch *) NULL),
												PSBIT_EXEMPLARDEFAULTPROPERTY,
												PS_EXEMPLARDEFAULTPROPERTY,
												VT_DISPATCH, IID_IThing, NULL)))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = pTransMachineEx->AddPropertyExt(CComBSTR("CurrentIndex"),
												CComVariant((short) 0),
												PSBIT_EXEMPLARDEFAULTPROPERTY,
												PS_ALLACCESSPROPERTY,
												VT_I2, IID_IDispatch, NULL)))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = CreatePropertyList(m_pWorld, &pItemList)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pTransMachineEx->AddPropertyExt(CComBSTR("ItemList"), 
												CComVariant((IDispatch *) pItemList), 
												PSBIT_EXEMPLARDEFAULTPROPERTY,
												PS_EXEMPLARDEFAULTCOLLECTION, 
												VT_DISPATCH, IID_IPropertyList, NULL)))
		goto ERROR_ENCOUNTERED;

    pItemList.Release();

	// Create "sub" exemplars with geometry for previous/next buttons, select button, & display
	// Previous Button
	if (FAILED(hr = m_pWorld->CreateExemplarEx(CComBSTR("Previous Button Exemplar"),
									   			 CComBSTR("PreviousButton"),
												 CComVariant(CComBSTR("Artifact")), &pPrevBtnEx)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pPrevBtnEx->put_String(bstrGeometryName, CComBSTR("Client/Exemplar/Vending/VButLeft.x"))))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = CreateVector(m_pWorld, 0.0, 0.0, 0.0, &pVector)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pPrevBtnEx->put_ObjectProperty(CComBSTR("Position"), pVector)))
		goto ERROR_ENCOUNTERED;
	pVector.Release();

	if (FAILED(hr = pPrevBtnEx->put_BOOL(CComBSTR("IsNoticeable"), VARIANT_TRUE)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pPrevBtnEx->put_BOOL(CComBSTR("IsTakeable"), VARIANT_FALSE)))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = pPrevBtnEx->CreateAndAddMethodExt(METHOD_CLIENT, pModule,
												 CComBSTR("TMchPreviousButton_OnLButtonDown"),
												 CComBSTR("OnLButtonDown"),
												 PSBIT_NONE, PS_ALLEXECUTEMETHOD)))
		goto ERROR_ENCOUNTERED;

	// Next Button
	if (FAILED(hr = m_pWorld->CreateExemplarEx(CComBSTR("Next Button Exemplar"),
												 CComBSTR("NextButton"),
												 CComVariant(CComBSTR("Artifact")), &pNextBtnEx)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pNextBtnEx->put_String(bstrGeometryName, CComBSTR("Client/Exemplar/Vending/VBuRight.x"))))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = CreateVector(m_pWorld, 0.0, 0.0, 0.0, &pVector)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pNextBtnEx->put_ObjectProperty(CComBSTR("Position"), pVector)))
		goto ERROR_ENCOUNTERED;
	pVector.Release();

	if (FAILED(hr = pNextBtnEx->put_BOOL(CComBSTR("IsNoticeable"), VARIANT_TRUE)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pNextBtnEx->put_BOOL(CComBSTR("IsTakeable"), VARIANT_FALSE)))
		goto ERROR_ENCOUNTERED;
	
	if (FAILED(hr = pNextBtnEx->CreateAndAddMethodExt(METHOD_CLIENT, pModule,
												 CComBSTR("TMchNextButton_OnLButtonDown"),
												 CComBSTR("OnLButtonDown"),
												 PSBIT_NONE, PS_ALLEXECUTEMETHOD)))
		goto ERROR_ENCOUNTERED;

	// Select Button
	if (FAILED(hr = m_pWorld->CreateExemplarEx(CComBSTR("Select Button Exemplar"),
												 CComBSTR("SelectButton"),
												 CComVariant(CComBSTR("Artifact")), &pSelectBtnEx)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pSelectBtnEx->put_String(bstrGeometryName, CComBSTR("Client/Exemplar/Vending/VButBuy.x"))))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = CreateVector(m_pWorld, 0.0, 0.0, 0.0, &pVector)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pSelectBtnEx->put_ObjectProperty(CComBSTR("Position"), pVector)))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = pSelectBtnEx->put_BOOL(CComBSTR("IsNoticeable"), VARIANT_TRUE)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pSelectBtnEx->put_BOOL(CComBSTR("IsTakeable"), VARIANT_FALSE)))
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = pSelectBtnEx->CreateAndAddMethodExt(METHOD_CLIENT, pModule,
												 CComBSTR("TMchSelectButton_OnLButtonDown"),
												 CComBSTR("OnLButtonDown"),
												 PSBIT_NONE, PS_ALLEXECUTEMETHOD)))
		goto ERROR_ENCOUNTERED;

	// Display
	if (SUCCEEDED(hr = m_pWorld->CreateExemplarEx(CComBSTR("Display Exemplar"),
											   CComBSTR("Display"),
											   CComVariant(CComBSTR("Artifact")), &pDisplayEx)))
    {
	    CComBSTR bstrGeomFile("worlds/plazas/commons/filerock.gif");
	    CComVariant varFile(bstrGeomFile);

	    CComDISPPARAMS dpInitGraphics(10, varFile, 
							      CComVariant(0.0f), CComVariant(0.45f), CComVariant(0.0f),
							      CComVariant(0.0f), CComVariant(0.0f), CComVariant(1.0f),
							      CComVariant(0.25f), CComVariant(0.25f), CComVariant(0.25f));

	    pDisplayEx->InvokeMethodExt(CComBSTR("InitializeSpriteGraphics"), (DISPPARAMS *) dpInitGraphics, NULL);
    }
    else
		goto ERROR_ENCOUNTERED;

	if (FAILED(hr = pDisplayEx->put_BOOL(CComBSTR("IsNoticeable"), VARIANT_TRUE)))
		goto ERROR_ENCOUNTERED;
	if (FAILED(hr = pDisplayEx->put_BOOL(CComBSTR("IsTakeable"), VARIANT_FALSE)))
		goto ERROR_ENCOUNTERED;
	// SetGraphic must be server-side so that we have the proper security context
	if (FAILED(hr = pDisplayEx->CreateAndAddMethodExt(METHOD_SERVER, pModule,
												 CComBSTR("TMchDisplay_SetGraphic"),
												 CComBSTR("SetGraphic"),
												 PSBIT_NONE, PS_ALLEXECUTEMETHOD)))
		goto ERROR_ENCOUNTERED;
	
	// Add in the methods
	for (iMethod=0; iMethod<cMethod; iMethod++)
	{
		bstrName = rgMethod[iMethod].pszName;
		if (rgMethod[iMethod].pszNameInternal == NULL)
			bstrNameInternal = bstrName;
		else
			bstrNameInternal = rgMethod[iMethod].pszNameInternal;
		if (FAILED(hr = pTransMachineEx->CreateAndAddMethodExt(	rgMethod[iMethod].lFlags,
														pModule,
														bstrNameInternal,
														bstrName,
														rgMethod[iMethod].psbits,
														rgMethod[iMethod].permissions)))
    		goto ERROR_ENCOUNTERED;
	}


    // Add menu items here
    return S_OK;

ERROR_ENCOUNTERED:
	
    return hr;
}