Index: /gsdl/branches/nzdl2/gsinstaller/DiskSpace.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/DiskSpace.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/DiskSpace.cpp	(revision 14219)
@@ -0,0 +1,71 @@
+#include <windows.h>
+
+#include "DiskSpace.h"
+
+typedef BOOL (* diskEx) (LPCTSTR root, PULARGE_INTEGER a, PULARGE_INTEGER B, PULARGE_INTEGER C);
+
+DiskSpace::DiskSpace(const char *rootName)
+{
+	char 	rootPath[128];
+	DWORD totalClusters;
+	OSVERSIONINFO osVerInfo;
+
+  // copy the rootname to our own path
+	strcpy(rootPath, rootName);
+
+  // get some guide to the os version
+	osVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+	GetVersionEx(&osVerInfo);
+
+  // if get disk free space fails then note fatal initialisation error
+	if (!GetDiskFreeSpace(rootName, &sectorsPerCluster, &bytesPerSector,
+												&freeClusters, &totalClusters))
+	{ this->initialised = false;
+    return;
+	}
+
+	// call the advanced form of getDiskSpace if we have access to it; this
+  // will cope with 2Gb+ partitions correctly 
+	if (osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
+			LOWORD(osVerInfo.dwBuildNumber) > 1000 ||
+      TRUE)
+	{ HMODULE module;
+		FARPROC proc;
+		ULARGE_INTEGER freeBytes, freeToCaller, totalBytes;
+
+		module	= LoadLibrary("KERNEL32.DLL");
+		proc 		= GetProcAddress(module, "GetDiskFreeSpaceEx");
+		if (proc == NULL)
+		{	this->initialised = true;
+			return;
+		}
+		(* ((diskEx) proc))(rootPath, &freeBytes, &freeToCaller, &totalBytes);
+		// Get free clusters - use the ULARGE_INTEGER variables to get the
+		// result and avoid overflow problems
+		//freeBytes = freeBytes / sectorsPerCluster; //(sectorsPerCluster * bytesPerSector);
+		//freeClusters = totalBytes;
+	}
+  this->initialised = true;
+	return;
+}
+
+bool DiskSpace::initialisedOk()
+{	return this->initialised;
+}
+
+unsigned long DiskSpace::totalFreeSpace()
+{ return this->freeClusters * this->sectorsPerCluster * this->bytesPerSector;
+}
+
+int DiskSpace::fileClusters(int fileSize)
+{	int sectors, clusters;
+
+	sectors	= (fileSize + this->bytesPerSector - 1) / this->bytesPerSector;
+	clusters	= (sectors + this->sectorsPerCluster - 1) / this->sectorsPerCluster;
+	return clusters;
+}
+
+int DiskSpace::fileSpace(int fileSize)
+{	return this->fileClusters(fileSize) * this->bytesPerSector * this->sectorsPerCluster;
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/DiskSpace.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/DiskSpace.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/DiskSpace.h	(revision 14219)
@@ -0,0 +1,19 @@
+#ifndef _DISKSPACE_H_
+#define _DISKSPACE_H_
+#include <windows.h>
+
+class DiskSpace {
+private:
+  DWORD sectorsPerCluster;
+  DWORD bytesPerSector;
+  DWORD freeClusters;
+  bool	initialised;
+protected:
+public:
+  DiskSpace(const char *root);
+  int 					fileSpace(int fileSize);
+  int 					fileClusters(int fileSize);
+  bool					initialisedOk();
+  unsigned long totalFreeSpace();
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/FilePath.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/FilePath.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/FilePath.cpp	(revision 14219)
@@ -0,0 +1,298 @@
+#include "FilePath.h"
+#include "File.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <dir.h>
+
+static char divider = '\\';
+static char dividerStr[] = "\\";
+
+bool __pathIsAValidRoot(string path)
+{	DWORD driveMask;
+	int		driveNum;
+
+  if (path.length() > 3)
+  {	return false;
+  }
+
+	if (path[1] != ':' || !isalpha(path[0]))
+  {	return false;
+  }
+  if (isupper(path[0]))
+  { driveNum = path[0] - 'A';
+  }
+  else
+  {	driveNum = path[0] - 'a';
+  }
+  if (driveNum > 25)
+  {	return false;
+  }
+  driveMask = GetLogicalDrives();
+  if ((driveMask & (1 << driveNum)) != (1 << driveNum))
+  {	return false;
+  }
+  return true;
+}
+
+FilePath::FilePath()
+{
+}
+
+FilePath::FilePath(int npaths, ...)
+{	va_list list;
+	string*	pathArray;
+
+  pathArray	= new string[npaths];
+
+  // initialise use of variable parameters
+  va_start(list, npaths);
+
+  if (pathArray)
+  { for (int i = 0; i < npaths; i ++)
+    { // get next parameter (guaranteed to be a char * by caller!!!)
+    	pathArray[i] = va_arg(list, char *);
+
+      // discount leading slashes
+      if (pathArray[i][0] == divider)
+      {	pathArray[i] = pathArray[i].substr(1);
+      }
+
+      // get rid of terminating slashes if present
+      if (pathArray[i][pathArray[i].length() - 1] == divider)
+      {	pathArray[i] = pathArray[i].substr(0, pathArray[i].length() - 1);
+      }
+    }
+  }
+
+  // end of variable arguments
+	va_end(list);
+
+  // construct path in the usual manner
+  if (npaths > 0)
+  {	this->path = pathArray[0];
+  }
+  for (int i = 1; i < npaths; i ++)
+  { // don't add slashes if suppressed
+   	if (pathArray[i][0] != '!')
+   	{	this->path.append("\\");
+	   	this->path.append(pathArray[i]);
+    }
+    // if slashes suppressed, skip the magic character
+    else
+    { this->path.append(pathArray[i].substr(1));
+    }
+  }
+
+  // destroy temporary array
+  if (pathArray)
+  {	delete[] pathArray;
+  }
+
+  // set if this is a valid root (unlikely in this circumstance)
+  this->is_aRoot = __pathIsAValidRoot(this->path);
+}
+
+/**
+ * Construct a Filepath from a directory and a sub-directory path
+ */
+FilePath::FilePath(string filePath, string subPath)
+{ // copy the directory path
+  this->path = filePath;
+
+  // if it didn't have a concluding divider, then add one
+  if (this->path[filePath.length()-1] != divider)
+  {	this->path.append(dividerStr);
+  }
+
+  // copy in the subdirectory path, eliminating any leading divider
+  if (subPath[0] != divider)
+  {	this->path.append(subPath);
+  }
+  else
+  {	this->path.append(subPath.substr(1));
+  }
+
+	// set if this is a valid root (unlikely when joining two paths)
+  this->is_aRoot = __pathIsAValidRoot(this->path);
+}
+
+FilePath::FilePath(string filePath)
+{ if (filePath.length() < 3)
+	{ this->path	= filePath;
+    this->path.append("\\");
+  }
+  else
+  { this->path	= filePath;
+  }
+
+  // check for a valid root
+  this->is_aRoot = __pathIsAValidRoot(this->path);
+}
+
+bool FilePath::isEmpty()
+{	return this->path.length() == 0;
+}
+
+bool FilePath::isRoot()
+{	return this->is_aRoot;
+}
+
+bool FilePath::equals(FilePath &other)
+{	if (this->path.compare(other.path) == 0)
+	{	return true;
+  }
+  return false;
+}
+
+bool FilePath::equals(const char *other)
+{	if (strcmp(this->path.c_str(), other) == 0)
+	{	return true;
+  }
+  return false;
+}
+
+/**
+ *  Create a filepath of the drive letter/colon only
+ */
+FilePath *FilePath::rootDrive()
+{	FilePath *reply = this->root();
+
+	if (reply->path.length() >= 2 &&
+  		reply->path[1] == ':' &&
+      isalpha(reply->path[0])) // if this is a drive letter destination
+  {	reply->path = reply->path.substr(0, 2);
+  }
+  else
+  {	reply->path = "";
+  }
+  return reply;
+}
+
+/**
+ * Create a filepath of the root of the given location
+ */
+FilePath *FilePath::root()
+{ // TODO: cope with network destinations
+	FilePath *reply = new FilePath(this->path);
+
+  unsigned int truncate = reply->path.find(divider);
+  if (truncate != -1) // if it's got a divider then skip past it;
+  										// we will assume that it's a drive letter first
+  {	truncate ++;
+  	reply->path = reply->path.substr(0, truncate);
+  }
+  // if we've got a drive, then we'll use it plus the divider
+  else if (reply->path[1] == ':' && reply->path.length() == 2 &&
+  				 isalpha(reply->path[0]))
+  {	reply->path = reply->path + dividerStr;
+  }
+  else
+  {	reply->path = "";
+  }
+  return reply;
+}
+
+/**
+ *  Just a quick check on the existence of a file.
+ */
+bool FilePath::exists()
+{ File f(this->path);
+
+	return f.exists();
+}
+
+/**
+ *  Get the immediate parent of the given filepath
+ */
+FilePath *FilePath::parent()
+{ // TODO: cope with network roots
+	FilePath *reply = new FilePath(this->path);
+
+	// get the last divider
+	unsigned int truncate	=	reply->path.find_last_of(divider);
+
+  // if it exists, then we can do a normal get parent
+  if (truncate != -1)
+  { // if it's the leftmost one as well then we'll skip it to
+    // give a parent of <drive>:\ as this patches some problems
+    // with windows calls!  Note that a parent call to the returned
+    // object in this case will return itself
+  	if (truncate == reply->path.find(divider))
+  	{	truncate ++;
+    }
+  	reply->path	= reply->path.substr(0, truncate);
+  }
+  // if we've got a drive letter only, then append the divider to
+  // patch problematic windows calls;  again subsequent parent
+  // calls to our returned object would in effect return itself
+  else if (reply->path[1] == ':' && reply->path.length() == 2 &&
+  				 isalpha(reply->path[0]))
+  {	reply->path = reply->path + dividerStr;
+  }
+  // a non-rooted object; return blank
+  else
+  {	reply->path = "";
+  }
+ 	reply->is_aRoot = __pathIsAValidRoot(reply->path);
+  return reply;
+}
+
+FilePath *FilePath::append(FilePath &subPath)
+{	return new FilePath(this->path, subPath.path);
+}
+
+FilePath *FilePath::append(char *subPath)
+{	return new FilePath(this->path, subPath);
+}
+
+const char *FilePath::cString()
+{	return this->path.c_str();
+}
+
+string FilePath::pathString()
+{	return this->path;
+}
+
+bool FilePath::ensureWriteablePath()
+{ //TODO: don't assume that all roots are writeable!
+	if (this->isRoot())
+  {	return true;
+  }
+
+	// does this path exist?
+	File thisFile(this->path);
+  bool reply = false;
+
+	// if not, ensure writeable parent
+  if (thisFile.exists() == false)
+  {	FilePath	*parent;
+
+  	// create parent reference
+  	parent	= this->parent();
+    if (parent->equals(thisFile.getFileName()))
+    { delete parent;
+    	return true;
+    }
+
+    // if parent is writeable then try to make the directory
+    if (parent->ensureWriteablePath())
+    { // make this directory; if it succeeded we reply positively
+    	if (mkdir(this->path.c_str()) == 0)
+      {	reply = true;
+      }
+    }
+    // destroy parent reference
+    delete parent;
+  }
+  else if (thisFile.isDirectory() == true)
+  {	// is this writeable by user?; if so we're okay
+  	if (thisFile.isWriteable())
+    {	reply = true;
+    }
+  }
+
+  return reply;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/FilePath.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/FilePath.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/FilePath.h	(revision 14219)
@@ -0,0 +1,31 @@
+#ifndef _FILEPATH_H_
+#define _FILEPATH_H_
+#include <string>
+using namespace std;
+
+class FilePath
+{	private:
+		string path;			// full path of this item
+    bool	 is_aRoot;	// indicates whether this directory/file is a file root
+	public:
+  	FilePath();
+  	FilePath(string filePath);
+    FilePath(string filePath, string filePath2);
+    FilePath(int nPaths, ...);
+    bool      equals(FilePath &path);
+    bool      equals(const char *path);
+    bool			isRoot();
+    bool			isEmpty();
+    FilePath *append(FilePath &path);
+    FilePath *append(char *path);
+    FilePath *parent();
+    FilePath *root();
+    FilePath *rootDrive();
+    bool ensureWriteablePath();
+    bool exists();
+    const char *cString();
+    string      pathString();
+    bool operator==(const FilePath &b) { return this->path == b.path; }
+    bool operator<(const FilePath &b) { return this->path < b.path; }
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/GSInstaller.tag
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/GSInstaller.tag	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/GSInstaller.tag	(revision 14219)
@@ -0,0 +1,11 @@
+bytesPerSector c:\working\c\gsinstaller\diskspace.h(4)V
+diskEx c:\working\c\gsinstaller\diskspace.cpp(5)T
+DiskSpace c:\working\c\gsinstaller\diskspace.cpp(7)F
+DiskSpace c:\working\c\gsinstaller\diskspace.h(1)C
+DiskSpace c:\working\c\gsinstaller\diskspace.h(8)P
+fileClusters c:\working\c\gsinstaller\diskspace.cpp(44)F
+fileClusters c:\working\c\gsinstaller\diskspace.h(10)P
+fileSpace c:\working\c\gsinstaller\diskspace.cpp(52)F
+fileSpace c:\working\c\gsinstaller\diskspace.h(9)P
+freeClusters c:\working\c\gsinstaller\diskspace.h(5)V
+sectorsPerCluster c:\working\c\gsinstaller\diskspace.h(3)V
Index: /gsdl/branches/nzdl2/gsinstaller/Splash.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/Splash.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/Splash.h	(revision 14219)
@@ -0,0 +1,8 @@
+#ifndef _SPLASH_H_
+#define _SPLASH_H_
+#define OEMRESOURCE 1
+#include <windows.h>
+
+long FAR PASCAL _export splash_windproc(HWND Window, UINT Message, WPARAM wParameter, LPARAM lParameter);
+void _export splash_show(HINSTANCE instance, unsigned int time);
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/bmpUtil.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/bmpUtil.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/bmpUtil.cpp	(revision 14219)
@@ -0,0 +1,106 @@
+#include "bmpUtil.h"
+
+#include <stdio.h>
+#include <mem.h>
+#include <stdlib.h>
+
+HPALETTE bmpUtil_getDIBPalette(LPBITMAPINFO bmpInfo, unsigned int colours)
+{	LPBITMAPINFOHEADER 	bmpHeader;
+	LPLOGPALETTE				logicalPalette;
+  HPALETTE 						reply = 0;
+
+	bmpHeader	= (LPBITMAPINFOHEADER) bmpInfo;
+    MessageBox(0, "A", "A", MB_OK);
+
+  if (colours)
+  {
+    MessageBox(0, "A", "A", MB_OK);
+  	logicalPalette = (LPLOGPALETTE) GlobalAlloc(GMEM_FIXED, sizeof (LOGPALETTE) + sizeof(PALETTEENTRY) * (colours));
+  	if (logicalPalette == NULL)
+    { return reply;
+    }
+
+    logicalPalette->palVersion = 0x300;
+    logicalPalette->palNumEntries = colours;
+    MessageBox(0, "A", "A", MB_OK);
+  	for (int i = 0; i < colours; i ++)
+    {	logicalPalette->palPalEntry[i].peRed		= bmpInfo->bmiColors[i].rgbRed;
+    	logicalPalette->palPalEntry[i].peGreen	= bmpInfo->bmiColors[i].rgbGreen;
+      logicalPalette->palPalEntry[i].peBlue		= bmpInfo->bmiColors[i].rgbBlue;
+      logicalPalette->palPalEntry[i].peFlags	= 0;
+    }
+    reply	= CreatePalette(logicalPalette);
+		GlobalFree((HGLOBAL) logicalPalette);
+  }
+  return reply;
+}
+
+HBITMAP _export bmpUtil_loadBitmap(HDC device, char *filename)
+{ BYTE							dummy[2];
+	BITMAPINFO			 	bitmapInfo;
+  OFSTRUCT					of;
+
+  HFILE 						file;
+	BITMAPFILEHEADER 	fileHeader;
+  LPRGBQUAD					colours;
+  LPBITMAPINFO			bitmapData;
+  LPBYTE						image;
+  unsigned int			colourCount;
+  HBITMAP						reply;
+  char buffer[40];
+
+  file = OpenFile(filename, &of, OF_READ);
+  if (!file)
+  {	return NULL;
+  }
+
+  if (!_lread(file, &fileHeader, sizeof(BITMAPFILEHEADER)))
+  { MessageBox(0, "M1", "M", MB_OK);
+  }
+	if (!_lread(file, &bitmapInfo.bmiHeader, 40))
+  { MessageBox(0, "M2", "M", MB_OK);
+  }
+
+	colourCount	= 1 << bitmapInfo.bmiHeader.biBitCount;
+  bitmapData = (BITMAPINFO *) GlobalAlloc(GMEM_FIXED, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * colourCount);
+  if (!bitmapData)
+  { MessageBox(0, "M3", "M", MB_OK);
+  }
+
+  bitmapData->bmiHeader = bitmapInfo.bmiHeader;
+
+  colours			= (RGBQUAD *) &bitmapData->bmiColors;
+  if (_lread(file, colours, sizeof(RGBQUAD) * colourCount) < colourCount)
+  { MessageBox(0, "M4", "M", MB_OK);
+  }
+
+  image = (BYTE FAR *) GlobalAlloc(GMEM_FIXED, sizeof(BYTE) * bitmapData->bmiHeader.biSizeImage);
+  if (!image)
+  { MessageBox(0, "M5", "M", MB_OK);
+  }
+  if (_lread(file, image, sizeof(BYTE) * bitmapData->bmiHeader.biSizeImage) < bitmapData->bmiHeader.biSizeImage)
+  { MessageBox(0, "M", "M6", MB_OK);
+  }
+
+  HPALETTE pal = bmpUtil_getDIBPalette(bitmapData, colourCount);
+  sprintf(buffer, "%d", (int) pal);
+  MessageBox(0, buffer, "M0", MB_OK);
+
+  reply = CreateCompatibleBitmap (device, 501, 228);
+  sprintf(buffer, "%d", reply);
+  MessageBox(0, buffer, "M1", MB_OK);
+  if (reply != NULL)
+  { int r = SetDIBits(device, reply, 0, bitmapData->bmiHeader.biHeight, image, bitmapData, DIB_RGB_COLORS);
+  	sprintf(buffer, "%d", r);
+    MessageBox(0, buffer, "M2", MB_OK);
+  	DeleteObject(reply);
+  }
+
+  reply = CreateDIBitmap( device, &bitmapData->bmiHeader, CBM_INIT, image, bitmapData, DIB_RGB_COLORS);
+  sprintf(buffer, "%d", reply);
+  MessageBox(0, buffer, "M", MB_OK);
+  GlobalFree((HLOCAL) bitmapData);
+  GlobalFree((HLOCAL) image);
+  _lclose(file);
+  return reply;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/bmpUtil.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/bmpUtil.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/bmpUtil.h	(revision 14219)
@@ -0,0 +1,6 @@
+#ifndef _BMPUTIL_H_
+#define _BMPUTIL_H_
+#include <windows.h>
+
+HBITMAP _export bmpUtil_loadBitmap(HDC device, char *name);
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/common.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/common.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/common.h	(revision 14219)
@@ -0,0 +1,7 @@
+#define dirpath_PROMPT	102
+#define dirpath_PROMPT	102
+#define dirpath_PATH	103
+#define dirpath_GROUP	101
+#define dirpath_BROWSE	105
+#define dirpath_OPTION	104
+#define IDC_STATICBITMAP1	101
Index: /gsdl/branches/nzdl2/gsinstaller/configFile.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/configFile.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/configFile.cpp	(revision 14219)
@@ -0,0 +1,213 @@
+#include "configFile.h"
+
+static char  	config_divider[] = ":";
+static char   config_eol[] = "\x0a";
+
+char *configureFile::filename(char *configFile)
+{ static char filename[512];
+	char *leaf;
+
+  GetModuleFileName(0, filename, 512);
+  leaf = strrchr(filename, '\\');
+  if (!leaf)
+  { return 0;
+	}
+
+  leaf ++;
+  strcpy(leaf, configFile);
+
+  return filename;
+}
+
+bool configureFile::concat(char *label, char *buffer, unsigned int &space)
+{ int loop;
+
+	// iterate through the list to find it
+	for (loop = 0; loop < configstr->count; loop ++)
+  { if (strcmp(configstr->item[loop].label, label) == 0)
+  	{	break;
+    }
+  }
+
+  // abort if not found
+  if (loop == configstr->count)
+  {	return false;
+  }
+
+  // don't concatenate if there's no space
+  if (strlen(configstr->item[loop].data) > space)
+  {	return false;
+  }
+
+  strcat(buffer, configstr->item[loop].data);
+  space -= strlen(configstr->item[loop].data);
+  return true;
+}
+
+void configureFile::get(char *label, char **to)
+{ int loop;
+
+  for (loop = 0; loop < configstr->count; loop ++)
+  { if (strcmp(configstr->item[loop].label, label) == 0)
+    { *to = new char[strlen(configstr->item[loop].data) + 1];
+      if (to)
+      { strcpy(*to, configstr->item[loop].data);
+        return;
+      }
+      else
+      { //Acorn: werr(0, msgs_lookup("MemConfg"));
+      }
+    }
+  }
+
+  *to = NULL;
+  return;
+}
+
+bool configureFile::put(char *label, char *value)
+{ int loop;
+  void *newstr;
+
+  for (loop = 0; loop < configstr->count; loop ++)
+  { if (strcmp(configstr->item[loop].label, label) == 0)
+    { strcpy(configstr->item[loop].data, value);
+      return true;
+    }
+  }
+
+
+  newstr = realloc(configstr, sizeof(config_str) +
+                              sizeof(config_item) * configstr->count);
+  if (!newstr)
+  {	return false;
+  }
+  strcpy(configstr->item[configstr->count].label, label);
+  strcpy(configstr->item[configstr->count].data, value);
+  configstr->count ++;
+  return true;
+}
+
+bool configureFile::scan(char *block, unsigned int &pos)
+{ int off = 0;
+	void *newstr;
+
+  newstr = realloc(configstr, sizeof(config_str) +
+                              sizeof(config_item) * configstr->count);
+  if (!newstr)
+  {	free(configstr);
+  	configstr	= NULL;
+  	return false;
+  }
+  configstr	= (config_str *) newstr;
+
+  while (block[pos] != ':')
+  { configstr->item[configstr->count].label[off] = block[pos];
+    off ++;
+    pos ++;
+  }
+  configstr->item[configstr->count].label[off] = '\0';
+
+  off = 0;
+  do
+  {	pos ++;
+  }	while (block[pos] <= ' ' && block[pos] != '\x0a' && block[pos] != '\x0d');
+
+  while(block[pos] >= ' ')
+  { configstr->item[configstr->count].data[off] = block[pos];
+    pos ++;
+    off ++;
+  }
+  configstr->item[configstr->count].data[off] = '\0';
+
+  do
+  { pos ++;
+  }
+	while (block[pos] <= ' ');
+
+  configstr->count ++;
+  return true;
+}
+
+bool configureFile::store(char *name)
+{ char *	varval;
+  int   	loop;
+	FILE *	fhandle;
+
+  varval = this->filename(name);
+
+  fhandle = fopen(varval, "wb+");
+  if (fhandle)
+  { loop = 0;
+    while(loop < configstr->count)
+    { fprintf(fhandle, "%s%s%s%s", configstr->item[loop].label, config_divider, configstr->item[loop].data, config_eol);
+      loop ++;
+    }
+
+    fclose(fhandle);
+  }
+
+//Acorn:  free(varval);
+  return TRUE;
+}
+
+configureFile::configureFile(char *name)
+{ unsigned int 		length, newlength;
+	unsigned int position;
+  char *	varval;
+  char *  block;
+  FILE *  fhandle;
+
+  configstr = (config_str *) malloc(sizeof(config_str));
+  if (!configstr)
+  { this->valid	= false;
+  	return;
+  }
+  configstr->count = 0;
+
+  varval = this->filename(name);
+
+  fhandle = fopen(varval, "rb");
+  if (fhandle)
+  { length = 0;
+
+  	//PC Method for fetching file
+  	block = (char *) malloc(20);
+    while ((newlength = fread(&block[length], sizeof(char), 20, fhandle)) != 0)
+    { void *newblock;
+
+    	length += newlength;
+    	newblock = realloc(block, length + 20);
+      if (!newblock)
+      {	free(block);
+        this->valid		= false;
+        fclose(fhandle);
+      	return;
+      }
+      block	= (char *) newblock;
+    }
+    //end of PC method
+
+    position	= 0;
+  	while (position < length)
+    { this->scan(block, position);
+    }
+
+    fclose(fhandle);
+  }
+  else
+  { // No config file MessageBox(0, "oops", "oops", MB_OK);
+  }
+
+  free(block);
+//Acorn:  free(varval);
+
+  this->valid = true;
+}
+
+configureFile::~configureFile()
+{ if (configstr)
+  { free(configstr);
+  	configstr	= NULL;
+  }
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/configFile.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/configFile.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/configFile.h	(revision 14219)
@@ -0,0 +1,35 @@
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+#include <stdio.h>
+#include <string.h>
+
+#include <windows.h>
+
+typedef struct
+{ char  label[32];
+  char  data[64];
+} config_item;
+
+typedef struct
+{ int         count;
+  config_item item[1];
+} config_str;
+
+class configureFile
+{
+	private:
+		config_str *	configstr;
+  	bool valid;
+
+    bool scan(char *buffer, unsigned int &pos);
+	public:
+  	configureFile(char *name);
+    char *filename(char *base);
+    bool put(char *label, char *value);
+    bool concat(char *label, char *buffer, unsigned int &space);
+    void get(char *label, char **to);
+  	bool store(char *);
+    bool isValid();
+    ~configureFile();
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/configurable.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/configurable.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/configurable.cpp	(revision 14219)
@@ -0,0 +1,35 @@
+#include "configurable.h"
+
+configurable::configurable()
+{
+}
+
+configurable::configurable(char *prompt)
+{	this->prompt		= prompt;
+	this->optPrompt	= 0;
+  this->final			= false;
+  this->option		= false;
+}
+
+configurable::configurable(char *prompt, char *optPrompt)
+{	this->prompt		= prompt;
+	this->optPrompt	= optPrompt;
+  this->final			= false;
+  this->option		= false;
+}
+
+void configurable::setOption(bool to)
+{	this->option		= to;
+}
+
+bool configurable::getOption()
+{	return this->option;
+}
+
+void configurable::setFinal(bool isFinal)
+{	this->final	= isFinal;
+}
+
+bool configurable::isFinal()
+{	return this->final;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/configurable.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/configurable.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/configurable.h	(revision 14219)
@@ -0,0 +1,22 @@
+#ifndef _CONFIGURE_H_
+class configurable
+{ private:
+	protected:
+  public:
+  	configurable();
+    configurable(char *prompt);
+    configurable(char *prompt, char *optPrompt);
+
+    void setFinal(bool isFinal);
+    bool isFinal();
+
+    void setOption(bool to);
+    bool getOption();
+    
+  	char *prompt;
+    bool  option;
+    bool	final;
+    char *optPrompt;
+};
+#define _CONFIGURE_H_ 1
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/copyProgress.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/copyProgress.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/copyProgress.cpp	(revision 14219)
@@ -0,0 +1,107 @@
+#include "copyProgress.h"
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdio.h>
+
+extern HINSTANCE app_instance;
+
+LRESULT CALLBACK copyProgressBar_windowProc(	HWND window, UINT message,
+																							WPARAM wParam, LPARAM lParam)
+{	switch (message)
+	{	case WM_CREATE:
+  	{	CREATESTRUCT *createStruct = (CREATESTRUCT *) lParam;
+    	long *createParams;
+    	copyProgressBar *progressBar;
+
+      createParams = (long *) createStruct->lpCreateParams;
+
+	 		SetWindowLong(window, GWL_USERDATA, createParams[0]);
+      progressBar = (copyProgressBar *) GetWindowLong(window, GWL_USERDATA);
+	    if (progressBar == NULL)
+      { MessageBox(0, "A", "A", MB_OK);
+      }
+
+      CreateWindowEx( 0, "STATIC", (char *) createParams[1], WS_CHILD | WS_VISIBLE,
+										 10, 5, 180, 20, window, (HMENU) 0,
+         		         app_instance, NULL);
+
+    }
+  	break;
+
+		default:
+			return(DefWindowProc(window, message, wParam, lParam));
+  }
+
+	return 0;
+}
+
+void copyProgressBar::registerClass()
+{	static bool registered = false;
+
+	if (registered == false)
+  {	WNDCLASS classdef;
+
+  	classdef.style 				= 0;
+    classdef.lpfnWndProc	= copyProgressBar_windowProc;
+    classdef.cbClsExtra		= 0;
+    classdef.cbWndExtra		= sizeof(copyProgressBar *) + sizeof(long);
+    classdef.hInstance		= app_instance;
+    classdef.hIcon				= 0;
+    classdef.hCursor			= NULL;
+    classdef.hbrBackground	= (HBRUSH) (COLOR_BTNFACE + 1);
+    classdef.lpszMenuName	= NULL;
+    classdef.lpszClassName	= "CopyProgressBar";
+    RegisterClass(&classdef);
+  	registered	= true;
+  }
+}
+
+copyProgressBar::copyProgressBar(unsigned long totalSize)
+{	this->total		= totalSize;
+	this->copied	= 0;
+}
+
+copyProgressBar::copyProgressBar()
+{	this->total		= 0;
+	this->copied	= 0;
+}
+
+void copyProgressBar::init(unsigned long totalSize)
+{	this->total		= totalSize;
+	this->copied	= 0;
+}
+
+void copyProgressBar::done(unsigned long bytesDone)
+{ unsigned int percent;
+  this->copied += bytesDone;
+
+  percent =(this->copied  * 100 / this->total);
+
+	SendMessage(this->progressBar, PBM_SETPOS, percent, 0L);
+}
+
+void copyProgressBar::show()
+{ long params[2];
+
+	params[0] = (long) this;
+  params[1] = (long) "Copying files....";
+  this->registerClass();
+	this->progressParent	= CreateWindowEx(WS_EX_APPWINDOW, "CopyProgressBar", "GreenStone Installer", WS_VISIBLE,
+																		 CW_USEDEFAULT, CW_USEDEFAULT, 200, 80, 0, (HMENU) 0,
+                         		         app_instance, (void *) params);
+	this->progressBar	= CreateWindowEx(0, PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE,
+																		 10, 30, 180, GetSystemMetrics(SM_CYVSCROLL), this->progressParent, (HMENU) 0,
+                         		         app_instance, NULL);
+}
+
+void copyProgressBar::close()
+{ return;
+	ShowWindow(this->progressBar, SW_HIDE);
+	DestroyWindow(this->progressBar);
+
+  ShowWindow(this->progressParent, SW_HIDE);
+  DestroyWindow(this->progressParent);
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/copyProgress.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/copyProgress.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/copyProgress.h	(revision 14219)
@@ -0,0 +1,21 @@
+#ifndef _COPYPROGRESS_H_
+#define _COPYPROGRESS_H_
+#include <windows.h>
+
+class copyProgressBar
+{	private:
+		unsigned long total;
+		unsigned long copied;
+    HWND					progressParent;
+    HWND					progressBar;
+	public:
+  	copyProgressBar();
+  	copyProgressBar(unsigned long totalSize);
+    void registerClass();
+    LRESULT CALLBACK windowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
+    void done(unsigned long bytesDone);
+    void init(unsigned long totalSize);
+    void show();
+    void close();
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/dirSelector.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/dirSelector.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/dirSelector.cpp	(revision 14219)
@@ -0,0 +1,148 @@
+#include "dirSelector.h"
+
+#include <stdio.h>
+#include <shlobj.h>
+
+extern HINSTANCE app_instance;
+
+int CALLBACK initSelect(HWND window, UINT message, LPARAM lParam, LONG lpData)
+{ TCHAR buffer[MAX_PATH];
+
+	switch (message)
+	{	case BFFM_INITIALIZED:
+  	{ dirSelector *selector = (dirSelector *) lpData;
+
+    	lstrcpy(buffer, selector->selectedPath());
+//      GetCurrentDirectory(sizeof(buffer) / sizeof(TCHAR), buffer);
+    	SendMessage(window, BFFM_SETSELECTION, TRUE, (LPARAM) buffer);
+      SendMessage(window, BFFM_SETSTATUSTEXT, 0, (LPARAM) buffer);
+    }
+    break;
+
+    case BFFM_SELCHANGED:
+    	if (SHGetPathFromIDList((LPITEMIDLIST) lParam, buffer))
+      {	SendMessage(window, BFFM_SETSTATUSTEXT, 0, (LPARAM) buffer);
+      }
+    break;
+  }
+  return 0;
+}
+
+dirSelector::dirSelector(char *_prompt, char *_title) : configurable(_prompt)
+{	this->path		= NULL;
+  this->title		= _title;
+}
+
+dirSelector::dirSelector(char *_prompt, char *_optPrompt, char *_title, FilePath *_defPath) :
+	configurable(_prompt, _optPrompt)
+{ this->path		= new char[strlen(_defPath->cString())+1];
+	strcpy(this->path, _defPath->cString());
+  this->title		= _title;
+}
+
+dirSelector::dirSelector(HGLOBAL dlgBlk)
+{	this->path			= NULL;
+	this->dlgBlock	= dlgBlk;
+}
+
+UINT APIENTRY hookProc(HWND dlg, UINT message,
+												WPARAM wParam, LPARAM lParam)
+{ switch (message)
+	{ case WM_INITDIALOG:
+  		CommDlg_OpenSave_HideControl(GetParent(dlg), edt1);
+  		CommDlg_OpenSave_HideControl(GetParent(dlg), stc3);
+      CommDlg_OpenSave_HideControl(GetParent(dlg), cmb1);
+  		CommDlg_OpenSave_HideControl(GetParent(dlg), stc2);
+  		CommDlg_OpenSave_HideControl(GetParent(dlg), chx1);
+      CommDlg_OpenSave_SetControlText(GetParent(dlg), IDOK, "Select");
+  	break;
+
+    case WM_NOTIFY:
+      if (((LPNMHDR) lParam)->code == CDN_INITDONE)
+      { CommDlg_OpenSave_HideControl(GetParent(dlg), edt1);
+      }
+      else if (((LPNMHDR) lParam)->code == CDN_FILEOK)
+      {	return 0;
+      }
+    break;
+  }
+	return 0;
+}
+
+void dirSelector::setPath(LPSTR newpath)
+{ if (this->path)
+	{ delete this->path;
+  }
+  this->path = new char[strlen(newpath) + 1];
+  strcpy(this->path, newpath);
+}
+
+void dirSelector::setPathFromEdit(HWND window)
+{	char *newpath;
+
+	newpath = new char[GetWindowTextLength(window) + 1];
+  if (newpath != NULL)
+  {	GetWindowText(window, newpath, GetWindowTextLength(window) + 1);
+  	if (this->path)
+	  {	delete this->path;
+  	}
+	  this->path = newpath;
+  }
+}
+
+void dirSelector::requestPath(HWND parent, LPSTR message)
+{ OPENFILENAME 	openStr;
+	char					fileName[256] = "dir.dir\0";
+  DWORD					error;
+  BROWSEINFO    bInfo;
+  int						image;
+
+  bInfo.hwndOwner = parent;
+  bInfo.pidlRoot				= NULL;
+  bInfo.pszDisplayName	= fileName;
+  bInfo.lpszTitle				= message;
+  bInfo.ulFlags					= BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
+  bInfo.lpfn						= initSelect;
+  bInfo.lParam					= (LONG) this;
+  bInfo.iImage					= image = 0;
+  LPITEMIDLIST itemList = SHBrowseForFolder(&bInfo);
+  if (itemList != NULL)
+  { SHGetPathFromIDList(itemList, fileName);
+  	this->setPath(fileName);
+  }
+  return;
+
+	openStr.lStructSize	= sizeof(OPENFILENAME);
+  openStr.hwndOwner		= parent;
+  openStr.hInstance		= 0;// app_instance; //this->dlgBlock;
+  openStr.lpstrFilter				= NULL;
+  openStr.lpstrCustomFilter	= NULL;
+  openStr.nMaxCustFilter		= NULL;
+  openStr.nFilterIndex			= 0;
+  openStr.lpstrFile					= fileName;
+  openStr.nMaxFile					= 255;
+  openStr.lpstrFileTitle		= NULL;
+  openStr.lpstrInitialDir		= NULL;
+  openStr.lpstrTitle				= message;
+  openStr.Flags							= OFN_ENABLEHOOK | OFN_NOTESTFILECREATE | OFN_NOVALIDATE | OFN_EXPLORER; //  || OFN_ENABLETEMPLATE | OFN_EXPLORER;
+  openStr.nFileOffset				= 0;
+  openStr.nFileExtension		= 4;
+  openStr.lpstrDefExt				= NULL;
+  openStr.lCustData					= NULL;
+  openStr.lpfnHook					= hookProc;
+  openStr.lpTemplateName		= 0; // "MySaveAsDlg";
+  if (GetSaveFileName(&openStr) == 0)
+  { error = CommDlgExtendedError();
+  }
+  else
+  { if (this->path != NULL)
+  	{ free(this->path);
+    }
+  	this->path = (char *) malloc (strlen(openStr.lpstrFile) + 1);
+  	strcpy(this->path, openStr.lpstrFile);
+  }
+}
+
+char *dirSelector::selectedPath()
+{	return this->path;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/dirSelector.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/dirSelector.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/dirSelector.h	(revision 14219)
@@ -0,0 +1,23 @@
+#ifndef _DIRSELECTOR_H_
+#include <windows.h>
+
+#include "configurable.h"
+#include "FilePath.h"
+
+class dirSelector : public configurable
+{	private:
+    char *title;
+	  char *path;
+    HGLOBAL dlgBlock;
+	protected:
+  public:
+  	dirSelector(char *prompt, char *title);
+    dirSelector(char *prompt, char *optPrompt, char *title, FilePath *defaultPath);
+    dirSelector(HGLOBAL dlgBlock);
+    void  requestPath(HWND parent, LPSTR message);
+    void  setPath(char *path);
+    void  setPathFromEdit(HWND editWindow);
+    char *selectedPath();
+};
+#define _DIRSELECTOR_H_
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/file.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/file.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/file.cpp	(revision 14219)
@@ -0,0 +1,143 @@
+#include <sys\stat.h>
+#include <dirent.h>
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "file.h"
+
+void File::_getDetails()
+{ struct stat statData;
+
+	if (this->name.length() < 5)
+  {	this->does_exist	= true;
+  	this->size				= 0;
+    this->is_dir			= true;
+    this->is_writable = true;
+  }
+  else
+  { if (stat (this->name.c_str(), &statData) == -1)
+	  { this->does_exist	= false;
+  		this->size				= 0;
+    	this->is_dir			= false;
+	    this->is_writable = false;
+  	}
+	  else
+  	{ this->does_exist  = (statData.st_mode & (S_IFDIR | S_IFREG)) != 0;
+	  	this->is_dir			= ((statData.st_mode & S_IFDIR) != 0);
+  	  this->size   			= statData.st_size;
+    	this->is_writable = ((statData.st_mode & S_IWRITE) != 0);
+    }
+  }
+}
+
+void File::getChildren()
+{ DIR *						directory;
+	struct dirent	*	entry;
+
+	directory = opendir(this->name.c_str());
+  if (directory == NULL)
+  {	return;
+  }
+
+  while ((entry = readdir(directory)) != NULL)
+  {	string childName;
+
+  	if (strcmp(entry->d_name, "..") == 0 ||
+    		strcmp(entry->d_name, ".") == 0)
+    {	continue;
+    }
+
+		childName = this->name;
+    childName.append("\\");
+    childName.append(entry->d_name);
+
+    this->children.push_back(*(new File(childName)));
+  }
+  closedir(directory);
+}
+
+File::File()
+{	this->size		= 0;
+}
+
+File::File(string filename)
+{	this->name		= filename;
+	this->_getDetails();
+	if (this->is_dir)
+  {	this->getChildren();
+  }
+}
+
+File::File(string filename, unsigned long filesize)
+{	this->name		= filename;
+	this->_getDetails();
+  if (this->is_dir)
+  {	this->getChildren();
+  }
+}
+
+unsigned long File::getDiskSpace(DiskSpace &diskSpace)
+{ unsigned long totalSize = 0;
+
+	if (this->is_dir)
+	{ vector<File>::iterator here = this->children.begin();
+  	vector<File>::iterator end	= this->children.end();
+
+    while (here != end)
+    {	totalSize	+=  here->getDiskSpace(diskSpace);
+    	here ++;
+    }
+  }
+  totalSize	+=	diskSpace.fileSpace(this->size);
+	return totalSize;
+}
+
+const char *File::getFileName()
+{	return this->name.c_str();
+}
+
+unsigned long File::getRawFileSize()
+{	return this->size;
+}
+
+unsigned long File::getFileSize()
+{	unsigned long	totalSize	= 0;
+
+	if (this->is_dir)
+  {	vector<File>::iterator here	= this->children.begin();
+  	vector<File>::iterator end	= this->children.end();
+
+	  while (here != end)
+  	{	totalSize	+=	here->getFileSize();
+  		here ++;
+	  }
+  }
+  totalSize	+=	this->size;
+  return totalSize;
+}
+
+vector<File>::iterator File::childBegin()
+{	return this->children.begin();
+}
+
+vector<File>::iterator File::childEnd()
+{	return this->children.end();
+}
+
+bool File::isDirectory()
+{	return this->is_dir;
+}
+
+bool File::isWriteable()
+{	return this->is_writable;
+}
+
+bool File::exists()
+{ return this->does_exist;
+}
+
+void File::copy(char *to)
+{
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/file.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/file.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/file.h	(revision 14219)
@@ -0,0 +1,38 @@
+#ifndef _FILE_H_
+#include <vector>
+#include <string>
+using namespace std;
+
+#include "DiskSpace.h"
+
+class File
+{	private:
+  	string				name;
+  	unsigned long size;
+		vector<File>	children;
+    bool					is_dir;
+    bool					does_exist;
+    bool          is_writable;
+
+		void _getDetails();
+    void getChildren();
+	protected:
+  public:
+  	File();
+    File(string filename, unsigned long filesize);
+    File(string filename);
+    void copy(char *destination);
+    bool isDirectory();
+    bool isWriteable();
+    bool exists();
+    unsigned long getRawFileSize();
+    unsigned long getFileSize();
+    const char *getFileName();
+    unsigned long getDiskSpace(DiskSpace &diskSpace);
+    vector<File>::iterator childBegin();
+    vector<File>::iterator childEnd();
+};
+
+typedef vector<File> FileVector;
+#define _FILE_H_
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/fileCopier.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/fileCopier.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/fileCopier.cpp	(revision 14219)
@@ -0,0 +1,253 @@
+#include "fileCopier.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <dir.h>
+
+fileCopySet::fileCopySet()
+{	this->sourceDir	= NULL;
+	this->destDir		= NULL;
+}
+
+fileCopySet::fileCopySet(FileVector files, FilePath &from, FilePath &to)
+{	this->fileList	= files;
+	this->sourceDir	= from;
+  this->destDir		= to;
+
+	FileVector::iterator here	= files.begin();
+  FileVector::iterator end	= files.end();
+
+  while (here != end)
+  {	this->dataSize	+=	here->getFileSize();
+  	here ++;
+  }
+}
+
+/**
+ *  Get the destination file name for a given source file; source and destination
+ *  directory locations are obtained from the object
+ */
+char *fileCopySet::destination(File *file)
+{	const char *oldname	= file->getFileName();
+	char *newname = (char *) malloc(strlen(oldname) - strlen(this->sourceDir.cString()) + strlen(this->destDir.cString()) + 1);
+
+  if (newname != NULL)
+  {	strcpy(newname, this->destDir.cString());
+  	strcat(newname, &oldname[strlen(this->sourceDir.cString())]);
+  }
+
+  return newname;
+}
+
+/**
+ * Copy a particular file to its destination
+ */
+bool fileCopySet::copyFile(File *file, copyProgressBar &progressBar)
+{ unsigned long copied = 0;
+	unsigned long bytes_read, bytes_written;
+	unsigned char buffer[65536];
+  FILE *read_handle, *write_handle;
+  char *destination;
+
+  // get destination as a char[] block; will free it later
+  destination	= this->destination(file);
+
+  // get read and write file handles
+  read_handle 	= fopen(file->getFileName(), "rb");
+  if (read_handle == NULL)
+  {	return false;
+  }
+	write_handle	= fopen(destination, "wb");
+  if (write_handle == NULL)
+  {	fclose(read_handle);
+  	return false;
+  }
+
+  while (copied < file->getFileSize())
+  {	// TODO: lock
+
+		// read so many bytes
+    if (file->getFileSize() - copied < 65536)
+    {	bytes_read = file->getFileSize() - copied;
+    }
+    else
+    {	bytes_read	= 65536;
+    }
+    bytes_read = fread((void *) buffer, 1, bytes_read, read_handle);
+
+  	// write so many bytes
+    bytes_written	=	fwrite((void *) buffer, 1, bytes_read, write_handle);
+
+  	// TODO: unlock
+
+    // note new bytes copied
+    copied					+=	bytes_written;
+  	this->dataSize	+= bytes_written;
+  }
+  fclose(read_handle);
+  fclose(write_handle);
+
+  // free destination filename text
+  delete destination;
+  return true;
+}
+
+/**
+ *  Copy a file "object" (may be a directory or a "proper" file) to it's
+ *  destination
+ */
+void fileCopySet::copy(File *file, copyProgressBar &progressBar)
+{ // just skip this file if it doesn't exist
+	if (file->exists() == false)
+	{	return;
+  }
+
+  // if a directory, scan it.
+	if (file->isDirectory())
+	{ // create directory
+    char *thisDestDir	= this->destination(file);
+    mkdir(thisDestDir);
+
+    // note amount of data copied
+  	// this->copied += file->getRawFileSize();
+
+  	// copy children
+    vector<File>::iterator here	= file->childBegin();
+    vector<File>::iterator end	= file->childEnd();
+    while (here != end)
+    {	this->copy(here, progressBar);
+    	here ++;
+    }
+
+    // delete constructed destination name
+    delete thisDestDir;
+  }
+  // not a directory; just copy the file
+  else
+  { // copy file itself
+  	this->copyFile(file, progressBar);
+  }
+  progressBar.done(file->getRawFileSize());
+}
+
+void fileCopySet::copy(copyProgressBar &progressBar)
+{	FileVector::iterator here = fileList.begin();
+	FileVector::iterator end	= fileList.end();
+
+  while (here != end)
+  {	this->copy(here, progressBar);
+  	here ++;
+  }
+}
+
+unsigned long fileCopySet::getCopiedSize(DiskSpace &space)
+{ // initialise counters for size
+	unsigned long copiedSize 		= 0;
+
+  // iterate through our list of files to obtain total space requirement
+  FileVector::iterator here = fileList.begin();
+	FileVector::iterator end	= fileList.end();
+
+  while (here != end)
+  {	copiedSize += here->getDiskSpace(space);
+  	here ++;
+  }
+
+  return copiedSize;
+}
+
+unsigned long fileCopySet::getOriginalSize()
+{ // initialise counters for size
+	return this->dataSize;
+}
+
+/**
+ *  Perform a check on the total space available at the destination; if not
+ *  enough then return false to indicate the error state
+ */
+bool fileCopier::checkSpace()
+{ fileCopySetList localSet = this->list;
+
+	do
+  { unsigned int i = 0;
+
+  	// get destination root and use it to obtain space check information
+    char buffer[120];
+		FilePath *destRoot = localSet[0].destDir.root();
+    strcpy(buffer, destRoot->cString());
+    MessageBox(0, buffer, "A", MB_OK);
+		DiskSpace space(destRoot->cString());
+
+	  // check that diskspace checking is functional
+	  if (space.initialisedOk() == false)
+  	{ delete destRoot;
+    	return false;
+  	}
+
+    // get size of the first set
+    unsigned long copiedSize = localSet[0].getCopiedSize(space);
+
+    // dispose of the first set
+    localSet.erase(localSet.begin());
+
+    // get all remaining sets and in turn if they share the root with
+    // the first root, add their size to the count and remove them from
+    // the local list of sets; otherwise skip
+  	while (i < localSet.size())
+    { // get a new root object for this set's destination
+    	FilePath *p = localSet[i].destDir.root();
+
+    	if (*destRoot == *p)
+      {	copiedSize	+=	localSet[i].getCopiedSize(space);
+      	localSet.erase(localSet.begin() + i);
+      }
+      else
+      {	i ++;
+      }
+
+      // delete the constructed root
+      delete p;
+    }
+
+    // dispose of destination root
+    delete destRoot;
+
+	  // return false if not enough space
+  	if (space.totalFreeSpace() < copiedSize)
+  	{ return false;
+  	}
+  } while (localSet.size() != 0);
+
+  // record size and initialise the progressbar with the same
+  this->dataSize	= 0;
+  for (unsigned int i = 0; i < this->list.size(); i ++)
+  {	this->dataSize	+= this->list[i].getOriginalSize();
+  }
+  this->progressBar.init(this->dataSize);
+
+  // return postive check
+  return true;
+}
+
+fileCopier::fileCopier(fileCopySetList &_list)
+{	this->list	= _list;
+  this->dataSize	= 0;
+  this->copied		= 0;
+}
+
+fileCopier::fileCopier()
+{ this->dataSize	= 0;
+  this->copied		= 0;
+}
+
+void fileCopier::copy()
+{	fileCopySetList::iterator here = list.begin();
+	fileCopySetList::iterator end	= list.end();
+
+  this->progressBar.show();
+  while (here != end)
+  {	here->copy(this->progressBar);
+  	here ++;
+  }
+  this->progressBar.close();
+}
Index: /gsdl/branches/nzdl2/gsinstaller/fileCopier.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/fileCopier.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/fileCopier.h	(revision 14219)
@@ -0,0 +1,41 @@
+#ifndef _FILECOPIER_H_
+#include "file.h"
+#include "filePath.h"
+#include "copyProgress.h"
+#include "diskSpace.h"
+
+class fileCopySet
+{ private:
+		FileVector    fileList;
+  	FilePath      sourceDir;
+		unsigned long	dataSize;
+  public:
+  	FilePath      destDir;
+    fileCopySet();
+  	fileCopySet(FileVector files, FilePath &from, FilePath &to);
+	  char *destination(File *file);
+    unsigned long getOriginalSize();
+    unsigned long getCopiedSize(DiskSpace &space);
+    bool copyFile(File *file, copyProgressBar &progressBar);
+    void copy(File *file, copyProgressBar &progressBar);
+    void copy(copyProgressBar &progressBar);
+};
+
+typedef vector<fileCopySet> fileCopySetList;
+
+class fileCopier
+{ private:
+		fileCopySetList	list;
+		unsigned long		dataSize;
+  	unsigned long 	copied;
+	  copyProgressBar progressBar;
+	protected:
+  public:
+  	fileCopier::fileCopier(fileCopySetList &list);
+    fileCopier::fileCopier();
+    void fileCopier::addSet(fileCopySet &set) { this->list.push_back(set); }
+    bool checkSpace();
+    void copy();
+};
+#define _FILECOPIER_H_
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/gs16bit.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gs16bit.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gs16bit.cpp	(revision 14219)
@@ -0,0 +1,270 @@
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "splash.h"
+#include "bmputil.h"
+
+// define the magic value used in GetWinFlags to show that this application
+// is running on a Windows NT box in 16-bit emulation mode.
+#define WF_WINNT 0x4000
+
+#ifdef _WIN32
+int GetWinFlags()
+{ return 0;
+}
+#endif
+
+HWND 				app_window;
+HINSTANCE 	app_instance;
+char *	app_cmdLine;
+
+typedef void (* splashfn) (HINSTANCE a, unsigned int time);
+typedef HBITMAP (* bmploadfn) (HDC device, LPSTR name);
+
+typedef struct
+{	BYTE	majorVersion;
+	BYTE	minorVersion;
+  WORD	buildNumber;
+  BOOL  debug;
+} win32sInfo, FAR * lpWin32sInfo;
+
+typedef enum
+{ Windows2x, Windows3_0x, Windows3_1x, Windows9x, WindowsNT
+}	gs16PlatformId;
+
+typedef struct
+{	gs16PlatformId	platform;
+	bool						win32s;
+}	gs16PlatformInfo;
+
+typedef int FAR PASCAL (* win32sInfoFn)(lpWin32sInfo);
+
+bool GS16bit_checkForWin32s()
+{	HANDLE 				w32sHandle;
+	win32sInfoFn	infoFnPtr;
+	win32sInfo  	w32sInfo;
+  bool					reply = false;
+
+	// try to get a handle onto the win32s library
+	w32sHandle	= LoadLibrary("W32SYS.DLL");
+
+  if (w32sHandle > HINSTANCE_ERROR)
+  { // now get the address of the GetWin32sInfo function
+  	infoFnPtr	= (win32sInfoFn) GetProcAddress(w32sHandle, "GETWIN32SINFO");
+
+    // if the function exists, we've got win32s1.1 or later
+  	if (infoFnPtr != NULL)
+    { if ((*infoFnPtr)((lpWin32sInfo) &w32sInfo) == 0) // no error state
+    	{	reply	= true;
+      }
+      else	// error - call didn't work; assume that we have a non-functional
+      			// win32s
+      {	reply = false;
+      }
+    }
+    // else we've got win32s 1.0.  TODO: We need to check if it's actually up and
+    // running;
+    else
+    {	reply = true;
+    }
+
+    // we need to free the library before finishing this function
+    FreeLibrary(w32sHandle);
+  }
+  // no win32s at all
+  else
+  {	reply = false;
+  }
+
+  return reply;
+}
+
+void GS16bit_getPlatformInfo(gs16PlatformInfo &info)
+{	DWORD version = GetVersion();
+
+  /**
+   * NB: Ignore ALL standard information on using GetVersion in the
+   *     standard Windows 3.1 SDK and Windows 32-bit SDK documentation;
+   *     the latter does not apply, and the former is (slightly but signif-
+   *     cantly) misdocumented.
+   *
+   *     On 16-bit windows (i.e. this program) take the following comments
+   *     as gospel.  Also refer to
+   *
+   *        http://support.microsoft.com/support/kb/articles/Q131/3/71.asp
+   */
+  BYTE majorVersion = LOBYTE(LOWORD(version));
+  BYTE minorVersion = HIBYTE(LOWORD(version));
+  BYTE dosVersion		= HIBYTE(HIWORD(version));
+
+  if (majorVersion < 3)
+  { info.platform	= Windows2x;
+  }
+  else if (majorVersion == 3 && minorVersion >= 95) // it's Windows 95 from the
+  																									// minor version; I guess that
+                                                    // 98 may have minor version == 98,
+                                                    // but I don't know!  Hence the
+                                                    // cautious check
+  { info.platform	= Windows9x;
+  }
+  else // we're running in "some sort" of Windows 3.x environment
+  { if (minorVersion == 10 && dosVersion == 5) 			// it could be running under WOW
+                                                		// (16-bit Windows emulation in
+                                                		//  Windows NT)
+  	{	if ((GetWinFlags() & WF_WINNT) == WF_WINNT)		// check for NT in emulation mode
+    	{ info.platform	= WindowsNT;
+      }
+      else
+      { info.platform	= Windows3_1x;
+      }
+    }
+    else if (minorVersion >= 10) //	perhaps Windows 3.11
+    {	info.platform = Windows3_1x;
+    }
+    else
+    { info.platform = Windows3_0x;
+    }
+  }
+
+  if (info.platform == Windows3_1x)
+  {	info.win32s	= GS16bit_checkForWin32s();
+  }
+  else
+  {	info.win32s	= false;
+  }
+}
+
+void GS16bit_checkWindowsVersion()
+{	gs16PlatformInfo	platformInfo;
+
+	GS16bit_getPlatformInfo(platformInfo);
+  if (platformInfo.platform == Windows3_0x ||
+  		platformInfo.platform == Windows2x)
+  {	MessageBox(app_window,
+  							"Greenstone cannot be installed on this computer.  It requires "
+                "Windows 3.10 or later",
+                "Greenstone Installer",
+                MB_OK);
+  }
+  else if (	platformInfo.platform == Windows3_1x &&
+            platformInfo.win32s	== false)
+  {	MessageBox(app_window,
+  							"Greenstone requires 32 bit Windows.  Win32s will now be installed "
+                "on your computer to provide this, before continuing with the main "
+                "installation.",
+                "Greenstone Installer",
+                MB_OK);
+  }
+  else
+  { char buffer[20];
+  	int	result;
+/*  	MessageBox(app_window,
+  							"Greenstone will now install", "Greenstone Installer", MB_OK);*/
+  	result = WinExec("gssetup.exe", SW_SHOWNORMAL);
+  }
+}
+
+long FAR PASCAL GS16bitWindProc(HWND		 	Window,
+																	WORD		 	Message,
+																	WPARAM		wParameter,
+																	LPARAM		lParameter)
+{ long reply = 0;
+
+  switch(Message)
+	{ case WM_CREATE:
+  	{
+    }
+  	break;
+
+  	case WM_COMMAND:
+		break;
+
+		case WM_CLOSE:
+			DestroyWindow(Window);
+		return 0L;
+
+		case WM_DESTROY:
+		{ PostQuitMessage(0);
+		}
+		break;
+
+		default:
+			return(DefWindowProc(Window, Message, wParameter, lParameter));
+	}
+  return reply;
+}
+
+void GS16bit_init(HINSTANCE instance, int Show)
+{ FARPROC showsplash;
+	FARPROC loadbmp;
+  HDC			dc;
+  char buffer[20];
+
+/*
+  dc	= GetDC(GetDesktopWindow());
+  bmpUtil_loadBitmap(dc, "C:\\gs.bmp");
+  ReleaseDC(GetDesktopWindow(), dc);
+*/
+//	showsplash = MakeProcInstance((FARPROC) splash_show, instance);
+//	(*(splashfn) showsplash)(instance, 3000);
+
+  GS16bit_checkWindowsVersion();
+
+	app_window = CreateWindow("GS16bit:Main", "GreenStone Installer",
+															WS_OVERLAPPEDWINDOW | WS_MINIMIZE | CS_DBLCLKS,
+															CW_USEDEFAULT,
+															0,
+															CW_USEDEFAULT,
+															0,
+															NULL,
+															NULL,
+															app_instance,
+															NULL);
+
+	ShowWindow(app_window, Show);
+
+  PostQuitMessage(0);
+}
+
+void WinClassInit(void)
+{ WNDCLASS 	Class;
+
+	Class.lpszClassName = "GS16bit:Main";
+	Class.hInstance     = app_instance;
+	Class.lpfnWndProc		= (WNDPROC) GS16bitWindProc;
+	Class.hCursor				= LoadCursor(NULL, IDC_ARROW);
+	Class.hIcon					= NULL; //LoadIcon(app_instance, "GSInstall");
+	Class.lpszMenuName  = NULL;
+	Class.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1);
+	Class.style 				= NULL;
+	Class.cbClsExtra		= 0;
+	Class.cbWndExtra		= 0;
+	RegisterClass(&Class);
+}
+
+int PASCAL WinMain(HINSTANCE Current,
+										HINSTANCE Previous,
+										LPSTR CmdLine,
+										int CmdShow)
+{ MSG msg;
+
+	app_cmdLine = (char *) LocalAlloc(LMEM_FIXED, lstrlen(CmdLine) + 1);
+	lstrcpy(app_cmdLine, CmdLine);
+
+	app_instance = Current;
+	/* -- init application */
+	if (!Previous)
+	{ WinClassInit();
+	}
+
+	/* -- init instance */
+  GS16bit_init(Current, CmdShow);
+
+	while (GetMessage(&msg, NULL, 0, 0))
+	{ TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+	return (int) msg.wParam;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/gs16bit.def
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gs16bit.def	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gs16bit.def	(revision 14219)
@@ -0,0 +1,10 @@
+EXETYPE WINDOWS
+
+DATA MULTIPLE MOVEABLE
+
+HEAPSIZE 8192
+STACKSIZE 8192
+EXPORTS GS16bitWindProc
+EXPORTS splash_windproc
+EXPORTS  bmpUtil_loadBitmap
+
Index: /gsdl/branches/nzdl2/gsinstaller/gsConfig.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsConfig.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsConfig.cpp	(revision 14219)
@@ -0,0 +1,9 @@
+#include "gsConfig.h"
+
+gsConfiguration::gsConfiguration()
+{
+}
+
+void gsConfiguration::install(char *exePath, char *collectPath)
+{	
+}
Index: /gsdl/branches/nzdl2/gsinstaller/gsConfig.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsConfig.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsConfig.h	(revision 14219)
@@ -0,0 +1,12 @@
+#ifndef _GSCONFIG_H_
+#define _GSCONFIG_H_
+#include <windows.h>
+
+class gsConfiguration
+{ private:
+	protected:
+  public:
+	  gsConfiguration();
+    void install(char *exePath, char *collectPath);
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/gsManifest.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsManifest.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsManifest.cpp	(revision 14219)
@@ -0,0 +1,236 @@
+#include "gsManifest.h"
+#include "fileCopier.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+gsManifest::gsManifest(FilePath &root)
+{	this->getManifest(root);
+	this->expandGroups();
+}
+
+bool gsManifest::getManifest(FilePath &root)
+{ FilePath *manifestPath = new FilePath((char *) root.cString(), "manifest.cfg");
+	FILE *    file;
+  DWORD			fileSize;
+  string		currentgroup;
+  char *		buffer;
+  char *		line;
+  char *		eol;
+
+	// open file handle for read access
+  file = fopen(manifestPath->cString(), "rb");
+	if (file == NULL)
+  {	return false;
+  }
+
+  // get size of file
+  File f(manifestPath->cString());
+  fileSize	= f.getFileSize();
+
+  // allocate buffer for whole file and read it in
+	buffer	= new char[fileSize];
+  if (fread(buffer, 1, fileSize, file) < fileSize)
+  {	// TODO: error handling
+  }
+  fclose(file);
+
+  //parse file into lines and send to the line fn
+  line	= buffer;
+  while ((eol = strchr(line, '\x0a')) != NULL) 	// use 0a for the eol to remove
+                                                // dependency on dos 0d,0a eol
+  {	*eol = '\0';
+
+    this->getManifestLine(line, currentgroup);
+
+  	line = eol + 1;
+  }
+  this->getManifestLine(line, currentgroup);
+
+	delete buffer;
+  return true;
+}
+
+bool gsManifest::getManifestLine(char *line, string &group)
+{ char *eol;	// we (potentially) need to clean up the end of
+              // line, and we won't use the eol from the main
+              // getManifest fn. as for the last line it'd be
+              // null.
+
+	// clean up the start of the line
+	while (*line <= ' ' && *line != '\0')
+	{ line ++;
+  }
+
+  // it's a blank line - don't bother!
+  if (line == '\0')
+  {	return true;
+  }
+
+  // clean up the end of line
+  eol	= line + strlen(line) - 1;
+  while (*eol <= ' ' && eol >= line)
+  {	*eol = '\0';
+  	eol --;
+  }
+
+  // does the line end with a colon?; if so take it as a group definition
+  if (*eol == ':')
+  { if (eol == line) // if it's literally just a colon do nothing
+  	{	return true;
+    }
+
+    // note the new group name
+  	string newgroup(line, 0, eol - line);
+    group = newgroup;
+  }
+  else
+  {	stringArray array;
+  	array	=	stringArray::words(line);
+
+    if (group.length() == 0)
+    {	this->manifests["all"].add(array);
+    }
+    else
+    {	this->manifests[group].add(array);
+    }
+  }
+  return true;
+}
+
+/**
+ * Expand all groups
+ */
+void gsManifest::expandGroups()
+{	strArrayMap::iterator here = this->manifests.begin();
+  strArrayMap::iterator end	= this->manifests.end();
+
+  while (here != end)
+  { this->expandGroup((*here).first);
+  	here ++;
+  }
+}
+
+/**
+ * expand a particular group
+ */
+void gsManifest::expandGroup(string &group)
+{	stringArray	&array = this->manifests[group];
+
+	unsigned int i = 0;
+  while (i < array.size())
+  {	if (this->isGroup(array[i]))
+  	{	this->expandGroupInstance(group, array[i]);
+    }
+    else
+    {	i ++;
+    }
+  }
+}
+
+/**
+ * expand a group instance inside a given group
+ */
+void gsManifest::expandGroupInstance(string parentgroup, string groupName)
+{ // remove the group instance from the parent
+	this->manifests[parentgroup].remove(groupName);
+
+	// create a "clean" name without the { } brackets
+	string group(groupName, 1, groupName.length() - 2);
+
+  // circular reference - we're kind and ignore it!!
+  if (parentgroup.compare(group) == 0)
+  {	return;
+  }
+
+  // lookup chidl group and add it to the parent
+	this->manifests[parentgroup].add(this->manifests[group]);
+}
+
+/**
+ * Check if a member of a group is itself a group - look for { } brackets
+ * around the name
+ */
+bool gsManifest::isGroup(string &name)
+{ if (name[0] == '{' && name[name.length()-1] == '}')
+ 	{	return true;
+  }
+	return false;
+}
+
+void gsManifest::expandMacro(string macro, string value)
+{	string macroRef = "\$(" + macro + ")";
+
+  strArrayMap::iterator here = this->manifests.begin();
+  strArrayMap::iterator end	= this->manifests.end();
+
+  while (here != end)
+  { stringArray &array = this->manifests[(*here).first];
+
+  	unsigned int i = 0;
+    while (i < array.size())
+    { unsigned int pos;
+    	while ((pos = array[i].find(macroRef)) < array[i].length() && pos != -1)
+			{	array[i].replace(pos, macroRef.length(), value);
+      }
+      i ++;
+    }
+    here ++;
+  }
+}
+
+void gsManifest::clearSelection()
+{	this->selected.empty();
+}
+
+void gsManifest::selectGroup(string &groupName, FilePath &destination)
+{ stringArray &groupArray = this->manifests[groupName];
+
+	groupArray	= this->manifests[groupName];
+  this->selected[destination].add(groupArray);
+}
+
+bool gsManifest::copy(FilePath *source)
+{ fileCopier	copy;
+
+	pathStringArrayMap::iterator here = this->selected.begin();
+  pathStringArrayMap::iterator end	= this->selected.end();
+
+  while (here != end)
+  { FileVector *fileList;
+  	stringArray &array = (*here).second;
+    FilePath path((*here).first);
+
+    // TODO: eliminate inefficiency; we're doing FilePath->string->FilePath in
+    // effect between constructing the copy lists, and then the sets as far
+    // as the destinations go
+  	fileList = this->selection(array);
+    fileCopySet copySet(*fileList, *source, path);
+    copy.addSet(copySet);
+		delete fileList;
+    here ++;
+  }
+
+  if (!copy.checkSpace())
+  {	return false;
+  }
+  copy.copy();
+  return true;
+}
+
+FileVector *gsManifest::selection(stringArray &array)
+{	FileVector *reply = new FileVector();
+
+  for (unsigned int i = 0; i < array.size(); i++)
+  { File file(array[i]);
+  	reply->push_back(file);
+  }
+  return reply;
+}
+
+FileVector *gsManifest::selection(FilePath &destination)
+{	return this->selection(this->selected[destination]);
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/gsManifest.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsManifest.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsManifest.h	(revision 14219)
@@ -0,0 +1,33 @@
+#ifndef _GSMANIFEST_H_
+#define _GSMANIFEST_H_
+#include <map>
+using namespace std;
+
+#include "File.h"
+#include "FilePath.h"
+#include "stringArray.h"
+
+typedef map<FilePath, stringArray, less<FilePath> > pathStringArrayMap;
+
+class gsManifest
+{	private:
+	protected:
+		strArrayMap					manifests;
+    pathStringArrayMap	selected;
+  public:
+  	gsManifest(FilePath &path);
+    bool getManifest(FilePath &path);
+    bool getManifestLine(char *line, string &macro);
+    void expandGroupInstance(string parent, string child);
+    void expandGroup(string &group);
+    void expandGroups();
+    bool isGroup(string &name);
+    void expandMacro(string macroName, string value);
+    void clearSelection();
+    bool copy(FilePath *source);
+    void selectGroup(string &groupName, FilePath &destination);
+    FileVector *selection(stringArray &array);
+    FileVector *selection(FilePath &destination);
+    bool selectCheckSpace();
+};
+#endif;
Index: /gsdl/branches/nzdl2/gsinstaller/gsPlatform.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsPlatform.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsPlatform.cpp	(revision 14219)
@@ -0,0 +1,171 @@
+#include "gsPlatform.h"
+
+#define ACCESS_READ 0x01
+#define ACCESS_WRITE 0x02
+
+gsPlatform::gsPlatform()
+{ this->platformInfo.dwOSVersionInfoSize	= sizeof(OSVERSIONINFO);
+	GetVersionEx(&this->platformInfo);
+}
+
+bool gsPlatform::isWindows9x()
+{	return (this->platformInfo.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS);
+}
+
+bool gsPlatform::isWindowsNT()
+{	return (this->platformInfo.dwPlatformId & VER_PLATFORM_WIN32_NT);
+}
+
+bool gsPlatform::isWindows32s()
+{	return (this->platformInfo.dwPlatformId & VER_PLATFORM_WIN32s);
+}
+
+bool gsPlatform::isOldWindows32s()
+{	if (this->platformInfo.dwMajorVersion == 0 ||
+			this->platformInfo.dwMinorVersion < 30)
+	{	return true;
+  }
+  return false;
+}
+
+bool gsPlatform::isExplorerShell()
+{	if (this->isWindows9x() ||
+			(this->isWindowsNT() && this->platformInfo.dwMajorVersion >= 4))
+	{	return true;
+  }
+  return false;
+}
+
+bool gsPlatform::isUserAdministrator()
+{ if (this->isWindowsNT())
+	{ HANDLE 	token;
+  	PSID    adminId;
+    PACL		aclData;
+  	PSECURITY_DESCRIPTOR			psdAdmin;
+    SID_IDENTIFIER_AUTHORITY	systemSidAuthority;
+    GENERIC_MAPPING						genericMapping;
+    PRIVILEGE_SET							privilegeSet;
+    DWORD		aclSize, status, structureSize;
+    BOOL		result;
+
+  	// Get an impersonation token
+  	ImpersonateSelf(SecurityImpersonation);
+
+    if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token))
+    {	if (GetLastError() != ERROR_NO_TOKEN)
+    	{	return false;
+      }
+
+      // if we didn't have an access token, take the process token instead
+      if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
+      {	return false;
+      }
+    }
+
+    // By now we have a valid process/thread token; now get information on the
+    // admin group in this domain
+    if (!AllocateAndInitializeSid(&systemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
+    															DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
+                                  &adminId))
+    {	return false;
+    }
+
+    // allocate space for security descriptor
+		psdAdmin	=	LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
+    if (psdAdmin == NULL)
+    {	return false;
+    }
+
+		// initialise descriptor
+    if (!InitializeSecurityDescriptor(psdAdmin, SECURITY_DESCRIPTOR_REVISION))
+    {	return false;
+    }
+
+    // get ACL size and allocate ACL block
+		aclSize	= sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(adminId) - sizeof(DWORD);
+    aclData	=	(PACL) LocalAlloc(LPTR, aclSize);
+    if (aclData == NULL)
+    {	return false;
+    }
+
+    // initalise the acl block
+    if (!InitializeAcl(aclData, aclSize, ACL_REVISION2))
+    {	return false;
+    }
+
+    // try to add the given item to the Access Control Entry (ACE) list (ACL)
+    if (!AddAccessAllowedAce(aclData, ACL_REVISION2, ACCESS_READ | ACCESS_WRITE, adminId))
+    {	return false;
+    }
+
+    // endeavour to add the acl to the discretionary acl (DACL)
+    if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, aclData, FALSE))
+    {	return false;
+    }
+
+    // endeavour to set the owner/group identification
+  	SetSecurityDescriptorGroup(psdAdmin, adminId, FALSE);
+  	SetSecurityDescriptorOwner(psdAdmin, adminId, FALSE);
+
+    // right, we've now built up a discretionary acl on the current user,
+    // finally get the generic mapping ready
+		genericMapping.GenericRead		= ACCESS_READ;
+    genericMapping.GenericWrite		= ACCESS_WRITE;
+    genericMapping.GenericExecute	= 0;
+    genericMapping.GenericAll			= ACCESS_READ | ACCESS_WRITE;
+
+    // do the actual access check
+    if (!AccessCheck(	psdAdmin, token, ACCESS_READ, &genericMapping,
+    									&privilegeSet, &structureSize, &status, &result))
+    {	return false;
+    }
+
+    // end impersonisation
+    RevertToSelf();
+    return result;
+  }
+	return true;
+}
+
+bool gsPlatform::reboot()
+{
+	// Check for appropriate privileges if this is NT
+	if (this->isWindowsNT())
+  {	HANDLE token;
+  	TOKEN_PRIVILEGES tkp;
+
+  	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+												&token))
+		{	return false;
+  	}
+
+  	LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
+
+    tkp.PrivilegeCount	= 1; // set one privilege
+    tkp.Privileges[0].Attributes	= SE_PRIVILEGE_ENABLED;
+
+    // Get the actual shutdown privilege
+    AdjustTokenPrivileges(token, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
+
+    // as we can't test a return value on the previous call, use GetLastError
+    if (GetLastError() != ERROR_SUCCESS)
+    {	return false;
+    }
+  }
+  return ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0);
+}
+
+string gsPlatform::platformString()
+{	if (this->isWindowsNT())
+	{	return gsPlatform_WINDOWSNT;
+  }
+  else if (this->isWindows9x())
+  {	return gsPlatform_WINDOWS9X;
+  }
+  else if (this->isWindows32s())
+  {	return gsPlatform_WINDOWS32S;
+  }
+  else
+  {	return gsPlatform_WINDOWS;
+  }
+}
Index: /gsdl/branches/nzdl2/gsinstaller/gsPlatform.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsPlatform.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsPlatform.h	(revision 14219)
@@ -0,0 +1,27 @@
+#ifndef _GSPLATFORM_H_
+#define _GSPLATFORM_H_
+#include <string>
+using namespace std;
+#include <windows.h>
+
+static string gsPlatform_WINDOWSNT("WindowsNT");
+static string gsPlatform_WINDOWS9X("Windows9x");
+static string gsPlatform_WINDOWS32S("Windows32s");
+static string gsPlatform_WINDOWS("Windows");
+
+class gsPlatform
+{	private:
+		OSVERSIONINFO	platformInfo;
+	protected:
+	public:
+		gsPlatform();
+    bool isWindows9x();
+    bool isWindowsNT();
+    bool isWindows32s();
+    bool isOldWindows32s();
+    bool isExplorerShell();
+    bool isUserAdministrator();
+    bool reboot();
+    string platformString();
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/gsProfile.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsProfile.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsProfile.cpp	(revision 14219)
@@ -0,0 +1,69 @@
+#include "gsProfile.h"
+
+#include <stdio.h>
+#include "stringArray.h"
+
+gsProfile::gsProfile(const char *fileName)
+{	this->fileName	= fileName;
+}
+
+bool gsProfile::ensureListMember(const char *sectionName, const char *listName,
+																	const char *listMember)
+{ char 				buffer[256] = "\0";
+	stringArray	*members;
+
+	if (GetPrivateProfileString(sectionName, listName, "",
+			     										buffer, 256, this->fileName) <= 0)
+  {	buffer[0] = '\0';
+  }
+  // add if needsbe
+  members	= new stringArray(buffer, ";");
+  if (members->includes(listMember) == false)
+  {	members->add(listMember);
+  	members->writeToCString(buffer, ";", 256);
+    delete members;
+    return WritePrivateProfileString(sectionName, listName, buffer, this->fileName);
+  }
+  delete members;
+  return true;
+}
+
+bool gsProfile::addListMember(const char *sectionName, const char *listName, const char *listMember)
+{ char buffer[256];
+  stringArray	*members;
+
+	GetPrivateProfileString(sectionName, listName, "",
+													buffer, 256, this->fileName);
+	// straightforward, unthinking, add
+  members	= new stringArray(buffer, ";");
+  members->add(listMember);
+  members->writeToCString(buffer, ";", 256);
+  delete members;
+  return WritePrivateProfileString(sectionName, listName, buffer, this->fileName);
+}
+
+bool gsProfile::removeListMember(const char *sectionName, const char *listName, const char *listMember)
+{ char buffer[256];
+  stringArray	*members;
+
+	GetPrivateProfileString(sectionName, listName, "",
+													buffer, 256, this->fileName);
+	// straightforward, unthinking, removal - if it isn't there, we won't need to
+  // worry!
+  members	= new stringArray(buffer, ";");
+  members->remove(listMember);
+  members->writeToCString(buffer, ";", 256);
+  delete members;
+
+  return WritePrivateProfileString(sectionName, listName, buffer, this->fileName);
+}
+
+bool gsProfile::writeString(const char *sectionName, const char *itemName, const char *itemValue)
+{	if (!WritePrivateProfileString(sectionName, itemName, itemValue, this->fileName))
+	{ DWORD error = GetLastError();
+  	char buffer[20];
+    sprintf(buffer, "%lx", error);
+    MessageBox(0, buffer, "", MB_OK);
+  }
+  return true;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/gsProfile.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsProfile.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsProfile.h	(revision 14219)
@@ -0,0 +1,16 @@
+#ifndef _GSPROFILE_H_
+#define _GSPROFILE_H_
+#include <windows.h>
+class gsProfile
+{
+	private:
+    const char *fileName;
+  protected:
+  public:
+  	gsProfile(const char *fileName);
+    bool ensureListMember(const char *sectionName, const char *listName, const char *listMember);
+    bool removeListMember(const char *sectionName, const char *listName, const char *listMember);
+    bool addListMember(const char *sectionName, const char *listName, const char *listMember);
+    bool writeString(const char *sectionName, const char *itemName, const char *itemValue);
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/gsProgman.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsProgman.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsProgman.cpp	(revision 14219)
@@ -0,0 +1,308 @@
+#include "gsProgman.h"
+
+#include <stdio.h>
+
+// include shell for explorer-based OS'es
+#include <shlobj.h>
+// include dde for old (win 3.1/winNT 3.5) OS'es
+#include <ddeml.h>
+
+#include "FilePath.h"
+
+extern HINSTANCE app_instance;
+
+/**
+ * A private function for Dde callbacks; in practice it needs to be here,
+ * but does nothing whatsoever
+ */
+HDDEDATA CALLBACK DdeCallBack(
+    UINT uType,	// transaction type
+    UINT uFmt,	// clipboard data format
+    HCONV hconv,	// handle to the conversation
+    HSZ hsz1,	// handle to a string
+    HSZ hsz2,	// handle to a string
+    HDDEDATA hdata,	// handle to a global memory object
+    DWORD dwData1,	// transaction-specific data
+    DWORD dwData2 	// transaction-specific data
+   )
+{	return NULL;
+}
+
+ /**
+ * A private little function to do DDE activity
+ */
+bool DDEShellCommand(DWORD instance, char *command)
+{	HSZ 			serviceName;
+	HCONV			conversation;
+  int				commandLength;
+  HDDEDATA	ddeData;
+  DWORD 		result;
+  bool			reply	= false;
+
+	// create DDE string from service request
+	serviceName	= DdeCreateStringHandle(instance, "PROGMAN", CP_WINANSI);
+  if (serviceName	== NULL)
+  {	/*char buffer[20];
+  	sprintf(buffer, "%d %d", DdeGetLastError(instance), instance);
+    MessageBox(0, buffer, "GSInstall", MB_OK);*/
+    return FALSE;
+  }
+
+  // strike up a conversation with the DDE service
+  if ((conversation = DdeConnect(instance, serviceName, serviceName, NULL)) != NULL)
+  {	commandLength	= lstrlen(command);
+
+		// send the message via DDE
+//    MessageBox(0, command, "Executing", MB_OK);
+  	ddeData	= DdeClientTransaction((LPBYTE) command, commandLength + 1,
+    																conversation, NULL, CF_TEXT, XTYP_EXECUTE,
+                                    1000, &result);
+		// if our reply isn't NULL, it succeeded
+    reply = (ddeData != NULL);
+    if (reply == false)
+    { /*
+    	char buffer[20];
+
+    	sprintf(buffer, "%d", DdeGetLastError(instance));
+      MessageBox(0, buffer, "DDE Error", MB_OK);*/
+    }
+
+    // disconnect the conversation
+    DdeDisconnect(conversation);
+  }
+  else
+  {	MessageBox(0, "DDE Connect failed", "GSInstall", MB_OK);
+  }
+
+  // free DDE string
+  DdeFreeStringHandle(instance, serviceName);
+  return reply;
+}
+
+gsProgramManager::gsProgramManager()
+{	this->platform 	= new gsPlatform();
+	this->connected	= false;
+}
+
+bool gsProgramManager::connect()
+{ HRESULT response;
+
+	if (this->platform->isExplorerShell())
+  { // Initialise the shell connection
+  	response = CoInitialize(NULL);
+    if (response < 0)
+    {	return false;
+    }
+  }
+  else
+  { FARPROC procPtr;
+
+  	procPtr	= MakeProcInstance((FARPROC) DdeCallBack, app_instance);
+
+  	instance	= 0L;
+  	if (DdeInitialize(&instance, (PFNCALLBACK) procPtr, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
+  	{ MessageBox(0, "DDE failed to initialise", "GSInstall", MB_OK);
+    	return false;
+    }
+  }
+  this->connected	= true;
+  return true;
+}
+
+bool gsProgramManager::disconnect()
+{ if (this->connected)
+	{	if (this->platform->isExplorerShell())
+		{	CoUninitialize();
+	  }
+  	else
+	  {	DdeUninitialize(instance);
+    }
+  }
+  this->connected	= false;
+  return true;
+}
+
+bool gsProgramManager::addProgramGroup(const char *groupName)
+{	//CreateGroup(groupName);
+	char buffer[256];
+
+  if (this->platform->isExplorerShell())
+  {	// add using shell controls
+  	LPITEMIDLIST pidl;
+
+    if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) == NOERROR)
+    { SHGetPathFromIDList(pidl, buffer);
+
+    	// Create the folder as required
+    	FilePath *path	= new FilePath(buffer, groupName);
+      if (!CreateDirectory((char *) path->cString(), NULL))
+      {	// it probably existed already - if so skip it!
+      	DWORD reason = GetLastError();
+        if (reason != ERROR_ALREADY_EXISTS)
+        {	return false;
+        }
+      }
+    }
+  }
+  else
+  { // add using program manager DDE
+  	sprintf(buffer, "[CreateGroup (%s)]", groupName);
+  	if (!DDEShellCommand(this->instance, buffer))
+    {	// flag error by returning false
+      return false;
+    }
+  }
+	return true;
+}
+
+bool gsProgramManager::addIcon( const char *groupName,				// group of the icon
+																const char *iconName,					// name of the icon
+                                const char *iconDestination, 	// destination file of the icon
+														    const char *description) 			// the textual description
+                                															// of the icon (not usually displayed)
+{	bool	 				reply = false;
+	char					buffer[MAX_PATH];
+
+  if (this->platform->isExplorerShell())
+  { // create item using the shell
+  	LPITEMIDLIST	pidl;
+    HRESULT hres;
+  	IShellLink* psl;
+    FilePath *	fullPath;
+
+	  if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
+  	{ return false;
+	  }
+
+		SHGetPathFromIDList(pidl, buffer);
+		fullPath	= new FilePath(4, buffer, groupName, iconName, "!.lnk");
+
+		// Get a pointer to the IShellLink interface.
+  	hres = CoCreateInstance(CLSID_ShellLink, NULL,
+  											     CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl);
+	  if (SUCCEEDED(hres))
+  	{ IPersistFile* ppf;
+
+    	// Set the path to the shortcut target, and add the
+	    // description.
+  	  psl->SetPath(iconDestination);
+
+    	psl->SetDescription(description);
+
+	    // Query IShellLink for the IPersistFile interface for saving the
+  	  // shortcut in persistent storage.
+    	hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf);
+
+	    if (SUCCEEDED(hres))
+  	  { WCHAR wsz[MAX_PATH];
+
+    	  // Ensure that the string is ANSI.
+      	MultiByteToWideChar(CP_ACP, 0, fullPath->cString(), -1, wsz, MAX_PATH);
+
+	      // store the link in the "persistent" file
+  	    reply = ppf->Save(wsz, TRUE);
+
+    	  // release the persistent file handle
+      	ppf->Release();
+	    }
+  	  psl->Release();
+	  }
+  }
+  else
+  {	// Back to the dark ages with win 3.1!
+
+  	// ensure that the requisite group is active; the add icon command will
+    // use the active group.
+  	sprintf(buffer, "[ShowGroup(%s,5)]", groupName);
+    if (!DDEShellCommand(this->instance, buffer))
+    { // TODO: articulate/determine possible errors; expand error handling
+			return false;
+    }
+
+    // and now add the item itself to the active (given) group
+    sprintf(buffer, "[AddItem(%s,%s)]", iconDestination, iconName);
+    if (!DDEShellCommand(this->instance, buffer))
+    {	// TODO: again work out what the problems could be
+    	return false;
+    }
+    reply = true;
+  }
+  return reply;
+}
+
+bool gsProgramManager::removeProgramGroup(const char *groupName)
+{	//CreateGroup(groupName);
+	char buffer[256];
+
+  if (this->platform->isExplorerShell())
+  {	// add using shell controls
+  	LPITEMIDLIST pidl;
+
+    if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) == NOERROR)
+    { SHGetPathFromIDList(pidl, buffer);
+
+    	// Create the folder as required
+    	FilePath *path	= new FilePath(buffer, groupName);
+      if (!RemoveDirectory((char *) path->cString()))
+      {	// TODO: find cause of failure to remove
+      	DWORD reason = GetLastError();
+        if (reason != 0)
+        {	return false;
+        }
+      }
+    }
+  }
+  else
+  { // add using program manager DDE
+  	sprintf(buffer, "[DeleteGroup (%s)]", groupName);
+  	if (!DDEShellCommand(this->instance, buffer))
+    {	// flag error by returning false
+      return false;
+    }
+  }
+	return true;
+}
+
+bool gsProgramManager::removeIcon(const char *groupName,				// group of the icon
+																	const char *iconName)					// name of the icon
+{	bool	 				reply = false;
+	char					buffer[MAX_PATH];
+
+  if (this->platform->isExplorerShell())
+  { // create item using the shell
+  	LPITEMIDLIST	pidl;
+    HRESULT hres;
+  	IShellLink* psl;
+    FilePath *	fullPath;
+
+	  if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
+  	{ return false;
+	  }
+
+		SHGetPathFromIDList(pidl, buffer);
+		fullPath	= new FilePath(4, buffer, groupName, iconName, "!.lnk");
+
+    // TODO: delete file
+  }
+  else
+  {	// Back to the dark ages with win 3.1!
+
+  	// ensure that the requisite group is active; the add icon command will
+    // use the active group.
+  	sprintf(buffer, "[ShowGroup(%s,5)]", groupName);
+    if (!DDEShellCommand(this->instance, buffer))
+    { // TODO: articulate/determine possible errors; expand error handling
+			return false;
+    }
+
+    // and now add the item itself to the active (given) group
+    sprintf(buffer, "[DeleteItem(%s)]", iconName);
+    if (!DDEShellCommand(this->instance, buffer))
+    {	// TODO: again work out what the problems could be
+    	return false;
+    }
+  }
+  return reply;
+}
+
+
Index: /gsdl/branches/nzdl2/gsinstaller/gsProgman.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsProgman.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsProgman.h	(revision 14219)
@@ -0,0 +1,28 @@
+#ifndef _GSPROGMAN_H_
+#define _GSPROGMAN_H_
+#include <windows.h>
+
+#include "gsPlatform.h"
+
+class gsProgramManager
+{
+	private:
+  	gsPlatform *platform;
+    DWORD				instance;
+    bool				connected;
+  protected:
+  public:
+  	// constructor
+  	gsProgramManager();
+
+    // connect/disconnect activity
+    bool connect();
+    bool disconnect();
+
+    bool addProgramGroup(const char *name);
+    bool removeProgramGroup(const char *name);
+    bool addIcon(	const char *groupName, const char *iconName, const char *iconDestination,
+    							const char *description);
+    bool removeIcon(	const char *groupName, const char *iconName);
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/gsRegistry.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsRegistry.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsRegistry.cpp	(revision 14219)
@@ -0,0 +1,101 @@
+#include "gsRegistry.h"
+
+gsRegistry::gsRegistry(configureFile &configFile)
+{ unsigned int space;
+
+	// Create string for volume key
+	strcpy(volumeKey, "Software\\");
+	space	= 255 - strlen(volumeKey);
+
+	configFile.concat("CompanyName", volumeKey, space);
+  strcat(volumeKey, "\\");
+	configFile.concat("CollectionName", volumeKey, space);
+  strcat(volumeKey, "\\");
+	configFile.concat("CollectionVolume", volumeKey, space);
+  strcat(volumeKey, "\\");
+	configFile.concat("CollectionVersion", volumeKey, space);
+
+	// Create string for collection key
+	strcpy(collectKey, "Software\\");
+	space	= 255 - strlen(collectKey);
+
+	configFile.concat("CompanyName", collectKey, space);
+  strcat(collectKey, "\\");
+	configFile.concat("CollectionName", collectKey, space);
+  strcat(collectKey, "\\");
+	configFile.concat("CollectionVersion", collectKey, space);
+}
+
+bool gsRegistry::ensureKeysExist()
+{	if (registry_ensureKeyExists(HKEY_LOCAL_MACHINE, this->collectKey) == false)
+	{	return false;
+  }
+  if (registry_ensureKeyExists(HKEY_LOCAL_MACHINE, this->volumeKey) == false)
+  {	return false;
+  }
+  return true;
+}
+
+bool gsRegistry::ensureKeyExists(HKEY base, const char *key)
+{	return(registry_ensureKeyExists(base, key));
+}
+
+bool gsRegistry::storeKeyString(HKEY base, const char *path, const char *item, const char *string)
+{	HKEY local;
+	bool	reply;
+
+  if (!registry_openkey(base, (char *) path, &local))
+ 	{	return false;
+  }
+  reply = registry_setstring(local, item, string);
+  registry_closekey(local);
+  return reply;
+}
+
+bool gsRegistry::collectionInstalled()
+{	return registry_keyExists(HKEY_LOCAL_MACHINE, this->collectKey);
+}
+
+bool gsRegistry::volumeInstalled()
+{	return registry_keyExists(HKEY_LOCAL_MACHINE, this->volumeKey);
+}
+
+char *gsRegistry::collectKeyId()
+{	return this->collectKey;
+}
+
+char *gsRegistry::volumeKeyId()
+{	return this->volumeKey;
+}
+
+char *gsRegistry::exeKeyId(char *exename)
+{	char *reply	= new char[256];
+
+	// Create string for exe path
+	strcpy(reply, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
+  strcat(reply, exename);
+  return reply;
+}
+
+FilePath *gsRegistry::collectionPath()
+{ char *path = NULL;
+	FilePath *reply = NULL;
+	HKEY key;
+
+  if (registry_openkey(HKEY_LOCAL_MACHINE, this->collectKey, &key))
+  {	if (registry_getstring(key, "library", &path))
+  	{ // get leaf (\library.exe) and remove it to give a path
+    	char *leaf;
+
+    	leaf	= strrchr(path, '\\');
+			if (leaf != NULL)
+      { *leaf = '\0';
+      }
+      reply	= new FilePath(path);
+      free(path);
+    }
+  	registry_closekey(key);
+  }
+  return reply;
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/gsRegistry.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsRegistry.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsRegistry.h	(revision 14219)
@@ -0,0 +1,25 @@
+#ifndef _GSREGISTRY_H_
+#define _GSREGISTRY_H_
+#include "registry.h"
+#include "configFile.h"
+#include "FilePath.h"
+
+class gsRegistry
+{	private:
+		char volumeKey[256];
+    char collectKey[256];
+	public:
+  	gsRegistry(configureFile &configFileb);
+		bool 			storeKeyString(	HKEY base, const char *path,
+    													const char *item, const char *string);
+    bool 			collectionInstalled();
+    bool 			volumeInstalled();
+    bool			ensureKeysExist();
+    bool			ensureKeyExists( HKEY base, const char *key);
+    char *		collectKeyId();
+    char *		volumeKeyId();
+    char *		exeKeyId(char *exeName);
+    FilePath *collectionPath();
+    Path();
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/gsinstall.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsinstall.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsinstall.cpp	(revision 14219)
@@ -0,0 +1,832 @@
+#include <vector>
+#include <string>
+using namespace std;
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+
+#include "dirSelector.h"
+#include "common.h"
+#include "configFile.h"
+#include "File.h"
+#include "FilePath.h"
+#include "FileCopier.h"
+#include "launchApp.h"
+#include "unInstall.h"
+
+#include "gsRegistry.h"
+#include "gsPlatform.h"
+#include "gsProgman.h"
+#include "gsProfile.h"
+#include "gsManifest.h"
+
+char *		app_cmdLine;
+static char app_name[] = "Greenstone Installer";
+HINSTANCE	app_instance;
+HWND		  app_window;
+
+bool			config_complete = false;
+// static char app_tmptext[100] = "George";
+
+typedef vector<dirSelector *> dirSelVector;
+
+class GSInstall
+{ private:
+		configureFile	*	configFile;
+		FilePath *			collectPath;
+    FilePath *			installToPath;
+    FilePath *			sourcePath;
+    FilePath *			gsdlSourcePath;
+    FilePath *			destinationPath;
+    FilePath *			dataDestPath;
+    bool            installExe;
+    bool						installVolume;
+    bool						installFullVolume;
+    gsPlatform			platform;
+    unInstaller	*		unInstall;
+
+    dirSelVector		selectedDirs;
+
+    gsRegistry *		gsRegister;
+    gsManifest *		manifest;
+
+    void				getSourcePath();
+	public:
+		GSInstall();
+    FilePath * 	collectionPath();
+    FilePath * 	installPath();
+    bool				copyFiles();
+    bool        updateRegistry();
+    bool				updateProfiles();
+    bool				updateProgman();
+    bool				installNetscape();
+    void				setDestination();
+    void				setManifest();
+    void				addSelectedDir(dirSelector *selector);
+};
+
+static string gsdl_DBHOME = "gdbmhome";
+static string gsdl_VLHOME = "gsdlhome";
+static string gsdl_STATIC = "staticpath";
+static string gsdl_COLLIST= "collections";
+
+void gsInstall_getDesktopExt(int *sx, int *sy)
+{
+	HDC dc = GetDC(GetDesktopWindow());
+  *sx = GetDeviceCaps(dc, HORZRES);
+  *sy = GetDeviceCaps(dc, VERTRES);
+  ReleaseDC(GetDesktopWindow(), dc);
+}
+
+/**
+ * Get various and nefarious details before we start trying an installation.
+ * The installation configuration file is read, we seek for an existing
+ * installation and reconfigure the default install settings appropriately.
+ * THe source path is also discovered.
+ */
+GSInstall::GSInstall()
+{ gsPlatform	platform;
+
+	// get the installation configuration file
+	this->configFile	= new configureFile("install.cfg");
+
+  // initialise the pointers that we test later this fn.
+  this->unInstall		= NULL;
+
+	// don't attempt this with windows 3.1
+  if (!platform.isWindows32s() || TRUE)
+  { // get the registry
+	  this->gsRegister	= new gsRegistry(*this->configFile);
+
+  	// TODO: in windows 3.1 we can't use the register as it isn't fully/properly
+	  //       implemented; we must get the existing path information from elsewhere
+  	if (gsRegister->collectionInstalled())
+	  {	// TODO: check if receptionist etc should be replaced or not
+
+  		// TODO: check build version of the volume
+
+	  	// Get location of the library executable from the registry; this
+	  	// is thence used to get the location of gsdl.ini etc.
+  		this->collectPath	= this->gsRegister->collectionPath();
+    	this->installToPath	= this->collectPath;
+
+	  	// TODO: if collectPath == NULL generate error
+
+      // get uninstall information from destination location
+      FilePath *uninstallPath	= new FilePath(this->collectPath->cString(), "uninstl.cfg");
+      this->unInstall	= new unInstaller(uninstallPath->cString());
+      delete uninstallPath;
+
+  	  // we don't need to install the exe files
+  		this->installExe = false||true;
+	  }
+  	else
+	  {	this->installToPath	= new FilePath("C:\\GSDL");
+			this->collectPath	= NULL;
+    	// we must install the exe files
+		  this->installExe	= true;
+  	}
+  }
+  else
+  {	// TODO: do windows 3.1 stuff here
+  	this->installToPath	= new FilePath("C:\\GSDL");
+    this->installExe = true;
+    this->collectPath	= NULL;
+  }
+
+  if (this->unInstall	== NULL)
+  {	this->unInstall	= new unInstaller("");
+  }
+
+  // assume for now we will install the full volume and the database
+  this->installVolume			= true;
+  this->installFullVolume	= true;
+
+  // get where we are installing from
+  this->getSourcePath();
+
+  // get the manifest
+  this->manifest = new gsManifest(*this->sourcePath);
+
+  // tell manifest the number of bits in the raw windows environment; this may
+  // be required for loading certain modules such as winsock; the number of
+  // macros is over-the-top, but is more robust to unforeseen future requirements
+/*  if (platform.isWindows32s())
+  {	this->manifest->expandMacro("WINBITS", "16");
+  	this->manifest->expandMacro("WIN16", "16");
+  	this->manifest->expandMacro("WIN32", "32");
+  }
+  else
+  {	this->manifest->expandMacro("WINBITS", "32");
+  	this->manifest->expandMacro("WIN16", "");
+  	this->manifest->expandMacro("WIN32", "32");
+  }
+*/
+  // inform manifests of collection directory name
+  char *buffer;
+  this->configFile->get("CollectionDirName", &buffer);
+  this->manifest->expandMacro("COLDIRNAME", buffer);
+  delete buffer;
+}
+
+/**
+ * get the source path for this install; we derive this from the path of this
+ * executable (the installer)
+ */
+void GSInstall::getSourcePath()
+{ static char filename[512];
+	FilePath	 *exePath;
+
+  // get the filepath of this executable
+  GetModuleFileName(0, filename, 512);
+  exePath	= new FilePath(filename);
+
+  // get the parent (i.e. the folder containing this executable) for the source
+  // folder
+  this->sourcePath	= exePath->parent();
+
+  // get the gsdl source path
+  this->gsdlSourcePath	= new FilePath(this->sourcePath->cString(), "gsdl");
+  delete exePath;
+}
+
+/**
+ * Controls the actual copying of the files; manifests of what to install
+ * are read in from a configuration on the hard drive - this should be basically
+ * greenstone dependent, and void of any collection-specific rubbish!
+ */
+bool GSInstall::copyFiles()
+{	FileVector *fileList;
+
+  // ensure that we have got the required destination and that we can write there
+  if (this->installExe)
+  { this->destinationPath->ensureWriteablePath();
+  }
+
+  // ensure that the destination path for the collection itself is available
+  if (this->installVolume)
+  {	this->dataDestPath->ensureWriteablePath();
+  }
+
+  // do the copy
+	this->manifest->copy(this->gsdlSourcePath);
+
+  return true;
+}
+
+/**
+ * Fulfill registry update requirements; first the keys are set up, then they
+ * are filled with key item/value pairs.
+ */
+bool GSInstall::updateRegistry()
+{ // don't do registry stuff under windows 32s
+	if (this->platform.isWindows32s() && FALSE)
+	{	return true;
+  }
+
+  // ensure all pertinent keys already exist for this volume/collection
+	this->gsRegister->ensureKeysExist();
+
+  // now move on to add key items
+	if (this->installExe)
+  { FilePath *serverPath	= new FilePath((char *) this->destinationPath->cString(), "server.exe");
+  	char *exeKeyPath;
+    gsPlatform platform;
+
+    // store the normal collection key information
+  	this->gsRegister->storeKeyString(	HKEY_LOCAL_MACHINE,
+  																		this->gsRegister->collectKeyId(),
+                                      "library",
+                                      serverPath->cString());
+
+    // This test is in fact for 9x or NT 4+; we're worried about the registry
+    // format, not about the shell as such
+  	if (platform.isExplorerShell())
+    { // get special app path key for windows 9x
+    	exeKeyPath	=	this->gsRegister->exeKeyId("library.exe");
+
+      // ensure that the exe key exists
+    	this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, exeKeyPath);
+
+    	// store default key for this application
+    	this->gsRegister->storeKeyString(	HKEY_LOCAL_MACHINE,
+  	  																	exeKeyPath,
+    	                                  NULL,
+      	                                serverPath->cString());
+
+      // store path for this application
+	    this->gsRegister->storeKeyString(	HKEY_LOCAL_MACHINE,
+  	  																	exeKeyPath,
+    	                                  "path",
+      	                                this->destinationPath->cString());
+      // delete the windows 9x speciall app path key
+			delete exeKeyPath;
+
+      // TODO: set up uninstall option
+    }
+    delete serverPath;
+  }
+
+  if (this->installVolume || this->installFullVolume)
+  {	// no actual key items are held in the volume key; for future use
+  }
+  return true;
+}
+
+/**
+ * Set the destination directory details
+ */
+void GSInstall::setDestination()
+{	this->destinationPath		= new FilePath(this->selectedDirs[0]->selectedPath());
+	this->installFullVolume	= this->selectedDirs[1]->getOption();
+  if (this->installFullVolume || true)	// NB: always take path from 2nd dialog
+  {	this->dataDestPath	= new FilePath(this->selectedDirs[1]->selectedPath());
+  }
+  else
+  {	this->dataDestPath  = this->destinationPath;
+  }
+}
+
+/**
+ *  Collate the manifest for installation
+ */
+void GSInstall::setManifest()
+{	if (this->installExe)
+	{	this->manifest->selectGroup("library", this->destinationPath->pathString());
+  }
+  if (this->installFullVolume)
+  {	this->manifest->selectGroup("collection", this->dataDestPath->pathString());
+  }
+  else
+  {	this->manifest->selectGroup("database", this->dataDestPath->pathString());
+  }
+}
+
+/**
+ * Update the program manager/explorer shell with icons, groups etc for this
+ * collection/application
+ */
+bool GSInstall::updateProgman()
+{ gsProgramManager 	progman;
+	char *            groupName = NULL;
+
+  // if we managed to get a connection to the program manager (or explorer
+  // shell) then do the requisite updates
+  if (progman.connect())
+  {	// get group name from folders
+  	this->configFile->get("ProgramGroupName", &groupName);
+	  if (groupName == NULL)
+  	{	// TODO: error handling
+    	progman.disconnect();
+		  delete groupName;
+  		return false;
+	  }
+
+	  // add the group
+		if (!progman.addProgramGroup(groupName))
+	  {	progman.disconnect();
+		  delete groupName;
+    	return false;
+  	}
+
+    // add a "server" icon
+    FilePath libraryPath(this->destinationPath->cString(), "library.exe");
+	  if (!progman.addIcon(groupName, "Library (without nextwork support)", libraryPath.cString(), ""))
+  	{ progman.disconnect();
+		  delete groupName;
+    	return false;
+	  }
+
+    // TODO: check for server existence
+    FilePath serverPath(this->destinationPath->cString(), "server.exe");
+	  if (!progman.addIcon(groupName, "Server", serverPath.cString(), ""))
+  	{	progman.disconnect();
+		  delete groupName;
+    	return false;
+	  }
+
+    FilePath readMePath(this->destinationPath->cString(), "readme.txt");
+	  if (!progman.addIcon(groupName, "ReadMe", readMePath.cString(), ""))
+  	{	progman.disconnect();
+		  delete groupName;
+    	return false;
+	  }
+
+    FilePath supportPath(this->destinationPath->cString(), "support.html");
+	  if (!progman.addIcon(groupName, "Technical Support", supportPath.cString(), ""))
+  	{	progman.disconnect();
+		  delete groupName;
+    	return false;
+	  }
+
+    // TODO: add uninstall support
+
+  	// dispose of group name
+	  delete groupName;
+
+    // disconnect from program manager
+    progman.disconnect();
+  }
+  return true;
+}
+
+/**
+ * Update the profile (ini) files associated with the program; these changes
+ * must be made after copying to files in the destination/executable folders
+ * as we can't write to CD-ROM (or at least we shouldn't - the install would
+ * become tainted).
+ */
+bool GSInstall::updateProfiles()
+{ FilePath *exePath;
+	FilePath *dataPath;
+  FilePath *iniPath;
+
+  // if we're installing the exe, then the exe path leads to the destination
+  // folder of this installation sequence;  if not, then we pick it up from
+  // the existing location of that folder
+	if (this->installExe)
+	{	exePath	= this->destinationPath;
+  }
+  else
+	{	exePath	= this->collectPath;
+  }
+  iniPath	= new FilePath((char *) exePath->cString(), "gsdl.ini");
+
+  // TODO: check if this 'if' structure is correct; suspect that it isn't quite
+  //       as we may not be installing the volume, but exe etc individually;
+  //       may be okay now but not future proof; also the destination directory
+  //       may or may not be tied to the exe directory if that existed already.
+  //       This all needs investigating
+  if (this->installVolume)
+  {	char volumeSectionName[100] = "\0";
+  	unsigned int space	= 99;
+
+    // Manufacture the appropriate section name now; an equivalent string
+    // is also constructed
+    this->configFile->concat("CollectionName", volumeSectionName, space);
+    strcat(volumeSectionName, "#");
+    space --;
+    this->configFile->concat("CollectionVolume", volumeSectionName, space);
+  	string volumeSectionString(volumeSectionName);
+
+    // if we're installing the full data for the collection, then take the
+    // data path to be at the selected destination directory for the collection
+    // files; otherwise take the data path to be on the CD/distribution media
+    if (this->installFullVolume)
+    {	dataPath	=	this->dataDestPath;
+    }
+    else
+    {	dataPath	= this->gsdlSourcePath;
+    }
+
+    // create a profile object to write to the gsdl.ini file
+    gsProfile gsdlProfile(iniPath->cString());
+
+    // if installing the executable, add the database and greenstone home
+    // directories
+    if (this->installExe)
+    {	// set the correct exe entries in gsdl.ini (in the gsdl section)
+			gsdlProfile.writeString("gsdl", "gsdlhome", dataPath->cString());
+      gsdlProfile.writeString("gsdl", "gdbmhome", this->dataDestPath->cString());
+
+      this->unInstall->record("gsdl", "profilewrite", 2, &gsdl_VLHOME,
+      												&dataPath->pathString());
+      this->unInstall->record("gsdl", "profilewrite", 2, &gsdl_DBHOME,
+      												&this->dataDestPath->pathString());
+    }
+
+    // set the correct collection volume entries in gsdl.ini
+    if (this->installVolume)
+    { // note the collection in the general gsdl section; and add the undo item too
+    	gsdlProfile.ensureListMember("gsdl", gsdl_COLLIST.c_str(), volumeSectionName);
+      this->unInstall->record("gsdl", "proflistensure", 2, &gsdl_COLLIST, &volumeSectionString);
+
+      // note the volume data in its own section
+    	gsdlProfile.writeString(volumeSectionName, "gsdlhome", dataPath->cString());
+    	gsdlProfile.writeString(volumeSectionName, "gdbmhome", this->dataDestPath->cString());
+    	gsdlProfile.writeString(volumeSectionName, "staticpath", dataPath->cString());
+
+      this->unInstall->record(volumeSectionName, "profilewrite", 2, &gsdl_VLHOME, &dataPath->pathString());
+      this->unInstall->record(volumeSectionName, "profilewrite", 2, &gsdl_DBHOME, &this->dataDestPath->pathString());
+      this->unInstall->record(volumeSectionName, "profilewrite", 2, &gsdl_STATIC, &dataPath->pathString());
+    }
+  }
+
+  // clean up
+  delete iniPath;
+
+  return true;
+}
+
+bool GSInstall::installNetscape()
+{	FilePath	netscape32Path(this->sourcePath->cString(), "netscape\\n32e405.exe");
+  FilePath	netscape16Path(this->sourcePath->cString(), "netscape\\n16e405.exe");
+
+  launchApp launchNetscape(netscape32Path);
+  launchNetscape.platformApp(gsPlatform_WINDOWS32S, netscape16Path);
+  if (launchNetscape.run(true, 1,
+		  										"This library is displayed using a web browser.  If you don't "
+    		                  "currently have a web browser installed on your machine you may "
+        		              "install the Netscape 4.05 browser now.\n\n"
+            		          "Note that if your current browser was provided by your internet "
+                		      "service provider, you should install Netscape in a different "
+                    		  "directory.\n\n"
+		                      "Would you like to install the Netscape 4.05 browser now?",
+    		                  "Greenstone Installer", false) < 0)
+  {	MessageBox(0, "Error", app_name, MB_OK);
+  	return false;
+  }
+  return true;
+}
+
+FilePath *GSInstall::collectionPath()
+{	return this->collectPath;
+}
+
+FilePath *GSInstall::installPath()
+{	return this->installToPath;
+}
+
+void GSInstall::addSelectedDir(dirSelector *selector)
+{	this->selectedDirs.push_back(selector);
+}
+
+typedef struct
+{ dirSelector * dirSelect;
+} GSInstall_dirPathData;
+
+HGLOBAL loadDirBrowser()
+{ HRSRC resHdl;
+
+	resHdl = FindResource(app_instance, "MySaveAsDlg", RT_DIALOG);
+  return LoadResource(app_instance, resHdl);
+}
+
+void gsInstall_wizard_centre(HWND dialog)
+{
+  RECT rect;
+  int sx, sy;
+  int dx, dy;
+
+  gsInstall_getDesktopExt(&sx, &sy);
+  GetWindowRect(dialog, &rect);
+
+  dx = (sx - rect.right + rect.left) >> 1;
+  dy = (sy - rect.bottom + rect.top) >> 1;
+  SetWindowPos(dialog, 0, dx, dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+}
+
+BOOL FAR PASCAL GSInstall_dlgproc(HWND Dialog, UINT Message, WPARAM wParam, LPARAM lParam)
+{ static bool first = true; 	// static variable to hack the position of the
+                              // whole wizard; note doing this in the wizard
+                              // property sheet initialisation DOES NOT WORK
+
+	switch (Message)
+	{	case WM_INITDIALOG:
+  	{	dirSelector *selector = (dirSelector *) ((PROPSHEETPAGE *) lParam)->lParam;
+
+    	SetDlgItemText(Dialog, dirpath_PROMPT, selector->prompt);
+      if (selector->optPrompt != NULL)
+      { SetDlgItemText(Dialog, dirpath_OPTION, selector->optPrompt);
+	      EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), true); // was false
+        EnableWindow(GetDlgItem(Dialog, dirpath_PATH), true);		// was false
+      }
+      else
+      { ShowWindow(GetDlgItem(Dialog, dirpath_OPTION), SW_HIDE);
+      }
+      SetWindowLong(Dialog, GWL_USERDATA, ((PROPSHEETPAGE *) lParam)->lParam);
+      SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath());
+
+      // if this is the first time this function is called, then centre the
+      // wizard into the centre of our screen.
+      if (first)
+      { gsInstall_wizard_centre(GetParent(Dialog));
+      	first = false;
+      }
+    }
+  	return TRUE;
+
+    case WM_COMMAND:
+    	switch (LOWORD(wParam))
+      {	case dirpath_BROWSE:
+      		((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->requestPath(Dialog, "Select Directory");
+          SetDlgItemText(Dialog, dirpath_PATH, ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->selectedPath());
+      	break;
+
+        case dirpath_OPTION:
+      		((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->setOption(IsDlgButtonChecked(Dialog, dirpath_OPTION));
+        	if (HIWORD(wParam) == BN_CLICKED && false) // don't do the enable/disable these days
+          { EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), IsDlgButtonChecked(Dialog, dirpath_OPTION));
+            EnableWindow(GetDlgItem(Dialog, dirpath_PATH), IsDlgButtonChecked(Dialog, dirpath_OPTION));
+          }
+        break;
+      }
+    break;
+
+    case WM_NOTIFY:
+    	switch (((LPNMHDR) lParam)->code)
+      { case PSN_SETACTIVE:
+      	{	dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA));
+        	if (selector->isFinal())
+        	{ PropSheet_SetWizButtons(GetParent(Dialog), PSWIZB_BACK | PSWIZB_FINISH);
+	        }
+  	      else
+    	    { PropSheet_SetWizButtons(GetParent(Dialog), PSWIZB_BACK | PSWIZB_NEXT);
+      	  }
+        }
+      	break;
+
+        case PSN_KILLACTIVE:
+      	{ // note the path from the dialog
+        	dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA));
+        	selector->setPathFromEdit(GetDlgItem(Dialog, dirpath_PATH));
+
+        	// create a new FilePath object to check on the proposed destination
+					FilePath *path = new FilePath(selector->selectedPath());
+          if (path->exists() == false)
+          { char buffer[128];
+
+          	sprintf(buffer, "Directory %s does not exist - create it?", selector->selectedPath());
+
+            // if the user cancelled that, then don't permit them to go to the next
+            // page of the wizard
+          	if (MessageBox(0, buffer, app_name, MB_YESNO | MB_TOPMOST) == IDNO)
+          	{	delete path;
+            	SetWindowLong(Dialog, DWL_MSGRESULT, TRUE);
+              return TRUE;
+            }
+          }
+          delete path;
+        }
+      	break;
+
+				case PSN_WIZNEXT:
+	      { if (((LPNMHDR) lParam)->idFrom == 0)
+  	    	{ // TODO: note a default here
+    	    }
+	      }
+        break;
+
+        case PSN_WIZFINISH:
+	      {	// Finish the activity now
+  	    	config_complete	= true;
+    	  }
+        break;
+      }
+    break;
+  }
+	return FALSE;
+}
+
+void GSInstall_init_propertySheet(PROPSHEETPAGE &ppage, char *prompt, char *optPrompt,
+																	char *title, GSInstall &installer, bool isFinal)
+{ GSInstall_dirPathData *data = new GSInstall_dirPathData;
+
+	data->dirSelect 	= new dirSelector(prompt, optPrompt, title, installer.installPath());
+  data->dirSelect->setFinal(isFinal);
+
+  installer.addSelectedDir(data->dirSelect);
+
+	ppage.dwSize		= sizeof(PROPSHEETPAGE);
+	ppage.dwFlags		= PSP_USETITLE;
+  ppage.hInstance	= app_instance;
+  ppage.pszTemplate	= "getDirPath";
+  ppage.pszIcon			= 0;
+  ppage.pszTitle		= app_name;
+  ppage.pfnDlgProc	= (DLGPROC) GSInstall_dlgproc;
+	ppage.lParam      = (LPARAM) data->dirSelect;
+  ppage.pfnCallback	= NULL;
+}
+
+int CALLBACK GSInstall_wizardProc(HWND dialog, UINT Message, LPARAM lParameter)
+{ switch (Message)
+	{ case PSCB_INITIALIZED :
+			// Process PSCB_INITIALIZED
+      gsInstall_wizard_centre(dialog);
+		break ;
+
+		case PSCB_PRECREATE :
+			// Process PSCB_PRECREATE
+		break ;
+
+		default :
+			// Unknown message
+		break ;
+	}
+  return 0;
+}
+
+bool GSInstall_init_wizard(GSInstall &install)
+{ PROPSHEETHEADER pshead;
+	PROPSHEETPAGE   ppage[2];
+  bool						reply;
+
+	ZeroMemory(&pshead, sizeof(PROPSHEETHEADER));
+	pshead.dwSize  = sizeof(PROPSHEETHEADER);
+	pshead.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_USEHICON | PSH_WIZARD;
+	pshead.hwndParent  = app_window;
+	pshead.hInstance   = app_instance;
+	pshead.hIcon       = NULL;
+	pshead.pszCaption  = "Greenstone Installer";
+	pshead.nPages      = 2;
+	pshead.nStartPage  = 0;
+	pshead.ppsp        = ppage;
+	pshead.pfnCallback = GSInstall_wizardProc;
+
+  GSInstall_init_propertySheet(	ppage[0],
+  															"Choose a directory to install your "
+                                "GreenStone software to.", NULL,
+                                "Select", install, false);
+  GSInstall_init_propertySheet(ppage[1],
+  															"Choose a directory to install the collection "
+                                "files to.\n\n"
+  															"You can also choose to install all the collection "
+                                "files onto your computer hard drive.\n\n"
+                                "If you do this, you will not have to load the "
+                                "CD-ROM each time you use your Greenstone software "
+                                "but more of your hard disk will be used.\n\n"
+                                "Some collection files must be installed on your "
+                                "computer.\n\n",
+                                "Install all collection files",
+                                "Select", install, true);
+
+  reply	= (PropertySheet (&pshead) >= 0);
+  return reply;
+}
+
+long FAR PASCAL GSInstallWindProc(HWND		 	Window,
+																	WORD		 	Message,
+																	WPARAM		wParameter,
+																	LPARAM		lParameter)
+{ long reply = 0;
+
+  switch(Message)
+	{ case WM_CREATE:
+  	{
+    }
+  	break;
+
+  	case WM_COMMAND:
+		break;
+
+    case WM_USER:
+    {	//dirSelector selector("Choose a Greenstone directory", "Select directory");
+
+      //selector.requestPath(Window, "Select directory");
+      GSInstall install;
+      GSInstall_init_wizard(install);
+      if (config_complete == false)
+      {	MessageBox(0, "Install cancelled", app_name, MB_OK);
+			}
+      else
+      { install.setDestination();
+      	install.setManifest();
+	      install.copyFiles();
+  	    install.updateProgman();
+    	  install.updateRegistry();
+        install.updateProfiles();
+        install.installNetscape();
+      }
+      DestroyWindow(Window);
+		}
+    break;
+
+		case WM_CLOSE:
+/*			if (!file_ischanged || IDCANCEL != file_query(Window, file_name))*/
+			DestroyWindow(Window);
+		return 0L;
+
+		case WM_DESTROY:
+		{ PostQuitMessage(0);
+		}
+		break;
+
+		default:
+			return(DefWindowProc(Window, Message, wParameter, lParameter));
+	}
+  return reply;
+}
+
+void GSInstall_init(HINSTANCE instance, int Show)
+{ int sx, sy;
+
+	gsInstall_getDesktopExt(&sx, &sy);
+
+	app_window = CreateWindow("GSInstall:Main", "GreenStone Installer",
+															WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | CS_DBLCLKS,
+															0, 0,
+															sx, sy,
+															NULL,
+															NULL,
+															app_instance,
+															NULL);
+
+	ShowWindow(app_window, Show);
+
+  PostMessage(app_window, WM_USER, 0, 0L);
+}
+
+void WinClassInit(void)
+{ WNDCLASS 	Class;
+
+	Class.lpszClassName = "GSInstall:Main";
+	Class.hInstance     = app_instance;
+	Class.lpfnWndProc		= (WNDPROC) GSInstallWindProc;
+	Class.hCursor				= LoadCursor(NULL, IDC_ARROW);
+	Class.hIcon					= NULL; //LoadIcon(app_instance, "GSInstall");
+	Class.lpszMenuName  = NULL;
+	Class.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1);
+	Class.style 				= NULL;
+	Class.cbClsExtra		= 0;
+	Class.cbWndExtra		= 0;
+	RegisterClass(&Class);
+/*
+	Class.lpszClassName = "GSInstall:Splash";
+	Class.hInstance     = app_instance;
+	Class.lpfnWndProc		= (WNDPROC) splash_windproc;
+	Class.hCursor				= LoadCursor(NULL, IDC_ARROW);
+	Class.hIcon					= NULL;
+	Class.lpszMenuName  = NULL;
+	Class.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
+	Class.style 				= NULL;
+	Class.cbClsExtra		= 0;
+	Class.cbWndExtra		= 0;
+	RegisterClass(&Class);*/
+}
+
+int PASCAL WinMain(HINSTANCE Current,
+										HINSTANCE Previous,
+										LPSTR CmdLine,
+										int CmdShow)
+{ MSG msg;
+//	HACCEL accel;
+
+	app_cmdLine = (char *) malloc(lstrlen(CmdLine) + 1);
+	lstrcpy(app_cmdLine, CmdLine);
+
+	app_instance = Current;
+	/* -- init application */
+	if (!Previous)
+	{ WinClassInit();
+  	InitCommonControls();
+//    grbStatic_registerClass(Current);
+	}
+
+	/* -- init instance */
+  GSInstall_init(Current, CmdShow);
+
+//  config_init("ReTreeval");
+
+//  accel	= LoadAccelerators(Current, "ReTreevalMenu");
+
+	while (GetMessage(&msg, NULL, 0, 0))
+	{ /*if (!TranslateAccelerator(app_window, accel, &msg))
+  	{ */
+    	TranslateMessage(&msg);
+			DispatchMessage(&msg);
+    /*}*/
+	}
+	return (int) msg.wParam;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/gsinstall.rc
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/gsinstall.rc	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/gsinstall.rc	(revision 14219)
@@ -0,0 +1,818 @@
+/****************************************************************************
+
+
+gsinstall.rc
+
+produced by Borland Resource Workshop
+
+
+*****************************************************************************/
+
+
+#include "common.h"
+
+getDirPath DIALOG 0, 0, 276, 140
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION ""
+FONT 8, "MS Sans Serif"
+{
+ CONTROL "Text1", dirpath_PROMPT, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 80, 0, 180, 96
+ CONTROL "dirpath_PATH", dirpath_PATH, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 108, 124, 120, 13
+ CONTROL "Path", -1, "static", SS_RIGHT | WS_CHILD | WS_VISIBLE, 84, 127, 18, 10
+ CONTROL "Browse...", dirpath_BROWSE, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 230, 124, 44, 14
+ CONTROL "CheckBox1", dirpath_OPTION, "button", BS_AUTOCHECKBOX | BS_LEFT | BS_TOP | BS_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 108, 101, 162, 17
+ CONTROL "SetupBmp", -1, "static", SS_BITMAP | WS_CHILD | WS_VISIBLE, 12, 20, 53, 86
+}
+
+SetupBmp BITMAP 
+{
+ '42 4D F6 2F 00 00 00 00 00 00 36 04 00 00 28 00'
+ '00 00 50 00 00 00 8C 00 00 00 01 00 08 00 00 00'
+ '00 00 C0 2B 00 00 00 00 00 00 00 00 00 00 00 01'
+ '00 00 00 00 00 00 1C 1A 1E 00 97 8A 69 00 5B 52'
+ '34 00 74 6E 4E 00 D0 C2 B4 00 33 36 25 00 AC A6'
+ '8E 00 5A 52 52 00 71 6E 6B 00 3B 46 30 00 92 8A'
+ '87 00 78 62 38 00 88 7E 6C 00 59 52 44 00 8C 7E'
+ '5C 00 28 2A 1E 00 68 62 53 00 9F 9A 89 00 45 46'
+ '3E 00 79 6E 5D 00 3C 3A 36 00 B4 AA AB 00 68 62'
+ '63 00 E3 DE D9 00 9C 97 7D 00 81 7E 7A 00 62 5A'
+ '45 00 3E 3E 29 00 7B 76 5D 00 24 2A 2A 00 A1 9A'
+ '97 00 91 8A 79 00 54 46 2E 00 73 6A 55 00 90 86'
+ '6D 00 9D 92 79 00 BF B6 AC 00 20 22 1E 00 61 5A'
+ '36 00 D9 D2 CC 00 AC A6 A0 00 7A 76 6B 00 94 92'
+ '88 00 30 32 22 00 66 62 5B 00 76 6E 63 00 6A 62'
+ '49 00 57 52 4C 00 54 4D 4B 00 90 8A 80 00 33 38'
+ '30 00 86 7E 73 00 3C 3E 30 00 F7 EE E9 00 61 5A'
+ '4B 00 44 46 38 00 B4 A2 86 00 53 4E 40 00 CC C2'
+ 'C6 00 AA A2 99 00 22 24 27 00 7B 77 65 00 55 49'
+ '38 00 7A 76 73 00 59 52 3D 00 60 5A 53 00 77 6A'
+ '4B 00 C1 B8 BD 00 9D 96 92 00 9C 9A 90 00 8B 86'
+ '7C 00 24 2B 23 00 B6 AE A0 00 EF E5 E8 00 2C 32'
+ '2B 00 73 6E 54 00 9D 94 88 00 74 63 4A 00 6D 5E'
+ '53 00 3E 38 25 00 90 86 65 00 71 6A 5C 00 75 65'
+ '54 00 44 42 37 00 84 72 63 00 9D 8D 80 00 6D 5D'
+ '4C 00 64 55 44 00 55 4A 40 00 84 70 5D 00 BF B2'
+ 'AC 00 87 79 6C 00 76 66 5B 00 64 56 4B 00 94 82'
+ '73 00 4C 41 30 00 BD AF 99 00 4C 4E 32 00 6F 6A'
+ '63 00 AC 9E 98 00 C7 BE B1 00 86 76 55 00 D0 CA'
+ 'C2 00 49 46 2D 00 94 81 6D 00 4D 40 29 00 9C 8C'
+ '78 00 20 22 22 00 B4 A8 9F 00 86 78 65 00 A6 9B'
+ '90 00 89 7E 65 00 58 4E 31 00 66 5A 3D 00 3C 32'
+ '23 00 4B 4E 39 00 64 54 3D 00 2D 2C 24 00 F2 E8'
+ 'DF 00 6C 5C 45 00 2D 2D 2B 00 8B 86 74 00 3D 3A'
+ '2F 00 5D 4E 40 00 D4 CD C9 00 2E 26 27 00 57 4E'
+ '38 00 62 5E 5A 00 8C 86 83 00 F9 F1 F2 00 B4 9E'
+ '7E 00 E3 DA D2 00 8C 76 4E 00 1F 1E 26 00 C9 C2'
+ 'BF 00 C8 BE BE 00 F2 EA E9 00 AB A6 9A 00 9A 92'
+ '80 00 F9 F6 F5 00 9D 8E 87 00 95 8A 71 00 70 63'
+ '41 00 E8 E0 DF 00 BC B6 B3 00 DC D6 D6 00 3F 42'
+ '40 00 D0 CC CF 00 88 70 48 00 7E 72 6A 00 A5 97'
+ '80 00 8C 81 7B 00 AB A2 90 00 AB A2 9F 00 BC B2'
+ 'B3 00 1C 1A 22 00 C4 C2 BA 00 84 8E 8E 00 47 49'
+ '46 00 38 3C 3E 00 6A 62 4E 00 D4 C6 CE 00 B4 AE'
+ 'A6 00 65 53 36 00 AE 9B 87 00 86 77 5D 00 6E 5C'
+ '34 00 7D 6F 55 00 B5 A8 99 00 7D 6A 55 00 7C 6A'
+ '5C 00 A5 92 80 00 35 32 2C 00 34 37 2A 00 74 72'
+ '72 00 9B 96 82 00 84 82 82 00 24 2E 32 00 A4 9E'
+ '9E 00 55 49 32 00 AC A7 A6 00 93 94 8E 00 F7 F0'
+ 'EE 00 24 26 2E 00 9D 96 8E 00 74 64 4E 00 6C 5E'
+ '5A 00 3F 39 2A 00 AC 9E 9E 00 4A 47 32 00 B4 A9'
+ 'A6 00 5C 56 52 00 8B 82 6D 00 5B 56 45 00 2C 2E'
+ '1E 00 6A 66 54 00 4B 4A 3F 00 7B 72 5D 00 3B 3E'
+ '37 00 B6 AE AA 00 6B 66 63 00 E8 E2 D8 00 64 5E'
+ '45 00 42 42 2A 00 94 8E 79 00 C4 BA AE 00 24 26'
+ '1E 00 DF D6 CE 00 6A 66 5C 00 79 72 64 00 5B 56'
+ '4B 00 92 8E 80 00 89 82 74 00 41 42 30 00 63 5E'
+ '4C 00 4B 4A 39 00 C8 C6 C8 00 7E 7A 73 00 5C 56'
+ '3D 00 63 5E 53 00 D8 CE C0 00 8D 82 66 00 6C 5E'
+ '3E 00 D2 C6 C0 00 9A 8E 70 00 C4 BA B4 00 30 32'
+ '26 00 53 4E 46 00 74 6A 6A 00 C0 BE B6 00 BC AA'
+ '8E 00 24 26 22 00 1F 1E 22 00 D4 C6 BA 00 6B 66'
+ '4E 00 B4 B2 A6 00 95 86 7B 00 A0 86 62 00 95 86'
+ '74 00 1E 1E 1E 00 5A 56 34 00 CC C6 B6 00 34 3A'
+ '25 00 74 72 6B 00 92 8E 87 00 74 66 3A 00 90 82'
+ '5E 00 83 82 7B 00 7C 7A 5E 00 24 2E 2A 00 A3 9E'
+ '98 00 55 4A 2D 00 AC AA A1 00 7B 7A 6C 00 94 96'
+ '89 00 6C 66 4A 00 2C 5C BA BA BA 5C 2C 4E 4E 5D'
+ '41 7F BA BF 07 41 BF 5D BF BF BF BF 41 D2 BF BF'
+ 'BF 07 30 D2 30 30 9E BF 2C 7F BF 2F 2F 30 2F 2F'
+ 'D2 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 07 2F 07 41 DB'
+ '41 7F 41 BF 41 7F 7F 7F 7F 2C 16 7F 7F 16 7F 16'
+ '16 16 16 16 C8 E4 BC 63 1E 63 1E 6E 44 44 44 B8'
+ '4C 4C B8 B5 2A 8C 31 F4 31 EC 31 55 0A 80 31 31'
+ '80 EC F7 46 33 C0 19 D9 97 31 46 80 0A 31 46 B0'
+ '46 80 0A 9D D3 80 80 F7 19 97 EC F7 80 0A 80 4C'
+ 'B8 B8 B8 44 FE 44 1E B5 45 1E 1E 1E 1E 1E BC FA'
+ '1E 3B 6C 28 99 15 99 A8 3B 63 A8 A8 3B 6E 44 A4'
+ 'B8 44 FE B8 8C 0A D3 0A 8C 0A 2A 0A 80 8C F4 97'
+ 'F4 80 F7 F7 F7 46 D4 9D D3 19 19 FD 29 D9 3F D9'
+ 'D9 AE D9 D9 B0 0A 31 F7 46 46 F7 31 D3 55 2A 6E'
+ '99 63 BC 1E 3B 44 1E 44 1E 99 B4 FA 63 B2 89 63'
+ '28 28 BE C7 C7 5A 28 FA 28 A8 6C 3B A8 3B A8 B8'
+ '6E B8 B8 B8 B8 AF 2A B8 AF 2A 55 2A D3 31 31 31'
+ '46 D3 31 1F 1F D3 F7 F3 DB 0D 12 92 C6 12 C6 9F'
+ '37 C4 E3 2F 41 2C 62 F3 19 F7 D3 0A B8 2A 2A 44'
+ 'FA 28 FA 3B 63 3B 3B FA FA 28 3B FA 3B 28 15 C7'
+ '9A C7 BE BE 9A 87 A8 63 99 48 A8 3B A8 63 3B 63'
+ '6E B8 4C B8 B5 2A 2A 2A 2A 31 D3 31 1F 46 D4 46'
+ '31 46 F4 D3 3F 41 9E 37 D5 53 C6 34 C6 C6 32 C6'
+ '09 53 37 37 C6 12 12 30 10 51 29 F4 0A 8C 2A 44'
+ '3B 98 63 1E 1E B4 99 89 FA 99 FA 3B 28 99 B4 43'
+ '43 C7 BE BE 9A D8 6C A8 3B A8 BC 3B 63 98 63 6E'
+ 'B8 B8 2A 4C 11 FE 8C 2A 2A 2A F4 F4 D3 D3 46 D3'
+ '31 D3 0C D2 D7 C6 C6 32 9F 32 32 B1 32 C6 32 D5'
+ '53 53 32 C6 09 73 D7 37 9E 2F 41 62 29 19 31 31'
+ '63 1E 3B 6E 6E 45 1E 99 1E 3B 99 99 FA 43 87 BE'
+ '28 B4 99 FC 43 93 A8 3B 3B A8 3B 98 63 1E 6E 6E'
+ '4C 2A B8 F4 B5 55 F4 45 0A 46 B8 31 46 31 79 0C'
+ '31 D0 D7 C6 53 B1 32 AC 4A 32 32 B1 AC 14 34 C6'
+ '14 14 32 14 34 D7 73 DA 40 39 9E 41 7F 16 FD F4'
+ 'FE B8 1E 44 B8 8C B8 11 44 1E 99 3B 3B 3B BC 3B'
+ '99 99 89 C7 9A A1 28 63 63 6E 63 63 98 6E 6E 44'
+ 'B8 45 FE 11 8A FE 2A 8A D3 0A D3 31 31 D3 D3 F7'
+ '10 09 53 34 4A AC 4A 4A 4A B1 AC AD 32 4A 32 32'
+ '32 4A 4A AC C6 34 53 C1 EA FF D6 30 07 DB C8 29'
+ 'B0 0A FE B8 4C 11 B8 B8 6E 11 6E 3B 1E 3B 3B 3B'
+ '28 EB A2 99 99 90 98 6E 6E 3B 63 28 98 63 44 2A'
+ 'B8 45 B8 B8 8C B8 2A 31 31 F4 31 31 D3 1F 33 10'
+ 'D5 D5 53 32 4A 4A 4A F9 F9 4A 4A 4A B1 75 B1 4A'
+ '78 4A 4A AD 32 32 37 73 10 2A A8 13 2F 07 41 D0'
+ '16 D4 8C 44 44 44 B8 44 6E 44 FA B2 1E 63 28 28'
+ 'FC 99 3B 99 3B FC 63 98 63 98 44 11 6E 63 6E B8'
+ '2A 8C F4 55 F4 F4 F4 D3 F4 F4 80 D3 D3 1F 13 C6'
+ 'D5 34 32 4A 4A F9 B1 1D B7 47 F9 75 E2 1D 78 75'
+ '78 75 F9 78 4A 32 32 D7 C1 F3 9A CF FD 36 D2 41'
+ '41 16 D9 FE B8 FE B8 6E B8 FA A8 63 98 99 48 99'
+ '6C FA 1E FA B2 99 63 6E 6E BC 44 96 B8 11 B8 11'
+ 'B8 B5 B8 8A 2A 2A 2A F4 FE 31 46 46 D4 3D 37 1B'
+ 'D5 34 32 4A 4A E2 1D 47 47 1D 1D 3C B7 B7 75 1D'
+ '1D 47 78 4A E2 4A 32 34 12 40 21 E1 7C D1 DB 41'
+ 'BF BF D0 D9 80 2A 2A FA 3B 1E 3B 99 FC BC 89 1E'
+ '45 FA 1E FA 99 D8 6E 6E 6E 6E B8 96 B5 B8 4C B8'
+ 'B8 AF 2A B8 2A D3 F4 D3 D3 46 F7 D4 F3 1A 32 32'
+ '4A E2 AD 4A 47 3C 1D B7 3C 47 B7 47 3C 1D B7 47'
+ '75 47 B7 78 4A 4A 05 32 F2 34 D7 D1 E5 87 2C D0'
+ '36 D2 D2 D0 FD 31 8A 44 6E 3B 3B 63 99 6E 45 FA'
+ 'FA 44 1E 44 28 3A 8C 1F 8A 31 2A B8 4C 96 4C 2A'
+ 'AF 0A 2A D3 2A D3 D3 80 D3 19 8D 3D 21 34 F2 32'
+ 'E2 4A F9 F9 B7 1D 1D 6B 3C B7 3C B7 3C 47 B7 1D'
+ '47 B7 78 1D 78 4A E2 4A AD AD 14 09 4B D8 3D 41'
+ '41 E3 41 10 08 31 D3 F4 D3 2A 45 B8 2A B8 11 FA'
+ '99 89 89 63 3B BE 6E B8 55 3F F3 5E D3 31 B8 FE'
+ '2A D3 D3 F4 2A 31 31 F7 46 C0 29 13 1A AD 32 AD'
+ '4A F9 1D 1D 47 47 B7 3C 6B 6B 85 B7 3C 6B B7 47'
+ 'B7 75 AC 47 47 1D F9 E2 4A 4A E2 32 34 D6 D9 0D'
+ 'D2 D2 2F 36 D0 D9 46 46 31 F4 F4 FE F4 FE 44 3B'
+ '1E 15 3B 28 FA 1E A8 B8 B8 31 1F CC 79 D4 0C C0'
+ 'D9 33 D4 97 D3 31 2A 1F 29 D1 5C D6 09 1B 1B E2'
+ 'E2 F9 1D 47 3C B7 B7 3C 6B B7 6B 3C 3C 3C 3C 47'
+ 'B7 B7 75 1D F9 7D B7 1D 1D 1D F9 05 32 D5 40 53'
+ '41 DB BF BF 2C 08 33 31 B5 B5 D3 B8 B5 2A 45 45'
+ '1E 1E 45 FA 45 1E 98 63 B8 0A F4 B8 55 EE 1F D3'
+ '79 97 79 79 5B D4 D4 29 08 51 C3 57 D5 34 32 E2'
+ 'E2 47 3C B7 3C 6B 6B 3C 3C E8 3C 3C 3C 6B 2B 3C'
+ 'E7 47 F9 F9 6B 47 6B 1D 1D 6B E7 4A AD 34 D5 09'
+ '36 10 DB 0D 10 62 D9 46 2A F4 44 45 45 45 1E B8'
+ '45 45 1E 44 B8 6E 63 63 44 9D 2A 63 6E 4C 1F 33'
+ '97 46 79 46 31 33 29 F3 29 C3 A0 1A D5 1B AD E2'
+ 'F9 B7 47 47 3C E7 B7 3C 6B 3C 85 6B 3C E7 47 B7'
+ '25 B7 1D B1 6B B7 3C 85 6B 6B E7 F9 E2 1B C6 1B'
+ '0D 2C 41 D2 D2 10 F3 F7 0A 2A B5 45 B5 45 1E 44'
+ 'B8 B8 FA 1E B5 45 89 3B 6E B5 6E A4 B8 11 B8 4C'
+ 'AF EC 46 CC 79 1F D4 6D 3D D1 4B 40 1B CB 05 E2'
+ 'F9 47 B7 3C E7 3C E8 6B 3C 85 6B 6B E8 6B B7 6B'
+ '3C 6B 6B 3C 1D 85 85 3C EF 3C B7 F9 4A 4A F2 32'
+ '92 C3 7F DB DB DB C8 F3 F7 31 2A 0A B5 45 44 1E'
+ '45 B8 2A 8C AF B8 98 FA 98 1E 63 6E B8 6E B8 FE'
+ 'F4 2A 31 D4 D9 5B 3D 51 52 51 2D 3E BD D5 4A F9'
+ 'F9 1D 3C 6B 85 85 E7 85 85 85 6B B7 F9 B7 1D 3C'
+ 'CE B7 3C B7 85 3C 6B 7D 6B F9 4A 47 4A F2 4A 4A'
+ 'C6 DB 2C 2C D0 DB 62 08 F7 1F 0A F4 B8 B5 44 FE'
+ 'B8 2A FE 8C AF FA 6E 63 6E 6E B8 44 B8 B8 6E 44'
+ '2A 2A D3 D4 C0 0C AA 52 C3 10 52 FB 67 F2 4A C2'
+ '4A 47 E7 3C 6B E8 85 6B E8 6B 6B 6B E7 25 6B 6B'
+ '3C 6B 3C 3C 3C 3C 6B 25 B7 05 1B E2 F9 2B E2 AD'
+ 'AD A0 DB 2C DB 2C C8 62 29 33 31 1F B5 2A B8 44'
+ '45 1E 2A FE 4C 45 B8 45 FA FA 6E 6E 6E 11 B5 2A'
+ 'AF 8A D3 97 D4 29 3D 2D 56 A0 A9 1B 67 1B F9 F9'
+ '3C 3C 3C E7 6B 3C 85 6B 6B E8 E8 85 E8 85 6B 85'
+ '6B 85 47 E7 E8 6B 6B 85 E2 1B 1B E2 E2 4A 4A 05'
+ '32 DB D2 D0 DB 10 A0 D0 F3 46 0A 80 45 2A 44 45'
+ 'B8 2A 2A 2A FE 45 FA FA 63 A4 B8 A4 FE 96 AF 2A'
+ '31 31 31 79 D4 22 D1 6F 10 13 56 1B 3E BB 05 6B'
+ '47 47 6B B7 E7 6B 6B 6B E8 3C 6B 6B 3C 6B EF 6B'
+ 'EF 6B 6B 6B 6B 6B 6B 6B 4A F2 AD E2 E2 E2 E2 2B'
+ '4A DB D2 DB D6 D0 D0 C8 AE 46 31 2A B5 2A 8A B5'
+ '2A 2A F4 44 44 3B 98 98 6E 44 B8 6E 2A 11 8C AF'
+ '31 31 D4 19 6D 95 2D 21 2D 51 FF CB 70 F2 E2 3C'
+ '2B 3C 3C 47 E7 6B 6B E8 6B 85 6B 3C 6B E8 85 6B'
+ '6B 85 E8 85 6B E8 6B 47 3C E7 3C 47 4A E2 E2 4A'
+ '4A C1 0D D2 10 D0 62 62 F3 D4 F7 2A 2A 44 B5 1E'
+ '1E B5 2A D3 B5 1E 6E 6E 63 A4 FE FE 4C B8 11 31'
+ '8A 79 46 22 3D 52 10 D6 A9 4B 57 D5 02 F2 47 47'
+ '3C 47 E7 6B 3C E7 85 6B 6B E8 E8 6B 25 E8 85 E8'
+ '3C 25 85 25 6B 6B 6B EF 6B 6B 6B 47 47 4A E2 F2'
+ '32 41 41 0D D2 DB 10 C3 F3 19 D3 F4 F4 AF 1E B5'
+ '45 1E 1E 45 2A 11 15 1E FA 11 B8 6E A4 D3 D3 CC'
+ '46 8D 33 0C 2D 13 21 D6 51 5C 57 F2 A6 BB F9 E7'
+ '3C E7 47 3C 6B 3C 6B 6B E8 EF E7 00 6B 6B E8 6B'
+ '9B E8 E8 25 E8 6B 85 6B EF E8 E7 E7 47 2B 05 4A'
+ '4A 73 0D E3 39 D2 36 D0 F3 29 D3 9D 0A 45 B8 FA'
+ '45 44 45 1E 11 1E FC 48 98 6E FA B8 4C 6E 2A 8A'
+ '46 97 D4 D1 13 10 52 56 2E 10 DA BB F5 4F E2 E7'
+ '6B 3C 3C 6B 6B 6B EF E8 25 6B 9B 6B E8 EF 6B 25'
+ 'EF 25 6B E8 6B E8 25 E8 E8 25 6B 47 47 2B E2 AD'
+ 'E2 D7 73 E3 36 2F 39 41 10 F3 D4 31 0A B5 B5 B5'
+ 'B8 11 1E B5 45 FA 89 90 11 FA 6E 44 FE 11 8A 2A'
+ '46 D4 33 F8 51 59 1A 4E C1 C3 71 34 84 5F F9 3C'
+ '3C E7 EF 6B E7 85 6B 85 25 E8 EF E8 6B 25 EF 25'
+ '6B 25 EF E8 EF 6B 25 25 E8 25 47 E7 E7 4A E2 E2'
+ '2B C4 2F 0D 9E 0D 36 10 13 29 19 19 31 FE 11 2A'
+ '44 45 45 3B FA 99 3B 28 3B B8 6E FA B8 2A 2A 31'
+ '1F FD 3D D1 13 D1 A0 10 10 A0 40 D5 ED 34 75 25'
+ 'E7 6B 6B E8 6B 6B 6B 6B E8 25 6B 6B EF 25 E8 E8'
+ 'EF 6B 6B E8 25 EF E8 E8 25 6B 6B 47 E7 E2 2B 2B'
+ 'B1 73 36 D2 36 0D 36 2C 08 29 D1 33 D3 F4 45 45'
+ 'FE 45 1E FA 3B 3B 3B 48 89 45 1E 6E B8 B8 2A 1F'
+ '31 D4 D1 2D 52 10 10 2E DB A0 02 3E 82 67 C2 E7'
+ '47 6B 25 6B EF 6B 25 6B 6B EF 6B E8 EF 6B E8 EF'
+ '25 EF 9B E8 6B 6B EF 6B 25 E7 E7 E7 47 2B E2 4A'
+ '4A 36 2F 73 E3 C1 36 39 C3 62 FD 33 31 31 2A 45'
+ '1E FA 45 FE 45 FA FA A2 FA 6E 45 11 6E FE AF 46'
+ 'D4 D1 C5 51 10 2E 10 10 CA EA CA 67 5A 7E F9 47'
+ '6B 6B 6B E8 6B E8 6B 6B EF E8 E8 6B E8 EF E8 6B'
+ 'E8 6B 25 25 EF EF 6B EF 6B 6B 0F 47 47 2B 2B E2'
+ 'E2 D6 C4 0D 39 9E 39 41 D6 D0 62 19 80 31 2A B8'
+ '28 3B 45 44 11 FA 1E BE 3B 6E 6E 2A 45 2A 31 79'
+ '79 D1 4B 51 52 10 A0 D6 C1 56 C1 34 E9 2E 4A E7'
+ '6B 25 E8 E8 EF EF E7 E8 6B 6B 25 6B 25 E8 25 25'
+ 'EF 25 EF 6B EF 25 E7 0F 25 25 6B E7 47 2B E2 E2'
+ 'E2 DB D2 40 9E 73 0D 36 1A C8 D0 D9 46 D4 31 F4'
+ '45 0A B8 2A FE 1E 3B 48 89 FA 2A 45 11 2A 1F 19'
+ '3D C5 D0 C3 C3 56 D6 D6 C1 D6 DA BD 27 F8 75 E7'
+ 'E7 6B E7 25 6B EF EF EF 9B 00 6B EF EF 25 E8 EF'
+ '25 EF 25 25 E8 6B E8 3C E7 EF 25 CE 2B AD 05 4A'
+ '32 36 2F 30 C1 0D 0D D2 36 D0 62 FD D9 F7 31 8A'
+ 'B5 1F D3 F4 31 FE 3B 5A 89 6E 44 B8 FE D3 79 2A'
+ 'D4 29 13 21 D0 10 D2 0D 36 DA 40 D7 27 79 E2 47'
+ 'EF EF E8 6B EF E8 25 E8 25 25 6B E8 25 E8 25 6B'
+ 'E8 E8 25 E8 6B 6B 25 E7 CE EF CE 0F 2B E2 F2 05'
+ '34 0D 36 D6 D6 36 36 39 DB D6 51 D1 FD FD 79 46'
+ '2A 31 D3 D3 D3 D3 63 28 89 63 6E 11 FE 79 46 46'
+ 'C0 0C D1 13 21 51 40 C1 D6 0D 1A 67 27 11 C2 E7'
+ 'E7 6B EF E7 EF EF EF 6B EF E8 EF 6B 9B 25 EF EF'
+ '25 25 9B 25 6B CE E7 6B CE 25 6B 0F F9 2B 2B 2B'
+ '37 36 D6 D6 41 10 C1 D2 C1 2C D0 2D D9 0C 19 8A'
+ '46 31 31 F4 FE 8A 63 89 3B 3B 3B 45 2A F4 D3 46'
+ 'FD D9 C5 C3 51 51 E3 36 D6 8E C1 37 27 60 F9 7D'
+ '25 E7 EF EF 6B 25 EF E8 25 6B E8 EF 25 25 E8 E8'
+ 'E8 6B 6B EF CE E8 3C 0F EF 6B 25 E7 0F C2 2B E2'
+ '37 C3 2F BF D2 D6 41 D2 36 D6 C3 08 F3 0C D4 F7'
+ '2A EC D3 F4 1F 6E FC A2 FA 45 B8 6E 45 FE 31 0C'
+ 'FD D1 51 51 13 D0 D2 D6 D6 D6 C1 FB 7C CD 05 47'
+ '3C E7 25 6B EF EF CE EF EF 00 25 25 EF E8 6B 6B'
+ 'EF E8 25 E8 E8 25 6B E8 E7 25 6B E7 E7 0F F9 2B'
+ '9E DB D6 10 D2 41 DB 41 36 41 D0 2D 29 46 31 D4'
+ '1F 46 31 31 0A 55 FA FA 3B 1E 44 FE CC 80 31 33'
+ '29 3D D0 D0 D1 41 C3 D6 5D C1 40 37 86 66 AD E7'
+ '6B 25 6B 25 9B E7 EF 6B 6B 25 6B E8 25 E8 25 E8'
+ 'CE 00 CE E8 25 25 6B 6B E8 25 25 EF 47 47 2B 2B'
+ 'C4 DB 10 D0 DB C3 36 36 D6 A0 62 C5 08 79 31 31'
+ '31 D3 31 FE 8A 6E FA 99 89 44 FE 8C D3 D3 79 0C'
+ 'F8 2D 51 21 DB 2C D0 D6 D6 36 1A 09 90 93 05 C2'
+ 'CE 85 25 85 CE 25 25 6B EF E8 EF 6B E8 EF EF 25'
+ 'E8 25 25 25 E8 EF 6B EF EF E8 25 47 25 0F 2B 2B'
+ '53 C1 36 DB 36 10 D2 DB 10 F3 51 51 3D E4 33 D4'
+ 'D4 FD D4 46 D3 AF FA 28 98 B8 2A FE D3 31 79 FD'
+ 'D1 D1 D6 D6 2F 10 52 10 56 A0 0D BD 3B 83 BB F9'
+ 'CE 25 25 EF 25 E8 6B 0F 6B 25 6B EF EF E8 6B E8'
+ '6B EF 85 EF E8 E8 25 25 E8 EF 25 E7 CE 0F C2 05'
+ '32 14 C4 36 0D 36 41 10 07 53 34 53 C4 0D 0D DB'
+ 'A0 C3 D1 D1 D1 33 1E EB 3B 45 B8 2A D3 79 D4 6F'
+ 'D1 51 D0 BF 0D D6 10 52 10 C3 10 B3 2A 76 34 7D'
+ 'CE E7 25 25 E8 EF 25 6B EF 6B 25 EF 25 EF 25 EF'
+ '25 25 25 6B 25 25 EF 25 25 E8 25 CE 0F F9 C2 32'
+ 'D5 AD 32 32 12 0D 37 32 D5 C4 36 D6 62 D0 D0 D1'
+ 'FD 3D D1 6D 5B D1 FA 99 FA B8 B8 8A D3 F7 D4 62'
+ 'D0 13 10 30 2E A0 2E 36 FF 10 A0 D7 19 88 D7 2B'
+ 'E7 E7 EF 25 E8 25 6B E8 E8 25 E8 E8 25 E8 CE E8'
+ '6B 25 E8 EF E8 E8 25 E8 E8 25 CE CE 0F 47 47 34'
+ 'D6 0D 14 32 C6 53 E3 41 C3 2C C3 D0 08 FD 29 33'
+ '46 31 D3 79 EE 31 44 3B 6E 8A 0A 2A D3 22 FD 2D'
+ 'D6 62 41 0D A0 EA 56 D6 A0 D6 EA 02 3D 35 C4 47'
+ 'CE E8 25 E8 25 25 25 6B EF E8 EF 25 25 25 EF E8'
+ '25 00 85 25 25 6B EF 6B 6B E8 E7 47 CE E7 2B C6'
+ 'D0 2C 10 36 10 10 2C 10 10 D0 D0 08 3D 08 33 79'
+ '31 46 F4 B5 B5 FE FE 6E 45 2A 1F 31 D3 80 0C C5'
+ 'DB C3 0D A0 36 A0 A0 A0 C3 36 D6 7E 7F B6 36 47'
+ 'CE 6B CE 6B E8 E8 E8 25 6B CE 25 25 EF 00 EF EF'
+ '25 6B CE 47 CE 6B 6B EF EF CE CE 25 E7 E7 F2 53'
+ '10 10 D0 51 62 2C DB 10 10 10 10 2D 62 FD FD F7'
+ '31 2A 2A B8 11 11 B8 38 3B 2A CC 31 D3 79 5B 51'
+ 'D0 D6 D2 56 10 56 56 56 10 C3 A0 73 C1 88 C3 47'
+ 'E7 CE 25 25 6B 25 25 25 EF 00 E8 E8 6B 25 3C 6B'
+ '25 25 E7 E7 7D 25 00 6B 6B CE 25 CE CE E7 F2 39'
+ '36 D0 2D 51 D0 51 C8 10 D0 D0 51 13 62 F3 FD 33'
+ 'F4 CC D3 8A FE 45 4C CC 4C 2A D3 46 D4 0C 3D 36'
+ 'D2 39 C3 A0 C3 56 A0 10 2E C3 1A 40 C4 35 95 C2'
+ 'CE EF 6B CE 6B 25 EF E8 E8 6B 25 25 EF 9B 25 EF'
+ 'E8 6B E7 7D 25 E8 25 EF 25 25 25 3C 47 2B D5 C4'
+ 'D2 DB 10 D2 2D 51 D1 62 D0 2C D0 C8 62 3D 29 D4'
+ 'D3 80 46 31 2A 11 AF 2A 4C 8A 55 D3 46 5B 3D 41'
+ '0D C1 52 2C 2E C3 56 10 A0 52 A0 DA 37 8F D4 78'
+ '25 6B CE 25 E8 6B 25 EF EF 25 6B EF EF 25 E8 E8'
+ 'EF 25 E7 E7 6B 6B EF EF E8 E8 6B CE E7 2B 09 36'
+ '10 D2 10 2C 10 62 29 FD 08 4B F3 C8 3D F3 3D 19'
+ 'F4 2A D3 2A D3 45 AF 8A 3B CC F4 D3 EE 0C D1 10'
+ '39 56 10 10 2E 10 C3 D6 A0 10 10 40 09 91 8A 7D'
+ 'E7 CE 25 6B 25 00 9B E8 25 E8 00 6B 6B E8 25 EF'
+ 'E8 CE 6B E7 CE 25 E8 6B 6B 6B 25 CE 47 05 53 0D'
+ '7F D6 10 3D 51 C8 D9 19 08 C5 2D F3 FD 33 19 33'
+ 'D4 8A FE F4 2A AF 4C 96 FA 1F EE 1F 1F 22 2D 10'
+ '41 39 C1 A0 EA 4E 56 A0 A0 2E EA 1A 32 D8 89 C2'
+ 'CE 25 25 E8 E8 25 EF 25 EF 25 E7 EF E7 6B E8 6B'
+ '6B CE CE 75 E8 E7 25 E7 25 CE E7 CE 0F F2 D5 41'
+ 'C3 62 13 62 51 D1 D0 2C 62 13 08 F3 F3 FD 19 46'
+ '46 FE 45 B8 31 11 AF 8A 6E 1F 1F 68 1F 29 C8 D0'
+ '2C D7 57 1A 10 56 A0 10 56 A0 FF D6 BB 24 24 E2'
+ 'E7 6B 25 25 EF 6B E8 E8 6B 6B EF E8 6B 6B 25 EF'
+ '25 EF 6B 25 25 E7 E7 E7 6B 25 25 E7 2B 34 D5 51'
+ '08 51 C8 C8 C3 DB D0 10 C3 51 2D 3D 3D D1 FD 79'
+ '46 F7 2A 45 B8 1E 96 AF 6E 1F 22 79 6D 3D 13 3D'
+ '51 D6 C1 37 36 57 36 A0 56 D6 2E 1A 34 99 DC 75'
+ 'CE 25 25 E8 6B 25 CE EF EF EF 25 E8 EF EF EF CE'
+ '25 6B CE 25 CE CE 0F 25 25 25 CE 6B 0F 09 37 13'
+ 'D0 2D D0 C3 D0 10 2C 10 C3 C8 D0 F3 F3 33 F7 FD'
+ '79 31 F4 8A 11 3B AB 31 A4 1F 1F 8D 5B 5B 6D 2D'
+ 'AA C3 56 57 3E 0D 7B 1A 36 EA A0 2E 1B 2A 83 78'
+ 'E7 E7 6B EF 25 E8 6B CE 6B 25 E8 EF CE 7D 25 25'
+ '85 CE C2 75 0F C2 E7 E7 25 E7 CE 6B 2B 34 C1 3D'
+ '51 10 D0 D0 10 D0 10 10 C3 D0 51 2D 08 D1 19 F7'
+ '46 31 46 FE FE 45 D3 6A AB 1F 31 3F 3D 0C DD 59'
+ '21 C3 4E D6 C1 5F 58 12 56 36 D6 A0 D5 19 88 1B'
+ 'CE 25 E7 25 25 25 EF E8 25 00 25 6B EF 25 6B E8'
+ 'CE CE 75 C2 75 7D 0F 25 6B 25 0F 0F F2 09 0D D0'
+ 'D0 2C 10 16 D0 DB D0 C3 08 10 2D F3 FD 33 3D F7'
+ '31 31 0A F4 B8 45 1F 55 55 D3 FD F3 5E 0C 6D D1'
+ '51 4E 10 2E 1A 57 53 37 DA D6 A0 CA D5 2C B6 3E'
+ 'E7 25 6B CE EF E8 6B 25 EF 6B E8 25 6B E8 25 E8'
+ 'EF CE 0F 7D 0F CE CE E7 47 25 47 47 D5 61 36 D0'
+ 'C8 10 2C 10 D0 DB C3 C3 51 13 13 08 FD D9 D4 F7'
+ '46 D3 F4 31 2A 45 55 CC 8A 1F C0 0C D4 C0 F8 AA'
+ 'A9 36 1A 56 57 57 DA 32 C6 57 57 36 B3 D2 B6 0D'
+ '6B 6B 6B EF 6B 6B E8 6B EF 25 25 EF CE E7 00 25'
+ '6B 6B 25 CE 25 CE 25 0F 25 CE 0F 2B 53 D5 C1 10'
+ 'DB C3 C3 10 C3 D0 D0 D0 C3 C8 D0 F3 FD 29 F7 19'
+ '46 31 0A FE FE 45 CC EE 96 B8 8A EC EC 0C 6D 59'
+ '52 52 1A 57 36 DA 5D 7E 14 57 0D CA 3E 92 88 51'
+ '47 0F CE CE 6B 25 25 EF 25 25 EF 7D 25 25 6B 25'
+ 'EF CE CE CE E7 CE 47 47 0F 3C 47 E2 09 D5 36 C3'
+ '10 D0 2C 41 DB D6 10 2C D0 51 51 51 D1 D9 F7 1F'
+ '46 8A 2A FE FE 45 55 D3 D3 B8 1F 8D 0C 6F 1C 3D'
+ '52 36 4D 36 2E 0D C1 40 D5 37 3E 7B 70 32 17 29'
+ '0F 6B CE CE 25 25 25 EF EF CE 7D CE EF EF 25 6B'
+ '6B 25 EF 75 E7 E7 C2 CE 47 47 E2 05 BD 09 DB 10'
+ '10 10 10 10 D6 10 10 10 D0 51 13 08 F3 3D 33 F7'
+ 'D3 31 2A 11 45 1E 55 AF 8A 18 CC EC 22 0C 6D 54'
+ '52 4E 56 56 36 36 39 3E 40 7B 20 37 7E E2 93 31'
+ '47 CE 7D 25 0F 25 7D 25 CE CE EF 6B 7D CE CE 6B'
+ '25 7D 6B 25 E7 C2 47 75 2B E2 2B 1B D7 D5 1A 10'
+ '41 D0 2C 36 DB 41 DB A0 51 13 D0 62 2D 3D F7 F7'
+ '46 31 F4 F4 11 45 4C 8A 1F AB 31 CC 79 68 3D C5'
+ 'AA 52 CA 1A 1A 36 1A 57 C1 0D 7E D7 5F 78 E5 98'
+ '75 47 E7 0F CE CE CE 25 0F 7D 25 EF 25 25 25 EF'
+ '25 6B 6B E7 E7 75 75 2B F9 C2 2B BB 67 37 41 36'
+ 'DB 36 41 2C 10 10 10 10 D0 51 D0 62 D1 F3 C0 46'
+ '46 0A 2A F4 FE 1E B8 AF 8A 55 FE EE 0C 68 6D C5'
+ 'AA 10 52 77 A0 56 36 57 0D 1A 1A 40 70 2B 28 CD'
+ '78 E8 CE 25 7D 25 EF 75 7D 6B 0F 7D 25 6B E8 25'
+ '25 CE CE C2 75 C2 E2 E2 C2 C2 05 D5 09 37 C3 12'
+ 'C1 36 1A 36 D6 D2 36 10 C3 51 D0 08 D1 FD 29 33'
+ 'F7 F4 8A 2A 11 FA AF D3 6A 1F AB 8D 0C 3D 6D 3D'
+ '51 10 C3 10 56 D6 36 57 36 1A 0D 1A DA AC 80 DF'
+ '75 CE CE CE 25 6B CE 25 CE 0F CE 0F CE CE 0F 0F'
+ '25 7D 0F 75 75 78 C2 2B 47 E7 2B 1B 34 53 36 A0'
+ 'E3 DB D2 0D C1 D2 D6 D0 10 10 21 62 F3 29 FD D4'
+ '46 31 F4 9D 11 1E D4 C0 6D 0C 29 D1 F3 2D 3D 54'
+ 'A9 C3 52 51 10 36 A0 10 CA 56 D6 36 40 AC 29 27'
+ 'AD CE 25 7D CE CE CE 7D CE CE 7D CE CE CE 25 25'
+ 'CE 75 0F 7D C2 2B E2 47 47 CE 2B CB F2 D2 E3 D2'
+ 'C1 D6 73 DB 36 39 36 D2 10 C3 D0 C8 29 F3 FD D4'
+ '19 D3 8A B5 11 1E 55 31 EC 79 46 C0 A5 1C 29 0C'
+ '13 A0 21 62 21 56 10 10 0D CA 56 56 2E AD 4E 76'
+ '7A 25 25 7D 25 CE 25 75 C2 72 CE 75 CE 0F 7D CE'
+ '25 7D C2 75 72 AC C2 E7 E7 47 2B 1B AD 0D C1 E3'
+ '36 D2 36 73 2F D2 39 36 0D 10 C3 C3 62 3D FD 33'
+ 'F7 46 0A 2A 2A 45 B8 AF 8A D3 79 79 79 3D F3 6D'
+ 'D0 52 10 13 13 10 10 2E EA D6 57 1A 74 7A 39 49'
+ 'C4 E7 6B EF C2 0F 0F C2 C2 CE CE CE 72 CE 6B E8'
+ '75 75 CE 75 05 05 C2 0F 0F E7 2B 09 32 0D 36 0D'
+ '36 0D C1 D2 DB D6 D2 D2 C1 36 10 C8 D1 D1 08 FD'
+ 'D4 31 31 F4 11 1E 11 FE 2A D3 55 B8 EE D1 D1 21'
+ 'A0 56 36 10 EC 52 D6 52 56 C3 CA 57 CA 34 AD 8F'
+ '36 CE CE 47 25 6B 75 75 72 CE 0F 75 CE 75 0F C2'
+ 'CE CE 75 C2 75 75 47 47 25 6B 05 CB 32 36 36 D2'
+ '36 C1 D2 C1 0D D2 36 D6 10 10 A0 C3 62 08 FD FD'
+ 'F7 46 31 31 2A 11 11 D3 23 EC EC B8 C0 0C 5C 52'
+ '4E 10 1A 36 3D 3D 52 36 10 56 56 36 D6 FB 7A 91'
+ 'D1 47 7D 0F CE 72 C2 C2 0F 75 75 75 75 72 0F 25'
+ '75 75 0F 0F 2B E2 2B 0F E7 0F F2 CB 32 C1 1A 2F'
+ '40 0D C1 DB 0D 1A D2 E3 D2 DB D0 C3 51 62 FD FD'
+ 'F7 46 8A 8A 11 1E 1F 68 68 8D 22 3D 6D F8 52 10'
+ '1A 36 36 77 56 21 A0 D6 D6 DB 36 D6 56 73 E2 66'
+ '46 C2 CE E7 C2 CE 72 72 05 72 4F C2 72 75 CE 7D'
+ '0F 0F 75 75 4F E2 2B C2 0F 47 F2 34 1B D2 36 D6'
+ 'D2 2F E3 36 D2 2F 0D 36 C1 36 C3 C8 62 2D 29 D4'
+ 'FD D4 F7 46 F4 11 EE CC EE 8A EE C0 0C 51 21 10'
+ '36 56 56 10 36 51 10 56 1A 57 1A 36 56 70 E2 EB'
+ 'AF 75 7D 0F 0F 75 72 72 72 75 72 75 72 72 0F 0F'
+ 'C2 0F 75 05 72 E2 C2 0F 0F C2 F2 F2 53 41 C1 C1'
+ '2F E3 C4 0D 0D 10 D6 10 2C 1A C3 EA D0 3D 29 FD'
+ '33 46 0A 0A FE 99 CC EC E0 AB CC 0C 6F 59 52 EA'
+ 'C3 52 1A A0 10 56 B9 1A 56 57 10 CA A0 7E 2B F4'
+ '48 C2 CE E7 0F 25 C2 75 C2 72 4F C2 72 72 7D 75'
+ '75 72 4F BB 1B 05 C2 E7 F9 2B 1B 1B C4 36 D2 C1'
+ '36 73 0D 0D 0D D2 C1 D2 10 D2 D0 C3 51 D1 F3 FD'
+ 'F7 F7 79 F4 45 28 EE 8D CC 11 EC 0C 6D A5 52 52'
+ 'A0 A9 4E 36 CA 36 A0 4E CA 1A 1A CA CA DA E2 33'
+ '04 75 6B CE 0F 75 72 72 4F 72 72 75 75 72 CE 2B'
+ '72 4F CB 4F 72 AC C2 47 C2 E2 1B 1B 2F 1A D2 36'
+ '36 C1 D2 C1 36 DB 41 DB 10 41 C3 51 62 62 2D C0'
+ '19 1F 31 D3 FE 99 6A 6A EE AB 23 C0 F8 0C 6D 52'
+ '56 52 A7 36 5D 52 2E 10 57 36 2E A0 5C 39 F2 13'
+ '27 E2 0F E7 CE C2 C2 72 72 72 72 75 72 72 4F 72'
+ '72 BB 69 70 1B 05 2B 0F 47 05 D5 F2 C3 36 D6 36'
+ '0D 36 D6 D6 D2 36 D6 DB D6 10 10 51 51 2D 2D 29'
+ 'D9 D4 46 31 45 11 5E 22 6A 96 55 22 6F A5 13 52'
+ '10 C3 56 36 CA EA 56 21 21 AA A9 2C 3E D7 F2 2F'
+ '91 5F 0F 75 0F 0F 72 4F BB 72 4F 72 72 AC AC 4F'
+ '69 69 FB 02 20 AD C2 C2 2B F2 CB 32 D6 10 DB D2'
+ 'D2 36 BF C1 D2 39 D6 DB C3 D6 D6 EA 51 F3 3D FD'
+ 'FD 19 F4 45 B5 45 EE 68 0C 0C CC 1F 68 6D A5 D1'
+ '68 4E 10 EA 5D 10 A0 EA 13 13 A0 5F 0D CA 7A 37'
+ '83 37 CE 25 CE C2 4F BB 72 72 BB 69 4F 72 69 BB'
+ 'BB 69 02 26 70 1B 2B C2 C2 F2 D5 05 1A 10 D6 DB'
+ '73 36 36 36 36 D2 C1 36 36 C3 10 C3 2D F3 D1 FD'
+ 'D4 F4 2A 31 2A 45 68 DD 6D 6D 6D 68 6D 6D F8 D1'
+ '13 C5 21 36 57 1A 36 36 52 EA 34 39 10 CA 34 1B'
+ '27 C1 3C 25 C2 75 05 4F 69 4F BB BB 69 69 69 69'
+ '69 FB 02 A3 FB F2 C2 C2 2B CB CB 7A 2F D6 C1 2C'
+ '0D D7 0D 40 C1 36 C1 0D 5D D6 2C D0 51 D1 F3 31'
+ '31 46 46 31 D3 B8 8D 0C 0C DD 6D 6D 6D 54 3D 51'
+ '10 36 10 DB 36 0D 0D 57 39 0D 0D 56 2E 36 CB AD'
+ '9C 10 47 6B 0F 05 4F 70 69 BB 4F BB 20 69 5F FB'
+ '20 B3 5F B3 67 05 47 2B 2B F2 CB 53 C4 D6 D6 1A'
+ '10 D2 39 58 C1 36 58 1A C1 D6 D6 A0 51 2D 62 3F'
+ 'FD D4 46 D3 46 FE 22 68 D4 5B 6F 3D 13 C5 13 D6'
+ '41 D6 10 56 C1 CA 1A 37 39 C1 A3 DA 1A D6 67 05'
+ 'C7 C0 47 0F C2 4F 4F B3 4F 20 20 1B FB 69 B3 3E'
+ 'F0 02 02 70 20 BB C2 CE 47 1B 1B 37 E3 36 0D 0D'
+ '10 10 D6 39 0D 41 7B D7 C1 C1 36 10 10 2D 62 29'
+ '29 F7 46 31 31 45 79 6F 6D DD 6D A5 13 21 51 52'
+ 'FF EA 52 1A 57 0D 0D C1 36 1A 0D 0D 1A D6 FB E2'
+ '2A 8C C2 CE 2B 05 CB 69 FB FB 5F 69 B3 02 B3 70'
+ '7E A3 7E B3 69 E2 47 C2 2B F2 32 37 0D 36 36 39'
+ '0D 0D 0D 39 C1 D2 C1 39 D7 39 0D C1 36 C3 D0 3D'
+ '29 D9 1F 1F 31 45 68 22 0C 6D F8 3D C5 51 C5 13'
+ '10 D6 52 41 C3 A0 52 5D D6 57 0D 7E 40 57 02 E2'
+ '3D E6 75 E7 05 20 20 FB 5F 3E 7E 20 7E B3 A3 DA'
+ '71 71 71 70 1B E2 0F C2 AD 34 32 C4 73 39 C1 39'
+ '73 58 36 D2 7E C1 1A DA C1 39 2F D6 D0 10 C3 08'
+ '3D 0C D4 31 0A 2A D4 68 6F 0C 6D 6D 54 C5 A9 13'
+ '36 36 2D 13 56 10 D6 DA 36 0D 57 7B 40 74 3E 2B'
+ 'DB 24 75 0F 72 1B 67 B3 02 70 02 02 7E 02 74 DE'
+ 'DE 8E DE 70 69 2B 47 C2 05 CB 34 1A 39 0D C1 CA'
+ 'D2 40 C1 0D E3 0D D2 0D D2 D2 73 0D D6 D0 62 62'
+ 'F3 19 79 79 79 8A 8D 68 C0 0C F8 54 3D A7 5C C3'
+ '36 7B 2D 51 10 52 10 D6 C1 36 74 0D 0D 51 7E 72'
+ '40 F1 AC E7 C2 CB 70 70 D7 7E 71 DE 8E 03 FF DE'
+ '4D B9 DE F0 1B E2 F9 E2 05 34 F2 0D 36 0D 36 0D'
+ '1A D6 C1 40 0D 36 36 40 40 C1 1A D2 1A 36 10 C3'
+ 'D1 FD 0C 19 31 2A EE 22 68 50 6D F8 AA A9 A7 52'
+ '53 C1 03 21 5C 10 FF 52 56 C1 0D 40 40 CA 36 05'
+ '34 E9 CB 0F 0F 1B 71 DA 8E 71 CA 03 F8 65 03 B9'
+ 'DA 8E DE 02 1B E2 47 2B AD D5 D5 D6 36 40 2F 0D'
+ '2F 36 0D 40 0D 36 5D 36 36 0D 1A DB 2C A0 C3 A0'
+ '29 FD FD D4 F4 FE 22 5E 68 A5 59 3D A7 AA 59 AA'
+ '7A 74 51 C3 52 13 5C 10 36 D6 57 A0 C1 4E FF 1B'
+ 'F2 5A 3E 25 0F 1B DA 2E 42 EA 8E 21 6F A7 8D 96'
+ 'DD 42 2E 26 1B 0F 47 2B 05 AD 53 DB D2 E3 1A D6'
+ '36 C1 7B C1 C1 C1 C1 36 DB 5D 3E 57 D6 10 51 51'
+ '2D 0C FD 33 33 1F 68 68 C0 6D 6D 59 59 FF 59 B9'
+ 'AD 56 C3 52 21 EA A0 10 5C 57 CA 56 0D 52 39 BB'
+ '05 98 CA 47 CE BB 74 71 A7 52 4D 21 3D 01 23 96'
+ '8A F8 1A 02 05 0F CE 2B F2 AD 37 10 2F C1 0D 0D'
+ '36 36 1A C4 40 E3 C1 C1 36 D2 58 C1 36 5D 21 51'
+ '51 E4 29 33 31 D3 EE 22 6F 6D A5 13 52 10 B9 A0'
+ '32 10 5C C3 A0 10 56 DB A0 36 1A 36 5D 36 2E 67'
+ '72 96 A9 0F 2B 4F B3 CA 42 FF 21 FF 6F 8D AB 18'
+ '18 1C 2E F0 F2 47 CE 05 1B F9 0D DB D6 36 0D D6'
+ 'D2 D6 A0 36 C4 DA 58 40 C1 36 36 73 10 D2 D6 51'
+ '51 2D FD 33 79 EC 8D 68 DD 6D F8 59 FF 21 59 56'
+ '7A 56 A0 57 56 2E 56 CA DE 1A 0D 36 CA 36 D4 67'
+ '2B 6D F6 47 25 72 5F DE 4D A7 C5 52 6F F8 22 96'
+ '8A 01 65 02 05 0F 0F 2B F2 E2 36 D6 A0 D2 10 C1'
+ '40 C1 41 41 0D 0D 39 C1 C1 1A 36 41 C1 10 4E A0'
+ '10 D1 2D 29 D4 D3 0C 0C 6D 3D A7 A9 21 AA 52 57'
+ '7E 57 1A 56 56 56 36 1A 56 57 1A 36 58 DE D0 FB'
+ '72 77 DD 75 CE 72 5F DE FF 94 6F F8 50 C5 4B 22'
+ '1F 23 DD F0 05 C2 0F 05 05 4A 36 10 D2 10 D6 10'
+ '0D 0D 39 40 A0 D6 39 36 7B 39 39 C1 1A A0 5D C3'
+ 'C3 3D D1 0C D9 33 5B 0C 6F C5 C5 52 52 42 59 7E'
+ '56 7B 40 40 7B 1A 1A 74 1A 57 57 36 DE 36 DA 67'
+ '05 02 E0 C2 E7 0F 7A 77 FF 6D F8 C5 0E DD 21 C5'
+ 'C0 6A 6F A3 2B CE 47 05 1B E2 1A 36 DB D6 10 D6'
+ '10 DB D2 C1 41 BF D2 1A 36 C1 36 41 C3 10 36 C3'
+ '2D FD D9 3F 1F 79 6D 54 A5 C5 13 A9 21 AA 10 C1'
+ '36 0D 7E 0D 7E BD 0D 1A DA 74 1A 36 1A 57 57 37'
+ '2B 69 0E 72 E7 0F 4F 70 8E F8 50 1F 6F 79 1C 1C'
+ 'DD F6 EA 70 C2 C2 47 2B 1B 32 D2 DB 36 36 DB 10'
+ '2C 10 10 36 D2 D6 C1 C1 C1 C1 36 5D 36 D6 D0 D0'
+ 'C3 08 FD 3D 33 D4 F8 3D 6D 54 C5 D1 A9 52 EA 4E'
+ '36 36 36 3E 5F 3E 40 0D 0D 5D 71 36 DE 1A 74 70'
+ '05 69 42 72 0F C2 05 5F 8E A5 68 E0 C0 22 50 33'
+ '0C F8 DE CB 2B C2 05 F2 1B 32 D2 C1 36 D6 D6 D2'
+ '36 C1 D6 10 DB 10 DB DB E3 2F 5D D6 A0 2E A0 C3'
+ '62 21 FD D4 3D 79 6F 6D 6D C5 6F 5C 4D 52 5C 56'
+ 'A0 DB 36 D2 58 53 58 0D E3 C1 1A 1A 7B 56 36 40'
+ '72 69 F5 69 7D CE 72 BB A3 A5 6F AB 55 CC 8A CC'
+ 'AF E0 FF CB 47 0F 2B 1B 34 37 D6 D6 D2 D6 DB D6'
+ '10 C1 DB 36 36 10 10 10 10 36 36 C1 36 10 2D C3'
+ '13 2D 29 D4 D4 46 6D 3D 3D A5 13 A9 52 77 B9 56'
+ '36 74 74 3E 3E 53 BD 7B 40 57 7B 7E DA 10 1A 1A'
+ '4F 4F DE FB 7D C2 0F BB B3 C5 8D 23 96 96 FA EE'
+ '23 18 42 CB 2B C2 2B F2 05 39 C8 10 10 DB 36 D2'
+ 'D2 DB 36 36 D6 10 DB 36 36 10 D0 10 41 36 D0 D0'
+ 'D1 D1 D1 D4 0A D3 C0 6F 3D A7 5C 52 10 A0 52 B9'
+ '1A 7B 7E C1 74 34 53 7B 3E C1 40 7E 58 57 36 71'
+ '4F 05 DE FB 47 0F C2 4F 70 A5 22 A4 6C E1 24 63'
+ '8A C0 F0 05 0F 47 E2 F2 32 39 D6 36 1A DB 2D D6'
+ 'D6 D6 36 0D D2 10 D6 36 A0 D2 D6 10 51 10 A0 D0'
+ 'D1 FD D9 46 EC F4 6D 3D 6D C5 4B AA C3 52 B9 77'
+ '1A 0D 0D 3E 0D C1 67 0D 7B 0D 57 DA 7E C1 DA 40'
+ '05 05 A6 FB 0F E7 CE 72 7E A7 23 06 6C 90 C7 90'
+ '6E A5 26 05 47 C2 05 1B 05 41 10 5D 36 36 D0 DB'
+ 'D2 0D 36 D6 C1 36 2F 36 D2 41 36 36 10 C3 D0 51'
+ '51 D1 79 31 79 D3 33 6F 6D 54 2D 5C 52 21 52 56'
+ 'A0 CA D6 CA 74 5D 57 1A 57 1A C1 57 D6 41 71 74'
+ '1B F2 69 20 0F CE 25 72 20 A7 A4 A8 5A 93 7C 87'
+ '60 5B FB 78 E7 C2 E2 1B AD 21 D0 D6 D6 D6 C3 D0'
+ '36 36 D2 36 0D 36 36 A0 D6 EA 10 10 2C C3 2D 2D'
+ 'D1 2D D9 D4 79 EC C0 0C 6F 54 1C C5 52 A9 B9 21'
+ '52 4E 2E 56 10 0D 0D 36 1A 1A 0D 57 D6 4E 1A 36'
+ 'CB 72 69 20 C2 CE 6B 72 69 42 23 A8 3A 17 17 27'
+ '24 DD B3 C2 25 2B E2 1B 34 2E C3 C3 C3 10 51 D1'
+ '10 A0 36 36 36 0D 36 E3 30 36 BF D6 C3 51 62 FD'
+ 'D1 2D 29 F7 33 79 79 0C AB EE 59 13 52 A9 AA 13'
+ '52 56 D6 56 41 56 36 CA 0D CA 1A 1A 1A DE 0D 1A'
+ '5F 05 69 69 C2 E7 0F 0F BB 71 5E 60 3A B6 49 17'
+ '64 6F 05 0F CE 2B E2 CB 34 5D 21 5C 10 57 D0 D1'
+ '36 DB 10 36 D2 D2 1A 0D 36 D6 D6 C3 D0 51 62 D1'
+ '2D D1 0C D4 79 31 5B 0C 8D 3D 59 52 21 3D C5 A7'
+ '52 A0 56 DB 1A 56 5D 36 CA 56 5D 57 57 57 57 DA'
+ '70 05 FB 70 72 CE EF 0F 4F 70 6F EB 7C B6 B6 CF'
+ 'BE A7 75 CE 47 2B E2 BB 34 A3 36 D2 57 0D D6 95'
+ '2D D0 41 36 DB 36 41 10 D0 A0 10 10 C3 D0 51 D1'
+ 'D1 6D 29 D4 19 31 68 C0 C0 6D 3D 3D 13 54 A5 A7'
+ '52 10 D6 36 D6 36 36 57 CA 57 57 74 7B 57 1A 0D'
+ 'DA 72 70 F0 4F CE 6B CE 4F 7E DD 60 7C 88 88 CF'
+ '98 26 1D CE C2 75 AD F2 32 37 39 36 36 C1 58 D6'
+ '3D 2D D6 36 51 D0 41 DB 10 A0 10 C3 21 C3 51 2D'
+ '2D F3 D1 6D C0 EE 0C C0 5B 6F 13 51 C5 3D A7 5C'
+ '10 2E 56 A0 57 2E 74 57 57 57 1A 57 CA 36 A3 1A'
+ 'A3 E2 5F A6 72 75 CE E7 72 5F 65 6E 86 88 49 27'
+ 'DD 20 0F E7 0F 2B 05 BB 37 3E 7B 20 3E A3 40 0D'
+ '10 DB D6 D6 56 51 13 D0 DB D0 D0 10 51 13 2D 2D'
+ '3D 3D D9 D9 5B 79 0C 0C 6D 0C 3D D1 59 6D 59 AA'
+ 'A9 56 56 52 4E A0 36 1A 57 57 0D 40 57 36 0D 57'
+ 'DA 2B 69 0B 05 0F 25 25 C2 4F 4D 96 DF B6 B6 DC'
+ 'A7 7A C2 E7 C2 E2 7A 05 53 3E 20 5F 14 C6 7B D6'
+ '36 D6 57 D2 36 D0 2C 13 13 C5 13 5C D0 2D 3D 29'
+ '29 29 5B 6D 5B D4 C0 0C 0C 54 A5 13 6F 6D C5 C5'
+ '52 10 36 57 B9 5C 36 36 56 74 CA 1A 1A 74 1A 1A'
+ '74 72 1B 94 67 0F 25 6B 0F BB 4D 96 49 B6 17 EE'
+ '5F C2 E7 CE 2B E2 F2 BB 3E D7 53 34 20 5F 5F 36'
+ '57 36 D6 1A 40 57 EA D0 C5 F3 D0 3D D1 62 0C 62'
+ 'F3 3D 29 0C 79 79 0C 6F 6D 6D A5 54 6D 6D C5 A9'
+ '52 56 57 0D 77 B9 77 36 56 36 2E 56 1A 1A 1A 57'
+ '71 05 F2 F6 FB E7 47 25 E8 72 A3 6A E9 64 8D 74'
+ 'AC E7 E7 CE 2B 1B F2 AD 3E 3E 5F 20 12 5F BD C1'
+ '0D 57 10 56 5D 1A 56 EA 13 D1 D1 3D D0 62 13 2D'
+ 'D1 6D D1 D4 D4 5E 22 C0 6D F8 3D 2D C5 C5 59 A5'
+ 'A0 56 5D 57 4E B9 10 CA 57 CA 77 2E 5D 56 36 1A'
+ '0D BB 1B 84 69 C2 CE E7 25 CE 3E 42 6D FF 71 69'
+ '0F 25 EF CE F2 FB CB 7A 7E C4 74 BD 7E 3E 3E 74'
+ '57 0D 57 E3 56 A0 1A 56 10 5C 2D 33 2D 6D D1 3D'
+ '51 3D 6D FD 0C 1F 0C 6D DD 6F C5 6D 54 6D 6D A7'
+ '56 36 36 10 EA EA B9 56 77 56 10 2E 56 A0 A0 2E'
+ '1A 1B CB 01 5F CE E8 25 E8 6B BB DE 0B 70 5F 72'
+ 'E7 E7 25 0F D5 F2 1B 7A 0D 3E 40 3E 3E 7B 7B 3E'
+ '3E 7E 7E 3E 0D 74 36 56 10 C3 52 D1 51 95 5B FD'
+ 'FD 33 D4 5B 79 D4 0C 6D 22 6F D1 D1 F8 6D A5 3D'
+ '10 52 EA EA 52 52 52 A0 10 10 A0 C3 56 A0 10 56'
+ '40 5F BD 04 70 E7 0F E8 EF 25 BB A3 84 59 70 BB'
+ '75 25 6B E7 F2 BB AD BB 7B 40 3E 20 0D 3E 58 37'
+ '3E 3E 3E 3E 20 3E 74 58 57 A0 5C AA 13 13 29 33'
+ '0C 5B D4 FD 33 D3 68 6D 29 6D AA 54 6F DD 6D 54'
+ '1A 52 56 2E AA A0 A9 AA 51 51 21 52 52 52 10 56'
+ '7E 67 2F 76 FF 47 CE 25 6B 2B 71 E6 27 17 98 8E'
+ 'C2 25 CE 25 2B 1B 1B 7A 7B 3E 7E 57 40 3E 0D 7E'
+ '3E 39 7E 37 20 3E 58 7E 74 74 EA 51 62 13 3D D4'
+ 'D4 29 D1 3D C0 D4 F8 29 2D A5 54 54 6D 6D 6D 52'
+ '0D 56 A0 52 52 4E 21 2C 5C 51 52 EA 52 A0 FF 1A'
+ '5F 73 51 35 21 0F CE CE E7 69 42 17 8B 8B C9 4D'
+ '78 E7 6B CE 0F F2 1B 7A 58 1A 7B 0D 58 40 3E 58'
+ '58 7E 3E 3E B3 5F B3 3E 3E 57 57 74 C5 13 2D 2D'
+ 'D4 79 79 5B 5B 79 C0 6F 6F F8 6D A5 6D 0C 68 6D'
+ 'B9 77 77 56 56 77 CA 56 EA 52 52 4E 56 36 A0 C1'
+ 'BD BD 3D C9 40 F9 47 0F 25 72 3E 68 60 E6 ED 70'
+ 'C2 CE CE E7 25 05 AD C6 58 74 0D C1 B3 D7 3E D7'
+ '71 7B 71 58 3E 3E 7E 3E 3E B3 3E 74 10 10 13 3D'
+ '29 3D D4 31 31 CC 6D 6D 6D 6F 54 6D 6D 6D 6D A9'
+ 'A0 52 A0 56 DE 41 4D 56 1A 4D 56 5D 4D 1A DB 36'
+ 'B3 1B BB D7 E2 CE CE E7 0F 0F 2B 1B BD B3 5F BB'
+ '0F 47 CE 25 E7 32 CA 7A CA 36 CA 1A 57 57 7B 74'
+ '7B 7B 57 74 40 7B 7B 58 7E 0D 74 7B 57 B9 B9 AA'
+ '54 0C 6D D4 EE EC DD 54 6D 59 59 6D 6F 6D 6D A7'
+ '52 52 56 10 56 EA 77 4E CA 77 7B 1A 57 D6 57 D6'
+ 'D5 2B F9 47 47 47 25 7D E7 E8 6B E7 47 E7 47 E7'
+ '47 6B 47 25 0F F2 C0 7A 36 4D 56 41 10 D6 57 1A'
+ '0D 0D 0D 57 1A 7B 40 0D 57 57 36 57 0D 36 CA EA'
+ '51 2D 5B D9 D4 D3 6D 6F 59 A7 A9 59 54 6D 6D A9'
+ '5C 10 21 A0 56 57 56 77 A0 56 0D 74 0D 77 1A 02'
+ '67 AD C2 E7 47 CE E7 25 25 6B 25 E7 6B 7D E7 E7'
+ 'CE CE E7 47 47 C2 34 1B 37 4E 10 CA 56 36 56 56'
+ 'DB CA 36 1A 36 56 56 1A CA 1A 36 5D D6 CA 56 56'
+ '2E 5C D1 0C 33 8D 6F A5 A7 52 52 59 59 59 AA 52'
+ 'B9 DE A9 52 10 56 4D 4E 77 DE 36 57 57 CA 3E 73'
+ '02 C1 F2 2B D5 40 C1 D2 C3 41 36 C1 39 37 37 D7'
+ '3E 34 34 CB E2 E2 05 67 34 FF 5C 10 36 A0 10 56'
+ 'EA 56 36 4E 2C 10 4E 36 56 56 4E CA 56 56 4E C3'
+ '52 C3 52 D1 54 EE 59 54 A5 5C A7 A7 59 A7 B9 B9'
+ 'B9 56 77 77 52 52 C3 10 36 10 74 1A A0 10 4D 70'
+ 'AD 2B 2B 1D 6B 6B 7D 25 E8 E7 6B 6B 6B E7 E7 25'
+ '78 47 75 C2 05 F2 1B 34 39 52 A0 4D A0 36 36 1A'
+ '56 36 4E A0 DE 56 2E EA 10 52 10 56 56 56 A0 52'
+ 'C3 52 13 D1 2D 5B A5 6D 54 59 59 94 59 65 A9 B9'
+ '56 B9 4D 56 56 52 52 AA 5C 4E 56 36 A0 1A 2E 21'
+ 'D5 F9 32 47 47 C2 E7 CE 47 75 AC 14 14 92 37 7A'
+ 'AC E2 75 47 2B E2 BB BB 56 52 56 56 36 56 56 36'
+ '36 57 B9 36 57 4E 36 56 36 4D 52 2C 52 A0 52 52'
+ 'EA 13 59 2D 59 3D 59 6F 59 A5 59 59 59 A9 A7 52'
+ 'B9 56 56 77 4D 56 B9 A9 A9 52 10 36 52 56 A0 56'
+ '70 DA 21 1B 2B 47 47 47 CE E7 47 47 47 47 E7 CE'
+ 'CE 0F 47 47 2B C8 51 32 A0 A9 52 A0 A0 A0 36 2E'
+ 'A0 E3 1A 36 36 36 56 10 10 10 5C C5 2D A0 56 EA'
+ '52 D1 4B 5C 13 2D 59 6D 0E A5 54 A5 59 59 A9 52'
+ '4D B9 4D 56 77 57 56 B9 B9 A0 56 10 42 13 36 71'
+ 'BD E2 E2 C2 47 3C E7 6B E8 EF E8 6B 47 6B 7D B7'
+ '7D 1D CE E2 32 15 CF CB D7 52 10 10 EA A0 4E 56'
+ '5D 56 A0 D6 52 A0 13 A0 5C 51 A9 C3 4B AA 5C C3'
+ '52 21 52 5C 59 3D 59 A5 6D 65 6D 6D 6D A9 A9 4D'
+ 'B9 B9 56 56 56 56 4D 36 52 B9 A0 56 A0 5C 10 DA'
+ '67 2F 39 2B C2 C2 7A D2 10 2D 29 D9 46 D4 33 0C'
+ '3D EA 39 BB 05 37 46 67 32 42 5C 52 10 C3 36 5D'
+ '74 4E 4E 77 52 AA 5C 52 52 52 A0 52 D0 52 2D 52'
+ '4E EA 52 21 52 C5 0E 6D 6D 59 59 A5 A9 59 A9 B9'
+ '52 B9 52 56 B9 77 56 4D 52 B9 77 1A 56 A0 2E 57'
+ '05 E2 E2 47 E7 B7 47 E7 6B E8 85 E7 6B E7 7D E7'
+ '0F 47 7D 47 E2 05 34 D5 37 13 62 21 52 4E 56 53'
+ '0D 57 77 57 56 1A 52 5C AA 10 52 13 D0 5C 5C 13'
+ 'C3 77 AA 13 52 AA 6D 6D 6D 0E 59 59 59 A9 A9 52'
+ '52 52 52 56 56 77 5D 56 B9 56 B9 56 77 77 77 57'
+ 'BD 32 D0 4A CE CE 75 75 75 32 53 C4 2F DB 2F 34'
+ 'AC 75 C2 47 C2 E2 BB 34 10 D1 3D 51 51 4D 0D 58'
+ '2E 5D 56 36 1A 57 DE B9 A0 A9 52 52 21 21 21 51'
+ '54 2D C5 5C A9 13 6F ED 6F 6D 6D 6D AA 65 A9 A9'
+ '5C 52 56 56 56 56 4D 57 4D 5D B9 10 56 36 0D DA'
+ '02 34 2E C2 E7 3C 7D 85 E7 E7 E7 7D 7D E7 E7 B7'
+ '47 7D 47 7D 2B D7 29 34 52 C5 2D 1C 54 10 E3 56'
+ '4E 77 56 2E 57 5D 5D 36 1A CA 21 2D 13 13 13 AA'
+ '62 1C 2D 6F 3D 5B 68 68 8D ED 6D A5 59 59 59 B9'
+ 'A9 56 52 56 B9 B9 4E 56 B9 A9 A0 56 56 56 4D 57'
+ '67 2C B0 32 E7 47 E7 47 78 9F 92 92 12 9F C6 7A'
+ 'AC 32 75 47 E2 67 F8 BB DA 10 52 AA 54 5D 57 77'
+ 'B9 56 57 57 56 57 56 56 56 10 52 52 2D 52 54 C5'
+ '59 D1 5B 54 6D 0C 8D 68 DD 6D A5 59 59 A9 AA A7'
+ 'A9 B9 56 B9 4E 4E B9 56 56 52 4E 56 56 52 B9 7E'
+ 'BB 65 CC 7A 47 F9 75 BB 39 0D 0D C1 58 53 34 C6'
+ '7A 34 F2 78 2B AD CB B3 53 56 1A B9 A9 36 56 57'
+ '56 B9 A0 5D 77 B9 56 56 56 A0 52 56 A7 5C 13 13'
+ '13 C5 5B 6D C0 5B EE 6A EE 6F 59 59 A5 59 52 A7'
+ '52 52 52 B9 56 B9 56 4D 56 FF B9 57 52 B9 56 77'
+ '05 78 F9 3C 6B 6B E8 3C 7D B7 CE 7D 6B 47 47 7D'
+ '0F 47 E7 47 E2 F2 D5 D5 7E 56 52 10 56 57 56 56'
+ '77 77 57 B9 56 5D 52 EA B9 A0 52 21 52 FF A7 AA'
+ '59 13 54 54 5B 5B 55 EE 22 68 6F 6D 59 A7 59 C5'
+ 'AA 52 5C 56 52 52 52 B9 A0 52 52 56 B9 B9 B9 52'
+ '58 AD 37 7A 7D E7 6B 3C E2 5F 5C AE D9 79 52 34'
+ 'AC 1D 7D F9 2B 32 7A D7 5C 10 52 CA 56 77 56 56'
+ '56 10 56 56 56 52 52 52 A9 5C 5C 52 52 4E 10 10'
+ '4D 52 2D 54 5B 6D 6A 23 CC EE 6F 54 6F 6D AA AA'
+ '59 59 52 52 B9 42 52 FF 5C 52 B9 52 52 52 2C B9'
+ 'FF B3 CD 98 E2 7D E7 47 E2 CA 5A 6C CC B9 20 E2'
+ 'C2 05 4A 75 F9 F2 34 1A A5 AA 4D 52 B9 52 B9 56'
+ 'B9 57 5D 4E B9 A0 52 52 52 A9 C5 13 AA 3D 5C 1A'
+ '5B AA 59 AA 6D 5B AB 5E 8A EE A5 6D A5 54 6D C5'
+ '59 59 52 52 52 52 AA 21 59 52 52 AA 52 5C B9 FF'
+ '10 3E CF 60 E2 F9 6B 7D AC 57 92 AC 1D AC 34 B3'
+ '1B 1B AD 4A E2 BB D5 C1 A7 AA A9 5C 52 52 AA B9'
+ '4E 56 77 52 B9 10 A9 52 4E 52 AA 52 59 59 5B 59'
+ '5B 56 2D 0C 6D 0C D3 CC CC 68 68 68 54 65 59 2D'
+ '6F A7 59 AA 5C 52 AA A9 AA AA 52 A9 52 A9 AA AA'
+ '52 1A 88 38 AC 7D 7D E7 75 78 75 78 78 1D 75 7A'
+ '61 D5 05 E2 E2 34 D5 D7 A9 52 A9 52 5C 4E A9 56'
+ '56 2C B9 EA 52 52 B9 52 AA 13 C5 C5 54 51 C5 59'
+ '13 2D C5 3D 0C C0 55 96 AB 0C 33 0C F8 54 2D 59'
+ 'AA 59 54 A9 59 59 59 A5 54 AA 2D C5 2D 54 3D C5'
+ '10 D2 76 6A 78 E7 85 B7 78 47 0D 36 7B 02 05 78'
+ 'F2 D6 D7 4A 4A CB BD 3E 5C A9 52 52 B9 B9 CA 57'
+ '56 B9 FF 52 A9 5C 52 A9 51 A9 13 AA AA A5 A9 D1'
+ '54 6D 6D 59 0C EE B8 55 23 33 68 8D 6D 6D 59 59'
+ '59 6D 2D 6D 6D 59 2D 6D 6D 54 6D 0C 54 6D 54 6D'
+ 'A7 7E 76 DD E2 B7 75 AC 75 AC C1 36 7E 39 D5 4A'
+ 'AC C1 79 32 F2 09 D7 58 A7 5C B9 2C 56 56 56 56'
+ '56 77 B9 5C 52 5C 5C 52 AA AA 5C 5C 5C AA 2D 59'
+ '6D 0C 0C 5B 95 33 6A AB EE EE C0 EE 0C DD 59 59'
+ '5B 6D 6D 6D 0C 54 DD AA AA 2D 54 3D 13 3D 3D 3D'
+ 'AA 7A 0C 77 78 78 58 E2 78 32 7B 7B 0D 58 3E 34'
+ '67 DA DE 05 1B 53 BD 58 59 AA 5C B9 52 36 4E 4E'
+ '52 41 52 52 A9 52 A7 A7 AA 59 AA 21 59 C5 54 54'
+ '95 5B 97 68 29 5E 1F EE EE 6A 6D 68 1F 22 F8 C5'
+ '6D 6D 5B 68 5E 3D 6D 2D 59 AA 52 52 A9 AA AA AA'
+ 'AA 7A 32 32 78 1D 4E AD AC 78 0D 5D 40 7E BD 8E'
+ 'EE 01 7E CB C6 5F 34 10 C5 54 54 AA B9 52 52 52'
+ '4E B9 B9 52 52 5C 52 5C 52 52 52 5C 52 AA F8 6D'
+ 'C0 5E C0 68 EE 55 6A 6A 22 5B 0C DD EE 68 EE 6D'
+ '54 6D D4 68 6A AA AA 54 AA C5 54 6D 6D 2D 5C A7'
+ 'C5 58 4A AD 1D 47 AD AD 32 AC 7A 58 C4 53 1B 1A'
+ '60 4B 09 09 D5 34 53 6D 59 54 3D 5C 52 10 52 B9'
+ '10 52 B9 2C 5C B9 52 B9 10 2D 13 59 54 59 95 5B'
+ '95 5B 33 C0 97 8A AB 68 22 22 68 5E 68 5E 68 5B'
+ '6D 5B 5B 31 5E 59 AA 54 3D 54 2D 54 2D C5 A9 AA'
+ '13 52 AC 78 78 1D F9 78 AD 80 11 34 AC 4A 4A D7'
+ 'C5 7A 34 34 BD 34 51 6D C0 5B 59 13 5C 5C 52 52'
+ 'A9 AA AA 52 52 52 52 A0 13 AA A9 13 2D AA 3D 54'
+ '6F 5E 0C D9 AB 8A 68 22 68 68 6F 6A 6A EE EC 8D'
+ '0C 0C EC 68 2D 6D C5 59 C5 2D AA 59 59 AA 62 A9'
+ 'A7 54 41 AC 4A 1D 7D 7D 32 AB 64 3E 78 AD 53 40'
+ 'BD D5 34 BD 7A C3 D1 5B 5E 5B 54 3D 59 13 A5 AA'
+ '54 C8 B9 2C 10 52 52 5C 21 C5 13 5C 54 59 2D 5B'
+ '5B EE D4 EC EE B8 5E 0C 6D 5B 6A 6A EE CC CC 31'
+ '6A 33 22 6D 59 AA 54 6D 54 3D 54 6D 3D 6D 59 13'
+ 'AA 54 2D 41 AC B1 14 78 78 32 3E C6 D5 58 7B D5'
+ '34 D5 7A C6 13 5E 8D 0C 29 3D 6D 3D 6D 6D 5B 5B'
+ '54 59 2D 5C 59 5C AA 52 AA AA 5C 62 6D 54 3D 5B'
+ '5B 5B 68 EE 6A 1F 68 6F 6D 6D 6D 33 33 1F EE 5E'
+ 'EE EC 68 2D 2D 5C 3D AA 59 54 59 6D 6D 95 6D 54'
+ '5C 54 59 6D 13 12 AC 1D 78 78 75 B1 32 AC AC 32'
+ '32 14 E3 54 0C 55 1F 55 1F EE C0 EE D4 EE 5B 6D'
+ '54 6D 6D 54 6D 54 54 2D 54 54 AA 59 29 54 5B 68'
+ '68 5E 23 55 EE EE 5E 6D 0C 0C EE CC 1F EE 5E EE'
+ '1F EE 33 AA 5C AA 5C C5 59 AA AA 2D 59 54 AA 3D'
+ '54 2D 2D 5B 6D 5B 41 C6 78 1D AC 75 78 AC AC 7A'
+ '58 13 54 68 5E 5B EE 5E 68 5B 97 0C 0C 5E 5E 0C'
+ '0C 6D 6D 6D AA D9 6D 6D 54 54 54 2D 5E C0 5E 0C'
+ 'EC EC D9 5E 33 EE EC 68 1F 6A 4C 55 EE 1F 29 5B'
+ '5B D9 6F 54 C5 59 59 2D 2D 54 6D 6D 6D 2D 59 54'
+ '6D 6D 6D 0C 5B 54 5B 54 10 36 BF 30 2F BF 10 AA'
+ '54 68 2D 5B 0C EE 33 5E 33 5B C0 EE EC 5E 97 6A'
+ '33 33 68 5E 0C EC 5E 1F EE 68 0C 5E EE 55 31 2A'
+ '31 EE AB 31 1F 0C A4 A4 55 6A CC 6A AB EE D4 8D'
+ '6A 96 55 0C 5B 5B 6D 54 6D 5B 2D 2D 2D 54 5B 6F'
+ '33 5B 0C 6D 5B 6D 6D 54 D9 5B 6D 54 59 AA 62 6D'
+ '5B 5B 5E 5E 68 33 0C EE 8D 5E 55 EE EE EE 5E CC'
+ 'EE 31 EC EC 8D EE 1F 1F EE 55 55 97 6A A4 AB AB'
+ '8A B8 96 11 96 8A B8 4C 96 96 AB 96 AB 6A EE 55'
+ '55 A4 AB 31 EE 33 0C 5B 5B 6F 5B 5B 3D 0C 5B 5B'
+ '5B 6D 5B 97 6A 0C 33 C0 5E 68 68 0C 68 33 5E 22'
+ '33 D4 EE 1F EE 8D 6A EE 31 55 55 55 8C 8A 55 8A'
+ 'D3 AB CC 55 8C 8A 55 55 55 55 6A 11 96 55 4C 6E'
+ 'A4 11 63 4C A4 4C 13 AA 5C AA 51 AA 10 5C 41 52'
+ 'DB 2D 2C DB DB DB 4E DB 41 BF DB 36 5D 2F D2 5D'
+ '41 DB D2 10 41 4E 41 DB DB 5D 36 D2 36 2F 36 41'
+ '4E 5D 5D 4E 36 7F 4E DB 10 5C 4E D0 AA 10 2C 5C'
+ '5C 4E 2C 10 D0 2C 5C 10 41 5C 10 C8 AA 2D 51 3D'
+ 'AA 3D AA 5C 13 D0'
+}
+
+MySaveAsDlg DIALOG 0, 0, 280, 163
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+CAPTION "Open"
+FONT 8, "MS Sans Serif"
+{
+ CONTROL "Look &in:", 1091, "STATIC", SS_LEFT | SS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 6, 41, 8
+ CONTROL "", 1137, "COMBOBOX", CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 50, 3, 138, 100
+ CONTROL "", 1088, "STATIC", SS_LEFT | WS_CHILD | NOT WS_VISIBLE, 188, 2, 82, 17
+ CONTROL "", 1120, "LISTBOX", LBS_NOTIFY | LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_MULTICOLUMN | WS_CHILD | NOT WS_VISIBLE | WS_BORDER | WS_HSCROLL, 4, 20, 272, 85
+ CONTROL "File &name:", 1090, "STATIC", SS_LEFT | SS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 166, 36, 8
+ CONTROL "", 1152, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 56, 164, 155, 12
+ CONTROL "Files of &type:", 1089, "STATIC", SS_LEFT | SS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 182, 46, 8
+ CONTROL "", 1136, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 56, 180, 155, 100
+ CONTROL "Open as &read-only", 1040, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 199, 74, 10
+ CONTROL "&Open", 1, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 222, 110, 50, 14
+ CONTROL "Cancel", 2, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 222, 128, 50, 14
+ CONTROL "&Help", 1038, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 222, 145, 50, 14
+}
+
+
Index: /gsdl/branches/nzdl2/gsinstaller/install.cfg
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/install.cfg	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/install.cfg	(revision 14219)
@@ -0,0 +1,6 @@
+CompanyName:FAO
+CollectionName:Humanity Development Library
+CollectionDirName:HDL
+CollectionVersion:1.0
+CollectionVolume:1
+ProgramGroupName:FAO Library
Index: /gsdl/branches/nzdl2/gsinstaller/launchApp.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/launchApp.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/launchApp.cpp	(revision 14219)
@@ -0,0 +1,57 @@
+#include "launchapp.h"
+
+#include "gsPlatform.h"
+
+launchApp::launchApp(FilePath &file)
+{	this->exeMap["default"] = file;
+}
+
+void launchApp::platformApp(string platform, FilePath &file)
+{	this->exeMap[platform] = file;
+}
+
+int launchApp::run(bool test, int deftest, string prompt, string header, bool wait)
+{ gsPlatform	platform;
+	FilePath		exePath;
+
+	if (test)
+  { // if user didn't want it then cancel
+  	if (MessageBox(0, prompt.c_str(), header.c_str(),
+    							 MB_YESNO | MB_ICONQUESTION | MB_SYSTEMMODAL |
+                   	 (deftest == 0 ? MB_DEFBUTTON1 : MB_DEFBUTTON2)) == IDNO)
+    {	return 0;
+    }
+  }
+
+  // get the executable for this platform
+  exePath	=	this->exeMap[platform.platformString()];
+
+  // if we didn't get it, get the default
+  if (exePath.isEmpty())
+  {	exePath	= this->exeMap["default"];
+  }
+
+  // couldn't find a path
+  if (exePath.isEmpty())
+  {	return -1;
+  }
+
+  // prepare process information fields
+  STARTUPINFO startup;
+  PROCESS_INFORMATION	process;
+	startup.cb				= sizeof(STARTUPINFO);
+  process.hProcess	=	0;
+
+	// execute the process
+  if (CreateProcess(exePath.cString(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &process) == 0)
+  {	DWORD	error	= GetLastError();
+  	return -2;
+  }
+
+  if (wait)
+  {	WaitForSingleObject(process.hProcess, INFINITE);
+  }
+
+  // success: return a positive number
+  return 1;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/launchApp.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/launchApp.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/launchApp.h	(revision 14219)
@@ -0,0 +1,20 @@
+#ifndef _LAUNCHAPP_H_
+#define _LAUNCHAPP_H_
+#include <string>
+#include <map>
+using namespace std;
+
+#include "FilePath.h"
+
+typedef map<string, FilePath, less<string> > _exeMap;
+
+class launchApp
+{	private:
+		_exeMap	exeMap;
+	public:
+  	launchApp(FilePath &appsrc);
+    void platformApp(string platform, FilePath &appsrc);
+    int run(bool test, int deftest, string prompt, string title, bool wait);
+};
+#endif
+
Index: /gsdl/branches/nzdl2/gsinstaller/manifest.cfg
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/manifest.cfg	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/manifest.cfg	(revision 14219)
@@ -0,0 +1,11 @@
+all:
+  {library} {collection}
+
+library:
+  gsdl.ini net32 net16 readme.html
+
+database:
+  collect\$(COLDIRNAME)\index\text\$(COLDIRNAME).ldb
+
+collection:
+  collect
Index: /gsdl/branches/nzdl2/gsinstaller/registry.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/registry.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/registry.cpp	(revision 14219)
@@ -0,0 +1,258 @@
+#include "registry.h"
+#include <stdlib.h>
+
+bool registry_createkey(HKEY key, const char *name, PHKEY keyout)
+{ LONG reply;
+	DWORD disposition;
+
+	reply = RegCreateKeyEx(	key, name, NULL, NULL,
+  												REG_OPTION_NON_VOLATILE,
+                          KEY_ALL_ACCESS, NULL,
+                          keyout, &disposition);
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_openkey(HKEY key, const char *name, PHKEY keyout)
+{ LONG reply;
+
+	reply = RegOpenKeyEx(key, name, NULL, KEY_QUERY_VALUE, keyout);
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_closekey(HKEY key)
+{ LONG reply;
+	reply = RegCloseKey(key);
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_keyExists(HKEY key, const char *name)
+{ HKEY local;
+
+	if (!registry_openkey(key, name, &local))
+  {	return false;
+  }
+  registry_closekey(local);
+  return true;
+}
+
+bool registry_ensureKeyExists(HKEY key, const char *name)
+{ HKEY local;
+
+	if (!registry_openkey(key, name, &local))
+	{	if (!registry_createkey(key, name, &local))
+  	{	return false;
+    }
+  }
+	registry_closekey(local);
+  return true;
+}
+
+bool registry_setstring(HKEY key, const char *name, const char *value)
+{ LONG reply;
+
+	reply = RegSetValueEx(key, (LPCTSTR) name, NULL, REG_SZ, (CONST BYTE *) value, strlen(value) + 1);
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_setlong(HKEY key, char *name, LONG value)
+{ LONG 	reply;
+	DWORD word;
+
+  word = (DWORD) value;
+	reply = RegSetValueEx(key, (LPCTSTR) name, NULL, REG_DWORD, (CONST BYTE *) &word, sizeof(DWORD));
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_setblock(HKEY key, char *name, char *data, int size)
+{ LONG 	reply;
+
+	reply = RegSetValueEx(key, name, NULL, REG_BINARY, (CONST BYTE *) data, size);
+  if (reply != ERROR_SUCCESS)
+  { // display_error();
+  	return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_setint(HKEY key, char *name, int value)
+{ return registry_setlong(key, name, (LONG) value);
+}
+
+bool registry_getstring(HKEY key, char *name, char **string)
+{ LONG reply;
+	DWORD type;
+  DWORD size;
+  BYTE  buffer[128];
+  int   tries = 0;
+
+  do
+  {
+		reply = RegQueryValueEx(key, name, NULL, &type, buffer, &size);
+  	if (reply != ERROR_SUCCESS)
+	  { //display_error();
+  		//sprintf(buffer, "%x {%s}", key, name);
+    	//MessageBox(0, buffer, name, MB_OK);
+	  }
+    tries ++;
+  } while (reply != ERROR_SUCCESS && tries < 3);
+
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+
+  *string = (char *) malloc(size);
+  if (*string == NULL)
+  { return FALSE;
+  }
+  strcpy(*string, (char *) buffer);
+  return TRUE;
+}
+
+bool registry_getint(HKEY key, char *name, int *out)
+{ DWORD type;
+	DWORD size;
+  LONG  reply;
+
+	reply = RegQueryValueEx(key, (LPTSTR) name, NULL, &type, (LPBYTE) out, &size);
+  if (reply != ERROR_SUCCESS)
+  {	return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_getlong(HKEY key, char *name, LONG *out)
+{ DWORD type;
+	DWORD size;
+  LONG  reply;
+  DWORD got;
+
+  size = sizeof(DWORD);
+
+	reply = RegQueryValueEx(key, name, NULL, &type, (LPBYTE) &got, &size);
+  if (reply != ERROR_SUCCESS)
+  { return FALSE;
+  }
+  *out = (LONG) got;
+  return TRUE;
+}
+
+int registry_getblock(HKEY key, char *name, char *data, int size)
+{ DWORD type;
+	DWORD lsize;
+  LONG  reply;
+
+  lsize = size;
+
+	reply = RegQueryValueEx(key, name, NULL, &type, (LPBYTE) data, &lsize);
+  if (reply != ERROR_SUCCESS)
+  { return -1;
+  }
+  return lsize;
+}
+
+bool registry_fetchlong(char *keystr, LONG *lptr)
+{ HKEY key;
+
+	if (!registry_openkey(HKEY_LOCAL_MACHINE, "Software\\Kudlian Soft\\ReTreeval", &key))
+	{ return FALSE;
+  }
+  if (!registry_getlong(key, keystr, lptr))
+  {	return FALSE;
+  }
+  if (registry_closekey(key) == FALSE)
+  { return FALSE;
+	}
+  return TRUE;
+}
+
+bool registry_fetchblock(char *keystr, char *data, int size)
+{ HKEY 	key;
+	int		read;
+
+	if (!registry_openkey(HKEY_LOCAL_MACHINE, "Software\\Kudlian Soft\\ReTreeval", &key))
+	{ return FALSE;
+  }
+  read = registry_getblock(key, keystr, data, size);
+  if (read < 0)
+  {	return FALSE;
+  }
+  if (registry_closekey(key) == FALSE)
+  { return FALSE;
+	}
+  return TRUE;
+}
+
+bool registry_storelong(char *keystr, LONG value)
+{ HKEY key;
+
+	if (!registry_createkey(HKEY_LOCAL_MACHINE, "Software\\Kudlian Soft\\ReTreeval", &key))
+  { return FALSE;
+  }
+  if (!registry_setlong(key, keystr, value))
+  {	return FALSE;
+  }
+  if (!registry_closekey(key))
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_storeint(char *keystr, int value)
+{ HKEY key;
+
+	if (!registry_createkey(HKEY_LOCAL_MACHINE, "Software\\Kudlian Soft\\ReTreeval", &key))
+  { return FALSE;
+  }
+  if (!registry_setint(key, keystr, value))
+  {	return FALSE;
+  }
+  if (!registry_closekey(key))
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_storeblock(char *keystr, char *data, int size)
+{ HKEY key;
+
+	if (!registry_createkey(HKEY_LOCAL_MACHINE, "Software\\Kudlian Soft\\ReTreeval", &key))
+  { return FALSE;
+  }
+  if (!registry_setblock(key, keystr, data, size))
+  {	return FALSE;
+  }
+  if (!registry_closekey(key))
+  { return FALSE;
+  }
+  return TRUE;
+}
+
+bool registry_storestring(char *keystr, char *value)
+{ HKEY key;
+
+	if (!registry_createkey(HKEY_LOCAL_MACHINE, "Software\\Kudlian Soft\\ReTreeval", &key))
+  { return FALSE;
+  }
+  if (!registry_setstring(key, keystr, value))
+  {	return FALSE;
+  }
+  if (!registry_closekey(key))
+  { return FALSE;
+  }
+  return TRUE;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/registry.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/registry.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/registry.h	(revision 14219)
@@ -0,0 +1,16 @@
+#ifndef _REGISTRY_H_
+#define _REGISTRY_H_
+#include <windows.h>
+
+bool registry_openkey(HKEY key, const char *name, PHKEY keyout);
+bool registry_storeblock(char *name, char *data, int size);
+bool registry_fetchblock(char *name, char *data, int size);
+bool registry_getstring(HKEY key, char *name, char **string);
+bool registry_setstring(HKEY key, const char *name, const char *string);
+bool registry_createkey(HKEY key, const char *name, PHKEY keyout);
+bool registry_closekey(HKEY key);
+bool registry_keyExists(HKEY key, const char *name);
+bool registry_ensureKeyExists(HKEY key, const char *name);
+#endif
+
+
Index: /gsdl/branches/nzdl2/gsinstaller/setup.rc
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/setup.rc	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/setup.rc	(revision 14219)
@@ -0,0 +1,771 @@
+IDB_BITMAP1 BITMAP 
+{
+ '42 4D F6 2F 00 00 00 00 00 00 36 04 00 00 28 00'
+ '00 00 50 00 00 00 8C 00 00 00 01 00 08 00 00 00'
+ '00 00 C0 2B 00 00 00 00 00 00 00 00 00 00 00 01'
+ '00 00 00 00 00 00 1C 1A 1E 00 97 8A 69 00 5B 52'
+ '34 00 74 6E 4E 00 D0 C2 B4 00 33 36 25 00 AC A6'
+ '8E 00 5A 52 52 00 71 6E 6B 00 3B 46 30 00 92 8A'
+ '87 00 78 62 38 00 88 7E 6C 00 59 52 44 00 8C 7E'
+ '5C 00 28 2A 1E 00 68 62 53 00 9F 9A 89 00 45 46'
+ '3E 00 79 6E 5D 00 3C 3A 36 00 B4 AA AB 00 68 62'
+ '63 00 E3 DE D9 00 9C 97 7D 00 81 7E 7A 00 62 5A'
+ '45 00 3E 3E 29 00 7B 76 5D 00 24 2A 2A 00 A1 9A'
+ '97 00 91 8A 79 00 54 46 2E 00 73 6A 55 00 90 86'
+ '6D 00 9D 92 79 00 BF B6 AC 00 20 22 1E 00 61 5A'
+ '36 00 D9 D2 CC 00 AC A6 A0 00 7A 76 6B 00 94 92'
+ '88 00 30 32 22 00 66 62 5B 00 76 6E 63 00 6A 62'
+ '49 00 57 52 4C 00 54 4D 4B 00 90 8A 80 00 33 38'
+ '30 00 86 7E 73 00 3C 3E 30 00 F7 EE E9 00 61 5A'
+ '4B 00 44 46 38 00 B4 A2 86 00 53 4E 40 00 CC C2'
+ 'C6 00 AA A2 99 00 22 24 27 00 7B 77 65 00 55 49'
+ '38 00 7A 76 73 00 59 52 3D 00 60 5A 53 00 77 6A'
+ '4B 00 C1 B8 BD 00 9D 96 92 00 9C 9A 90 00 8B 86'
+ '7C 00 24 2B 23 00 B6 AE A0 00 EF E5 E8 00 2C 32'
+ '2B 00 73 6E 54 00 9D 94 88 00 74 63 4A 00 6D 5E'
+ '53 00 3E 38 25 00 90 86 65 00 71 6A 5C 00 75 65'
+ '54 00 44 42 37 00 84 72 63 00 9D 8D 80 00 6D 5D'
+ '4C 00 64 55 44 00 55 4A 40 00 84 70 5D 00 BF B2'
+ 'AC 00 87 79 6C 00 76 66 5B 00 64 56 4B 00 94 82'
+ '73 00 4C 41 30 00 BD AF 99 00 4C 4E 32 00 6F 6A'
+ '63 00 AC 9E 98 00 C7 BE B1 00 86 76 55 00 D0 CA'
+ 'C2 00 49 46 2D 00 94 81 6D 00 4D 40 29 00 9C 8C'
+ '78 00 20 22 22 00 B4 A8 9F 00 86 78 65 00 A6 9B'
+ '90 00 89 7E 65 00 58 4E 31 00 66 5A 3D 00 3C 32'
+ '23 00 4B 4E 39 00 64 54 3D 00 2D 2C 24 00 F2 E8'
+ 'DF 00 6C 5C 45 00 2D 2D 2B 00 8B 86 74 00 3D 3A'
+ '2F 00 5D 4E 40 00 D4 CD C9 00 2E 26 27 00 57 4E'
+ '38 00 62 5E 5A 00 8C 86 83 00 F9 F1 F2 00 B4 9E'
+ '7E 00 E3 DA D2 00 8C 76 4E 00 1F 1E 26 00 C9 C2'
+ 'BF 00 C8 BE BE 00 F2 EA E9 00 AB A6 9A 00 9A 92'
+ '80 00 F9 F6 F5 00 9D 8E 87 00 95 8A 71 00 70 63'
+ '41 00 E8 E0 DF 00 BC B6 B3 00 DC D6 D6 00 3F 42'
+ '40 00 D0 CC CF 00 88 70 48 00 7E 72 6A 00 A5 97'
+ '80 00 8C 81 7B 00 AB A2 90 00 AB A2 9F 00 BC B2'
+ 'B3 00 1C 1A 22 00 C4 C2 BA 00 84 8E 8E 00 47 49'
+ '46 00 38 3C 3E 00 6A 62 4E 00 D4 C6 CE 00 B4 AE'
+ 'A6 00 65 53 36 00 AE 9B 87 00 86 77 5D 00 6E 5C'
+ '34 00 7D 6F 55 00 B5 A8 99 00 7D 6A 55 00 7C 6A'
+ '5C 00 A5 92 80 00 35 32 2C 00 34 37 2A 00 74 72'
+ '72 00 9B 96 82 00 84 82 82 00 24 2E 32 00 A4 9E'
+ '9E 00 55 49 32 00 AC A7 A6 00 93 94 8E 00 F7 F0'
+ 'EE 00 24 26 2E 00 9D 96 8E 00 74 64 4E 00 6C 5E'
+ '5A 00 3F 39 2A 00 AC 9E 9E 00 4A 47 32 00 B4 A9'
+ 'A6 00 5C 56 52 00 8B 82 6D 00 5B 56 45 00 2C 2E'
+ '1E 00 6A 66 54 00 4B 4A 3F 00 7B 72 5D 00 3B 3E'
+ '37 00 B6 AE AA 00 6B 66 63 00 E8 E2 D8 00 64 5E'
+ '45 00 42 42 2A 00 94 8E 79 00 C4 BA AE 00 24 26'
+ '1E 00 DF D6 CE 00 6A 66 5C 00 79 72 64 00 5B 56'
+ '4B 00 92 8E 80 00 89 82 74 00 41 42 30 00 63 5E'
+ '4C 00 4B 4A 39 00 C8 C6 C8 00 7E 7A 73 00 5C 56'
+ '3D 00 63 5E 53 00 D8 CE C0 00 8D 82 66 00 6C 5E'
+ '3E 00 D2 C6 C0 00 9A 8E 70 00 C4 BA B4 00 30 32'
+ '26 00 53 4E 46 00 74 6A 6A 00 C0 BE B6 00 BC AA'
+ '8E 00 24 26 22 00 1F 1E 22 00 D4 C6 BA 00 6B 66'
+ '4E 00 B4 B2 A6 00 95 86 7B 00 A0 86 62 00 95 86'
+ '74 00 1E 1E 1E 00 5A 56 34 00 CC C6 B6 00 34 3A'
+ '25 00 74 72 6B 00 92 8E 87 00 74 66 3A 00 90 82'
+ '5E 00 83 82 7B 00 7C 7A 5E 00 24 2E 2A 00 A3 9E'
+ '98 00 55 4A 2D 00 AC AA A1 00 7B 7A 6C 00 94 96'
+ '89 00 6C 66 4A 00 2C 5C BA BA BA 5C 2C 4E 4E 5D'
+ '41 7F BA BF 07 41 BF 5D BF BF BF BF 41 D2 BF BF'
+ 'BF 07 30 D2 30 30 9E BF 2C 7F BF 2F 2F 30 2F 2F'
+ 'D2 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 07 2F 07 41 DB'
+ '41 7F 41 BF 41 7F 7F 7F 7F 2C 16 7F 7F 16 7F 16'
+ '16 16 16 16 C8 E4 BC 63 1E 63 1E 6E 44 44 44 B8'
+ '4C 4C B8 B5 2A 8C 31 F4 31 EC 31 55 0A 80 31 31'
+ '80 EC F7 46 33 C0 19 D9 97 31 46 80 0A 31 46 B0'
+ '46 80 0A 9D D3 80 80 F7 19 97 EC F7 80 0A 80 4C'
+ 'B8 B8 B8 44 FE 44 1E B5 45 1E 1E 1E 1E 1E BC FA'
+ '1E 3B 6C 28 99 15 99 A8 3B 63 A8 A8 3B 6E 44 A4'
+ 'B8 44 FE B8 8C 0A D3 0A 8C 0A 2A 0A 80 8C F4 97'
+ 'F4 80 F7 F7 F7 46 D4 9D D3 19 19 FD 29 D9 3F D9'
+ 'D9 AE D9 D9 B0 0A 31 F7 46 46 F7 31 D3 55 2A 6E'
+ '99 63 BC 1E 3B 44 1E 44 1E 99 B4 FA 63 B2 89 63'
+ '28 28 BE C7 C7 5A 28 FA 28 A8 6C 3B A8 3B A8 B8'
+ '6E B8 B8 B8 B8 AF 2A B8 AF 2A 55 2A D3 31 31 31'
+ '46 D3 31 1F 1F D3 F7 F3 DB 0D 12 92 C6 12 C6 9F'
+ '37 C4 E3 2F 41 2C 62 F3 19 F7 D3 0A B8 2A 2A 44'
+ 'FA 28 FA 3B 63 3B 3B FA FA 28 3B FA 3B 28 15 C7'
+ '9A C7 BE BE 9A 87 A8 63 99 48 A8 3B A8 63 3B 63'
+ '6E B8 4C B8 B5 2A 2A 2A 2A 31 D3 31 1F 46 D4 46'
+ '31 46 F4 D3 3F 41 9E 37 D5 53 C6 34 C6 C6 32 C6'
+ '09 53 37 37 C6 12 12 30 10 51 29 F4 0A 8C 2A 44'
+ '3B 98 63 1E 1E B4 99 89 FA 99 FA 3B 28 99 B4 43'
+ '43 C7 BE BE 9A D8 6C A8 3B A8 BC 3B 63 98 63 6E'
+ 'B8 B8 2A 4C 11 FE 8C 2A 2A 2A F4 F4 D3 D3 46 D3'
+ '31 D3 0C D2 D7 C6 C6 32 9F 32 32 B1 32 C6 32 D5'
+ '53 53 32 C6 09 73 D7 37 9E 2F 41 62 29 19 31 31'
+ '63 1E 3B 6E 6E 45 1E 99 1E 3B 99 99 FA 43 87 BE'
+ '28 B4 99 FC 43 93 A8 3B 3B A8 3B 98 63 1E 6E 6E'
+ '4C 2A B8 F4 B5 55 F4 45 0A 46 B8 31 46 31 79 0C'
+ '31 D0 D7 C6 53 B1 32 AC 4A 32 32 B1 AC 14 34 C6'
+ '14 14 32 14 34 D7 73 DA 40 39 9E 41 7F 16 FD F4'
+ 'FE B8 1E 44 B8 8C B8 11 44 1E 99 3B 3B 3B BC 3B'
+ '99 99 89 C7 9A A1 28 63 63 6E 63 63 98 6E 6E 44'
+ 'B8 45 FE 11 8A FE 2A 8A D3 0A D3 31 31 D3 D3 F7'
+ '10 09 53 34 4A AC 4A 4A 4A B1 AC AD 32 4A 32 32'
+ '32 4A 4A AC C6 34 53 C1 EA FF D6 30 07 DB C8 29'
+ 'B0 0A FE B8 4C 11 B8 B8 6E 11 6E 3B 1E 3B 3B 3B'
+ '28 EB A2 99 99 90 98 6E 6E 3B 63 28 98 63 44 2A'
+ 'B8 45 B8 B8 8C B8 2A 31 31 F4 31 31 D3 1F 33 10'
+ 'D5 D5 53 32 4A 4A 4A F9 F9 4A 4A 4A B1 75 B1 4A'
+ '78 4A 4A AD 32 32 37 73 10 2A A8 13 2F 07 41 D0'
+ '16 D4 8C 44 44 44 B8 44 6E 44 FA B2 1E 63 28 28'
+ 'FC 99 3B 99 3B FC 63 98 63 98 44 11 6E 63 6E B8'
+ '2A 8C F4 55 F4 F4 F4 D3 F4 F4 80 D3 D3 1F 13 C6'
+ 'D5 34 32 4A 4A F9 B1 1D B7 47 F9 75 E2 1D 78 75'
+ '78 75 F9 78 4A 32 32 D7 C1 F3 9A CF FD 36 D2 41'
+ '41 16 D9 FE B8 FE B8 6E B8 FA A8 63 98 99 48 99'
+ '6C FA 1E FA B2 99 63 6E 6E BC 44 96 B8 11 B8 11'
+ 'B8 B5 B8 8A 2A 2A 2A F4 FE 31 46 46 D4 3D 37 1B'
+ 'D5 34 32 4A 4A E2 1D 47 47 1D 1D 3C B7 B7 75 1D'
+ '1D 47 78 4A E2 4A 32 34 12 40 21 E1 7C D1 DB 41'
+ 'BF BF D0 D9 80 2A 2A FA 3B 1E 3B 99 FC BC 89 1E'
+ '45 FA 1E FA 99 D8 6E 6E 6E 6E B8 96 B5 B8 4C B8'
+ 'B8 AF 2A B8 2A D3 F4 D3 D3 46 F7 D4 F3 1A 32 32'
+ '4A E2 AD 4A 47 3C 1D B7 3C 47 B7 47 3C 1D B7 47'
+ '75 47 B7 78 4A 4A 05 32 F2 34 D7 D1 E5 87 2C D0'
+ '36 D2 D2 D0 FD 31 8A 44 6E 3B 3B 63 99 6E 45 FA'
+ 'FA 44 1E 44 28 3A 8C 1F 8A 31 2A B8 4C 96 4C 2A'
+ 'AF 0A 2A D3 2A D3 D3 80 D3 19 8D 3D 21 34 F2 32'
+ 'E2 4A F9 F9 B7 1D 1D 6B 3C B7 3C B7 3C 47 B7 1D'
+ '47 B7 78 1D 78 4A E2 4A AD AD 14 09 4B D8 3D 41'
+ '41 E3 41 10 08 31 D3 F4 D3 2A 45 B8 2A B8 11 FA'
+ '99 89 89 63 3B BE 6E B8 55 3F F3 5E D3 31 B8 FE'
+ '2A D3 D3 F4 2A 31 31 F7 46 C0 29 13 1A AD 32 AD'
+ '4A F9 1D 1D 47 47 B7 3C 6B 6B 85 B7 3C 6B B7 47'
+ 'B7 75 AC 47 47 1D F9 E2 4A 4A E2 32 34 D6 D9 0D'
+ 'D2 D2 2F 36 D0 D9 46 46 31 F4 F4 FE F4 FE 44 3B'
+ '1E 15 3B 28 FA 1E A8 B8 B8 31 1F CC 79 D4 0C C0'
+ 'D9 33 D4 97 D3 31 2A 1F 29 D1 5C D6 09 1B 1B E2'
+ 'E2 F9 1D 47 3C B7 B7 3C 6B B7 6B 3C 3C 3C 3C 47'
+ 'B7 B7 75 1D F9 7D B7 1D 1D 1D F9 05 32 D5 40 53'
+ '41 DB BF BF 2C 08 33 31 B5 B5 D3 B8 B5 2A 45 45'
+ '1E 1E 45 FA 45 1E 98 63 B8 0A F4 B8 55 EE 1F D3'
+ '79 97 79 79 5B D4 D4 29 08 51 C3 57 D5 34 32 E2'
+ 'E2 47 3C B7 3C 6B 6B 3C 3C E8 3C 3C 3C 6B 2B 3C'
+ 'E7 47 F9 F9 6B 47 6B 1D 1D 6B E7 4A AD 34 D5 09'
+ '36 10 DB 0D 10 62 D9 46 2A F4 44 45 45 45 1E B8'
+ '45 45 1E 44 B8 6E 63 63 44 9D 2A 63 6E 4C 1F 33'
+ '97 46 79 46 31 33 29 F3 29 C3 A0 1A D5 1B AD E2'
+ 'F9 B7 47 47 3C E7 B7 3C 6B 3C 85 6B 3C E7 47 B7'
+ '25 B7 1D B1 6B B7 3C 85 6B 6B E7 F9 E2 1B C6 1B'
+ '0D 2C 41 D2 D2 10 F3 F7 0A 2A B5 45 B5 45 1E 44'
+ 'B8 B8 FA 1E B5 45 89 3B 6E B5 6E A4 B8 11 B8 4C'
+ 'AF EC 46 CC 79 1F D4 6D 3D D1 4B 40 1B CB 05 E2'
+ 'F9 47 B7 3C E7 3C E8 6B 3C 85 6B 6B E8 6B B7 6B'
+ '3C 6B 6B 3C 1D 85 85 3C EF 3C B7 F9 4A 4A F2 32'
+ '92 C3 7F DB DB DB C8 F3 F7 31 2A 0A B5 45 44 1E'
+ '45 B8 2A 8C AF B8 98 FA 98 1E 63 6E B8 6E B8 FE'
+ 'F4 2A 31 D4 D9 5B 3D 51 52 51 2D 3E BD D5 4A F9'
+ 'F9 1D 3C 6B 85 85 E7 85 85 85 6B B7 F9 B7 1D 3C'
+ 'CE B7 3C B7 85 3C 6B 7D 6B F9 4A 47 4A F2 4A 4A'
+ 'C6 DB 2C 2C D0 DB 62 08 F7 1F 0A F4 B8 B5 44 FE'
+ 'B8 2A FE 8C AF FA 6E 63 6E 6E B8 44 B8 B8 6E 44'
+ '2A 2A D3 D4 C0 0C AA 52 C3 10 52 FB 67 F2 4A C2'
+ '4A 47 E7 3C 6B E8 85 6B E8 6B 6B 6B E7 25 6B 6B'
+ '3C 6B 3C 3C 3C 3C 6B 25 B7 05 1B E2 F9 2B E2 AD'
+ 'AD A0 DB 2C DB 2C C8 62 29 33 31 1F B5 2A B8 44'
+ '45 1E 2A FE 4C 45 B8 45 FA FA 6E 6E 6E 11 B5 2A'
+ 'AF 8A D3 97 D4 29 3D 2D 56 A0 A9 1B 67 1B F9 F9'
+ '3C 3C 3C E7 6B 3C 85 6B 6B E8 E8 85 E8 85 6B 85'
+ '6B 85 47 E7 E8 6B 6B 85 E2 1B 1B E2 E2 4A 4A 05'
+ '32 DB D2 D0 DB 10 A0 D0 F3 46 0A 80 45 2A 44 45'
+ 'B8 2A 2A 2A FE 45 FA FA 63 A4 B8 A4 FE 96 AF 2A'
+ '31 31 31 79 D4 22 D1 6F 10 13 56 1B 3E BB 05 6B'
+ '47 47 6B B7 E7 6B 6B 6B E8 3C 6B 6B 3C 6B EF 6B'
+ 'EF 6B 6B 6B 6B 6B 6B 6B 4A F2 AD E2 E2 E2 E2 2B'
+ '4A DB D2 DB D6 D0 D0 C8 AE 46 31 2A B5 2A 8A B5'
+ '2A 2A F4 44 44 3B 98 98 6E 44 B8 6E 2A 11 8C AF'
+ '31 31 D4 19 6D 95 2D 21 2D 51 FF CB 70 F2 E2 3C'
+ '2B 3C 3C 47 E7 6B 6B E8 6B 85 6B 3C 6B E8 85 6B'
+ '6B 85 E8 85 6B E8 6B 47 3C E7 3C 47 4A E2 E2 4A'
+ '4A C1 0D D2 10 D0 62 62 F3 D4 F7 2A 2A 44 B5 1E'
+ '1E B5 2A D3 B5 1E 6E 6E 63 A4 FE FE 4C B8 11 31'
+ '8A 79 46 22 3D 52 10 D6 A9 4B 57 D5 02 F2 47 47'
+ '3C 47 E7 6B 3C E7 85 6B 6B E8 E8 6B 25 E8 85 E8'
+ '3C 25 85 25 6B 6B 6B EF 6B 6B 6B 47 47 4A E2 F2'
+ '32 41 41 0D D2 DB 10 C3 F3 19 D3 F4 F4 AF 1E B5'
+ '45 1E 1E 45 2A 11 15 1E FA 11 B8 6E A4 D3 D3 CC'
+ '46 8D 33 0C 2D 13 21 D6 51 5C 57 F2 A6 BB F9 E7'
+ '3C E7 47 3C 6B 3C 6B 6B E8 EF E7 00 6B 6B E8 6B'
+ '9B E8 E8 25 E8 6B 85 6B EF E8 E7 E7 47 2B 05 4A'
+ '4A 73 0D E3 39 D2 36 D0 F3 29 D3 9D 0A 45 B8 FA'
+ '45 44 45 1E 11 1E FC 48 98 6E FA B8 4C 6E 2A 8A'
+ '46 97 D4 D1 13 10 52 56 2E 10 DA BB F5 4F E2 E7'
+ '6B 3C 3C 6B 6B 6B EF E8 25 6B 9B 6B E8 EF 6B 25'
+ 'EF 25 6B E8 6B E8 25 E8 E8 25 6B 47 47 2B E2 AD'
+ 'E2 D7 73 E3 36 2F 39 41 10 F3 D4 31 0A B5 B5 B5'
+ 'B8 11 1E B5 45 FA 89 90 11 FA 6E 44 FE 11 8A 2A'
+ '46 D4 33 F8 51 59 1A 4E C1 C3 71 34 84 5F F9 3C'
+ '3C E7 EF 6B E7 85 6B 85 25 E8 EF E8 6B 25 EF 25'
+ '6B 25 EF E8 EF 6B 25 25 E8 25 47 E7 E7 4A E2 E2'
+ '2B C4 2F 0D 9E 0D 36 10 13 29 19 19 31 FE 11 2A'
+ '44 45 45 3B FA 99 3B 28 3B B8 6E FA B8 2A 2A 31'
+ '1F FD 3D D1 13 D1 A0 10 10 A0 40 D5 ED 34 75 25'
+ 'E7 6B 6B E8 6B 6B 6B 6B E8 25 6B 6B EF 25 E8 E8'
+ 'EF 6B 6B E8 25 EF E8 E8 25 6B 6B 47 E7 E2 2B 2B'
+ 'B1 73 36 D2 36 0D 36 2C 08 29 D1 33 D3 F4 45 45'
+ 'FE 45 1E FA 3B 3B 3B 48 89 45 1E 6E B8 B8 2A 1F'
+ '31 D4 D1 2D 52 10 10 2E DB A0 02 3E 82 67 C2 E7'
+ '47 6B 25 6B EF 6B 25 6B 6B EF 6B E8 EF 6B E8 EF'
+ '25 EF 9B E8 6B 6B EF 6B 25 E7 E7 E7 47 2B E2 4A'
+ '4A 36 2F 73 E3 C1 36 39 C3 62 FD 33 31 31 2A 45'
+ '1E FA 45 FE 45 FA FA A2 FA 6E 45 11 6E FE AF 46'
+ 'D4 D1 C5 51 10 2E 10 10 CA EA CA 67 5A 7E F9 47'
+ '6B 6B 6B E8 6B E8 6B 6B EF E8 E8 6B E8 EF E8 6B'
+ 'E8 6B 25 25 EF EF 6B EF 6B 6B 0F 47 47 2B 2B E2'
+ 'E2 D6 C4 0D 39 9E 39 41 D6 D0 62 19 80 31 2A B8'
+ '28 3B 45 44 11 FA 1E BE 3B 6E 6E 2A 45 2A 31 79'
+ '79 D1 4B 51 52 10 A0 D6 C1 56 C1 34 E9 2E 4A E7'
+ '6B 25 E8 E8 EF EF E7 E8 6B 6B 25 6B 25 E8 25 25'
+ 'EF 25 EF 6B EF 25 E7 0F 25 25 6B E7 47 2B E2 E2'
+ 'E2 DB D2 40 9E 73 0D 36 1A C8 D0 D9 46 D4 31 F4'
+ '45 0A B8 2A FE 1E 3B 48 89 FA 2A 45 11 2A 1F 19'
+ '3D C5 D0 C3 C3 56 D6 D6 C1 D6 DA BD 27 F8 75 E7'
+ 'E7 6B E7 25 6B EF EF EF 9B 00 6B EF EF 25 E8 EF'
+ '25 EF 25 25 E8 6B E8 3C E7 EF 25 CE 2B AD 05 4A'
+ '32 36 2F 30 C1 0D 0D D2 36 D0 62 FD D9 F7 31 8A'
+ 'B5 1F D3 F4 31 FE 3B 5A 89 6E 44 B8 FE D3 79 2A'
+ 'D4 29 13 21 D0 10 D2 0D 36 DA 40 D7 27 79 E2 47'
+ 'EF EF E8 6B EF E8 25 E8 25 25 6B E8 25 E8 25 6B'
+ 'E8 E8 25 E8 6B 6B 25 E7 CE EF CE 0F 2B E2 F2 05'
+ '34 0D 36 D6 D6 36 36 39 DB D6 51 D1 FD FD 79 46'
+ '2A 31 D3 D3 D3 D3 63 28 89 63 6E 11 FE 79 46 46'
+ 'C0 0C D1 13 21 51 40 C1 D6 0D 1A 67 27 11 C2 E7'
+ 'E7 6B EF E7 EF EF EF 6B EF E8 EF 6B 9B 25 EF EF'
+ '25 25 9B 25 6B CE E7 6B CE 25 6B 0F F9 2B 2B 2B'
+ '37 36 D6 D6 41 10 C1 D2 C1 2C D0 2D D9 0C 19 8A'
+ '46 31 31 F4 FE 8A 63 89 3B 3B 3B 45 2A F4 D3 46'
+ 'FD D9 C5 C3 51 51 E3 36 D6 8E C1 37 27 60 F9 7D'
+ '25 E7 EF EF 6B 25 EF E8 25 6B E8 EF 25 25 E8 E8'
+ 'E8 6B 6B EF CE E8 3C 0F EF 6B 25 E7 0F C2 2B E2'
+ '37 C3 2F BF D2 D6 41 D2 36 D6 C3 08 F3 0C D4 F7'
+ '2A EC D3 F4 1F 6E FC A2 FA 45 B8 6E 45 FE 31 0C'
+ 'FD D1 51 51 13 D0 D2 D6 D6 D6 C1 FB 7C CD 05 47'
+ '3C E7 25 6B EF EF CE EF EF 00 25 25 EF E8 6B 6B'
+ 'EF E8 25 E8 E8 25 6B E8 E7 25 6B E7 E7 0F F9 2B'
+ '9E DB D6 10 D2 41 DB 41 36 41 D0 2D 29 46 31 D4'
+ '1F 46 31 31 0A 55 FA FA 3B 1E 44 FE CC 80 31 33'
+ '29 3D D0 D0 D1 41 C3 D6 5D C1 40 37 86 66 AD E7'
+ '6B 25 6B 25 9B E7 EF 6B 6B 25 6B E8 25 E8 25 E8'
+ 'CE 00 CE E8 25 25 6B 6B E8 25 25 EF 47 47 2B 2B'
+ 'C4 DB 10 D0 DB C3 36 36 D6 A0 62 C5 08 79 31 31'
+ '31 D3 31 FE 8A 6E FA 99 89 44 FE 8C D3 D3 79 0C'
+ 'F8 2D 51 21 DB 2C D0 D6 D6 36 1A 09 90 93 05 C2'
+ 'CE 85 25 85 CE 25 25 6B EF E8 EF 6B E8 EF EF 25'
+ 'E8 25 25 25 E8 EF 6B EF EF E8 25 47 25 0F 2B 2B'
+ '53 C1 36 DB 36 10 D2 DB 10 F3 51 51 3D E4 33 D4'
+ 'D4 FD D4 46 D3 AF FA 28 98 B8 2A FE D3 31 79 FD'
+ 'D1 D1 D6 D6 2F 10 52 10 56 A0 0D BD 3B 83 BB F9'
+ 'CE 25 25 EF 25 E8 6B 0F 6B 25 6B EF EF E8 6B E8'
+ '6B EF 85 EF E8 E8 25 25 E8 EF 25 E7 CE 0F C2 05'
+ '32 14 C4 36 0D 36 41 10 07 53 34 53 C4 0D 0D DB'
+ 'A0 C3 D1 D1 D1 33 1E EB 3B 45 B8 2A D3 79 D4 6F'
+ 'D1 51 D0 BF 0D D6 10 52 10 C3 10 B3 2A 76 34 7D'
+ 'CE E7 25 25 E8 EF 25 6B EF 6B 25 EF 25 EF 25 EF'
+ '25 25 25 6B 25 25 EF 25 25 E8 25 CE 0F F9 C2 32'
+ 'D5 AD 32 32 12 0D 37 32 D5 C4 36 D6 62 D0 D0 D1'
+ 'FD 3D D1 6D 5B D1 FA 99 FA B8 B8 8A D3 F7 D4 62'
+ 'D0 13 10 30 2E A0 2E 36 FF 10 A0 D7 19 88 D7 2B'
+ 'E7 E7 EF 25 E8 25 6B E8 E8 25 E8 E8 25 E8 CE E8'
+ '6B 25 E8 EF E8 E8 25 E8 E8 25 CE CE 0F 47 47 34'
+ 'D6 0D 14 32 C6 53 E3 41 C3 2C C3 D0 08 FD 29 33'
+ '46 31 D3 79 EE 31 44 3B 6E 8A 0A 2A D3 22 FD 2D'
+ 'D6 62 41 0D A0 EA 56 D6 A0 D6 EA 02 3D 35 C4 47'
+ 'CE E8 25 E8 25 25 25 6B EF E8 EF 25 25 25 EF E8'
+ '25 00 85 25 25 6B EF 6B 6B E8 E7 47 CE E7 2B C6'
+ 'D0 2C 10 36 10 10 2C 10 10 D0 D0 08 3D 08 33 79'
+ '31 46 F4 B5 B5 FE FE 6E 45 2A 1F 31 D3 80 0C C5'
+ 'DB C3 0D A0 36 A0 A0 A0 C3 36 D6 7E 7F B6 36 47'
+ 'CE 6B CE 6B E8 E8 E8 25 6B CE 25 25 EF 00 EF EF'
+ '25 6B CE 47 CE 6B 6B EF EF CE CE 25 E7 E7 F2 53'
+ '10 10 D0 51 62 2C DB 10 10 10 10 2D 62 FD FD F7'
+ '31 2A 2A B8 11 11 B8 38 3B 2A CC 31 D3 79 5B 51'
+ 'D0 D6 D2 56 10 56 56 56 10 C3 A0 73 C1 88 C3 47'
+ 'E7 CE 25 25 6B 25 25 25 EF 00 E8 E8 6B 25 3C 6B'
+ '25 25 E7 E7 7D 25 00 6B 6B CE 25 CE CE E7 F2 39'
+ '36 D0 2D 51 D0 51 C8 10 D0 D0 51 13 62 F3 FD 33'
+ 'F4 CC D3 8A FE 45 4C CC 4C 2A D3 46 D4 0C 3D 36'
+ 'D2 39 C3 A0 C3 56 A0 10 2E C3 1A 40 C4 35 95 C2'
+ 'CE EF 6B CE 6B 25 EF E8 E8 6B 25 25 EF 9B 25 EF'
+ 'E8 6B E7 7D 25 E8 25 EF 25 25 25 3C 47 2B D5 C4'
+ 'D2 DB 10 D2 2D 51 D1 62 D0 2C D0 C8 62 3D 29 D4'
+ 'D3 80 46 31 2A 11 AF 2A 4C 8A 55 D3 46 5B 3D 41'
+ '0D C1 52 2C 2E C3 56 10 A0 52 A0 DA 37 8F D4 78'
+ '25 6B CE 25 E8 6B 25 EF EF 25 6B EF EF 25 E8 E8'
+ 'EF 25 E7 E7 6B 6B EF EF E8 E8 6B CE E7 2B 09 36'
+ '10 D2 10 2C 10 62 29 FD 08 4B F3 C8 3D F3 3D 19'
+ 'F4 2A D3 2A D3 45 AF 8A 3B CC F4 D3 EE 0C D1 10'
+ '39 56 10 10 2E 10 C3 D6 A0 10 10 40 09 91 8A 7D'
+ 'E7 CE 25 6B 25 00 9B E8 25 E8 00 6B 6B E8 25 EF'
+ 'E8 CE 6B E7 CE 25 E8 6B 6B 6B 25 CE 47 05 53 0D'
+ '7F D6 10 3D 51 C8 D9 19 08 C5 2D F3 FD 33 19 33'
+ 'D4 8A FE F4 2A AF 4C 96 FA 1F EE 1F 1F 22 2D 10'
+ '41 39 C1 A0 EA 4E 56 A0 A0 2E EA 1A 32 D8 89 C2'
+ 'CE 25 25 E8 E8 25 EF 25 EF 25 E7 EF E7 6B E8 6B'
+ '6B CE CE 75 E8 E7 25 E7 25 CE E7 CE 0F F2 D5 41'
+ 'C3 62 13 62 51 D1 D0 2C 62 13 08 F3 F3 FD 19 46'
+ '46 FE 45 B8 31 11 AF 8A 6E 1F 1F 68 1F 29 C8 D0'
+ '2C D7 57 1A 10 56 A0 10 56 A0 FF D6 BB 24 24 E2'
+ 'E7 6B 25 25 EF 6B E8 E8 6B 6B EF E8 6B 6B 25 EF'
+ '25 EF 6B 25 25 E7 E7 E7 6B 25 25 E7 2B 34 D5 51'
+ '08 51 C8 C8 C3 DB D0 10 C3 51 2D 3D 3D D1 FD 79'
+ '46 F7 2A 45 B8 1E 96 AF 6E 1F 22 79 6D 3D 13 3D'
+ '51 D6 C1 37 36 57 36 A0 56 D6 2E 1A 34 99 DC 75'
+ 'CE 25 25 E8 6B 25 CE EF EF EF 25 E8 EF EF EF CE'
+ '25 6B CE 25 CE CE 0F 25 25 25 CE 6B 0F 09 37 13'
+ 'D0 2D D0 C3 D0 10 2C 10 C3 C8 D0 F3 F3 33 F7 FD'
+ '79 31 F4 8A 11 3B AB 31 A4 1F 1F 8D 5B 5B 6D 2D'
+ 'AA C3 56 57 3E 0D 7B 1A 36 EA A0 2E 1B 2A 83 78'
+ 'E7 E7 6B EF 25 E8 6B CE 6B 25 E8 EF CE 7D 25 25'
+ '85 CE C2 75 0F C2 E7 E7 25 E7 CE 6B 2B 34 C1 3D'
+ '51 10 D0 D0 10 D0 10 10 C3 D0 51 2D 08 D1 19 F7'
+ '46 31 46 FE FE 45 D3 6A AB 1F 31 3F 3D 0C DD 59'
+ '21 C3 4E D6 C1 5F 58 12 56 36 D6 A0 D5 19 88 1B'
+ 'CE 25 E7 25 25 25 EF E8 25 00 25 6B EF 25 6B E8'
+ 'CE CE 75 C2 75 7D 0F 25 6B 25 0F 0F F2 09 0D D0'
+ 'D0 2C 10 16 D0 DB D0 C3 08 10 2D F3 FD 33 3D F7'
+ '31 31 0A F4 B8 45 1F 55 55 D3 FD F3 5E 0C 6D D1'
+ '51 4E 10 2E 1A 57 53 37 DA D6 A0 CA D5 2C B6 3E'
+ 'E7 25 6B CE EF E8 6B 25 EF 6B E8 25 6B E8 25 E8'
+ 'EF CE 0F 7D 0F CE CE E7 47 25 47 47 D5 61 36 D0'
+ 'C8 10 2C 10 D0 DB C3 C3 51 13 13 08 FD D9 D4 F7'
+ '46 D3 F4 31 2A 45 55 CC 8A 1F C0 0C D4 C0 F8 AA'
+ 'A9 36 1A 56 57 57 DA 32 C6 57 57 36 B3 D2 B6 0D'
+ '6B 6B 6B EF 6B 6B E8 6B EF 25 25 EF CE E7 00 25'
+ '6B 6B 25 CE 25 CE 25 0F 25 CE 0F 2B 53 D5 C1 10'
+ 'DB C3 C3 10 C3 D0 D0 D0 C3 C8 D0 F3 FD 29 F7 19'
+ '46 31 0A FE FE 45 CC EE 96 B8 8A EC EC 0C 6D 59'
+ '52 52 1A 57 36 DA 5D 7E 14 57 0D CA 3E 92 88 51'
+ '47 0F CE CE 6B 25 25 EF 25 25 EF 7D 25 25 6B 25'
+ 'EF CE CE CE E7 CE 47 47 0F 3C 47 E2 09 D5 36 C3'
+ '10 D0 2C 41 DB D6 10 2C D0 51 51 51 D1 D9 F7 1F'
+ '46 8A 2A FE FE 45 55 D3 D3 B8 1F 8D 0C 6F 1C 3D'
+ '52 36 4D 36 2E 0D C1 40 D5 37 3E 7B 70 32 17 29'
+ '0F 6B CE CE 25 25 25 EF EF CE 7D CE EF EF 25 6B'
+ '6B 25 EF 75 E7 E7 C2 CE 47 47 E2 05 BD 09 DB 10'
+ '10 10 10 10 D6 10 10 10 D0 51 13 08 F3 3D 33 F7'
+ 'D3 31 2A 11 45 1E 55 AF 8A 18 CC EC 22 0C 6D 54'
+ '52 4E 56 56 36 36 39 3E 40 7B 20 37 7E E2 93 31'
+ '47 CE 7D 25 0F 25 7D 25 CE CE EF 6B 7D CE CE 6B'
+ '25 7D 6B 25 E7 C2 47 75 2B E2 2B 1B D7 D5 1A 10'
+ '41 D0 2C 36 DB 41 DB A0 51 13 D0 62 2D 3D F7 F7'
+ '46 31 F4 F4 11 45 4C 8A 1F AB 31 CC 79 68 3D C5'
+ 'AA 52 CA 1A 1A 36 1A 57 C1 0D 7E D7 5F 78 E5 98'
+ '75 47 E7 0F CE CE CE 25 0F 7D 25 EF 25 25 25 EF'
+ '25 6B 6B E7 E7 75 75 2B F9 C2 2B BB 67 37 41 36'
+ 'DB 36 41 2C 10 10 10 10 D0 51 D0 62 D1 F3 C0 46'
+ '46 0A 2A F4 FE 1E B8 AF 8A 55 FE EE 0C 68 6D C5'
+ 'AA 10 52 77 A0 56 36 57 0D 1A 1A 40 70 2B 28 CD'
+ '78 E8 CE 25 7D 25 EF 75 7D 6B 0F 7D 25 6B E8 25'
+ '25 CE CE C2 75 C2 E2 E2 C2 C2 05 D5 09 37 C3 12'
+ 'C1 36 1A 36 D6 D2 36 10 C3 51 D0 08 D1 FD 29 33'
+ 'F7 F4 8A 2A 11 FA AF D3 6A 1F AB 8D 0C 3D 6D 3D'
+ '51 10 C3 10 56 D6 36 57 36 1A 0D 1A DA AC 80 DF'
+ '75 CE CE CE 25 6B CE 25 CE 0F CE 0F CE CE 0F 0F'
+ '25 7D 0F 75 75 78 C2 2B 47 E7 2B 1B 34 53 36 A0'
+ 'E3 DB D2 0D C1 D2 D6 D0 10 10 21 62 F3 29 FD D4'
+ '46 31 F4 9D 11 1E D4 C0 6D 0C 29 D1 F3 2D 3D 54'
+ 'A9 C3 52 51 10 36 A0 10 CA 56 D6 36 40 AC 29 27'
+ 'AD CE 25 7D CE CE CE 7D CE CE 7D CE CE CE 25 25'
+ 'CE 75 0F 7D C2 2B E2 47 47 CE 2B CB F2 D2 E3 D2'
+ 'C1 D6 73 DB 36 39 36 D2 10 C3 D0 C8 29 F3 FD D4'
+ '19 D3 8A B5 11 1E 55 31 EC 79 46 C0 A5 1C 29 0C'
+ '13 A0 21 62 21 56 10 10 0D CA 56 56 2E AD 4E 76'
+ '7A 25 25 7D 25 CE 25 75 C2 72 CE 75 CE 0F 7D CE'
+ '25 7D C2 75 72 AC C2 E7 E7 47 2B 1B AD 0D C1 E3'
+ '36 D2 36 73 2F D2 39 36 0D 10 C3 C3 62 3D FD 33'
+ 'F7 46 0A 2A 2A 45 B8 AF 8A D3 79 79 79 3D F3 6D'
+ 'D0 52 10 13 13 10 10 2E EA D6 57 1A 74 7A 39 49'
+ 'C4 E7 6B EF C2 0F 0F C2 C2 CE CE CE 72 CE 6B E8'
+ '75 75 CE 75 05 05 C2 0F 0F E7 2B 09 32 0D 36 0D'
+ '36 0D C1 D2 DB D6 D2 D2 C1 36 10 C8 D1 D1 08 FD'
+ 'D4 31 31 F4 11 1E 11 FE 2A D3 55 B8 EE D1 D1 21'
+ 'A0 56 36 10 EC 52 D6 52 56 C3 CA 57 CA 34 AD 8F'
+ '36 CE CE 47 25 6B 75 75 72 CE 0F 75 CE 75 0F C2'
+ 'CE CE 75 C2 75 75 47 47 25 6B 05 CB 32 36 36 D2'
+ '36 C1 D2 C1 0D D2 36 D6 10 10 A0 C3 62 08 FD FD'
+ 'F7 46 31 31 2A 11 11 D3 23 EC EC B8 C0 0C 5C 52'
+ '4E 10 1A 36 3D 3D 52 36 10 56 56 36 D6 FB 7A 91'
+ 'D1 47 7D 0F CE 72 C2 C2 0F 75 75 75 75 72 0F 25'
+ '75 75 0F 0F 2B E2 2B 0F E7 0F F2 CB 32 C1 1A 2F'
+ '40 0D C1 DB 0D 1A D2 E3 D2 DB D0 C3 51 62 FD FD'
+ 'F7 46 8A 8A 11 1E 1F 68 68 8D 22 3D 6D F8 52 10'
+ '1A 36 36 77 56 21 A0 D6 D6 DB 36 D6 56 73 E2 66'
+ '46 C2 CE E7 C2 CE 72 72 05 72 4F C2 72 75 CE 7D'
+ '0F 0F 75 75 4F E2 2B C2 0F 47 F2 34 1B D2 36 D6'
+ 'D2 2F E3 36 D2 2F 0D 36 C1 36 C3 C8 62 2D 29 D4'
+ 'FD D4 F7 46 F4 11 EE CC EE 8A EE C0 0C 51 21 10'
+ '36 56 56 10 36 51 10 56 1A 57 1A 36 56 70 E2 EB'
+ 'AF 75 7D 0F 0F 75 72 72 72 75 72 75 72 72 0F 0F'
+ 'C2 0F 75 05 72 E2 C2 0F 0F C2 F2 F2 53 41 C1 C1'
+ '2F E3 C4 0D 0D 10 D6 10 2C 1A C3 EA D0 3D 29 FD'
+ '33 46 0A 0A FE 99 CC EC E0 AB CC 0C 6F 59 52 EA'
+ 'C3 52 1A A0 10 56 B9 1A 56 57 10 CA A0 7E 2B F4'
+ '48 C2 CE E7 0F 25 C2 75 C2 72 4F C2 72 72 7D 75'
+ '75 72 4F BB 1B 05 C2 E7 F9 2B 1B 1B C4 36 D2 C1'
+ '36 73 0D 0D 0D D2 C1 D2 10 D2 D0 C3 51 D1 F3 FD'
+ 'F7 F7 79 F4 45 28 EE 8D CC 11 EC 0C 6D A5 52 52'
+ 'A0 A9 4E 36 CA 36 A0 4E CA 1A 1A CA CA DA E2 33'
+ '04 75 6B CE 0F 75 72 72 4F 72 72 75 75 72 CE 2B'
+ '72 4F CB 4F 72 AC C2 47 C2 E2 1B 1B 2F 1A D2 36'
+ '36 C1 D2 C1 36 DB 41 DB 10 41 C3 51 62 62 2D C0'
+ '19 1F 31 D3 FE 99 6A 6A EE AB 23 C0 F8 0C 6D 52'
+ '56 52 A7 36 5D 52 2E 10 57 36 2E A0 5C 39 F2 13'
+ '27 E2 0F E7 CE C2 C2 72 72 72 72 75 72 72 4F 72'
+ '72 BB 69 70 1B 05 2B 0F 47 05 D5 F2 C3 36 D6 36'
+ '0D 36 D6 D6 D2 36 D6 DB D6 10 10 51 51 2D 2D 29'
+ 'D9 D4 46 31 45 11 5E 22 6A 96 55 22 6F A5 13 52'
+ '10 C3 56 36 CA EA 56 21 21 AA A9 2C 3E D7 F2 2F'
+ '91 5F 0F 75 0F 0F 72 4F BB 72 4F 72 72 AC AC 4F'
+ '69 69 FB 02 20 AD C2 C2 2B F2 CB 32 D6 10 DB D2'
+ 'D2 36 BF C1 D2 39 D6 DB C3 D6 D6 EA 51 F3 3D FD'
+ 'FD 19 F4 45 B5 45 EE 68 0C 0C CC 1F 68 6D A5 D1'
+ '68 4E 10 EA 5D 10 A0 EA 13 13 A0 5F 0D CA 7A 37'
+ '83 37 CE 25 CE C2 4F BB 72 72 BB 69 4F 72 69 BB'
+ 'BB 69 02 26 70 1B 2B C2 C2 F2 D5 05 1A 10 D6 DB'
+ '73 36 36 36 36 D2 C1 36 36 C3 10 C3 2D F3 D1 FD'
+ 'D4 F4 2A 31 2A 45 68 DD 6D 6D 6D 68 6D 6D F8 D1'
+ '13 C5 21 36 57 1A 36 36 52 EA 34 39 10 CA 34 1B'
+ '27 C1 3C 25 C2 75 05 4F 69 4F BB BB 69 69 69 69'
+ '69 FB 02 A3 FB F2 C2 C2 2B CB CB 7A 2F D6 C1 2C'
+ '0D D7 0D 40 C1 36 C1 0D 5D D6 2C D0 51 D1 F3 31'
+ '31 46 46 31 D3 B8 8D 0C 0C DD 6D 6D 6D 54 3D 51'
+ '10 36 10 DB 36 0D 0D 57 39 0D 0D 56 2E 36 CB AD'
+ '9C 10 47 6B 0F 05 4F 70 69 BB 4F BB 20 69 5F FB'
+ '20 B3 5F B3 67 05 47 2B 2B F2 CB 53 C4 D6 D6 1A'
+ '10 D2 39 58 C1 36 58 1A C1 D6 D6 A0 51 2D 62 3F'
+ 'FD D4 46 D3 46 FE 22 68 D4 5B 6F 3D 13 C5 13 D6'
+ '41 D6 10 56 C1 CA 1A 37 39 C1 A3 DA 1A D6 67 05'
+ 'C7 C0 47 0F C2 4F 4F B3 4F 20 20 1B FB 69 B3 3E'
+ 'F0 02 02 70 20 BB C2 CE 47 1B 1B 37 E3 36 0D 0D'
+ '10 10 D6 39 0D 41 7B D7 C1 C1 36 10 10 2D 62 29'
+ '29 F7 46 31 31 45 79 6F 6D DD 6D A5 13 21 51 52'
+ 'FF EA 52 1A 57 0D 0D C1 36 1A 0D 0D 1A D6 FB E2'
+ '2A 8C C2 CE 2B 05 CB 69 FB FB 5F 69 B3 02 B3 70'
+ '7E A3 7E B3 69 E2 47 C2 2B F2 32 37 0D 36 36 39'
+ '0D 0D 0D 39 C1 D2 C1 39 D7 39 0D C1 36 C3 D0 3D'
+ '29 D9 1F 1F 31 45 68 22 0C 6D F8 3D C5 51 C5 13'
+ '10 D6 52 41 C3 A0 52 5D D6 57 0D 7E 40 57 02 E2'
+ '3D E6 75 E7 05 20 20 FB 5F 3E 7E 20 7E B3 A3 DA'
+ '71 71 71 70 1B E2 0F C2 AD 34 32 C4 73 39 C1 39'
+ '73 58 36 D2 7E C1 1A DA C1 39 2F D6 D0 10 C3 08'
+ '3D 0C D4 31 0A 2A D4 68 6F 0C 6D 6D 54 C5 A9 13'
+ '36 36 2D 13 56 10 D6 DA 36 0D 57 7B 40 74 3E 2B'
+ 'DB 24 75 0F 72 1B 67 B3 02 70 02 02 7E 02 74 DE'
+ 'DE 8E DE 70 69 2B 47 C2 05 CB 34 1A 39 0D C1 CA'
+ 'D2 40 C1 0D E3 0D D2 0D D2 D2 73 0D D6 D0 62 62'
+ 'F3 19 79 79 79 8A 8D 68 C0 0C F8 54 3D A7 5C C3'
+ '36 7B 2D 51 10 52 10 D6 C1 36 74 0D 0D 51 7E 72'
+ '40 F1 AC E7 C2 CB 70 70 D7 7E 71 DE 8E 03 FF DE'
+ '4D B9 DE F0 1B E2 F9 E2 05 34 F2 0D 36 0D 36 0D'
+ '1A D6 C1 40 0D 36 36 40 40 C1 1A D2 1A 36 10 C3'
+ 'D1 FD 0C 19 31 2A EE 22 68 50 6D F8 AA A9 A7 52'
+ '53 C1 03 21 5C 10 FF 52 56 C1 0D 40 40 CA 36 05'
+ '34 E9 CB 0F 0F 1B 71 DA 8E 71 CA 03 F8 65 03 B9'
+ 'DA 8E DE 02 1B E2 47 2B AD D5 D5 D6 36 40 2F 0D'
+ '2F 36 0D 40 0D 36 5D 36 36 0D 1A DB 2C A0 C3 A0'
+ '29 FD FD D4 F4 FE 22 5E 68 A5 59 3D A7 AA 59 AA'
+ '7A 74 51 C3 52 13 5C 10 36 D6 57 A0 C1 4E FF 1B'
+ 'F2 5A 3E 25 0F 1B DA 2E 42 EA 8E 21 6F A7 8D 96'
+ 'DD 42 2E 26 1B 0F 47 2B 05 AD 53 DB D2 E3 1A D6'
+ '36 C1 7B C1 C1 C1 C1 36 DB 5D 3E 57 D6 10 51 51'
+ '2D 0C FD 33 33 1F 68 68 C0 6D 6D 59 59 FF 59 B9'
+ 'AD 56 C3 52 21 EA A0 10 5C 57 CA 56 0D 52 39 BB'
+ '05 98 CA 47 CE BB 74 71 A7 52 4D 21 3D 01 23 96'
+ '8A F8 1A 02 05 0F CE 2B F2 AD 37 10 2F C1 0D 0D'
+ '36 36 1A C4 40 E3 C1 C1 36 D2 58 C1 36 5D 21 51'
+ '51 E4 29 33 31 D3 EE 22 6F 6D A5 13 52 10 B9 A0'
+ '32 10 5C C3 A0 10 56 DB A0 36 1A 36 5D 36 2E 67'
+ '72 96 A9 0F 2B 4F B3 CA 42 FF 21 FF 6F 8D AB 18'
+ '18 1C 2E F0 F2 47 CE 05 1B F9 0D DB D6 36 0D D6'
+ 'D2 D6 A0 36 C4 DA 58 40 C1 36 36 73 10 D2 D6 51'
+ '51 2D FD 33 79 EC 8D 68 DD 6D F8 59 FF 21 59 56'
+ '7A 56 A0 57 56 2E 56 CA DE 1A 0D 36 CA 36 D4 67'
+ '2B 6D F6 47 25 72 5F DE 4D A7 C5 52 6F F8 22 96'
+ '8A 01 65 02 05 0F 0F 2B F2 E2 36 D6 A0 D2 10 C1'
+ '40 C1 41 41 0D 0D 39 C1 C1 1A 36 41 C1 10 4E A0'
+ '10 D1 2D 29 D4 D3 0C 0C 6D 3D A7 A9 21 AA 52 57'
+ '7E 57 1A 56 56 56 36 1A 56 57 1A 36 58 DE D0 FB'
+ '72 77 DD 75 CE 72 5F DE FF 94 6F F8 50 C5 4B 22'
+ '1F 23 DD F0 05 C2 0F 05 05 4A 36 10 D2 10 D6 10'
+ '0D 0D 39 40 A0 D6 39 36 7B 39 39 C1 1A A0 5D C3'
+ 'C3 3D D1 0C D9 33 5B 0C 6F C5 C5 52 52 42 59 7E'
+ '56 7B 40 40 7B 1A 1A 74 1A 57 57 36 DE 36 DA 67'
+ '05 02 E0 C2 E7 0F 7A 77 FF 6D F8 C5 0E DD 21 C5'
+ 'C0 6A 6F A3 2B CE 47 05 1B E2 1A 36 DB D6 10 D6'
+ '10 DB D2 C1 41 BF D2 1A 36 C1 36 41 C3 10 36 C3'
+ '2D FD D9 3F 1F 79 6D 54 A5 C5 13 A9 21 AA 10 C1'
+ '36 0D 7E 0D 7E BD 0D 1A DA 74 1A 36 1A 57 57 37'
+ '2B 69 0E 72 E7 0F 4F 70 8E F8 50 1F 6F 79 1C 1C'
+ 'DD F6 EA 70 C2 C2 47 2B 1B 32 D2 DB 36 36 DB 10'
+ '2C 10 10 36 D2 D6 C1 C1 C1 C1 36 5D 36 D6 D0 D0'
+ 'C3 08 FD 3D 33 D4 F8 3D 6D 54 C5 D1 A9 52 EA 4E'
+ '36 36 36 3E 5F 3E 40 0D 0D 5D 71 36 DE 1A 74 70'
+ '05 69 42 72 0F C2 05 5F 8E A5 68 E0 C0 22 50 33'
+ '0C F8 DE CB 2B C2 05 F2 1B 32 D2 C1 36 D6 D6 D2'
+ '36 C1 D6 10 DB 10 DB DB E3 2F 5D D6 A0 2E A0 C3'
+ '62 21 FD D4 3D 79 6F 6D 6D C5 6F 5C 4D 52 5C 56'
+ 'A0 DB 36 D2 58 53 58 0D E3 C1 1A 1A 7B 56 36 40'
+ '72 69 F5 69 7D CE 72 BB A3 A5 6F AB 55 CC 8A CC'
+ 'AF E0 FF CB 47 0F 2B 1B 34 37 D6 D6 D2 D6 DB D6'
+ '10 C1 DB 36 36 10 10 10 10 36 36 C1 36 10 2D C3'
+ '13 2D 29 D4 D4 46 6D 3D 3D A5 13 A9 52 77 B9 56'
+ '36 74 74 3E 3E 53 BD 7B 40 57 7B 7E DA 10 1A 1A'
+ '4F 4F DE FB 7D C2 0F BB B3 C5 8D 23 96 96 FA EE'
+ '23 18 42 CB 2B C2 2B F2 05 39 C8 10 10 DB 36 D2'
+ 'D2 DB 36 36 D6 10 DB 36 36 10 D0 10 41 36 D0 D0'
+ 'D1 D1 D1 D4 0A D3 C0 6F 3D A7 5C 52 10 A0 52 B9'
+ '1A 7B 7E C1 74 34 53 7B 3E C1 40 7E 58 57 36 71'
+ '4F 05 DE FB 47 0F C2 4F 70 A5 22 A4 6C E1 24 63'
+ '8A C0 F0 05 0F 47 E2 F2 32 39 D6 36 1A DB 2D D6'
+ 'D6 D6 36 0D D2 10 D6 36 A0 D2 D6 10 51 10 A0 D0'
+ 'D1 FD D9 46 EC F4 6D 3D 6D C5 4B AA C3 52 B9 77'
+ '1A 0D 0D 3E 0D C1 67 0D 7B 0D 57 DA 7E C1 DA 40'
+ '05 05 A6 FB 0F E7 CE 72 7E A7 23 06 6C 90 C7 90'
+ '6E A5 26 05 47 C2 05 1B 05 41 10 5D 36 36 D0 DB'
+ 'D2 0D 36 D6 C1 36 2F 36 D2 41 36 36 10 C3 D0 51'
+ '51 D1 79 31 79 D3 33 6F 6D 54 2D 5C 52 21 52 56'
+ 'A0 CA D6 CA 74 5D 57 1A 57 1A C1 57 D6 41 71 74'
+ '1B F2 69 20 0F CE 25 72 20 A7 A4 A8 5A 93 7C 87'
+ '60 5B FB 78 E7 C2 E2 1B AD 21 D0 D6 D6 D6 C3 D0'
+ '36 36 D2 36 0D 36 36 A0 D6 EA 10 10 2C C3 2D 2D'
+ 'D1 2D D9 D4 79 EC C0 0C 6F 54 1C C5 52 A9 B9 21'
+ '52 4E 2E 56 10 0D 0D 36 1A 1A 0D 57 D6 4E 1A 36'
+ 'CB 72 69 20 C2 CE 6B 72 69 42 23 A8 3A 17 17 27'
+ '24 DD B3 C2 25 2B E2 1B 34 2E C3 C3 C3 10 51 D1'
+ '10 A0 36 36 36 0D 36 E3 30 36 BF D6 C3 51 62 FD'
+ 'D1 2D 29 F7 33 79 79 0C AB EE 59 13 52 A9 AA 13'
+ '52 56 D6 56 41 56 36 CA 0D CA 1A 1A 1A DE 0D 1A'
+ '5F 05 69 69 C2 E7 0F 0F BB 71 5E 60 3A B6 49 17'
+ '64 6F 05 0F CE 2B E2 CB 34 5D 21 5C 10 57 D0 D1'
+ '36 DB 10 36 D2 D2 1A 0D 36 D6 D6 C3 D0 51 62 D1'
+ '2D D1 0C D4 79 31 5B 0C 8D 3D 59 52 21 3D C5 A7'
+ '52 A0 56 DB 1A 56 5D 36 CA 56 5D 57 57 57 57 DA'
+ '70 05 FB 70 72 CE EF 0F 4F 70 6F EB 7C B6 B6 CF'
+ 'BE A7 75 CE 47 2B E2 BB 34 A3 36 D2 57 0D D6 95'
+ '2D D0 41 36 DB 36 41 10 D0 A0 10 10 C3 D0 51 D1'
+ 'D1 6D 29 D4 19 31 68 C0 C0 6D 3D 3D 13 54 A5 A7'
+ '52 10 D6 36 D6 36 36 57 CA 57 57 74 7B 57 1A 0D'
+ 'DA 72 70 F0 4F CE 6B CE 4F 7E DD 60 7C 88 88 CF'
+ '98 26 1D CE C2 75 AD F2 32 37 39 36 36 C1 58 D6'
+ '3D 2D D6 36 51 D0 41 DB 10 A0 10 C3 21 C3 51 2D'
+ '2D F3 D1 6D C0 EE 0C C0 5B 6F 13 51 C5 3D A7 5C'
+ '10 2E 56 A0 57 2E 74 57 57 57 1A 57 CA 36 A3 1A'
+ 'A3 E2 5F A6 72 75 CE E7 72 5F 65 6E 86 88 49 27'
+ 'DD 20 0F E7 0F 2B 05 BB 37 3E 7B 20 3E A3 40 0D'
+ '10 DB D6 D6 56 51 13 D0 DB D0 D0 10 51 13 2D 2D'
+ '3D 3D D9 D9 5B 79 0C 0C 6D 0C 3D D1 59 6D 59 AA'
+ 'A9 56 56 52 4E A0 36 1A 57 57 0D 40 57 36 0D 57'
+ 'DA 2B 69 0B 05 0F 25 25 C2 4F 4D 96 DF B6 B6 DC'
+ 'A7 7A C2 E7 C2 E2 7A 05 53 3E 20 5F 14 C6 7B D6'
+ '36 D6 57 D2 36 D0 2C 13 13 C5 13 5C D0 2D 3D 29'
+ '29 29 5B 6D 5B D4 C0 0C 0C 54 A5 13 6F 6D C5 C5'
+ '52 10 36 57 B9 5C 36 36 56 74 CA 1A 1A 74 1A 1A'
+ '74 72 1B 94 67 0F 25 6B 0F BB 4D 96 49 B6 17 EE'
+ '5F C2 E7 CE 2B E2 F2 BB 3E D7 53 34 20 5F 5F 36'
+ '57 36 D6 1A 40 57 EA D0 C5 F3 D0 3D D1 62 0C 62'
+ 'F3 3D 29 0C 79 79 0C 6F 6D 6D A5 54 6D 6D C5 A9'
+ '52 56 57 0D 77 B9 77 36 56 36 2E 56 1A 1A 1A 57'
+ '71 05 F2 F6 FB E7 47 25 E8 72 A3 6A E9 64 8D 74'
+ 'AC E7 E7 CE 2B 1B F2 AD 3E 3E 5F 20 12 5F BD C1'
+ '0D 57 10 56 5D 1A 56 EA 13 D1 D1 3D D0 62 13 2D'
+ 'D1 6D D1 D4 D4 5E 22 C0 6D F8 3D 2D C5 C5 59 A5'
+ 'A0 56 5D 57 4E B9 10 CA 57 CA 77 2E 5D 56 36 1A'
+ '0D BB 1B 84 69 C2 CE E7 25 CE 3E 42 6D FF 71 69'
+ '0F 25 EF CE F2 FB CB 7A 7E C4 74 BD 7E 3E 3E 74'
+ '57 0D 57 E3 56 A0 1A 56 10 5C 2D 33 2D 6D D1 3D'
+ '51 3D 6D FD 0C 1F 0C 6D DD 6F C5 6D 54 6D 6D A7'
+ '56 36 36 10 EA EA B9 56 77 56 10 2E 56 A0 A0 2E'
+ '1A 1B CB 01 5F CE E8 25 E8 6B BB DE 0B 70 5F 72'
+ 'E7 E7 25 0F D5 F2 1B 7A 0D 3E 40 3E 3E 7B 7B 3E'
+ '3E 7E 7E 3E 0D 74 36 56 10 C3 52 D1 51 95 5B FD'
+ 'FD 33 D4 5B 79 D4 0C 6D 22 6F D1 D1 F8 6D A5 3D'
+ '10 52 EA EA 52 52 52 A0 10 10 A0 C3 56 A0 10 56'
+ '40 5F BD 04 70 E7 0F E8 EF 25 BB A3 84 59 70 BB'
+ '75 25 6B E7 F2 BB AD BB 7B 40 3E 20 0D 3E 58 37'
+ '3E 3E 3E 3E 20 3E 74 58 57 A0 5C AA 13 13 29 33'
+ '0C 5B D4 FD 33 D3 68 6D 29 6D AA 54 6F DD 6D 54'
+ '1A 52 56 2E AA A0 A9 AA 51 51 21 52 52 52 10 56'
+ '7E 67 2F 76 FF 47 CE 25 6B 2B 71 E6 27 17 98 8E'
+ 'C2 25 CE 25 2B 1B 1B 7A 7B 3E 7E 57 40 3E 0D 7E'
+ '3E 39 7E 37 20 3E 58 7E 74 74 EA 51 62 13 3D D4'
+ 'D4 29 D1 3D C0 D4 F8 29 2D A5 54 54 6D 6D 6D 52'
+ '0D 56 A0 52 52 4E 21 2C 5C 51 52 EA 52 A0 FF 1A'
+ '5F 73 51 35 21 0F CE CE E7 69 42 17 8B 8B C9 4D'
+ '78 E7 6B CE 0F F2 1B 7A 58 1A 7B 0D 58 40 3E 58'
+ '58 7E 3E 3E B3 5F B3 3E 3E 57 57 74 C5 13 2D 2D'
+ 'D4 79 79 5B 5B 79 C0 6F 6F F8 6D A5 6D 0C 68 6D'
+ 'B9 77 77 56 56 77 CA 56 EA 52 52 4E 56 36 A0 C1'
+ 'BD BD 3D C9 40 F9 47 0F 25 72 3E 68 60 E6 ED 70'
+ 'C2 CE CE E7 25 05 AD C6 58 74 0D C1 B3 D7 3E D7'
+ '71 7B 71 58 3E 3E 7E 3E 3E B3 3E 74 10 10 13 3D'
+ '29 3D D4 31 31 CC 6D 6D 6D 6F 54 6D 6D 6D 6D A9'
+ 'A0 52 A0 56 DE 41 4D 56 1A 4D 56 5D 4D 1A DB 36'
+ 'B3 1B BB D7 E2 CE CE E7 0F 0F 2B 1B BD B3 5F BB'
+ '0F 47 CE 25 E7 32 CA 7A CA 36 CA 1A 57 57 7B 74'
+ '7B 7B 57 74 40 7B 7B 58 7E 0D 74 7B 57 B9 B9 AA'
+ '54 0C 6D D4 EE EC DD 54 6D 59 59 6D 6F 6D 6D A7'
+ '52 52 56 10 56 EA 77 4E CA 77 7B 1A 57 D6 57 D6'
+ 'D5 2B F9 47 47 47 25 7D E7 E8 6B E7 47 E7 47 E7'
+ '47 6B 47 25 0F F2 C0 7A 36 4D 56 41 10 D6 57 1A'
+ '0D 0D 0D 57 1A 7B 40 0D 57 57 36 57 0D 36 CA EA'
+ '51 2D 5B D9 D4 D3 6D 6F 59 A7 A9 59 54 6D 6D A9'
+ '5C 10 21 A0 56 57 56 77 A0 56 0D 74 0D 77 1A 02'
+ '67 AD C2 E7 47 CE E7 25 25 6B 25 E7 6B 7D E7 E7'
+ 'CE CE E7 47 47 C2 34 1B 37 4E 10 CA 56 36 56 56'
+ 'DB CA 36 1A 36 56 56 1A CA 1A 36 5D D6 CA 56 56'
+ '2E 5C D1 0C 33 8D 6F A5 A7 52 52 59 59 59 AA 52'
+ 'B9 DE A9 52 10 56 4D 4E 77 DE 36 57 57 CA 3E 73'
+ '02 C1 F2 2B D5 40 C1 D2 C3 41 36 C1 39 37 37 D7'
+ '3E 34 34 CB E2 E2 05 67 34 FF 5C 10 36 A0 10 56'
+ 'EA 56 36 4E 2C 10 4E 36 56 56 4E CA 56 56 4E C3'
+ '52 C3 52 D1 54 EE 59 54 A5 5C A7 A7 59 A7 B9 B9'
+ 'B9 56 77 77 52 52 C3 10 36 10 74 1A A0 10 4D 70'
+ 'AD 2B 2B 1D 6B 6B 7D 25 E8 E7 6B 6B 6B E7 E7 25'
+ '78 47 75 C2 05 F2 1B 34 39 52 A0 4D A0 36 36 1A'
+ '56 36 4E A0 DE 56 2E EA 10 52 10 56 56 56 A0 52'
+ 'C3 52 13 D1 2D 5B A5 6D 54 59 59 94 59 65 A9 B9'
+ '56 B9 4D 56 56 52 52 AA 5C 4E 56 36 A0 1A 2E 21'
+ 'D5 F9 32 47 47 C2 E7 CE 47 75 AC 14 14 92 37 7A'
+ 'AC E2 75 47 2B E2 BB BB 56 52 56 56 36 56 56 36'
+ '36 57 B9 36 57 4E 36 56 36 4D 52 2C 52 A0 52 52'
+ 'EA 13 59 2D 59 3D 59 6F 59 A5 59 59 59 A9 A7 52'
+ 'B9 56 56 77 4D 56 B9 A9 A9 52 10 36 52 56 A0 56'
+ '70 DA 21 1B 2B 47 47 47 CE E7 47 47 47 47 E7 CE'
+ 'CE 0F 47 47 2B C8 51 32 A0 A9 52 A0 A0 A0 36 2E'
+ 'A0 E3 1A 36 36 36 56 10 10 10 5C C5 2D A0 56 EA'
+ '52 D1 4B 5C 13 2D 59 6D 0E A5 54 A5 59 59 A9 52'
+ '4D B9 4D 56 77 57 56 B9 B9 A0 56 10 42 13 36 71'
+ 'BD E2 E2 C2 47 3C E7 6B E8 EF E8 6B 47 6B 7D B7'
+ '7D 1D CE E2 32 15 CF CB D7 52 10 10 EA A0 4E 56'
+ '5D 56 A0 D6 52 A0 13 A0 5C 51 A9 C3 4B AA 5C C3'
+ '52 21 52 5C 59 3D 59 A5 6D 65 6D 6D 6D A9 A9 4D'
+ 'B9 B9 56 56 56 56 4D 36 52 B9 A0 56 A0 5C 10 DA'
+ '67 2F 39 2B C2 C2 7A D2 10 2D 29 D9 46 D4 33 0C'
+ '3D EA 39 BB 05 37 46 67 32 42 5C 52 10 C3 36 5D'
+ '74 4E 4E 77 52 AA 5C 52 52 52 A0 52 D0 52 2D 52'
+ '4E EA 52 21 52 C5 0E 6D 6D 59 59 A5 A9 59 A9 B9'
+ '52 B9 52 56 B9 77 56 4D 52 B9 77 1A 56 A0 2E 57'
+ '05 E2 E2 47 E7 B7 47 E7 6B E8 85 E7 6B E7 7D E7'
+ '0F 47 7D 47 E2 05 34 D5 37 13 62 21 52 4E 56 53'
+ '0D 57 77 57 56 1A 52 5C AA 10 52 13 D0 5C 5C 13'
+ 'C3 77 AA 13 52 AA 6D 6D 6D 0E 59 59 59 A9 A9 52'
+ '52 52 52 56 56 77 5D 56 B9 56 B9 56 77 77 77 57'
+ 'BD 32 D0 4A CE CE 75 75 75 32 53 C4 2F DB 2F 34'
+ 'AC 75 C2 47 C2 E2 BB 34 10 D1 3D 51 51 4D 0D 58'
+ '2E 5D 56 36 1A 57 DE B9 A0 A9 52 52 21 21 21 51'
+ '54 2D C5 5C A9 13 6F ED 6F 6D 6D 6D AA 65 A9 A9'
+ '5C 52 56 56 56 56 4D 57 4D 5D B9 10 56 36 0D DA'
+ '02 34 2E C2 E7 3C 7D 85 E7 E7 E7 7D 7D E7 E7 B7'
+ '47 7D 47 7D 2B D7 29 34 52 C5 2D 1C 54 10 E3 56'
+ '4E 77 56 2E 57 5D 5D 36 1A CA 21 2D 13 13 13 AA'
+ '62 1C 2D 6F 3D 5B 68 68 8D ED 6D A5 59 59 59 B9'
+ 'A9 56 52 56 B9 B9 4E 56 B9 A9 A0 56 56 56 4D 57'
+ '67 2C B0 32 E7 47 E7 47 78 9F 92 92 12 9F C6 7A'
+ 'AC 32 75 47 E2 67 F8 BB DA 10 52 AA 54 5D 57 77'
+ 'B9 56 57 57 56 57 56 56 56 10 52 52 2D 52 54 C5'
+ '59 D1 5B 54 6D 0C 8D 68 DD 6D A5 59 59 A9 AA A7'
+ 'A9 B9 56 B9 4E 4E B9 56 56 52 4E 56 56 52 B9 7E'
+ 'BB 65 CC 7A 47 F9 75 BB 39 0D 0D C1 58 53 34 C6'
+ '7A 34 F2 78 2B AD CB B3 53 56 1A B9 A9 36 56 57'
+ '56 B9 A0 5D 77 B9 56 56 56 A0 52 56 A7 5C 13 13'
+ '13 C5 5B 6D C0 5B EE 6A EE 6F 59 59 A5 59 52 A7'
+ '52 52 52 B9 56 B9 56 4D 56 FF B9 57 52 B9 56 77'
+ '05 78 F9 3C 6B 6B E8 3C 7D B7 CE 7D 6B 47 47 7D'
+ '0F 47 E7 47 E2 F2 D5 D5 7E 56 52 10 56 57 56 56'
+ '77 77 57 B9 56 5D 52 EA B9 A0 52 21 52 FF A7 AA'
+ '59 13 54 54 5B 5B 55 EE 22 68 6F 6D 59 A7 59 C5'
+ 'AA 52 5C 56 52 52 52 B9 A0 52 52 56 B9 B9 B9 52'
+ '58 AD 37 7A 7D E7 6B 3C E2 5F 5C AE D9 79 52 34'
+ 'AC 1D 7D F9 2B 32 7A D7 5C 10 52 CA 56 77 56 56'
+ '56 10 56 56 56 52 52 52 A9 5C 5C 52 52 4E 10 10'
+ '4D 52 2D 54 5B 6D 6A 23 CC EE 6F 54 6F 6D AA AA'
+ '59 59 52 52 B9 42 52 FF 5C 52 B9 52 52 52 2C B9'
+ 'FF B3 CD 98 E2 7D E7 47 E2 CA 5A 6C CC B9 20 E2'
+ 'C2 05 4A 75 F9 F2 34 1A A5 AA 4D 52 B9 52 B9 56'
+ 'B9 57 5D 4E B9 A0 52 52 52 A9 C5 13 AA 3D 5C 1A'
+ '5B AA 59 AA 6D 5B AB 5E 8A EE A5 6D A5 54 6D C5'
+ '59 59 52 52 52 52 AA 21 59 52 52 AA 52 5C B9 FF'
+ '10 3E CF 60 E2 F9 6B 7D AC 57 92 AC 1D AC 34 B3'
+ '1B 1B AD 4A E2 BB D5 C1 A7 AA A9 5C 52 52 AA B9'
+ '4E 56 77 52 B9 10 A9 52 4E 52 AA 52 59 59 5B 59'
+ '5B 56 2D 0C 6D 0C D3 CC CC 68 68 68 54 65 59 2D'
+ '6F A7 59 AA 5C 52 AA A9 AA AA 52 A9 52 A9 AA AA'
+ '52 1A 88 38 AC 7D 7D E7 75 78 75 78 78 1D 75 7A'
+ '61 D5 05 E2 E2 34 D5 D7 A9 52 A9 52 5C 4E A9 56'
+ '56 2C B9 EA 52 52 B9 52 AA 13 C5 C5 54 51 C5 59'
+ '13 2D C5 3D 0C C0 55 96 AB 0C 33 0C F8 54 2D 59'
+ 'AA 59 54 A9 59 59 59 A5 54 AA 2D C5 2D 54 3D C5'
+ '10 D2 76 6A 78 E7 85 B7 78 47 0D 36 7B 02 05 78'
+ 'F2 D6 D7 4A 4A CB BD 3E 5C A9 52 52 B9 B9 CA 57'
+ '56 B9 FF 52 A9 5C 52 A9 51 A9 13 AA AA A5 A9 D1'
+ '54 6D 6D 59 0C EE B8 55 23 33 68 8D 6D 6D 59 59'
+ '59 6D 2D 6D 6D 59 2D 6D 6D 54 6D 0C 54 6D 54 6D'
+ 'A7 7E 76 DD E2 B7 75 AC 75 AC C1 36 7E 39 D5 4A'
+ 'AC C1 79 32 F2 09 D7 58 A7 5C B9 2C 56 56 56 56'
+ '56 77 B9 5C 52 5C 5C 52 AA AA 5C 5C 5C AA 2D 59'
+ '6D 0C 0C 5B 95 33 6A AB EE EE C0 EE 0C DD 59 59'
+ '5B 6D 6D 6D 0C 54 DD AA AA 2D 54 3D 13 3D 3D 3D'
+ 'AA 7A 0C 77 78 78 58 E2 78 32 7B 7B 0D 58 3E 34'
+ '67 DA DE 05 1B 53 BD 58 59 AA 5C B9 52 36 4E 4E'
+ '52 41 52 52 A9 52 A7 A7 AA 59 AA 21 59 C5 54 54'
+ '95 5B 97 68 29 5E 1F EE EE 6A 6D 68 1F 22 F8 C5'
+ '6D 6D 5B 68 5E 3D 6D 2D 59 AA 52 52 A9 AA AA AA'
+ 'AA 7A 32 32 78 1D 4E AD AC 78 0D 5D 40 7E BD 8E'
+ 'EE 01 7E CB C6 5F 34 10 C5 54 54 AA B9 52 52 52'
+ '4E B9 B9 52 52 5C 52 5C 52 52 52 5C 52 AA F8 6D'
+ 'C0 5E C0 68 EE 55 6A 6A 22 5B 0C DD EE 68 EE 6D'
+ '54 6D D4 68 6A AA AA 54 AA C5 54 6D 6D 2D 5C A7'
+ 'C5 58 4A AD 1D 47 AD AD 32 AC 7A 58 C4 53 1B 1A'
+ '60 4B 09 09 D5 34 53 6D 59 54 3D 5C 52 10 52 B9'
+ '10 52 B9 2C 5C B9 52 B9 10 2D 13 59 54 59 95 5B'
+ '95 5B 33 C0 97 8A AB 68 22 22 68 5E 68 5E 68 5B'
+ '6D 5B 5B 31 5E 59 AA 54 3D 54 2D 54 2D C5 A9 AA'
+ '13 52 AC 78 78 1D F9 78 AD 80 11 34 AC 4A 4A D7'
+ 'C5 7A 34 34 BD 34 51 6D C0 5B 59 13 5C 5C 52 52'
+ 'A9 AA AA 52 52 52 52 A0 13 AA A9 13 2D AA 3D 54'
+ '6F 5E 0C D9 AB 8A 68 22 68 68 6F 6A 6A EE EC 8D'
+ '0C 0C EC 68 2D 6D C5 59 C5 2D AA 59 59 AA 62 A9'
+ 'A7 54 41 AC 4A 1D 7D 7D 32 AB 64 3E 78 AD 53 40'
+ 'BD D5 34 BD 7A C3 D1 5B 5E 5B 54 3D 59 13 A5 AA'
+ '54 C8 B9 2C 10 52 52 5C 21 C5 13 5C 54 59 2D 5B'
+ '5B EE D4 EC EE B8 5E 0C 6D 5B 6A 6A EE CC CC 31'
+ '6A 33 22 6D 59 AA 54 6D 54 3D 54 6D 3D 6D 59 13'
+ 'AA 54 2D 41 AC B1 14 78 78 32 3E C6 D5 58 7B D5'
+ '34 D5 7A C6 13 5E 8D 0C 29 3D 6D 3D 6D 6D 5B 5B'
+ '54 59 2D 5C 59 5C AA 52 AA AA 5C 62 6D 54 3D 5B'
+ '5B 5B 68 EE 6A 1F 68 6F 6D 6D 6D 33 33 1F EE 5E'
+ 'EE EC 68 2D 2D 5C 3D AA 59 54 59 6D 6D 95 6D 54'
+ '5C 54 59 6D 13 12 AC 1D 78 78 75 B1 32 AC AC 32'
+ '32 14 E3 54 0C 55 1F 55 1F EE C0 EE D4 EE 5B 6D'
+ '54 6D 6D 54 6D 54 54 2D 54 54 AA 59 29 54 5B 68'
+ '68 5E 23 55 EE EE 5E 6D 0C 0C EE CC 1F EE 5E EE'
+ '1F EE 33 AA 5C AA 5C C5 59 AA AA 2D 59 54 AA 3D'
+ '54 2D 2D 5B 6D 5B 41 C6 78 1D AC 75 78 AC AC 7A'
+ '58 13 54 68 5E 5B EE 5E 68 5B 97 0C 0C 5E 5E 0C'
+ '0C 6D 6D 6D AA D9 6D 6D 54 54 54 2D 5E C0 5E 0C'
+ 'EC EC D9 5E 33 EE EC 68 1F 6A 4C 55 EE 1F 29 5B'
+ '5B D9 6F 54 C5 59 59 2D 2D 54 6D 6D 6D 2D 59 54'
+ '6D 6D 6D 0C 5B 54 5B 54 10 36 BF 30 2F BF 10 AA'
+ '54 68 2D 5B 0C EE 33 5E 33 5B C0 EE EC 5E 97 6A'
+ '33 33 68 5E 0C EC 5E 1F EE 68 0C 5E EE 55 31 2A'
+ '31 EE AB 31 1F 0C A4 A4 55 6A CC 6A AB EE D4 8D'
+ '6A 96 55 0C 5B 5B 6D 54 6D 5B 2D 2D 2D 54 5B 6F'
+ '33 5B 0C 6D 5B 6D 6D 54 D9 5B 6D 54 59 AA 62 6D'
+ '5B 5B 5E 5E 68 33 0C EE 8D 5E 55 EE EE EE 5E CC'
+ 'EE 31 EC EC 8D EE 1F 1F EE 55 55 97 6A A4 AB AB'
+ '8A B8 96 11 96 8A B8 4C 96 96 AB 96 AB 6A EE 55'
+ '55 A4 AB 31 EE 33 0C 5B 5B 6F 5B 5B 3D 0C 5B 5B'
+ '5B 6D 5B 97 6A 0C 33 C0 5E 68 68 0C 68 33 5E 22'
+ '33 D4 EE 1F EE 8D 6A EE 31 55 55 55 8C 8A 55 8A'
+ 'D3 AB CC 55 8C 8A 55 55 55 55 6A 11 96 55 4C 6E'
+ 'A4 11 63 4C A4 4C 13 AA 5C AA 51 AA 10 5C 41 52'
+ 'DB 2D 2C DB DB DB 4E DB 41 BF DB 36 5D 2F D2 5D'
+ '41 DB D2 10 41 4E 41 DB DB 5D 36 D2 36 2F 36 41'
+ '4E 5D 5D 4E 36 7F 4E DB 10 5C 4E D0 AA 10 2C 5C'
+ '5C 4E 2C 10 D0 2C 5C 10 41 5C 10 C8 AA 2D 51 3D'
+ 'AA 3D AA 5C 13 D0'
+}
Index: /gsdl/branches/nzdl2/gsinstaller/splash.c
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/splash.c	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/splash.c	(revision 14219)
@@ -0,0 +1,135 @@
+#include "Splash.h"
+
+#define bool int
+#define false 0
+#define true 1
+
+UINT		timer;
+HWND  	splash_window;
+BOOL		splash_done;
+HBITMAP splash_bmp;
+int			splash_bmpheight;
+
+void CALLBACK splash_timerproc(HWND Window, UINT Message, UINT id, DWORD time)
+{	splash_done	= TRUE;
+  KillTimer(NULL, 0);
+}
+
+long FAR PASCAL _export splash_windproc(HWND Window, UINT Message, WPARAM wParameter, LPARAM lParameter)
+{	switch (Message)
+	{ case WM_CREATE:
+  	{ timer = SetTimer(NULL, 0, 3000, (TIMERPROC) splash_timerproc);
+    }
+  	break;
+
+  	case WM_TIMER: // valid id; just kill window after timer elapses
+      splash_done = TRUE;
+    	KillTimer(Window, 0);
+  	break;
+
+    case WM_DESTROY:
+      splash_window = 0;
+    break;
+
+		case WM_PAINT:
+		{ PAINTSTRUCT	PaintInfo;
+    	HDC					dc, bmpDC;
+      BITMAP			bmpData;
+      POINT				origin, size;                                        
+
+			dc = BeginPaint(Window, &PaintInfo);
+      bmpDC	= CreateCompatibleDC(dc);
+      SelectObject(bmpDC, splash_bmp);
+
+      GetObject(splash_bmp, sizeof(BITMAP), (LPVOID) &bmpData);
+
+      size.x = bmpData.bmWidth;
+      size.y = bmpData.bmHeight;
+      DPtoLP(dc, &size, 1);
+
+      origin.x = 0;
+      origin.y = 0;
+      DPtoLP(dc, &origin, 1);
+
+      BitBlt(dc, 0, 0, size.x, size.y,
+             bmpDC, origin.x, origin.y, SRCCOPY);
+
+      DeleteDC(bmpDC);
+			EndPaint(Window, &PaintInfo);
+		}
+		break;
+
+    case WM_COMMAND:
+    break;
+
+  	default:
+			return(DefWindowProc(Window, Message, wParameter, lParameter));
+  }
+	return 0L;
+}
+
+void splash_register(HINSTANCE instance)
+{ WNDCLASS Class;
+	static bool registered = false;
+  if (registered == false)
+  {	Class.lpszClassName = "Generic:Splash";
+		Class.hInstance     = instance;
+		Class.lpfnWndProc		= (WNDPROC) splash_windproc;
+		Class.hCursor				= LoadCursor(NULL, IDC_ARROW);
+		Class.hIcon					= NULL;
+		Class.lpszMenuName  = NULL;
+		Class.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
+		Class.style 				= NULL;
+		Class.cbClsExtra		= 0;
+		Class.cbWndExtra		= 0;
+		RegisterClass(&Class);
+    registered	= TRUE;
+	}
+}
+
+void _export splash_show(HINSTANCE instance, unsigned int time)
+{ MSG 		msg;
+  RECT 		r;
+  BITMAP	bmpData;
+  POINT		size;
+  int     sx, sy;
+  HDC     dc;
+
+  splash_register(instance);
+
+  splash_bmp	= LoadBitmap(instance, (LPCSTR) MAKEINTRESOURCE(9007));
+	splash_done = FALSE;
+
+  GetObject(splash_bmp, sizeof(BITMAP), (LPVOID) &bmpData);
+  size.x = bmpData.bmWidth;
+  size.y = bmpData.bmHeight;
+
+  r.left		= 0;
+  r.top	 		= 0;
+  r.right		= size.x;
+  r.bottom	= size.y;
+  AdjustWindowRect(&r, 0, TRUE);
+
+  splash_bmpheight	= size.y;
+  dc = GetDC(GetDesktopWindow());
+  sx = GetDeviceCaps(dc, HORZRES);
+  sy = GetDeviceCaps(dc, VERTRES);
+  ReleaseDC(GetDesktopWindow(), dc);
+
+	splash_window = CreateWindow("Generic:Splash", "Greenstone Installer",
+																WS_DLGFRAME | WS_VISIBLE,
+                                (sx - r.right + r.left) / 2,
+                                (sy - r.bottom + r.top) / 2,
+                                r.right-r.left, r.bottom-r.top,
+                                0, 0, instance, NULL);
+  while (GetMessage(&msg, NULL, NULL, NULL) &&
+  				splash_done == FALSE)
+  { if (msg.message == WM_TIMER)
+  	{ msg.hwnd = splash_window;
+    }
+  	TranslateMessage(&msg);
+  	DispatchMessage(&msg);
+  }
+  DestroyWindow(splash_window);
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/splash.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/splash.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/splash.cpp	(revision 14219)
@@ -0,0 +1,131 @@
+#include "Splash.h"
+
+UINT		timer;
+HWND  	splash_window;
+BOOL		splash_done;
+HBITMAP splash_bmp;
+int			splash_bmpheight;
+
+void CALLBACK splash_timerproc(HWND Window, UINT Message, UINT id, DWORD time)
+{	splash_done	= TRUE;
+  KillTimer(NULL, 0);
+}
+
+long FAR PASCAL _export splash_windproc(HWND Window, UINT Message, WPARAM wParameter, LPARAM lParameter)
+{	switch (Message)
+	{ case WM_CREATE:
+  	{ timer = SetTimer(NULL, 0, 3000, (TIMERPROC) splash_timerproc);
+    }
+  	break;
+
+  	case WM_TIMER: // valid id; just kill window after timer elapses
+      splash_done = TRUE;
+    	KillTimer(Window, 0);
+  	break;
+
+    case WM_DESTROY:
+      splash_window = 0;
+    break;
+
+		case WM_PAINT:
+		{ PAINTSTRUCT	PaintInfo;
+    	HDC					dc, bmpDC;
+      BITMAP			bmpData;
+      POINT				origin, size;                                        
+
+			dc = BeginPaint(Window, &PaintInfo);
+      bmpDC	= CreateCompatibleDC(dc);
+      SelectObject(bmpDC, splash_bmp);
+
+      GetObject(splash_bmp, sizeof(BITMAP), (LPVOID) &bmpData);
+
+      size.x = bmpData.bmWidth;
+      size.y = bmpData.bmHeight;
+      DPtoLP(dc, &size, 1);
+
+      origin.x = 0;
+      origin.y = 0;
+      DPtoLP(dc, &origin, 1);
+
+      BitBlt(dc, 0, 0, size.x, size.y,
+             bmpDC, origin.x, origin.y, SRCCOPY);
+
+      DeleteDC(bmpDC);
+			EndPaint(Window, &PaintInfo);
+		}
+		break;
+
+    case WM_COMMAND:
+    break;
+
+  	default:
+			return(DefWindowProc(Window, Message, wParameter, lParameter));
+  }
+	return 0L;
+}
+
+void splash_register(HINSTANCE instance)
+{ WNDCLASS Class;
+	static bool registered = false;
+  if (registered == false)
+  {	Class.lpszClassName = "Generic:Splash";
+		Class.hInstance     = instance;
+		Class.lpfnWndProc		= (WNDPROC) splash_windproc;
+		Class.hCursor				= LoadCursor(NULL, IDC_ARROW);
+		Class.hIcon					= NULL;
+		Class.lpszMenuName  = NULL;
+		Class.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
+		Class.style 				= NULL;
+		Class.cbClsExtra		= 0;
+		Class.cbWndExtra		= 0;
+		RegisterClass(&Class);
+    registered	= TRUE;
+	}
+}
+
+void _export splash_show(HINSTANCE instance, unsigned int time)
+{ MSG 		msg;
+  RECT 		r;
+  BITMAP	bmpData;
+  POINT		size;
+  int     sx, sy;
+  HDC     dc;
+
+  splash_register(instance);
+
+  splash_bmp	= LoadBitmap(instance, (LPCSTR) MAKEINTRESOURCE(9007));
+	splash_done = FALSE;
+
+  GetObject(splash_bmp, sizeof(BITMAP), (LPVOID) &bmpData);
+  size.x = bmpData.bmWidth;
+  size.y = bmpData.bmHeight;
+
+  r.left		= 0;
+  r.top	 		= 0;
+  r.right		= size.x;
+  r.bottom	= size.y;
+  AdjustWindowRect(&r, 0, TRUE);
+
+  splash_bmpheight	= size.y;
+  dc = GetDC(GetDesktopWindow());
+  sx = GetDeviceCaps(dc, HORZRES);
+  sy = GetDeviceCaps(dc, VERTRES);
+  ReleaseDC(GetDesktopWindow(), dc);
+
+	splash_window = CreateWindow("Generic:Splash", "Greenstone Installer",
+																WS_DLGFRAME | WS_VISIBLE,
+                                (sx - r.right + r.left) / 2,
+                                (sy - r.bottom + r.top) / 2,
+                                r.right-r.left, r.bottom-r.top,
+                                0, 0, instance, NULL);
+  while (GetMessage(&msg, NULL, NULL, NULL) &&
+  				splash_done == FALSE)
+  { if (msg.message == WM_TIMER)
+  	{ msg.hwnd = splash_window;
+    }
+  	TranslateMessage(&msg);
+  	DispatchMessage(&msg);
+  }
+  DestroyWindow(splash_window);
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/stringArray.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/stringArray.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/stringArray.cpp	(revision 14219)
@@ -0,0 +1,167 @@
+#include "stringArray.h"
+
+/**
+ * Constructor: create a new string array
+ */
+stringArray::stringArray()
+{
+}
+
+stringArray::stringArray(char *instring, char *divider)
+{	char *parse, *next;
+	int		count = 1;
+
+  parse	= instring;
+  while ((next = strstr(parse, divider)) != NULL)
+  { if (next != parse)
+  	{	string newString(parse, 0, next-parse);
+		  this->array.push_back(newString);
+    }
+    parse = next + strlen(divider);
+  }
+  if (strlen(parse) > 0)
+  { string newString(parse);
+		this->array.push_back(parse);
+  }
+}
+
+/**
+ * Add a new string to the array
+ */
+void stringArray::add(string member)
+{	if (!this->includes(member))
+	{ this->array.push_back(member);
+  }
+}
+
+void stringArray::add(char *member)
+{	string newString(member);
+  this->add(newString);
+}
+
+void stringArray::add(stringArray &other)
+{ vector<string>::iterator here = other.array.begin();
+	vector<string>::iterator end	= other.array.end();
+
+  while (here != end)
+  {	this->add(*here);
+  	here ++;
+  }
+  for (int i = 0; i < other.size(); i ++)
+  {	this->add(other[i]);
+  }
+}
+
+/**
+ * Remove a string from the array
+ */
+void stringArray::remove(string member)
+{	int memberPos;
+
+	memberPos	= this->indexOf(member);
+  if (memberPos >= 0)
+  { this->array.erase(this->array.begin() + memberPos);
+  }
+}
+
+void stringArray::remove(char *member)
+{ string removeMember(member);
+	this->remove(removeMember);
+}
+
+/**
+ * Check if the array includes the given string
+ */
+bool stringArray::includes(string member)
+{	return (this->indexOf(member) >= 0);
+}
+
+bool stringArray::includes(char *member)
+{	return (this->indexOf(member) >= 0);
+}
+
+/**
+ * Return an index of the location of the given string into the array.
+ * -1 indicates that it does not exist
+ */
+int stringArray::indexOf(string member)
+{ vector<string>::iterator here = this->array.begin();
+  vector<string>::iterator end  = this->array.end();
+
+  int i = 0;
+  while (here != end)
+  { if (here->compare(member) == 0)
+  	{	return i;
+    }
+  	here ++;
+    i ++;
+  }
+  return -1;
+}
+
+int stringArray::indexOf(char *member)
+{	string memberString(member);
+	return this->indexOf(memberString);
+}
+
+/**
+ * Write the array into a c string, separated by commas
+ */
+int stringArray::writeToCString(char *buffer, char *divider, int bufflen)
+{ int i = 0;
+	vector<string>::iterator here = this->array.begin();
+	vector<string>::iterator end = this->array.end();
+  buffer[0] = '\0';
+
+	while (here != end)
+	{ const char *hereCString;
+
+  	hereCString = here->c_str();
+
+  	if ((strlen(hereCString) + (i > 0 ? 1 : 0)) >= bufflen)
+  		break;
+
+  	if (i > 0)
+    {	strcat(buffer, divider);
+     	bufflen -= strlen(divider);
+    }
+    strcat(buffer, hereCString);
+    bufflen	-= strlen(hereCString);
+    i ++;
+    here ++;
+  }
+  return i;
+}
+
+stringArray stringArray::words(char *buffer)
+{	stringArray reply;
+	unsigned int at = 0;
+  unsigned int start;
+
+  while (buffer[at] != '\0' && buffer[at] <= ' ')
+  {	at ++;
+  }
+
+	while (buffer[at] != '\0')
+  { start = at;
+  	while (buffer[at] > ' ' && buffer[at] != '\0')
+  	{	at ++;
+    }
+    string newWord(buffer, start, at - start);
+    reply.add(newWord);
+
+    while (buffer[at] <= ' ' && buffer[at] != '\0')
+    {	at ++;
+    }
+  }
+  return reply;
+}
+
+string &stringArray::operator[] (const unsigned int a)
+{ return this->array[a];
+}
+
+void stringArray::clear()
+{	this->array.empty();
+}
+
Index: /gsdl/branches/nzdl2/gsinstaller/stringArray.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/stringArray.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/stringArray.h	(revision 14219)
@@ -0,0 +1,33 @@
+#ifndef _STRINGARRAY_H_
+#define _STRINGARRAY_H_
+#include <string>
+#include <vector>
+#include <map>
+using namespace std;
+#include <string.h>
+
+class stringArray
+{	private:
+	protected:
+  public:
+		vector<string> array;
+  	stringArray();
+  	stringArray(char *list, char *divider);
+    void add(char *member);
+    void add(string member);
+    void add(stringArray &array);
+    void remove(char *member);
+    void remove(string member);
+    void clear();
+    bool includes(char *member);
+    bool includes(string member);
+    static stringArray words(char *line);
+    unsigned int size(){ return this->array.size(); };
+    int  indexOf(char *member);
+    int  indexOf(string member);
+    int  writeToCString(char *buffer, char *divider, int bufflen);
+    string &operator[](const unsigned int);
+};
+
+typedef map<string, stringArray, less<string> > strArrayMap;
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/stringArrayMap.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/stringArrayMap.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/stringArrayMap.cpp	(revision 14219)
@@ -0,0 +1,47 @@
+#include "stringArrayMap.h"
+
+stringArrayMap::stringArrayMap()
+{
+}
+
+void stringArrayMap::add(string key, stringArray array)
+{	this->_map[key].add(array);
+}
+
+void stringArrayMap::addToArray(string key, string item)
+{ this->_map[key].add(item);
+}
+
+void stringArrayMap::readArray(string key, stringArray &toArray)
+{	toArray	= this->_map[key];
+}
+
+stringArray &stringArrayMap::operator[] (const string &name)
+{ return this->_map[name];
+}
+
+string &stringArrayMap::key(unsigned int pos)
+{ map<string, stringArray, less<string> >::iterator here = this->_map.begin();
+	while (pos > 0)
+  { here ++;
+  	pos --;
+  }
+  return (*here).first;
+}
+
+stringArray &stringArrayMap::array(unsigned int pos)
+{	map<string, stringArray, less<string> >::iterator here = this->_map.begin();
+	while (pos > 0)
+  {	here ++;
+  	pos --;
+  }
+  return (*here).second;
+}
+
+void stringArrayMap::clear()
+{	this->_map.empty();
+}
+
+unsigned int stringArrayMap::size()
+{	return this->_map.size();
+}
Index: /gsdl/branches/nzdl2/gsinstaller/stringArrayMap.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/stringArrayMap.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/stringArrayMap.h	(revision 14219)
@@ -0,0 +1,25 @@
+#ifndef _STRINGARRAYMAP_H_
+#define _STRINGARRAYMAP_H_
+#include <string>
+#include <map>
+using namespace std;
+
+#include "stringArray.h"
+typedef map<string, stringArray, less<string> > strArrayMap;
+
+class stringArrayMap
+{ private:
+	protected:
+  public:
+		map<string, stringArray, less<string> > _map;
+  	stringArrayMap();
+  	void add(string key, stringArray array);
+    void addToArray(string key, string item);
+    void readArray(string key, stringArray &array);
+    string &key(unsigned int pos);
+    stringArray &array(unsigned int pos);
+    void clear();
+    unsigned int size();
+    stringArray &operator[] (const string &name);
+};
+#endif
Index: /gsdl/branches/nzdl2/gsinstaller/unInstall.cpp
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/unInstall.cpp	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/unInstall.cpp	(revision 14219)
@@ -0,0 +1,195 @@
+#include "unInstall.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "File.h"
+
+unInstaller::unInstaller(string &fileName)
+{ if (fileName != "")
+	{	this->readFile(fileName);
+  }
+}
+
+unInstaller::unInstaller(const char *fileName)
+{	string filename = fileName;
+
+	if (fileName != "")
+  {	this->readFile(filename);
+  }
+}
+
+bool unInstaller::readFile(string &fileName)
+{ FILE *f;
+	File  finfo(fileName.c_str());
+  string	currentGroup;
+  char   *line, *eol;
+
+	f = fopen(fileName.c_str(), "rb");
+  if (f == NULL)
+  {	return false;
+  }
+
+  char *buffer = new char[finfo.getFileSize()];
+	if (buffer == NULL)
+  {	return false;
+  }
+
+  if (fread(buffer, 1, finfo.getFileSize(), f) < finfo.getFileSize())
+  {	return false;
+  }
+  fclose(f);
+
+  //parse file into lines and send to the line fn
+  line	= buffer;
+  while ((eol = strchr(line, '\x0a')) != NULL) 	// use 0a for the eol to remove
+                                                // dependency on dos 0d,0a eol
+  {	*eol = '\0';
+
+    this->getLine(line, currentGroup);
+
+  	line = eol + 1;
+  }
+  this->getLine(line, currentGroup);
+
+  delete buffer;
+  return true;
+}
+
+bool unInstaller::getLine(char *line, string &group)
+{ char *eol;	// we (potentially) need to clean up the end of
+              // line, and we won't use the eol from the main
+              // getManifest fn. as for the last line it'd be
+              // null.
+
+	// clean up the start of the line
+	while (*line <= ' ' && *line != '\0')
+	{ line ++;
+  }
+
+  // it's a blank line - don't bother!
+  if (line == '\0')
+  {	return true;
+  }
+
+  // clean up the end of line
+  eol	= line + strlen(line) - 1;
+  while (*eol <= ' ' && eol >= line)
+  {	*eol = '\0';
+  	eol --;
+  }
+
+  // if it's a new group, read in the group name
+  if (*line == '[' && *eol == ']')
+  { string newgroup(line, 1, eol - line - 1);
+  	group = newgroup;
+    return true;
+  }
+  // otherwise it should be a command
+  else
+  {	char *equals = strchr(line, '=');
+
+  	// if it has no equals it's invalid; ignore it
+  	if (equals == NULL)
+    {	return true;
+    }
+    else
+		{	unInstallCommand command;
+
+    	string cmd(line, 0, equals-line);
+    	command.command	= cmd;
+
+      stringArray params = stringArray::words(equals+1);
+      command.parameters	= params;
+
+      this->_map[group].push_back(command);
+    }
+  }
+  return true;
+}
+
+bool unInstaller::saveToFile(string fileName)
+{	unInstallCommandMap::iterator here	= this->_map.begin();
+  unInstallCommandMap::iterator end  = this->_map.end();
+  string group = "";
+
+  FILE *f;
+  f = fopen(fileName.c_str(), "wb");
+  if (f == NULL)
+  {	return false;
+  }
+
+  while (here != end)
+  { // if we've changed groups, note the start of the new one
+  	fprintf(f, "[%s]\n", (*here).first.c_str());
+
+    // write the group line-by-line
+    unInstallCommandList::iterator groupHere	= (*here).second.begin();
+    unInstallCommandList::iterator groupEnd		= (*here).second.end();
+    while (groupHere != groupEnd)
+    { fprintf(f, "%s=", (*groupHere).command.c_str());
+
+      fprintf(f, "%s", (*groupHere).parameters[0].c_str());
+    	for (unsigned int p = 1; p < (*groupHere).parameters.size(); p ++)
+      { fprintf(f, " %s", (*groupHere).parameters[p].c_str());
+      }
+    	groupEnd ++;
+    }
+  	here ++;
+  }
+  fclose(f);
+  return true;
+}
+
+void unInstaller::unInstall(string &listName)
+{	if (listName == uninstall_ALL)
+	{	unInstallCommandMap::reverse_iterator here	= this->_map.rbegin();
+  	unInstallCommandMap::reverse_iterator end   = this->_map.rend();
+
+    while (here != end)
+    { this->unInstallGroup((*here).second);
+    	here ++;
+    }
+    this->_map.empty();
+  }
+  else
+  {	this->unInstallGroup(this->_map[listName]);
+  	this->_map.erase(listName);
+  }
+}
+
+void unInstaller::unInstallGroup(unInstallCommandList &list)
+{ for (int i = list.size() - 1; i >= 0; i --)
+	{	// execute uninstall
+   	this->execCommand(list[i].command, list[i].parameters);
+  }
+}
+
+bool unInstaller::execCommand(string &name, stringArray &params)
+{ // undo the command
+	return true;
+}
+
+bool unInstaller::record(string group, string cmd, string parameter)
+{ unInstallCommand command;
+
+	command.command	= cmd;
+  command.parameters.add(parameter);
+
+  this->_map[group].push_back(command);
+  return true;
+}
+
+bool unInstaller::record(string group, string cmd, int count, ...)
+{ va_list list;
+
+	va_start(list, count);
+	unInstallCommand command;
+
+	command.command	= cmd;
+  command.parameters.add(*va_arg(list, string *));
+  va_end(list);
+
+  this->_map[group].push_back(command);
+
+  return true;
+}
Index: /gsdl/branches/nzdl2/gsinstaller/unInstall.h
===================================================================
--- /gsdl/branches/nzdl2/gsinstaller/unInstall.h	(revision 14219)
+++ /gsdl/branches/nzdl2/gsinstaller/unInstall.h	(revision 14219)
@@ -0,0 +1,37 @@
+#ifndef _UNINSTALL_H_
+#define _UNINSTALL_H_
+#include <string>
+#include <vector>
+#include <map>
+using namespace std;
+
+#include "stringArray.h"
+
+static string uninstall_ALL = "all";
+
+typedef struct unInstallCommand
+{	string			command;
+	stringArray	parameters;
+} unInstallCommand;
+
+typedef vector<unInstallCommand> unInstallCommandList;
+
+typedef map<string, unInstallCommandList, less<string> > unInstallCommandMap;
+
+class unInstaller
+{ private:
+		unInstallCommandMap _map;
+    void unInstallGroup(unInstallCommandList &list);
+    bool readFile(string &fileName);
+    bool getLine(char *line, string &groupname);
+	public:
+  	unInstaller(string &fileName);
+    unInstaller(const char *fileName);
+    void unInstall(string &listName);
+    bool record(string group, string cmd, string param);
+    bool record(string group, string cmd, int count, ...);
+    bool saveToFile(string filename);
+    bool execCommand(string &command, stringArray &params);
+};
+
+#endif
