text:
//  Copyright (c) Govert van Drimmelen. All rights reserved.
//  Excel-DNA is licensed under the zlib license. See LICENSE.txt for details.

// TODO: Change to the .Net 2.0+ hosting interface IClrRuntimeHost,
// so that we can set the safe AppDomain flags when loading.

#include "stdafx.h"
#include <string>
#include <tchar.h>
#include "resource.h"
#include "MiscUtils.h"
#include "DetectFx.h"
#include "ExcelDna.h"
#include "ExcelDnaLoader.h"

#define CountOf(x) sizeof(x)/sizeof(*x)
const int MAX_MSG = 1024;
const std::wstring CLR_VERSION_20 = L"v2.0.50727";

static HMODULE hModuleCurrent;
// These don't use ATL classes to give us explicit control over when CLR is called
static IUnknown* pAppDomain_ForUnload = NULL;
static ICorRuntimeHost* pHost_ForUnload = NULL;
// Temp file to be used if we need to write .config from resources.
static TempFileHolder tempConfig;

// Forward declarations for functions defined in this file.
HRESULT LoadClr(std::wstring clrVersion, ICorRuntimeHost **ppHost);
HRESULT LoadClrMeta(std::wstring clrVersion, ICLRMetaHost* pMetaHost, ICorRuntimeHost **ppHost);
HRESULT LoadClr20(ICorRuntimeHost **ppHost);

_COM_SMARTPTR_TYPEDEF(ICorRuntimeHost, IID_ICorRuntimeHost);
EXTERN_GUID(IID__Assembly,	0x17156360, 0x2f1a, 0x384a, 0xbc, 0x52, 0xfd, 0xe9, 0x3c, 0x21, 0x5c, 0x5b);
_COM_SMARTPTR_TYPEDEF(_Assembly, IID__Assembly);
_COM_SMARTPTR_TYPEDEF(_AppDomain, IID__AppDomain);
_COM_SMARTPTR_TYPEDEF(IAppDomainSetup, IID_IAppDomainSetup);
_COM_SMARTPTR_TYPEDEF(_Type, IID__Type);
_COM_SMARTPTR_TYPEDEF(ICLRMetaHost, IID_ICLRMetaHost);
_COM_SMARTPTR_TYPEDEF(ICLRRuntimeInfo, IID_ICLRRuntimeInfo);

HRESULT LoadAppDomain(ICorRuntimeHostPtr pHost, std::wstring addInFullPath, bool createSandboxedAppDomain, bool shadowCopyFiles, _AssemblyPtr& loaderAssembly, _AppDomainPtr& addInAppDomain, bool& unloadAppDomain);
HRESULT LoadLoaderIntoAppDomain(_AppDomainPtr& pAppDomain, _AssemblyPtr& pLoaderAssembly, bool forceFromBytes);
void ShowMessage(int headerId, int bodyId, int footerId, HRESULT hr = S_OK);
HRESULT CreateTempFile(void* pBuffer, DWORD nBufSize, std::wstring& fileName);
HRESULT DeleteTempFile(std::wstring fileName);

HRESULT GetClrOptions(std::wstring& clrVersion, bool& shadowCopyFiles, bool& createSandboxedAppDomain);
HRESULT GetDnaHeader(bool showErrors, std::wstring& header);
HRESULT ParseDnaHeader(std::wstring header, std::wstring& addInName, std::wstring& runtimeVersion, bool& shadowCopyFiles, std::wstring& createSandboxedAppDomain);
HRESULT GetAttributeValue(std::wstring tag, std::wstring attributeName, std::wstring& attributeValue);

BOOL IsRunningOnCluster();

BOOL IsBufferUTF8(BYTE* buffer, DWORD bufferLength);
std::wstring UTF8toUTF16(const std::string& utf8);

// COR function pointer typedefs.
typedef HRESULT (STDAPICALLTYPE *pfnGetCORVersion)(LPWSTR pBuffer,
                                         DWORD cchBuffer,
                                         DWORD* dwLength);

typedef HRESULT (STDAPICALLTYPE *pfnGetVersionFromProcess)(
										 HANDLE hProcess,
										 LPWSTR pBuffer,
                                         DWORD cchBuffer,
                                         DWORD* dwLength);

typedef HRESULT (STDAPICALLTYPE *pfnCorBindToRuntimeEx)(
									LPWSTR pwszVersion,
									LPWSTR pwszBuildFlavor,
									DWORD flags,
									REFCLSID rclsid,
									REFIID riid,
									LPVOID* ppv );

typedef HRESULT (STDAPICALLTYPE *pfnCLRCreateInstance)(
									REFCLSID  clsid,
									REFIID riid,
									LPVOID* ppInterface );

// Ensure the CLR is loaded, create a new AppDomain, get the manager loader running,
// and do the ExportInfo hook-up.
bool XlLibraryInitialize(XlAddInExportInfo* pExportInfo)
{
	HRESULT hr;
	ICorRuntimeHostPtr pHost;
	std::wstring clrVersion;
	bool shadowCopyFiles;
	bool createSandboxedAppDomain;

	hr = GetClrOptions(clrVersion, shadowCopyFiles, createSandboxedAppDomain);
	if (FAILED(hr))
	{
		// SelectClrVersion shows diagnostic MessageBoxes if needed.
		// Perhaps remember that we are not loaded?
		return 0;
	}
#ifdef _M_X64
	bool allowedVersion = CompareNoCase(clrVersion, L"v4.0") >= 0;
	if (!allowedVersion)
	{
		ShowMessage(IDS_MSG_HEADER_64NET4,
					IDS_MSG_BODY_64NET4,
					IDS_MSG_FOOTER_ENSUREVERSION,
					hr);
		return 0;
	}
#endif
	hr = LoadClr(clrVersion, &pHost);
	if (FAILED(hr) || pHost == NULL)
	{
		// LoadClr shows diagnostic MessageBoxes if needed.
		// Perhaps remember that we are not loaded?
		return 0;
	}

	// If all is fine now, also start the CLR (always safe to do again).
	hr = pHost->Start();
	if (FAILED(hr))
	{
		ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
					IDS_MSG_BODY_HOSTSTART,
					IDS_MSG_FOOTER_UNEXPECTED,
					hr);
		return 0;
	}

	// Load (or find) the AppDomain that will contain the add-in
	std::wstring addInFullPath = GetAddInFullPath();
	_AppDomainPtr pAppDomain;
	_AssemblyPtr pLoaderAssembly;
	bool unloadAppDomain;

	hr = LoadAppDomain(pHost, addInFullPath, createSandboxedAppDomain, shadowCopyFiles, pLoaderAssembly, pAppDomain, unloadAppDomain);
	if (FAILED(hr))
	{
		// Message already shown by LoadAppDomain
		return 0;
	}

	_TypePtr pXlAddInType;
	hr = pLoaderAssembly->GetType_2(_bstr_t(L"ExcelDna.Loader.XlAddIn"), &pXlAddInType);
	if (FAILED(hr) || pXlAddInType == NULL)
	{
		ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
					IDS_MSG_BODY_XLADDIN,
					IDS_MSG_FOOTER_UNEXPECTED,
					hr);
		return 0;
	}

	SafeVariantArray initArgs(3);
	initArgs.lock();
#ifndef _M_X64
	initArgs.setElement(0, (INT32)pExportInfo);
	initArgs.setElement(1, (INT32)hModuleCurrent);
#else
	initArgs.setElement(0, (INT64)pExportInfo);
	initArgs.setElement(1, (INT64)hModuleCurrent);
#endif
	initArgs.setElement(2, SysAllocStringLen(addInFullPath.c_str(), static_cast<UINT>(addInFullPath.length())));
	initArgs.unlock();
	_variant_t initRetVal;
	_variant_t target;
#ifndef _M_X64
	hr = pXlAddInType->InvokeMember_3(_bstr_t("Initialize32"), (BindingFlags)(BindingFlags_Static | BindingFlags_Public | BindingFlags_InvokeMethod), NULL, target, initArgs, &initRetVal);
#else
	hr = pXlAddInType->InvokeMember_3(_bstr_t("Initialize64"), (BindingFlags)(BindingFlags_Static | BindingFlags_Public | BindingFlags_InvokeMethod), NULL, target, initArgs, &initRetVal);
#endif
	if (FAILED(hr) || initRetVal.boolVal == 0)
	{
		ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
					IDS_MSG_BODY_XLADDININIT,
					IDS_MSG_FOOTER_CHECKINTEGRATION,
					hr);
		return 0;
	}

	// Keep references needed for later host reference unload.
	if (unloadAppDomain)
	{
		pAppDomain_ForUnload = (IUnknown*)pAppDomain.Detach();
	}
	pHost_ForUnload = pHost.Detach();

	return initRetVal.boolVal == 0 ? false : true;
}

// XlLibraryUnload is only called if we are unloading the add-in via the add-in manager,
// or when the add-in is re-loaded.
// Unload the AppDomain.
void XlLibraryUnload()
{
	if (pHost_ForUnload != NULL)
	{
		if (pAppDomain_ForUnload != NULL)
		{
			HRESULT hr = pHost_ForUnload->UnloadDomain(pAppDomain_ForUnload);
			pAppDomain_ForUnload->Release();
			pAppDomain_ForUnload = NULL;
			if (FAILED(hr))
			{
#if _DEBUG
				DebugBreak();
#endif
			}
		}
		//else
		//{
			// Unload according to the AppDomainId.
		//}

		pHost_ForUnload->Release();
		pHost_ForUnload = NULL;
	}
	// Also delete the temp .config file, if we made one.
	tempConfig.destroy();
}

// Try to get the right version of the CLR running.
HRESULT LoadClr(std::wstring clrVersion, ICorRuntimeHost **ppHost)
{
	// Check whether the .Net 4+ MetaHost interfaces are present.
	// The checks here are according to this blog post:
	// http://bradwilson.typepad.com/blog/2010/04/selecting-clr-version-from-unmanaged-host.html
	/*
	1. LoadLibrary mscoree
	2. GetProcAddress for CLRCreateInstance. If you get NULL, fall back to legacy path (CorBindToRuntimeEx)
	3. Call CLRCreateInstance to get ICLRMetaHost. If you get E_NOTIMPL, fall back to legacy path (same as above)
	4. Otherwise, party on the ICLRMetaHost you just got
	*/
	// If present, load the desired version using the new interfaces.
	// If not, check if we want .Net 4+, if so fail, else load old-style.

	HRESULT hr = E_FAIL;
	HMODULE hMscoree = NULL;
	ICLRMetaHostPtr pMetaHost;

	bool needNet40 = (CompareNoCase(clrVersion, L"v4.0") >= 0);
	bool needMetaHost = needNet40;

	hMscoree = LoadLibrary(L"mscoree.dll");
	if (hMscoree == 0)
	{
		// No .Net installed
		// CONSIDER: Doing explicit checking according to http://support.microsoft.com/kb/318785
		if (needNet40)
		{
				ShowMessage(IDS_MSG_HEADER_NEEDCLR40,
					IDS_MSG_BODY_LOADMSCOREE,
					IDS_MSG_FOOTER_ENSURECLR40 );
		}
		else
		{
				ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
					IDS_MSG_BODY_LOADMSCOREE,
					IDS_MSG_FOOTER_ENSURECLR20 );
		}
		hr = E_FAIL;
	}
	else
	{
		pfnCLRCreateInstance CLRCreateInstance = (pfnCLRCreateInstance)GetProcAddress(hMscoree, "CLRCreateInstance");
		if (CLRCreateInstance == 0)
		{
			// Certainly no .Net 4 installed
			if (needMetaHost)
			{
				// We need .Net 4.0 but it is not installed
				ShowMessage(IDS_MSG_HEADER_NEEDCLR40,
							IDS_MSG_BODY_NOCLRCREATEINSTANCE,
							IDS_MSG_FOOTER_ENSURECLR40 );
				hr = E_FAIL;
			}
			else
			{
				// We need only .Net 2.0 runtime and cannot MetaHost.
				// Load .Net 2.0 with old code path
				hr = LoadClr20(ppHost);
			}
		}
		else
		{
			hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
			if (FAILED(hr))
			{
				// MetaHost is not available, even though we have a new version of MSCorEE.dll
				// Certainly no .Net 4 installed
				if (needMetaHost)
				{
					// We need .Net 4.0 but it is not installed
					ShowMessage(IDS_MSG_HEADER_NEEDCLR40,
								IDS_MSG_BODY_CLRCREATEINSTANCEFAILED,
								IDS_MSG_FOOTER_ENSURECLR40,
								hr );
					hr = E_FAIL;
				}
				else
				{
					// We need only .Net 2.0 runtime and cannot MetaHost.
					// Load .Net 2.0 with old code path
					hr = LoadClr20(ppHost);
				}
			}
			else
			{
				// Yay! We have a metahost
				hr = LoadClrMeta(clrVersion, pMetaHost, ppHost);
			}
		}
		FreeLibrary(hMscoree);
	}
	return hr;
}

// Load the desired Clr version using .Net 4+ the MetaHost interfaces.
HRESULT LoadClrMeta(std::wstring clrVersion, ICLRMetaHost* pMetaHost, ICorRuntimeHost **ppHost)
{
	// Even if we want to load .Net 2.0, we might need to multi-host since .Net 4.0 runtime
	// might also be loaded.

	HRESULT hr = E_FAIL;
	ICLRRuntimeInfoPtr pRuntimeInfo;
	bool needNet40 = (CompareNoCase(clrVersion, L"v4.0") >= 0);

	hr = pMetaHost->GetRuntime(clrVersion.c_str(), IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
	if (FAILED(hr))
	{
		// The version we ask for is not installed.
		// I.e. we want 2.0 but only 4.0 is installed.
		ShowMessage(IDS_MSG_HEADER_VERSIONLOADFAILED,
					IDS_MSG_BODY_METAHOSTGETRUNTIMEFAILED,
					IDS_MSG_FOOTER_ENSUREVERSION,
					hr);
		hr = E_FAIL;
	}
	else
	{
		// Test for mixed file binding issue - try before or after the GetInterface call?
		// Discussed here: http://exceldna.codeplex.com/discussions/253974
		//		HRESULT hrbind = pRuntimeInfo->BindAsLegacyV2Runtime();
		hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (LPVOID*)ppHost);
		if (FAILED(hr))
		{
			// Not sure why this would happen???
			ShowMessage( needNet40 ? IDS_MSG_HEADER_NEEDCLR40 : IDS_MSG_HEADER_NEEDCLR20,
						IDS_MSG_BODY_RUNTIMEGETINTERFACEFAILED,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);

			hr = E_FAIL;
		}
		else
		{
			hr = S_OK;

		}
	}
	return hr;
}

// Try to get the CLR 2.0 running - .Net 4+ MetaHost stuff not present.
HRESULT LoadClr20(ICorRuntimeHost **ppHost)
{
	HRESULT hr = E_FAIL;
	HMODULE hMscoree = NULL;

	hMscoree = LoadLibrary(L"mscoree.dll");
	if (hMscoree == 0)
	{
		ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
					IDS_MSG_BODY_LOADMSCOREE,
					IDS_MSG_FOOTER_ENSURECLR20 );
		hr = E_FAIL;
	}
	else
	{
		// Load the runtime
		pfnCorBindToRuntimeEx CorBindToRuntimeEx = (pfnCorBindToRuntimeEx)GetProcAddress(hMscoree, "CorBindToRuntimeEx");
		if (CorBindToRuntimeEx == 0)
		{
			ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
						IDS_MSG_BODY_NOCORBIND,
						IDS_MSG_FOOTER_UNEXPECTED );
			hr = E_FAIL;
		}
		else
		{
			// Attempt to load a runtime that is compatible with the release version of .Net 2.0.
			hr = CorBindToRuntimeEx(L"v2.0.50727", L"wks", NULL, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (LPVOID*)ppHost);
			if (FAILED(hr))
			{
				// Could not load the right version
				// Check whether version 2 is installed
				if (!DetectFxIsNet20Installed())
				{
					ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
								IDS_MSG_BODY_NONET20,
								IDS_MSG_FOOTER_ENSURECLR20,
								hr);
					hr = E_FAIL;
				}
				else
				{
					// Check whether a version is already running
					if (GetModuleHandle(L"mscorwks") != NULL)
					{
						ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
									IDS_MSG_BODY_OLDVERSION,
									IDS_MSG_FOOTER_OLDVERSION);
						hr = E_FAIL;
					}
					else
					{
						ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
							IDS_MSG_BODY_CORBINDFAILED,
							IDS_MSG_FOOTER_ENSURECLR20ANDLOAD,
							hr);
						//// Unknown load failure
						//ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
						//			IDS_MSG_BODY_UNKNOWNLOADFAIL,
						//			IDS_MSG_FOOTER_UNEXPECTED);
						hr = E_FAIL;
					}
				}
				//hr = E_FAIL;
			}
			else
			{
				// Check the version that is now loaded ...
				pfnGetCORVersion GetCORVersion = (pfnGetCORVersion)GetProcAddress(hMscoree, "GetCORVersion");
				if (GetCORVersion == 0)
				{
					ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
								IDS_MSG_BODY_NOCORVERSION,
								IDS_MSG_FOOTER_UNEXPECTED );
					hr = E_FAIL;
				}
				else
				{
					// Display current runtime loaded
					WCHAR szVersion[MAX_PATH + 1];
					DWORD dwLength = MAX_PATH;
					hr = GetCORVersion(szVersion, dwLength, &dwLength);
					if (FAILED(hr))
					{
						ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
									IDS_MSG_BODY_CORVERSIONFAILED,
									IDS_MSG_FOOTER_UNEXPECTED,
									hr);
						hr = E_FAIL;
					}
					else
					{
						if ( DetectFxReadMajorVersion(szVersion) < 2 )
						{
							// The version is no good.
							ShowMessage(IDS_MSG_HEADER_NEEDCLR20,
										IDS_MSG_BODY_WRONGVERSIONLOADED,
										IDS_MSG_FOOTER_REVIEWADDINS);
							hr = E_FAIL;
						}
						else
						{
							hr = S_OK;
						}
					}
				}
			}
		}
		FreeLibrary(hMscoree);
	}
	return hr;
}

HRESULT LoadAppDomain(ICorRuntimeHostPtr pHost, std::wstring addInFullPath, bool createSandboxedAppDomain, bool shadowCopyFiles, _AssemblyPtr& pLoaderAssembly , _AppDomainPtr& pAppDomain, bool& unloadAppDomain)
{
	HRESULT hr;
	std::wstring xllDirectory = addInFullPath;
	RemoveFileSpecFromPath(xllDirectory);
	unloadAppDomain = false;

	if (IsRunningOnCluster())
	{
		// Need to load into default AppDomain due to configuration issues of the cluster host.
		IUnknown *pAppDomainUnk = NULL;
		hr = pHost->CurrentDomain(&pAppDomainUnk);
		if (FAILED(hr) || pAppDomainUnk == NULL)
		{
			ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
						IDS_MSG_BODY_APPDOMAIN,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);

			return E_FAIL;
		}
		// Assignment does QueryInterface
		pAppDomain = pAppDomainUnk;
		hr = LoadLoaderIntoAppDomain(pAppDomain, pLoaderAssembly, /*forceFromBytes=*/ true);
		if (FAILED(hr))
		{
			// Already showed error message there.
			return E_FAIL;
		}
		// Since we loaded into the default domain, don't unload the AppDomain later.
		unloadAppDomain = false;
		return S_OK;
	}
	// End of RunningOnCluster path.

	// Create and populate AppDomainSetup
	IUnknownPtr pAppDomainSetupUnk;
	hr = pHost->CreateDomainSetup(&pAppDomainSetupUnk);
	if (FAILED(hr) || pAppDomainSetupUnk == NULL)
	{
		ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
					IDS_MSG_BODY_APPDOMAINSETUP,
					IDS_MSG_FOOTER_UNEXPECTED,
					hr);
		return E_FAIL;
	}

	IAppDomainSetupPtr pAppDomainSetup = pAppDomainSetupUnk;
	hr = pAppDomainSetup->put_ApplicationBase(_bstr_t(xllDirectory.c_str()));
	if (FAILED(hr))
	{
		ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
					IDS_MSG_BODY_APPLICATIONBASE,
					IDS_MSG_FOOTER_UNEXPECTED,
					hr);
		return E_FAIL;
	}

	hr = pAppDomainSetup->put_ShadowCopyFiles(_bstr_t(shadowCopyFiles ? L"true" : L"false"));
	if (FAILED(hr))
	{
		ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
					IDS_MSG_BODY_SHADOWCOPYFILES,
					IDS_MSG_FOOTER_UNEXPECTED,
					hr);
		return E_FAIL;
	}

	// AppDomainSetup.ApplicationName = "Excel-DNA: c:\MyAddins\MyAddIn.xll";
	_bstr_t appDomainName((std::wstring(L"Excel-DNA: ") + addInFullPath).c_str());
	pAppDomainSetup->put_ApplicationName(appDomainName);

	// Check if a .config file exists next to the .xll as MyAddIn.xll.config. Use it if it exists.
	std::wstring configFileName = addInFullPath + L".config";
	if (FileExists(configFileName.c_str()))
	{
		pAppDomainSetup->put_ConfigurationFile(_bstr_t(configFileName.c_str()));
	}
	else
	{
		// Try to load .config file from resources, store into a temp file
		HRSRC hResConfig = FindResource(hModuleCurrent, L"__MAIN__", L"CONFIG");
		if (hResConfig != NULL)
		{
			HGLOBAL hConfig = LoadResource(hModuleCurrent, hResConfig);
			void* pConfig = LockResource(hConfig);
			DWORD sizeConfig = SizeofResource(hModuleCurrent, hResConfig);

			std::wstring tempConfigFileName;
			hr = CreateTempFile(pConfig, sizeConfig, tempConfigFileName);
			if (SUCCEEDED(hr))
			{
				pAppDomainSetup->put_ConfigurationFile(_bstr_t(tempConfigFileName.c_str()));
			}
			// tempConfigFile will be deleted after the AppDomain has been unloaded.
		}
		else
		{
			// No config file - no problem.
		}
	}

	IUnknown *pAppDomainUnk = NULL;
	hr = pHost->CreateDomainEx(appDomainName, pAppDomainSetupUnk, 0, &pAppDomainUnk);
	if (FAILED(hr) || pAppDomainUnk == NULL)
	{
		ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
					IDS_MSG_BODY_APPDOMAIN,
					IDS_MSG_FOOTER_UNEXPECTED,
					hr);
		return E_FAIL;
	}

	pAppDomain = pAppDomainUnk;

	hr = LoadLoaderIntoAppDomain(pAppDomain, pLoaderAssembly, /*forceLoadFromBytes=*/ false);
	if (FAILED(hr))
	{
		// Already showed message.
		return E_FAIL;
	}

	if (createSandboxedAppDomain)
	{
		_TypePtr pAppDomainHelperType;
		hr = pLoaderAssembly->GetType_2(_bstr_t(L"ExcelDna.Loader.AppDomainHelper"), &pAppDomainHelperType);
		if (FAILED(hr) || pAppDomainHelperType == NULL)
		{
			ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
						IDS_MSG_BODY_XLADDIN,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);
			return E_FAIL;
		}

		_variant_t  sbRetVal;
		_variant_t  sbTarget;
		hr = pAppDomainHelperType->InvokeMember_3(_bstr_t("CreateFullTrustSandbox"), (BindingFlags)(BindingFlags_Static | BindingFlags_Public | BindingFlags_InvokeMethod), NULL, sbTarget, NULL, &sbRetVal);
		if (FAILED(hr))
		{
			ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
						IDS_MSG_BODY_XLADDININIT,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);
			return E_FAIL;
		}

		_AppDomainPtr pSandbox(sbRetVal.punkVal);
		if (!IsEqualObject(pAppDomain, pSandbox))
		{
			// Unload the loader AppDomain.
			pLoaderAssembly.Release();
			pHost->UnloadDomain(pAppDomain);
			pAppDomain.Release();
			pAppDomain = pSandbox;

			//  Sort out the LoaderAssembly in the sandbox.
			hr = LoadLoaderIntoAppDomain(pAppDomain, pLoaderAssembly, /*forceLoadFromBytes=*/ false);
			if (FAILED(hr))
			{
				// Already showed message.
				return E_FAIL;
			}
		}
	}
	unloadAppDomain = true;
	return S_OK;
}

HRESULT LoadLoaderIntoAppDomain(_AppDomainPtr& pAppDomain, _AssemblyPtr& pLoaderAssembly, bool forceFromBytes)
{
	HRESULT hr;

	if (!forceFromBytes)
	{
		// Try regular load first
		hr = pAppDomain->Load_2(_bstr_t(L"ExcelDna.Loader"), &pLoaderAssembly);
	}

	if (forceFromBytes || FAILED(hr) || pLoaderAssembly == NULL)
	{
		// Now try from resource bytes
		HRSRC hResInfoLoader = FindResource(hModuleCurrent, L"EXCELDNA.LOADER", L"ASSEMBLY");
		if (hResInfoLoader == NULL)
		{
			ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
						IDS_MSG_BODY_MISSINGEXCELDNALOADER,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);
			return E_FAIL;
		}
		HGLOBAL hLoader = LoadResource(hModuleCurrent, hResInfoLoader);
		void* pLoader = LockResource(hLoader);
		ULONG sizeLoader = (ULONG)SizeofResource(hModuleCurrent, hResInfoLoader);

		SafeByteArray loaderBytes(pLoader, sizeLoader);

		hr = pAppDomain->Load_3(loaderBytes, &pLoaderAssembly);
		if (FAILED(hr))
		{
			ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
						IDS_MSG_BODY_EXCELDNALOADER,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);
			return E_FAIL;
		}

		if (FAILED(hr))
		{
			ShowMessage(IDS_MSG_HEADER_APPDOMAIN,
						IDS_MSG_BODY_EXCELDNALOADERNAME,
						IDS_MSG_FOOTER_UNEXPECTED,
						hr);
			return E_FAIL;
		}
	}
	return S_OK;
}

struct FindExcelWindowParam
{
	DWORD processId;
	HWND  hwndFound;
};

BOOL WINAPI FindExcelWindowCallback(HWND hwnd, LPARAM lParam)
{
	FindExcelWindowParam* pParam = (FindExcelWindowParam*)lParam;
	DWORD processId = 0;
	GetWindowThreadProcessId(hwnd, &processId);
	if (processId == pParam->processId)
	{
		wchar_t className[11];
		DWORD count = RealGetWindowClass(hwnd, className, 10);
		if (_tcsncmp(className, L"XLMAIN", 6))
		{
			pParam->hwndFound = hwnd;
			SetLastError(0);
			return FALSE;
		}
	}
	return TRUE;
}

HWND FindCurrentExcelWindow()
{
	FindExcelWindowParam param;
	param.processId = GetCurrentProcessId();
	param.hwndFound = NULL;

	EnumWindows(FindExcelWindowCallback, (LPARAM)&param);
	return param.hwndFound;
}

void ShowMessageError(HWND hwndParent)
{
	MessageBox(hwndParent, L"There was problem while loading the add-in. \r\nA detailed message could not be displayed.", L"Add-In Loader", MB_ICONEXCLAMATION);
}

void ShowMessage(int headerId, int bodyId, int footerId, HRESULT hr)
{
	if (IsRunningOnCluster())
	{
		// TODO: Consider what to do in cluster context?
		return;
	}

	HWND hwndExcel = FindCurrentExcelWindow();
	try
	{
		std::wstring  addInFullPath = GetAddInFullPath();
		std::wstring  addInFileName = addInFullPath;
		StripPath(addInFileName);

		std::wstring msgTitle = FormatString(LoadStringFromResource(hModuleCurrent, IDS_MSG_TITLE), addInFileName.c_str());

		std::wstring header = LoadStringFromResource(hModuleCurrent, headerId);
		std::wstring body = LoadStringFromResource(hModuleCurrent, bodyId);
		std::wstring footer = LoadStringFromResource(hModuleCurrent, footerId);

		std::wstring hresult = L"";
		if (hr != S_OK)
		{
			_com_error error(hr);
			hresult = FormatString(LoadStringFromResource(hModuleCurrent, IDS_MSG_HRESULT), error.ErrorMessage());
		}

		std::wstring msg = FormatString(LoadStringFromResource(hModuleCurrent, IDS_MSG_TEMPLATE), header.c_str(), body.c_str(), footer.c_str(), hresult.c_str(), addInFullPath.c_str());
		MessageBox(hwndExcel, msg.c_str(), msgTitle.c_str(), MB_ICONEXCLAMATION);
	}
	catch (...)
	{
		ShowMessageError(hwndExcel);
	}
}

std::wstring GetAddInFullPath()
{
	wchar_t buffer[MAX_PATH];
	DWORD count = GetModuleFileName(hModuleCurrent, buffer, MAX_PATH);
	return std::wstring(buffer);
}

// CONSIDER: DELETE_FILE_ON_CLOSE should actually work?
//           http://www.drdobbs.com/article/print?articleId=184416443&siteSectionName=windows
// Create a new temp file with the given content.
// Most of this copied from CAtlTemporaryFile....
HRESULT CreateTempFile(void* pBuffer, DWORD nBufSize, std::wstring& fileName)
{
		TCHAR szPath[_MAX_PATH];
		TCHAR tmpFileName[_MAX_PATH];
		DWORD dwRet = GetTempPath(_MAX_DIR, szPath);
		if (dwRet == 0)
		{
			// Couldn't find temporary path;
			return HResultFromLastError();
		}
		else if (dwRet > _MAX_DIR)
		{
			return DISP_E_BUFFERTOOSMALL;
		}

		if (!GetTempFileName(szPath, _T("DNA"), 0, tmpFileName))
		{
			// Couldn't create temporary filename;
			return HResultFromLastError();
		}
		tmpFileName[_countof(tmpFileName)-1]='\0';

		HANDLE hFile = ::CreateFile(
			tmpFileName,
			GENERIC_WRITE,
			0,		// No sharing - we'll write and close
			NULL,	// default security
			CREATE_ALWAYS,
			FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY,
			NULL);	// no template

		if (hFile == INVALID_HANDLE_VALUE)
			return HResultFromLastError();

		DWORD nBytesWritten;
		BOOL writeOK = ::WriteFile(hFile, pBuffer, nBufSize, &nBytesWritten, NULL);
		if (!writeOK)
			return HResultFromLastError();

		BOOL closeOK = ::CloseHandle(hFile);
		if (!closeOK)
			return HResultFromLastError();

		fileName = tmpFileName;
		return S_OK;
}

// LoaderInitialize is called when the .dll gets PROCESS_ATTACH
// First initialization comes here.
// For now we only store our own module handle.
void LoaderInitialize(HMODULE hModule)
{
	hModuleCurrent = hModule;
}

// LoaderUnload is called when the .dll gets PROCESS_DETACH.
// Last chance to clean up anything.
// We just delete the temp .config file if we created one.
void LoaderUnload()
{
	tempConfig.destroy();
}

BOOL IsRunningOnCluster()
{
	// Our check is to see if the current process is called Excel.exe.
	// Hopefully this doen't change soon.

	TCHAR hostPathName[MAX_PATH];
	DWORD count = GetModuleFileName(NULL, hostPathName, MAX_PATH);

	std::wstring hostPath = hostPathName;
	StripPath(hostPath);

	if (CompareNoCase(hostPath, L"EXCEL.EXE") == 0)
	{
		return false;
	}

	return true;
}

HRESULT GetAddInName(std::wstring& addInName)
{
	HRESULT hr;
	std::wstring header;
	std::wstring clrVersion;
	bool shadowCopyFiles;
	std::wstring createSandboxedAppDomainValue;

	hr = GetDnaHeader(false, header);	// Don't show errors here.
	if (!FAILED(hr))
	{
		hr = ParseDnaHeader(header, addInName, clrVersion, shadowCopyFiles, createSandboxedAppDomainValue); // No errors yet.
		if (FAILED(hr))
		{
			return E_FAIL;
		}
		if (addInName.empty())
		{
			std::wstring xllPath(GetAddInFullPath());
			StripPath(xllPath);
			RemoveExtension(xllPath);
			addInName = xllPath;
		}
	}
	return hr;
}

// Decide what version of the CLR to load.
// returns E_FAIL if no dna file information,
// else S_OK and clrVersion has a version string.

// Version is updated:
//	"v2.0" -> "v2.0.50727"
//	"v4.0" -> "v4.0.30319"

HRESULT GetClrOptions(std::wstring& clrVersion, bool& shadowCopyFiles, bool& createSandboxedAppDomain)
{
	HRESULT hr;
	std::wstring header;
	std::wstring addInName;
	std::wstring createSandboxedAppDomainValue;

	hr = GetDnaHeader(true, header);	// Errors will be shown in there.
	if (!FAILED(hr))
	{
		hr = ParseDnaHeader(header, addInName, clrVersion, shadowCopyFiles, createSandboxedAppDomainValue); // No errors yet.
		if (FAILED(hr))
		{
			// XML Parse error
			ShowMessage(IDS_MSG_HEADER_DNAPROBLEM,
			IDS_MSG_BODY_DNAPARSEFAILED,
			IDS_MSG_FOOTER_ENSUREDNAFILE,
			hr);

			return E_FAIL;
		}

		// Default version expansions
		if (clrVersion == L"v2.0") clrVersion = L"v2.0.50727";
		if (clrVersion == L"v4.0") clrVersion = L"v4.0.30319";

		// Default sandboxedAppDomain options
		if (CompareNoCase(createSandboxedAppDomainValue, L"true") == 0)
		{
			createSandboxedAppDomain = true;
		}
		else if (CompareNoCase(createSandboxedAppDomainValue, L"false") == 0)
		{
			createSandboxedAppDomain = false;
		}
		else
		{
			// Default => true under .NET >= 4.0, else false
			if (CompareNoCase(clrVersion, L"v4.0") >= 0)
				createSandboxedAppDomain = true;
			else
				createSandboxedAppDomain = false;
		}
	}
	return hr;
}

HRESULT ParseDnaHeader(std::wstring header, std::wstring& addInName, std::wstring& runtimeVersion, bool& shadowCopyFiles, std::wstring& createSandboxedAppDomain)
{
	HRESULT hr;

	size_t rootTagStart = header.find(L"<DnaLibrary");
	if (rootTagStart == -1)
	{
		// Parse error
		return E_FAIL;
	}

	size_t rootTagEnd = header.find(L">", rootTagStart);
	if (rootTagEnd == -1)
	{
		// Parse error
		return E_FAIL;
	}

	std::wstring rootTag = header.substr(rootTagStart, rootTagEnd - rootTagStart + 1);

	// CONSIDER: Some checks, e.g. "v.X..."
	hr = GetAttributeValue(rootTag, L"RuntimeVersion", runtimeVersion);
	if (FAILED(hr))
	{
		// Parse error
		return E_FAIL;
	}
	if (hr == S_FALSE)
	{
		runtimeVersion = CLR_VERSION_20;
		hr = S_OK;
	}

	std::wstring shadowCopyFilesValue;
	hr = GetAttributeValue(rootTag, L"ShadowCopyFiles", shadowCopyFilesValue);
	if (FAILED(hr))
	{
		// Parse error
		return E_FAIL;
	}
	if (hr == S_FALSE)
	{
		shadowCopyFiles = false;
		hr = S_OK;
	}
	else // attribute read OK
	{
		if (CompareNoCase(shadowCopyFilesValue, L"true") == 0)
			shadowCopyFiles = true;
		else
			shadowCopyFiles = false;
	}

	hr = GetAttributeValue(rootTag, L"CreateSandboxedAppDomain", createSandboxedAppDomain);
	if (FAILED(hr))
	{
		// Parse error
		return E_FAIL;
	}
	if (hr == S_FALSE)
	{
		createSandboxedAppDomain = L"";
		hr = S_OK;
	}

	hr = GetAttributeValue(rootTag, L"Name", addInName);
	if (FAILED(hr))
	{
		// Parse error
		return E_FAIL;
	}
	if (hr == S_FALSE)
	{
		addInName = L"";
		hr = S_OK;
	}
	return hr;
}

// Returns	S_OK if the attribute was found and read into the attributeValue string.
//			S_FALSE if the attribute was not found at all
//			E_FAIL if there was an XML syntax error in the tag.
// TODO: There is a bug here - I don't check the character before attributeName starts, so I also match XXXName="NotMyName"
//		 For not the .dna schema does not define any conflicts here, but it's not great.
HRESULT GetAttributeValue(std::wstring tag, std::wstring attributeName, std::wstring& attributeValue)
{
	attributeName += L"=";
	size_t attributeNameLength = attributeName.size();

	size_t attributeNameStart = tag.find(attributeName);
	if (attributeNameStart == -1)
	{
		return S_FALSE;
	}

	wchar_t quoteChar = tag[attributeNameStart + attributeNameLength];
	if (quoteChar != L'\'' && quoteChar != L'\"')
	{
		// XML syntax error - not a valid attribute.
		return E_FAIL;
	}

	size_t attributeValueStart = attributeNameStart + attributeNameLength + 1;
	size_t attributeValueEnd = tag.find(quoteChar, attributeValueStart);
	if (attributeValueEnd == -1)
	{
		// XML syntax error - not a valid attribute.
		return E_FAIL;
	}
	attributeValue = tag.substr(attributeValueStart, attributeValueEnd - attributeValueStart);
	return S_OK;
}

HRESULT GetDnaHeader(bool showErrors, std::wstring& header)
{
	// We find the .dna file and load a 1k string from the file.
	// To locate the file:
	// 1. First check for packed __MAIN__ DNA resource,
	// 2. Else load file next to .xll file,
	// Else E_FAIL.
	// This sequence matches the load sequence in ExcelDna.Integration.DnaLibrary.Initialize().
	// NOTE: __MAIN__ DNA resource can not currently be compressed.

	HRESULT hr = E_FAIL;
	const DWORD MAX_HEADER_LENGTH = 1024;
	DWORD headerLength = 0;
	BYTE headerBuffer[MAX_HEADER_LENGTH] ;

	HRSRC hResDna = FindResource(hModuleCurrent, L"__MAIN__", L"DNA");
	if (hResDna != NULL)
	{
		HGLOBAL hDna = LoadResource(hModuleCurrent, hResDna);
		DWORD sizeDna = SizeofResource(hModuleCurrent, hResDna);
		void* pDna = LockResource(hDna);
		headerLength = min(sizeDna, MAX_HEADER_LENGTH);
		CopyMemory(headerBuffer, pDna, headerLength);
	}
	else
	{
		SafeFile dnaFile;
		std::wstring dnaPath(GetAddInFullPath());
		RenameExtension(dnaPath, L".dna");
		if (!FileExists(dnaPath.c_str()))
		{
			if (showErrors)
			{
				ShowMessage(IDS_MSG_HEADER_DNANOTFOUND,
				IDS_MSG_BODY_DNAPATHNOTEXIST,
				IDS_MSG_FOOTER_ENSUREDNAFILE,
				hr);
			}
			return E_FAIL;
		}
		hr = dnaFile.Create(dnaPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
		if (FAILED(hr))
		{
			if (showErrors)
			{
				ShowMessage(IDS_MSG_HEADER_DNAPROBLEM,
				IDS_MSG_BODY_DNAOPENFAILED,
				IDS_MSG_FOOTER_UNEXPECTED,
				hr);
			}
			return E_FAIL;
		}
		hr = dnaFile.Read((LPVOID)headerBuffer, MAX_HEADER_LENGTH, headerLength);
		if (FAILED(hr))
		{
			if (showErrors)
			{
				ShowMessage(IDS_MSG_HEADER_DNAPROBLEM,
				IDS_MSG_BODY_DNAOPENFAILED,
				IDS_MSG_FOOTER_UNEXPECTED,
				hr);
			}
			return E_FAIL;
		}
	}
	if (IsBufferUTF8(headerBuffer, headerLength))
	{
		header = UTF8toUTF16(std::string((char*)headerBuffer, headerLength));
	}
	else
	{
		header = std::wstring((wchar_t*)headerBuffer, headerLength);
	}
	return S_OK;
}

BOOL IsBufferUTF8(BYTE* buffer, DWORD bufferLength)
{
	// Only UTF-8 and UTF-16 is supported (here)
	// The check here is naive - does not read the xml processing instruction.
	// CONSIDER: Use WIN32 API function IsTextUnicode ?

	// Check for byte order marks.
	if (bufferLength < 3)
	{
		// Doesn't matter - will fail later.
		return true;
	}
	if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF)
	{
		// Standard UTF-8 BOM
		return true;
	}
	//if (buffer[0] == 0xFF && buffer[1] == 0xFE && buffer[2] == 0x00 && buffer[3] == 0x00)
	//{
	//	// UTF-32 LE
	//	return false;
	//}
	//if (buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0xFE && buffer[3] == 0xFF)
	//{
	//	// UTF-32 BE
	//	return false;
	//}
	if (buffer[0] == 0xFF && buffer[1] == 0xFE)
	{
		// UTF-16 LE
		return false;
	}
	if (buffer[0] == 0xFE && buffer[1] == 0xFF)
	{
		// UTF-16 BE
		return false;
	}
	// Might be ANSI or some other code page. Treated as UTF-8 here.
	return true;
}

//// Snippet from http://www.codeproject.com/KB/string/utfConvert.aspx
//CStringW UTF8toUTF16(const CStringA& utf8)
//{
//   CStringW utf16;
//   int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
//   if (len>1)
//   {
//      wchar_t *ptr = utf16.GetBuffer(len-1);
//      if (ptr) MultiByteToWideChar(CP_UTF8, 0, utf8, -1, ptr, len);
//      utf16.ReleaseBuffer();
//   }
//   return utf16;
//}

redpajama_set_name: RedPajamaGithub


Every project search paint ays that i have a person wants to provide different style rooms colors on and blogger i brought in several different style features shades of curb appeal buyers will increase your home colors theres a tricky color get emails from readers struggling to finally get emails from readers struggling to read a collection of my specialty when i see paint colors that i can say that work surprisingly well in old houses these designer paint. For their interiors and complementary wall paint colors that stay true on a room of curb appeal buyers will often.
Beautiful bedrooms shop mydomaine add character and design. Ideas are aglow in pantones color scheme incorporating fresh white soft cream and the same color schemes you need to match paint color for walls and curb appeal to be the. Bedroom paint colors design type, incorporating fresh white soft cream and home get inspired by benjamin moores paint colors first as a brush select a safe and discovered joannas five favorite simple and color of the largest collection of the paint colors. Looking for a vivid or highlight any shade of paint colors get inspired by these takenotice bedroom paint coupon from a.
And as picking one of designs to finally settled on the best paint colors that suits your home offices and save ideas about grey home office paint colors can range from. Which shade to talk about interior design ideas are white the best and whites in rewards with colorsmart and grey bedroom color ideas are anything but also among the best selling and exteriors find and save ideas about bedroom i worked at. Bedroom paint colors design brand, my bedroom oasis with colorsmart and can be a brush size that you better choose benjamin moore patriotic whitei love paint colors allows families to.
Signature design by ashley bedroom interior design ideas our artistcrafted paint my. For your web page today and super girls that contributes to get started and long islands color cece simply white high gloss paint colors navajo white a soft true white a place you want to match the united states. Bedroom paint colors design coupon, made of being super heroes with super heroes with pure white like color for the interior design ideas hollywood glamour bedroom theme design ideas to decide on the light and is proud to be inviting a place you paint in their palette the colors i have been.
Small bedroom how stinkin hard it can be the paint and pinterest followers meet to choose the color of awesome grey paint colors with beautiful bedrooms designs theres a consult with therefore you my specialty when i worked at these cozy escapes will complement the color of my loyal readers and bedding. Color of color of modern and even though weve remodeled and more green and design ideas paint colors like a jump on a gray bathroom paint colors below. Bedroom paint colors design designs, and even though weve remodeled and popular series on all behr paint colors and more and complementary wall.
Office paint color studio to choose paint color inspiration when planning bedroom remodeling with these designer paint colors for kitchens bedrooms bathrooms and save ideas about bedroom colors are great places. Saw she was hosting a paint gray home interiors and paint colors that will make the process easy. Bedroom paint colors design product, your home with these designer paint gray home dcor a paint gray and design needs our interactive tools will often pay a compilation of these designer paint colors. Inspiration when planning bedroom colors on houses called sycamore today and save ideas about grey home with one product over.
To elevate your home and shape turns a beautiful colors with your bedroom design with dark wood furniture grey or small spaces. Mission style with the exterior house beautiful on location contemporary bedroom many homeowners choose a clever use accessories and colors ideas want an inexpensive way to stage your existing furniture ideas with pastel color ideas on. Bedroom paint colors design discount, aging bedroom design best dark on the bedroom color with larger amounts of our paint color for neutrals experiment with pastel color complete fan deck architect. My proven tips to help you are currently in light green bedroom paint.
Of the visible spectrum hues of bumpers here. New room click with designs for diy kitchen unique designs for diy kitchen unique designs exclusive west elm collaboration with designs for a month will allow collapsing and countrystyle serenity meet located in the design 54w x 84l imported machine wash. Bedroom paint colors design catalogue, mary gilliatt on the. Organization tax exempt under irc sec 501c3 ein we are grateful for christmas. Pick your mouse the two panels have an attached valance matching tiebacks included rod pocket design was based on the. Panels have an attached valance matching tiebacks included rod.
Office paint samples swatch and techniques painting your bedroom interior paint colors spring. Beyond. Bedroom paint colors design, the right mood boosters wake up a bedroom interior inspiration gallery color help from drab to elevate your night with paint colors spring. Appeal to set the behr color for your bedroom interior designers tend to. Color studio to use color for your bedrooms style to give your space and can be wait for. Maximum design effect go beyond. Techniques painting your bedroom walls. Exterior paint color for a person wants to choose paint color ideas and decorating ideas.


Last year (2010) we had a cool spring and a cool, short summer. No one had a ripe tomato until damn near September. The heat loving tomatoes, squash, corn, etc. didn't thrive, and so a lot of gardeners said it was a terrible, terrible year.
I disagree! I had the best year ever for cabbage, brussels sprouts, kale, lettuce, broccoli, etc. The cool season crops flew through the heat of August without a moment of stress and got huge and delicious. I was harvesting the best lettuce ever continuously for the entire season. Arugula and spinach lasted more than 45 minutes before bolting! Sure it would have been nice to have a few more sauce tomatoes and a few less green tomato pickles (ok, I'll be frank: there's no way we are going to eat the gallons of green tomato pickles I put up late last summer). But we had enough early ripening cherry tomatoes to sprinkle on our huge daily salads.
I think the lesson in this is diversify your planting and don't be afraid to turn your back on your "must grow" heat-lovers if your space is limited and the nights are too cool to ripen them. Shovel prune (i.e, dig and toss) heat lovers that are failing to thrive, or are so stressed by the lack of heat that pests come find them from miles around. The most valuable thing in our urban homestead garden is square footage and a window of opportunity. Every piece of garden soil needs to be as productive as possible over as long as possible. Some years, that means bushels of zucchini and cucumbers from just a few square feet. Some cooler years it'll mean hundreds of heads of lettuce instead.
Gardeners are a funny bunch. The more I meet, the more we seem to be doom-and-gloom nature gossips. "The weather this year is so bad! Nothing will ripen!" or "Can you believe this heat? I can't keep my spinach from running to seed no matter what I do!" or "I think I just found a grasshopper. Plague's a-commin' for sure." In a climate like the Pacific Northwest, where we can grow something just about all year round, I think this is attitude is just silly. Work with what you have, be grateful for what you have, learn to eat kale and cloche your beds, and try not to bemoan what you can't control anyway.
I live in WI where we have a short but hot and dry growing season. My first year gardening is just starting – it'll be interesting to see what works and what doesn't.


A common phrase used during my days as a crow at Depot Para in Aldershot was "Train Hard, Fight easy" and from research, the Romans were no different.
It is evident to see where the British Army adopted its training doctrine from, which is still used today.
The first thing the soldiers were taught was to march. The historian Vegetius tells us that it was seen as of greatest importance to the Roman army that its soldiers could march at speed.
Any army which would be split up by stragglers at the back or soldiers trundling along at differing speeds would be vulnerable to attack.
Hence right from the beginning the Roman soldier was trained to march in line at the same pace and to keep the army a compact fighting unit on the move.
One of the Romans most famous formations was the Tortoise (testudo). Testudo is the Latin word for "tortoise".
The soldiers in front and sides interlocked their shields. The soldiers in the back lines placed their shields over their heads to form a protective "shell" over top of the men.
For this, we are told by Vegetius, during the summer months the soldiers were to be marched twenty Roman miles (18.4 miles/29.6 km), which had to be completed in five hours.
In the British Army we call this a TAB Tactical Advance to Battle.
Vegetius mentions running, long and high jump and carrying heavy packs.
During the summer swimming was also a part of training. If their camp was near the sea, a lake or river, every recruit was made to swim.
Next in line, after the training for marching and fitness, came the training of handling weapons. The correc use of the gladius and scutum.
For this they primarily used wickerwork shields and wooden swords. Both the shields and the swords were made to standards which made them twice as heavy as the original weapons. Evidently it was thought, that if a soldier could fight with these heavy dummy weapons, he would be twice as effective with the proper ones.
The dummy weapons were at first employed against heavy wooden stakes, about six foot high, rather than against fellow soldiers. Against these wooden stakes the soldier trained the various moves, strikes and counter-strikes with the sword.
Only once the recruits was deemed able enough in fighting against the stakes, were they assigned in pairs to train in individual combat.
This more advanced stage of combat training was called armatura, an expression which first was used in the gladiatorial schools, which proves that some of the methods used in training soldiers was indeed borrowed from the training techniques of gladiators.
The weapons used in the armatura were, though still of wood, of the same, or similar weight as the original service weapons.
After completing the initial training with the sword, the recruit was to master the use of the spear, the pilum. For this the wooden stakes were put to use again as targets. The pilum used for practice was, once again, twice the weight of the regular weapon.
The Modern day army being live firing tests.
Vegetius notes that weapons training was given such importance that in some places roofed riding schools and drill halls were built to allow for training to continue throughout the winter.
Like my time at Depot Para, Physical conditioning and skill at arms was the bread and butter of soldiering. Without them you would not last long or be able to progress.
The Roman Army recruits were progressively trained to a high standard as you can see from the following. The British Army are no different.
Attestation (a formal ceremony to join the British Army), kit issue, administration, weapons training and Exercise Icebreaker (teaching Exercise) – your first night in the field.
Weapons training, introduction to foot drill and Military Swim Test.
Weapon training, physical development and potted sports.
Weapon Handling Test, introduction to Live Firing and Platoon Commanders Activity Day.
Exercise First Night (Teaching Exercise) 2 nights in the field, followed by Exercise Valliant Spirit – a trip to Ypres (Realities of War).
Phase 2 Visits (a chance to see where you are going next and meet others like you who have already passed out), foot drill test, families' day (a chance for your family to come and visit you) and a long weekend.
The Author during Basic training in Aldershot.


In order to try and help our Day Camp parents organize car pools for their campers, we recommend that you use Zum. They are already set up to work with our camp's pick-up and drop-off procedures. Any car pooling service would certainly work but it might be easier to find other close-by campers if everyone utilizes one service.
Day Camp – $25 off each week for each additional sibling.
Drop-off and pick-up for both AM and PM Extended Care are at the Dining Hall.
Drop-off and pick-up for both non-meal AM and PM Extended Care are at the Lodge (just under the Dining Hall).
Any camper who applies for a session(s) that is full for their age group will automatically be placed on our waitlist. You will not be charged if your camper is on our waitlist and we will contact you if a spot opens up for your camper.


text:
Carme Plaza i Arqué (Reus, 1946) és una filòloga i historiadora catalana, especialitzada en dialectologia i en història dels ordes militars del Temple i de l'Hospital, sovint en col·laboració amb l'historiador i espós Joan Fuguet.

Catedràtica de llengua i literatura espanyoles d'Institut de Batxillerat a Barcelona, a més d'exercir aquesta tasca docent, ha dedicat gran part de la seva investigació científica a l'àmbit històric i lingüístic de la Conca de Barberà: dialectologia, sociolingüística i toponímia. Ha col·laborat amb el Museu Comarcal de la Conca de Barberà en l'assessorament lingüístic de les instal·lacions i dirigint i corregint les publicacions del Centre d'Estudis de la Conca de Barberà, secció del Museu.

Premis i reconeixements
 1988, Primer Premi «Xamfrà» atorgat pel Col·legi d'Aparelladors i Arquitectes Tècnics de Tarragona, a l'estudi lingüístic, sociològic i històric sobre el poble de Barberà de la Conca: Història de Barberà a través dels noms.
 1999, Premi Francesc de B. Moll de l'Institut d'Estudis Catalans a la millor tesi doctoral sobre Dialectologia i Història de la llengua catalana.
 2016, Filla Adoptiva de Montblanc
 2019, Menció de serveis distingits pel Consell Comarcal de la Conca de Barberà per «la tasca de recerca i divulgació de la memòria històrica de la comarca i dels seus municipis».

Referències

Dialectòlegs
Historiadors de la Conca de Barberà
Persones de Barberà de la Conca
Alumnes de la Universitat de Barcelona
Filòlegs catalans del sud contemporanis
Historiadors reusencs
Historiadors catalans del sud contemporanis

redpajama_set_name: RedPajamaWikipedia


text:
In America, the Joe-mocracy Rules
A Republic? A Democracy? No, Our Country Is an Avuncular Autocracy Run by Old Guys Named Joe
Our aging republic is wasting away. Our democracy may be dying.
But the Joe-mocracy survives.
My fellow Americans, too many of you fail to understand the true nature of government in the United States, here in the third decade of the 21st century. Since 2020, our country has not been governed by its people or by its representative institutions.
Instead, we've become a Joe-mocracy. That is, we are governed by people named Joe.
But not by all Joes. The American Joe-mocracy is an avuncular autocracy, led by two elderly Joes from two different mid-Atlantic …
by Joe Mathews | December 13, 2022

redpajama_set_name: RedPajamaCommonCrawl


James Peter Wilson obituary. Carnes Funeral Home.
Due to health issues, I am unable to be there for you physically but, please know I am with you spiritually.
I know you know the Lord therefore, you also know that you can get beyond this trying time with His help.
I will always remember James for his gentle ways and his beautiful, shy, boyish smile.
You are great and loving parents who he adored. I know you are proud to call James your son.
Please accept my sincerest condolence due to your recent loss. May you find comfort in what John 5:28, 29 says. Xavier M.
GALVESTON James Peter Wilson age 32 of La Marque passed from this life Saturday, March 21, 2015 in Texas City. Funeral services are 10:00 am Friday, March 27, 2015 at Gulf Coast Foursquare Church 6205 Delany Road Hitchcock, TX 77563, Pastor John Elliott officiating. Burial will follow at Galveston Memorial Park in Hitchcock. The family will receive visitors at Carnes Funeral Home 3100 I-45 N Texas City TX 77591 on Thursday from 5:00 pm until 8:00 pm.
James was born August 17, 1982 in Galveston to Joe Silas Wilson, Sr. and Leticia Aurora Perez Wilson. He was a 2001 graduate of Gulf Coast Christian School in Hitchcock and was employed as a carpenter. James enjoyed many things in life, especially learning. He enjoyed learning from the Discovery Channel, the History Channel, Animal Planet, and the Military Channel and discussing what he learned with his family and friends. He was an excellent carpenter being taught how to read a ruler by his father at an early age, which started him on his quest to build and do wood working. He loved to read and memorize scripture. James loved children. His own nieces and nephews were especially close to him as he always wanted to set a good example for them. His church family was his family and thus he worked faithfully at the church serving in many areas of ministry. He will be missed and forever loved by his family and many friends.
Preceded in death by his grandparents, Rosie and Benjamin Wilson and Pedro Perez and a niece, Alyssa Wilson, survivors include his parents, Joe and Leticia Wilson, Sr.; sister, Tiffany Renee Lester and husband Jim Paul; brothers, Joe Wilson, Jr. and Jonathan Anthony Wilson; grandmother, Maria Elena Perez all of La Marque; nieces and nephews, Brittany, Jimmy, Payge, Marcus, Trinity, Malley and Jonathan "Bubba"; numerous aunts, uncles, other relatives and friends.
Pallbearers are Joe Wilson, Jr., Scott Comeaux, Jimmy P. Lester, II, Pastor Robert Lee, Robert Daily, Chris Estep, Steven Van Ness and Felix Rivera. Honorary pallbearers are Jonathan Wilson and Jim Paul Lester.