/*
    dlditool - Dynamically Linked Disk Interface patch tool
    Copyright (C) 2006  Michael Chisholm (Chishm)

	Send all queries to chishm@hotmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	* v1.24d - 2010-06-14 - zeromus
		* Modified for inclusion in desmume

	* v1.24 - 2007-08-02 - SmileyDude
		* Now using EXIT_SUCCESS and EXIT_FAILURE at the suggestion of MachinShin.
		* Defined EXIT_NO_DLDI_SECTION for when there is no DLDI section in a file.
		* Added cast to strcmp() call to appease the compiler.
		
	* v1.23 - 2007-01-23 - Chishm
		* Fixed bug when DLDI section doesn't exist
		* addr_t is now a signed int

	* v1.22 - 2007-01-12 - WinterMute
		* add search paths for dldi files

	* v1.21 - 2007-01-12 - Chishm
		* Improved error messages

	* v1.20 - 2007-01-11 - Chishm
		* Changed offset calculation method

	* v1.10 - 2007-01-07 - Chishm
		* Removed assumptions about endianess of computer
			* Word size shouldn't matter now either, except that an int type must be at least 32 bits long
		* Added *.sc.nds and *.gba.nds file extensions
		* Improved command line argument parsing

	* v1.01 - 2006-12-30 - Chishm
		* Minor bugfix parsing 3 arguments

	* v1.00 - 2006-12-25 - Chishm
		* Original release
*/
#ifndef VERSION
#define VERSION "v1.24"
#endif

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>

#ifndef _MSC_VER
#include <stdint.h>
#include <unistd.h>
#include <sys/param.h>
#else
typedef int int32_t;
#define MAXPATHLEN      1024
#endif

#include <sys/stat.h>
#include "streams/file_stream_transforms.h"

namespace DLDI
{

//#ifndef bool
// typedef enum {false = 0, true = !0} bool;
//#endif

typedef int32_t addr_t;
typedef unsigned char data_t;

#define FEATURE_MEDIUM_CANREAD	0x00000001
#define FEATURE_MEDIUM_CANWRITE	0x00000002
#define FEATURE_SLOT_GBA	0x00000010
#define FEATURE_SLOT_NDS	0x00000020

#define MAGIC_TOKEN 0xBF8DA5ED

#define FIX_ALL	0x01
#define FIX_GLUE	0x02
#define FIX_GOT	0x04
#define FIX_BSS	0x08

#define DLDI_VERSION 1

#define EXIT_NO_DLDI_SECTION	2

enum DldiOffsets {
	DO_magicString = 0x00,			// "\xED\xA5\x8D\xBF Chishm"
	DO_magicToken = 0x00,			// 0xBF8DA5ED
	DO_magicShortString = 0x04,		// " Chishm"
	DO_version = 0x0C,
	DO_driverSize = 0x0D,
	DO_fixSections = 0x0E,
	DO_allocatedSpace = 0x0F,

	DO_friendlyName = 0x10,

	DO_text_start = 0x40,			// Data start
	DO_data_end = 0x44,				// Data end
	DO_glue_start = 0x48,			// Interworking glue start	-- Needs address fixing
	DO_glue_end = 0x4C,				// Interworking glue end
	DO_got_start = 0x50,			// GOT start					-- Needs address fixing
	DO_got_end = 0x54,				// GOT end
	DO_bss_start = 0x58,			// bss start					-- Needs setting to zero
	DO_bss_end = 0x5C,				// bss end

	// IO_INTERFACE data
	DO_ioType = 0x60,
	DO_features = 0x64,
	DO_startup = 0x68,	
	DO_isInserted = 0x6C,	
	DO_readSectors = 0x70,	
	DO_writeSectors = 0x74,
	DO_clearStatus = 0x78,
	DO_shutdown = 0x7C,
	DO_code = 0x80
};

const data_t dldiMagicString[] = "\xED\xA5\x8D\xBF Chishm";
const char dldiFileExtension[] = ".dldi";


void printUsage (char* programName) {
	printf ("Usage:\n");
	printf ("%s <dldi> <app>\n", programName);
	printf ("   <dldi>        the dldi patch file to apply\n");
	printf ("   <app>         the application binary to apply the patch to\n");
	return;
}

addr_t readAddr (data_t *mem, addr_t offset) {
	return (addr_t)( 
			(mem[offset + 0] << 0) |
			(mem[offset + 1] << 8) |
			(mem[offset + 2] << 16) |
			(mem[offset + 3] << 24)
		);
}

void writeAddr (data_t *mem, addr_t offset, addr_t value) {
	mem[offset + 0] = (data_t)(value >> 0);
	mem[offset + 1] = (data_t)(value >> 8);
	mem[offset + 2] = (data_t)(value >> 16);
	mem[offset + 3] = (data_t)(value >> 24);
}

int stringCaseInsensitiveCompare (const char *str1, const char *str2) {
	while (tolower(*str1) == tolower(*str2)) {
		if (*str1 == '\0') {
			return 0;
		}
		str1++;
		str2++;
	}
	return (tolower(*str1) - tolower(*str2));
}

bool stringEndsWith (const char *str, const char *end) {
	const char* strEnd;
	if (strlen (str) < strlen(end)) {
		return false;
	}
	strEnd = &str[strlen (str) - strlen(end)];
	return (stringCaseInsensitiveCompare (strEnd, end) == 0);			
}

bool stringStartsWith (const char *str, const char *start) {
	return (strstr (str, start) == str);
}

addr_t quickFind (const data_t* data, const data_t* search, size_t dataLen, size_t searchLen) {
	const int32_t* dataChunk = (const int32_t*) data;
	int searchChunk = ((const int32_t*)search)[0];
	addr_t i;
	addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int32_t));

	for ( i = 0; i < dataChunkEnd; i++) {
		if (dataChunk[i] == searchChunk) {
			if ((i*sizeof(int32_t) + searchLen) > dataLen) {
				return -1;
			}
			if (memcmp (&data[i*sizeof(int32_t)], search, searchLen) == 0) {
				return i*sizeof(int32_t);
			}
		}
	}

	return -1;
}

#ifndef __LIBRETRO__
FILE *openDLDIFile(const char *argv0, char *dldiFileName ) {


	FILE *dldiFile;
	char *dldiPATH;
	char appPath[MAXPATHLEN];
	char appName[MAXPATHLEN];
	char appPathName[MAXPATHLEN];

	char *ptr, *lastSlash;
	struct stat buf;

	// add .dldi extension to filename
	if (!stringEndsWith (dldiFileName, dldiFileExtension)) {
		strcat (dldiFileName, dldiFileExtension);
	}

	printf ("Trying \"%s\"\n", dldiFileName);
	// try opening from current directory
	dldiFile = (FILE*)fopen(dldiFileName,"rb");

	if ( NULL != dldiFile ) return dldiFile;

	// check if the filename has a path component
	// check both slash varieties, win32 understands both
	// if we have a directory separator don't bother with search paths
	if ( NULL != strstr(dldiFileName,"\\") ) return NULL;
	if ( NULL != strstr(dldiFileName,"/") ) return NULL;
	
	// check for DLDIPATH in environment
	dldiPATH = getenv("DLDIPATH");
	

	if ( NULL != dldiPATH ) {
		strcpy(appPath,dldiPATH);
		if ( appPath[strlen(appPath)] != '\\' &&  appPath[strlen(appPath)] != '/' )
			strcat(appPath,"/");
		strcat ( appPath, dldiFileName );
		
		printf ("Trying \"%s\"\n", appPath);
		dldiFile = (FILE*)fopen(appPath,"rb");

		if ( NULL != dldiFile ) return dldiFile;
		 
	}
	
	
	lastSlash = NULL;
	ptr = (char *)argv0;
		
	while ( *(ptr++) != 0 ) {
		if ( *ptr == '\\' || * ptr == '/' )
			lastSlash = ptr;
	}

	if ( NULL != lastSlash ) {
		*(lastSlash++) = '\0';
		strcpy(appPath, argv0);
		strcpy(appName, lastSlash);
		strcat(appPath, "/");
	} else {
		strcpy(appPath, "");
		strcpy(appName, argv0);
	}
			 

	// finally try in the application path
	// if argv0 contains a directory separator we have a path component

	if ( NULL == strstr(appPath,"\\") &&  NULL == strstr(appPath,"/") ) {

		// no path in argv0 so search system path
		char *sysPATH = getenv("PATH");
		char *nextPATH;
		char *thisPATH = sysPATH;
		printf("Searching system path\n%s\n",sysPATH);
		
		while(1) {
			nextPATH = strstr(thisPATH, ":" ); // find next PATH separator

			if ( NULL != nextPATH )
				*(nextPATH++) = '\0'; // terminate string, point to next component

			strcpy(appPath,thisPATH);
			strcat(appPath,"/");
			strcpy(appPathName,appPath);
			strcat(appPathName,appName);		// add application name

			if ( stat_utf8(appPathName,&buf) == 0 )	// if it exists we found the path
				break;
			
			thisPATH = nextPATH;
			strcpy(appPath,"");		// empty path
			if ( thisPATH == NULL) break;
		}
	}

	strcat(appPath,"dldi/");		// add dldi folder
	strcat(appPath,dldiFileName);	// add dldi filename to path
	printf ("Trying \"%s\"\n", appPath);

	return (FILE*)fopen(appPath,"rb");		// no more places to check, just return this handle
}
#endif

//int main(int argc, char* argv[])
//{
//	
//	char *dldiFileName = NULL;
//	char *appFileName = NULL;
//
//	addr_t memOffset;			// Offset of DLDI after the file is loaded into memory
//	addr_t patchOffset;			// Position of patch destination in the file
//	addr_t relocationOffset;	// Value added to all offsets within the patch to fix it properly
//	addr_t ddmemOffset;			// Original offset used in the DLDI file
//	addr_t ddmemStart;			// Start of range that offsets can be in the DLDI file
//	addr_t ddmemEnd;			// End of range that offsets can be in the DLDI file
//	addr_t ddmemSize;			// Size of range that offsets can be in the DLDI file
//
//	addr_t addrIter;
//
//	FILE* dldiFile;
//	FILE* appFile;
//
//	data_t *pDH;
//	data_t *pAH;
//
//	data_t *appFileData = NULL;
//	size_t appFileSize = 0;
//	data_t *dldiFileData = NULL;
//	size_t dldiFileSize = 0;
//	
//	int i;
//
//	printf ("Dynamically Linked Disk Interface patch tool " VERSION " by Michael Chisholm (Chishm)\n\n");
//
//	for (i = 1; i < argc; i++) {
//		if (dldiFileName == NULL) {
//			dldiFileName = (char*) malloc (strlen (argv[i]) + 1 + sizeof(dldiFileExtension));
//			if (!dldiFileName) {
//				return EXIT_FAILURE;
//			}
//			strcpy (dldiFileName, argv[i]);
//		} else if (appFileName == NULL) {
//			appFileName = (char*) malloc (strlen (argv[i]) + 1);
//			if (!appFileName) {
//				return EXIT_FAILURE;
//			}
//			strcpy (appFileName, argv[i]);
//		} else {
//			printUsage (argv[0]);
//			return EXIT_FAILURE;
//		}
//	}
//
//	if ((dldiFileName == NULL) || (appFileName == NULL)) {
//		printUsage (argv[0]);
//		return EXIT_FAILURE;
//	}
//
//	if (!(dldiFile = openDLDIFile(argv[0],dldiFileName))) {
//		printf ("Cannot open \"%s\" - %s\n", dldiFileName, strerror(errno));
//			return EXIT_FAILURE;
//	}
//
//	if (!(appFile = (FILE*)fopen(appFileName, "rb+"))) {
//		printf ("Cannot open \"%s\" - %s\n", appFileName, strerror(errno));
//		return EXIT_FAILURE;
//	}
//
//	// Load the app file and the DLDI patch file
//	fseek (appFile, 0, SEEK_END);
//	appFileSize = ftell(appFile);
//	appFileData = (data_t*) malloc (appFileSize);
//	fseek (appFile, 0, SEEK_SET);
//
//	fseek (dldiFile, 0, SEEK_END);
//	dldiFileSize = ftell(dldiFile);
//	dldiFileData = (data_t*) malloc (dldiFileSize);
//	fseek (dldiFile, 0, SEEK_SET);
//
//	if (!appFileData || !dldiFileData) {
//		fclose (appFile);
//		fclose (dldiFile);
//		if (appFileData) free (appFileData);
//		if (dldiFileData) free (dldiFileData);
//		printf ("Out of memory\n");
//		return EXIT_FAILURE;
//	}
//
//	fread (appFileData, 1, appFileSize, appFile);
//	fread (dldiFileData, 1, dldiFileSize, dldiFile);
//	fclose (dldiFile);
//
//	// Find the DSDI reserved space in the file
//	patchOffset = quickFind (appFileData, dldiMagicString, appFileSize, sizeof(dldiMagicString)/sizeof(char));
//
//	if (patchOffset < 0) {
//		printf ("%s does not have a DLDI section\n", appFileName);
//		return EXIT_NO_DLDI_SECTION;
//	}
//
//	pDH = dldiFileData;
//	pAH = &appFileData[patchOffset];
//
//	// Make sure the DLDI file is valid and usable
//	if (strcmp ((char*)dldiMagicString, (char*)&pDH[DO_magicString]) != 0) {
//		printf ("Invalid DLDI file\n");
//		return EXIT_FAILURE;
//	}
//	if (pDH[DO_version] != DLDI_VERSION) {
//		printf ("Incorrect DLDI file version. Expected %d, found %d.\n", DLDI_VERSION, pDH[DO_version]);
//		return EXIT_FAILURE;
//	}
//	if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) {
//		printf ("Not enough space for patch. Available %d bytes, need %d bytes\n", ( 1 << pAH[DO_allocatedSpace]), ( 1 << pDH[DO_driverSize]) );
//		return EXIT_FAILURE;
//	}
//
//	memOffset = readAddr (pAH, DO_text_start);
//	if (memOffset == 0) {
//			memOffset = readAddr (pAH, DO_startup) - DO_code;
//	}
//	ddmemOffset = readAddr (pDH, DO_text_start);
//	relocationOffset = memOffset - ddmemOffset;
//
//	printf ("Old driver:          %s\n", &pAH[DO_friendlyName]);
//	printf ("New driver:          %s\n", &pDH[DO_friendlyName]);
//	printf ("\n");
//	printf ("Position in file:    0x%08X\n", patchOffset);
//	printf ("Position in memory:  0x%08X\n", memOffset);
//	printf ("Patch base address:  0x%08X\n", ddmemOffset);
//	printf ("Relocation offset:   0x%08X\n", relocationOffset);
//	printf ("\n");
//
//	ddmemStart = readAddr (pDH, DO_text_start);
//	ddmemSize = (1 << pDH[DO_driverSize]);
//	ddmemEnd = ddmemStart + ddmemSize;
//
//	// Remember how much space is actually reserved
//	pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace];
//	// Copy the DLDI patch into the application
//	memcpy (pAH, pDH, dldiFileSize);
//
//	// Fix the section pointers in the header
//	writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset);
//	writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset);
//	writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset);
//	writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset);
//	writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset);
//	writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset);
//	writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset);
//	writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset);
//	// Fix the function pointers in the header
//	writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset);
//	writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset);
//	writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset);
//	writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset);
//	writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset);
//	writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset);
//
//	if (pDH[DO_fixSections] & FIX_ALL) { 
//		// Search through and fix pointers within the data section of the file
//		for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) {
//			if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
//				writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
//			}
//		}
//	}
//
//	if (pDH[DO_fixSections] & FIX_GLUE) { 
//		// Search through and fix pointers within the glue section of the file
//		for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) {
//			if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
//				writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
//			}
//		}
//	}
//
//	if (pDH[DO_fixSections] & FIX_GOT) { 
//		// Search through and fix pointers within the Global Offset Table section of the file
//		for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) {
//			if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
//				writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
//			}
//		}
//	}
//
//	if (pDH[DO_fixSections] & FIX_BSS) { 
//		// Initialise the BSS to 0
//		memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start));
//	}
//
//	// Write the patch back to the file
//	fseek (appFile, patchOffset, SEEK_SET);
//	fwrite (pAH, 1, ddmemSize, appFile);
//	fclose (appFile);
//
//	free (appFileData);
//	free (dldiFileData);
//
//	printf ("Patched successfully\n");
//
//	return EXIT_SUCCESS;
//}

//  Source File: mpcf.dldi
//         Time: 6/14/2010 9:38 PM
// Orig. Offset: 0 / 0x00000000
//       Length: 1876 / 0x00000754 (bytes)
data_t mpcf_dldi[1876] =
{
    0xED, 0xA5, 0x8D, 0xBF, 0x20, 0x43, 0x68, 0x69, 0x73, 0x68, 0x6D, 0x00, 0x01, 0x0B, 0x0C, 0x00, 
    0x47, 0x42, 0x41, 0x20, 0x4D, 0x6F, 0x76, 0x69, 0x65, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 
    0x20, 0x28, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x46, 0x6C, 0x61, 0x73, 0x68, 0x29, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x80, 0xBF, 0x54, 0x07, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF, 
    0x50, 0x07, 0x80, 0xBF, 0x50, 0x07, 0x80, 0xBF, 0x54, 0x07, 0x80, 0xBF, 0x70, 0x07, 0x80, 0xBF, 
    0x4D, 0x50, 0x43, 0x46, 0x13, 0x00, 0x00, 0x00, 0x3C, 0x01, 0x80, 0xBF, 0x98, 0x01, 0x80, 0xBF, 
    0x78, 0x02, 0x80, 0xBF, 0xC8, 0x04, 0x80, 0xBF, 0xC8, 0x01, 0x80, 0xBF, 0x10, 0x07, 0x80, 0xBF, 
    0x0D, 0xC0, 0xA0, 0xE1, 0xF8, 0xDF, 0x2D, 0xE9, 0x04, 0xB0, 0x4C, 0xE2, 0x28, 0xD0, 0x4B, 0xE2, 
    0xF0, 0x6F, 0x9D, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x10, 0x40, 0x2D, 0xE9, 0x2C, 0x40, 0x9F, 0xE5, 
    0x00, 0x30, 0xD4, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x24, 0x20, 0x9F, 0xE5, 0x05, 0x00, 0x00, 0x1A, 
    0x00, 0x00, 0x52, 0xE3, 0x1C, 0x00, 0x9F, 0xE5, 0x0F, 0xE0, 0xA0, 0x11, 0x12, 0xFF, 0x2F, 0x11, 
    0x01, 0x30, 0xA0, 0xE3, 0x00, 0x30, 0xC4, 0xE5, 0x10, 0x40, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 
    0x54, 0x07, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x48, 0x07, 0x80, 0xBF, 0x04, 0xE0, 0x2D, 0xE5, 
    0x40, 0x30, 0x9F, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x04, 0xD0, 0x4D, 0xE2, 0x38, 0x00, 0x9F, 0xE5, 
    0x38, 0x10, 0x9F, 0xE5, 0x0F, 0xE0, 0xA0, 0x11, 0x13, 0xFF, 0x2F, 0x11, 0x30, 0x00, 0x9F, 0xE5, 
    0x00, 0x30, 0x90, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x28, 0x30, 0x9F, 0xE5, 0x02, 0x00, 0x00, 0x0A, 
    0x00, 0x00, 0x53, 0xE3, 0x0F, 0xE0, 0xA0, 0x11, 0x13, 0xFF, 0x2F, 0x11, 0x04, 0xD0, 0x8D, 0xE2, 
    0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x48, 0x07, 0x80, 0xBF, 
    0x58, 0x07, 0x80, 0xBF, 0x4C, 0x07, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x09, 0x14, 0xA0, 0xE3, 
    0x06, 0x18, 0x81, 0xE2, 0xB0, 0x30, 0xD1, 0xE1, 0x03, 0x30, 0xE0, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 
    0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0xB0, 0x30, 0xC1, 0xE1, 0xB0, 0x20, 0xD1, 0xE1, 
    0x04, 0xE0, 0x2D, 0xE5, 0xAA, 0xCC, 0xA0, 0xE3, 0x55, 0xEC, 0xE0, 0xE3, 0x03, 0x00, 0x52, 0xE1, 
    0xAA, 0xE0, 0x4E, 0xE2, 0x55, 0xC0, 0x8C, 0xE2, 0x00, 0x00, 0xA0, 0xE3, 0x03, 0x00, 0x00, 0x1A, 
    0xB0, 0xE0, 0xC1, 0xE1, 0xB0, 0x30, 0xD1, 0xE1, 0x0C, 0x00, 0x53, 0xE0, 0x01, 0x00, 0xA0, 0x13, 
    0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x26, 0x35, 0xA0, 0xE3, 0x03, 0x37, 0x83, 0xE2, 
    0x50, 0x20, 0xA0, 0xE3, 0xB0, 0x20, 0xC3, 0xE1, 0xB0, 0x00, 0xD3, 0xE1, 0x00, 0x08, 0xA0, 0xE1, 
    0x20, 0x08, 0xA0, 0xE1, 0xFF, 0x00, 0x00, 0xE2, 0x50, 0x00, 0x50, 0xE3, 0x00, 0x00, 0xA0, 0x13, 
    0x01, 0x00, 0xA0, 0x03, 0x1E, 0xFF, 0x2F, 0xE1, 0x09, 0x34, 0xA0, 0xE3, 0x0E, 0x38, 0x83, 0xE2, 
    0xB0, 0x20, 0xD3, 0xE1, 0x80, 0x00, 0x12, 0xE3, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xA0, 0xE3, 
    0x01, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x50, 0xE1, 0x08, 0x00, 0x00, 0x0A, 0x09, 0x34, 0xA0, 0xE3, 
    0x0E, 0x38, 0x83, 0xE2, 0xB0, 0x20, 0xD3, 0xE1, 0x26, 0x17, 0xA0, 0xE3, 0x96, 0x1C, 0x81, 0xE2, 
    0x80, 0x00, 0x12, 0xE3, 0x01, 0x00, 0x80, 0xE2, 0x80, 0x10, 0x81, 0xE2, 0xF4, 0xFF, 0xFF, 0x1A, 
    0x26, 0x15, 0xA0, 0xE3, 0x03, 0x17, 0x81, 0xE2, 0xB0, 0x30, 0xD1, 0xE1, 0x50, 0x30, 0x13, 0xE2, 
    0x01, 0x00, 0xA0, 0x13, 0x1E, 0xFF, 0x2F, 0x11, 0x26, 0x27, 0xA0, 0xE3, 0x96, 0x2C, 0x82, 0xE2, 
    0x03, 0x00, 0xA0, 0xE1, 0x80, 0x20, 0x82, 0xE2, 0x01, 0x00, 0x00, 0xEA, 0x02, 0x00, 0x50, 0xE1, 
    0x0A, 0x00, 0x00, 0x0A, 0xB0, 0x30, 0xD1, 0xE1, 0x50, 0x30, 0x13, 0xE2, 0x01, 0x00, 0x80, 0xE2, 
    0xF9, 0xFF, 0xFF, 0x0A, 0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 
    0x03, 0x00, 0x50, 0xE1, 0x00, 0x00, 0xA0, 0xC3, 0x01, 0x00, 0xA0, 0xD3, 0x1E, 0xFF, 0x2F, 0xE1, 
    0x03, 0x00, 0xA0, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1, 0xF0, 0x4B, 0x2D, 0xE9, 0x09, 0x34, 0xA0, 0xE3, 
    0x0E, 0x38, 0x83, 0xE2, 0xB0, 0xC0, 0xD3, 0xE1, 0x80, 0x00, 0x1C, 0xE3, 0x10, 0xD0, 0x4D, 0xE2, 
    0x01, 0x90, 0xA0, 0xE1, 0x02, 0xE0, 0xA0, 0xE1, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0xC0, 0xA0, 0xE3, 
    0x01, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x5C, 0xE1, 0x08, 0x00, 0x00, 0x0A, 0x09, 0x34, 0xA0, 0xE3, 
    0x0E, 0x38, 0x83, 0xE2, 0xB0, 0x20, 0xD3, 0xE1, 0x26, 0x17, 0xA0, 0xE3, 0x96, 0x1C, 0x81, 0xE2, 
    0x80, 0x00, 0x12, 0xE3, 0x01, 0xC0, 0x8C, 0xE2, 0x80, 0x10, 0x81, 0xE2, 0xF4, 0xFF, 0xFF, 0x1A, 
    0x26, 0xC5, 0xA0, 0xE3, 0x03, 0xC7, 0x8C, 0xE2, 0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x30, 0x13, 0xE2, 
    0x26, 0x17, 0xA0, 0x03, 0x96, 0x1C, 0x81, 0x02, 0x03, 0x20, 0xA0, 0x01, 0x80, 0x10, 0x81, 0x02, 
    0x02, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1, 0x67, 0x00, 0x00, 0x0A, 
    0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x00, 0x13, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF9, 0xFF, 0xFF, 0x0A, 
    0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1, 
    0x5E, 0x00, 0x00, 0xCA, 0xFF, 0x00, 0x59, 0xE3, 0x00, 0x30, 0xA0, 0x83, 0x0C, 0x30, 0x8D, 0x85, 
    0x5E, 0x00, 0x00, 0x9A, 0x00, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 
    0x09, 0x54, 0xA0, 0xE3, 0x04, 0x30, 0x8D, 0xE5, 0x0C, 0x30, 0x9D, 0xE5, 0x20, 0x4C, 0xA0, 0xE1, 
    0x0E, 0xB0, 0xA0, 0xE1, 0x05, 0x60, 0xA0, 0xE1, 0x20, 0x74, 0xA0, 0xE1, 0x05, 0x20, 0xA0, 0xE1, 
    0x20, 0x18, 0xA0, 0xE1, 0x05, 0xC0, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE1, 0x05, 0xE0, 0xA0, 0xE1, 
    0x01, 0x57, 0x85, 0xE2, 0xB0, 0x30, 0xC5, 0xE1, 0x04, 0x30, 0x9D, 0xE5, 0x0F, 0x40, 0x04, 0xE2, 
    0x06, 0x68, 0x86, 0xE2, 0xB0, 0x30, 0xC6, 0xE1, 0xFF, 0x70, 0x07, 0xE2, 0x02, 0x27, 0x82, 0xE2, 
    0xFF, 0x10, 0x01, 0xE2, 0x0A, 0x08, 0x80, 0xE2, 0xE0, 0x40, 0x84, 0xE3, 0x03, 0xC7, 0x8C, 0xE2, 
    0x0E, 0xE8, 0x8E, 0xE2, 0x20, 0x30, 0xA0, 0xE3, 0xB0, 0x70, 0xC2, 0xE1, 0xB0, 0x10, 0xC0, 0xE1, 
    0xB0, 0x40, 0xCC, 0xE1, 0xB0, 0x30, 0xCE, 0xE1, 0x0B, 0x80, 0xA0, 0xE1, 0x01, 0x90, 0x59, 0xE2, 
    0x3E, 0x00, 0x00, 0x3A, 0x26, 0x25, 0xA0, 0xE3, 0x03, 0x27, 0x82, 0xE2, 0xB0, 0x30, 0xD2, 0xE1, 
    0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3, 
    0x26, 0x17, 0xA0, 0x13, 0x96, 0x1C, 0x81, 0x12, 0x02, 0x00, 0xA0, 0x11, 0x80, 0x10, 0x81, 0x12, 
    0x00, 0x20, 0xA0, 0x13, 0x02, 0x00, 0x00, 0x1A, 0x0D, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1, 
    0x26, 0x00, 0x00, 0x0A, 0xB0, 0x30, 0xD0, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 
    0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF6, 0xFF, 0xFF, 0x1A, 
    0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1, 
    0x1A, 0x00, 0x00, 0xCA, 0x01, 0x00, 0x18, 0xE3, 0x0B, 0x10, 0xA0, 0x01, 0xFF, 0x20, 0xA0, 0x03, 
    0x09, 0x04, 0xA0, 0x03, 0x0E, 0x00, 0x00, 0x0A, 0x08, 0x10, 0xA0, 0xE1, 0xFF, 0x00, 0xA0, 0xE3, 
    0x09, 0xC4, 0xA0, 0xE3, 0xB0, 0x30, 0xDC, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 
    0x01, 0x00, 0x40, 0xE2, 0x43, 0x24, 0xA0, 0xE1, 0x01, 0x00, 0x70, 0xE3, 0x01, 0x20, 0xC1, 0xE5, 
    0x00, 0x30, 0xC1, 0xE5, 0x02, 0x10, 0x81, 0xE2, 0xF5, 0xFF, 0xFF, 0x1A, 0x02, 0x8C, 0x88, 0xE2, 
    0xCD, 0xFF, 0xFF, 0xEA, 0x01, 0x20, 0x42, 0xE2, 0xB0, 0x30, 0xD0, 0xE1, 0x01, 0x00, 0x72, 0xE3, 
    0xB2, 0x30, 0xC1, 0xE0, 0xFA, 0xFF, 0xFF, 0x1A, 0x02, 0xBC, 0x8B, 0xE2, 0xC6, 0xFF, 0xFF, 0xEA, 
    0x00, 0x00, 0xA0, 0xE3, 0x10, 0xD0, 0x8D, 0xE2, 0xF0, 0x4B, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 
    0x09, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0x0C, 0x30, 0x8D, 0xE5, 0x9C, 0xFF, 0xFF, 0xEA, 
    0x01, 0x00, 0xA0, 0xE3, 0xF6, 0xFF, 0xFF, 0xEA, 0xF0, 0x4B, 0x2D, 0xE9, 0x09, 0x34, 0xA0, 0xE3, 
    0x0E, 0x38, 0x83, 0xE2, 0xB0, 0xC0, 0xD3, 0xE1, 0x80, 0x00, 0x1C, 0xE3, 0x10, 0xD0, 0x4D, 0xE2, 
    0x01, 0x90, 0xA0, 0xE1, 0x02, 0xE0, 0xA0, 0xE1, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0xC0, 0xA0, 0xE3, 
    0x01, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x5C, 0xE1, 0x08, 0x00, 0x00, 0x0A, 0x09, 0x34, 0xA0, 0xE3, 
    0x0E, 0x38, 0x83, 0xE2, 0xB0, 0x20, 0xD3, 0xE1, 0x26, 0x17, 0xA0, 0xE3, 0x96, 0x1C, 0x81, 0xE2, 
    0x80, 0x00, 0x12, 0xE3, 0x01, 0xC0, 0x8C, 0xE2, 0x80, 0x10, 0x81, 0xE2, 0xF4, 0xFF, 0xFF, 0x1A, 
    0x26, 0xC5, 0xA0, 0xE3, 0x03, 0xC7, 0x8C, 0xE2, 0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x30, 0x13, 0xE2, 
    0x26, 0x17, 0xA0, 0x03, 0x96, 0x1C, 0x81, 0x02, 0x03, 0x20, 0xA0, 0x01, 0x80, 0x10, 0x81, 0x02, 
    0x02, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1, 0x65, 0x00, 0x00, 0x0A, 
    0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x00, 0x13, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF9, 0xFF, 0xFF, 0x0A, 
    0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1, 
    0x5C, 0x00, 0x00, 0xCA, 0xFF, 0x00, 0x59, 0xE3, 0x00, 0x30, 0xA0, 0x83, 0x0C, 0x30, 0x8D, 0x85, 
    0x5C, 0x00, 0x00, 0x9A, 0x00, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 
    0x09, 0x54, 0xA0, 0xE3, 0x04, 0x30, 0x8D, 0xE5, 0x0C, 0x30, 0x9D, 0xE5, 0x20, 0x4C, 0xA0, 0xE1, 
    0x0E, 0xB0, 0xA0, 0xE1, 0x05, 0x60, 0xA0, 0xE1, 0x20, 0x74, 0xA0, 0xE1, 0x05, 0x20, 0xA0, 0xE1, 
    0x20, 0x18, 0xA0, 0xE1, 0x05, 0xC0, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE1, 0x05, 0xE0, 0xA0, 0xE1, 
    0x01, 0x57, 0x85, 0xE2, 0xB0, 0x30, 0xC5, 0xE1, 0x04, 0x30, 0x9D, 0xE5, 0x0F, 0x40, 0x04, 0xE2, 
    0x06, 0x68, 0x86, 0xE2, 0xB0, 0x30, 0xC6, 0xE1, 0xFF, 0x70, 0x07, 0xE2, 0x02, 0x27, 0x82, 0xE2, 
    0xFF, 0x10, 0x01, 0xE2, 0x0A, 0x08, 0x80, 0xE2, 0xE0, 0x40, 0x84, 0xE3, 0x03, 0xC7, 0x8C, 0xE2, 
    0x0E, 0xE8, 0x8E, 0xE2, 0x30, 0x30, 0xA0, 0xE3, 0xB0, 0x70, 0xC2, 0xE1, 0xB0, 0x10, 0xC0, 0xE1, 
    0xB0, 0x40, 0xCC, 0xE1, 0xB0, 0x30, 0xCE, 0xE1, 0x0B, 0x80, 0xA0, 0xE1, 0x01, 0x90, 0x59, 0xE2, 
    0x3C, 0x00, 0x00, 0x3A, 0x26, 0x25, 0xA0, 0xE3, 0x03, 0x27, 0x82, 0xE2, 0xB0, 0x30, 0xD2, 0xE1, 
    0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3, 
    0x26, 0x17, 0xA0, 0x13, 0x96, 0x1C, 0x81, 0x12, 0x02, 0x00, 0xA0, 0x11, 0x80, 0x10, 0x81, 0x12, 
    0x00, 0x20, 0xA0, 0x13, 0x02, 0x00, 0x00, 0x1A, 0x0D, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1, 
    0x24, 0x00, 0x00, 0x0A, 0xB0, 0x30, 0xD0, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 
    0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF6, 0xFF, 0xFF, 0x1A, 
    0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1, 
    0x18, 0x00, 0x00, 0xCA, 0x01, 0x00, 0x18, 0xE3, 0x0B, 0x10, 0xA0, 0x01, 0xFF, 0x20, 0xA0, 0x03, 
    0x09, 0x04, 0xA0, 0x03, 0x0C, 0x00, 0x00, 0x0A, 0x08, 0x10, 0xA0, 0xE1, 0xFF, 0x00, 0xA0, 0xE3, 
    0x09, 0xC4, 0xA0, 0xE3, 0x00, 0x30, 0xD1, 0xE5, 0x01, 0x20, 0xD1, 0xE5, 0x01, 0x00, 0x40, 0xE2, 
    0x02, 0x34, 0x83, 0xE1, 0x01, 0x00, 0x70, 0xE3, 0xB0, 0x30, 0xCC, 0xE1, 0x02, 0x10, 0x81, 0xE2, 
    0xF7, 0xFF, 0xFF, 0x1A, 0x02, 0x8C, 0x88, 0xE2, 0xCF, 0xFF, 0xFF, 0xEA, 0x01, 0x20, 0x42, 0xE2, 
    0xB2, 0x30, 0xD1, 0xE0, 0x01, 0x00, 0x72, 0xE3, 0xB0, 0x30, 0xC0, 0xE1, 0xFA, 0xFF, 0xFF, 0x1A, 
    0x02, 0xBC, 0x8B, 0xE2, 0xC8, 0xFF, 0xFF, 0xEA, 0x00, 0x00, 0xA0, 0xE3, 0x10, 0xD0, 0x8D, 0xE2, 
    0xF0, 0x4B, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x09, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 
    0x0C, 0x30, 0x8D, 0xE5, 0x9E, 0xFF, 0xFF, 0xEA, 0x01, 0x00, 0xA0, 0xE3, 0xF6, 0xFF, 0xFF, 0xEA, 
    0x04, 0xE0, 0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0xAA, 0xFE, 0xFF, 0xEB, 0x04, 0xD0, 0x8D, 0xE2, 
    0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x0D, 0xC0, 0xA0, 0xE1, 0xF8, 0xDF, 0x2D, 0xE9, 
    0x04, 0xB0, 0x4C, 0xE2, 0x28, 0xD0, 0x4B, 0xE2, 0xF0, 0x6F, 0x9D, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 
    0xDC, 0x00, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 
}; //unsigned char mpcf_dldi[1876]

data_t r4_dldi[2276] =
{
	0xED, 0xA5, 0x8D, 0xBF, 0x20, 0x43, 0x68, 0x69, 0x73, 0x68, 0x6D, 0x00, 0x01, 0x0D, 0x0E, 0x00, 
	0x52, 0x34, 0x28, 0x44, 0x53, 0x29, 0x20, 0x2D, 0x20, 0x52, 0x65, 0x76, 0x6F, 0x6C, 0x75, 0x74, 
	0x69, 0x6F, 0x6E, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x44, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x80, 0xBF, 0xE4, 0x08, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF, 0xB8, 0x00, 0x80, 0xBF, 
	0xE0, 0x08, 0x80, 0xBF, 0xE0, 0x08, 0x80, 0xBF, 0xE4, 0x08, 0x80, 0xBF, 0x00, 0x09, 0x80, 0xBF, 
	0x52, 0x34, 0x54, 0x46, 0x23, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x80, 0xBF, 0xD0, 0x03, 0x80, 0xBF, 
	0xD8, 0x04, 0x80, 0xBF, 0x24, 0x03, 0x80, 0xBF, 0x5C, 0x01, 0x80, 0xBF, 0x64, 0x01, 0x80, 0xBF, 
	0x0D, 0xC0, 0xA0, 0xE1, 0xF8, 0xDF, 0x2D, 0xE9, 0x04, 0xB0, 0x4C, 0xE2, 0x28, 0xD0, 0x4B, 0xE2, 
	0xF0, 0x6F, 0x9D, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0xC0, 0x9F, 0xE5, 0x1C, 0xFF, 0x2F, 0xE1, 
	0x29, 0x05, 0x80, 0xBF, 0x00, 0xC0, 0x9F, 0xE5, 0x1C, 0xFF, 0x2F, 0xE1, 0x4D, 0x05, 0x80, 0xBF, 
	0x78, 0x47, 0xC0, 0x46, 0xD6, 0x01, 0x00, 0xEA, 0x10, 0x40, 0x2D, 0xE9, 0x2C, 0x40, 0x9F, 0xE5, 
	0x00, 0x30, 0xD4, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x24, 0x20, 0x9F, 0xE5, 0x05, 0x00, 0x00, 0x1A, 
	0x00, 0x00, 0x52, 0xE3, 0x1C, 0x00, 0x9F, 0xE5, 0x0F, 0xE0, 0xA0, 0x11, 0x12, 0xFF, 0x2F, 0x11, 
	0x01, 0x30, 0xA0, 0xE3, 0x00, 0x30, 0xC4, 0xE5, 0x10, 0x40, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 
	0xE4, 0x08, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x08, 0x80, 0xBF, 0x04, 0xE0, 0x2D, 0xE5, 
	0x40, 0x30, 0x9F, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x04, 0xD0, 0x4D, 0xE2, 0x38, 0x00, 0x9F, 0xE5, 
	0x38, 0x10, 0x9F, 0xE5, 0x0F, 0xE0, 0xA0, 0x11, 0x13, 0xFF, 0x2F, 0x11, 0x30, 0x00, 0x9F, 0xE5, 
	0x00, 0x30, 0x90, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x28, 0x30, 0x9F, 0xE5, 0x02, 0x00, 0x00, 0x0A, 
	0x00, 0x00, 0x53, 0xE3, 0x0F, 0xE0, 0xA0, 0x11, 0x13, 0xFF, 0x2F, 0x11, 0x04, 0xD0, 0x8D, 0xE2, 
	0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x08, 0x80, 0xBF, 
	0xE8, 0x08, 0x80, 0xBF, 0xDC, 0x08, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xA0, 0xE3, 
	0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1, 0x70, 0x40, 0x2D, 0xE9, 
	0x00, 0x50, 0xA0, 0xE1, 0x03, 0x00, 0xA0, 0xE1, 0x02, 0x40, 0xA0, 0xE1, 0x01, 0x60, 0xA0, 0xE1, 
	0xC4, 0xFF, 0xFF, 0xEB, 0x01, 0x33, 0xA0, 0xE3, 0xA4, 0x51, 0x83, 0xE5, 0x04, 0xE1, 0x86, 0xE0, 
	0x03, 0xC0, 0xA0, 0xE1, 0x41, 0x46, 0xA0, 0xE3, 0xA4, 0x31, 0x9C, 0xE5, 0x02, 0x05, 0x13, 0xE3, 
	0x09, 0x00, 0x00, 0x0A, 0x10, 0x30, 0x94, 0xE5, 0x0E, 0x00, 0x56, 0xE1, 0x23, 0x0C, 0xA0, 0xE1, 
	0x23, 0x24, 0xA0, 0xE1, 0x23, 0x18, 0xA0, 0xE1, 0x01, 0x20, 0xC6, 0x35, 0x02, 0x10, 0xC6, 0x35, 
	0x03, 0x00, 0xC6, 0x35, 0x00, 0x30, 0xC6, 0x35, 0x04, 0x60, 0x86, 0xE2, 0xA4, 0x31, 0x9C, 0xE5, 
	0x00, 0x00, 0x53, 0xE3, 0xEF, 0xFF, 0xFF, 0xBA, 0x70, 0x40, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 
	0xF0, 0x41, 0x2D, 0xE9, 0x00, 0x80, 0xA0, 0xE1, 0x01, 0x70, 0xA0, 0xE1, 0x00, 0x50, 0xA0, 0xE3, 
	0x01, 0x43, 0xA0, 0xE3, 0x41, 0x66, 0xA0, 0xE3, 0x07, 0x00, 0xA0, 0xE1, 0xA5, 0xFF, 0xFF, 0xEB, 
	0xA4, 0x81, 0x84, 0xE5, 0xA4, 0x31, 0x94, 0xE5, 0x02, 0x05, 0x13, 0xE3, 0x02, 0x00, 0x00, 0x0A, 
	0x10, 0x30, 0x96, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x01, 0x50, 0xA0, 0x03, 0xA4, 0x31, 0x94, 0xE5, 
	0x00, 0x00, 0x53, 0xE3, 0xF6, 0xFF, 0xFF, 0xBA, 0x00, 0x00, 0x55, 0xE3, 0xF1, 0xFF, 0xFF, 0x0A, 
	0xF0, 0x41, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0xF0, 0x40, 0x2D, 0xE9, 0x0C, 0xD0, 0x4D, 0xE2, 
	0x00, 0xC0, 0xA0, 0xE1, 0x20, 0xEC, 0xA0, 0xE1, 0x00, 0x40, 0xA0, 0xE3, 0x20, 0x58, 0xA0, 0xE1, 
	0x20, 0x64, 0xA0, 0xE1, 0x44, 0x30, 0xE0, 0xE3, 0x0D, 0x00, 0xA0, 0xE1, 0x07, 0x30, 0xCD, 0xE5, 
	0x06, 0xE0, 0xCD, 0xE5, 0x05, 0x50, 0xCD, 0xE5, 0x04, 0x60, 0xCD, 0xE5, 0x02, 0x50, 0xA0, 0xE1, 
	0x03, 0xC0, 0xCD, 0xE5, 0x01, 0x60, 0xA0, 0xE1, 0x02, 0x40, 0xCD, 0xE5, 0x01, 0x40, 0xCD, 0xE5, 
	0x00, 0x40, 0xCD, 0xE5, 0x83, 0xFF, 0xFF, 0xEB, 0xE1, 0x34, 0xA0, 0xE3, 0x16, 0x37, 0x83, 0xE2, 
	0x01, 0x23, 0xA0, 0xE3, 0x06, 0x3A, 0x83, 0xE2, 0xA4, 0x31, 0x82, 0xE5, 0x05, 0xE1, 0x86, 0xE0, 
	0x0D, 0x70, 0xA0, 0xE1, 0x02, 0xC0, 0xA0, 0xE1, 0x41, 0x56, 0xA0, 0xE3, 0xA4, 0x31, 0x9C, 0xE5, 
	0x02, 0x05, 0x13, 0xE3, 0x0D, 0x00, 0x00, 0x0A, 0x0E, 0x00, 0x56, 0xE1, 0x09, 0x00, 0x00, 0x2A, 
	0x03, 0x00, 0x16, 0xE3, 0x03, 0x30, 0xD6, 0x15, 0x00, 0x20, 0xD6, 0x15, 0x01, 0x10, 0xD6, 0x15, 
	0x02, 0x00, 0xD6, 0x15, 0x03, 0x3C, 0xA0, 0x11, 0x01, 0x24, 0x82, 0x11, 0x00, 0x38, 0x83, 0x11, 
	0x00, 0x40, 0x96, 0x05, 0x03, 0x40, 0x82, 0x11, 0x10, 0x40, 0x85, 0xE5, 0x04, 0x60, 0x86, 0xE2, 
	0xA4, 0x31, 0x9C, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0xEB, 0xFF, 0xFF, 0xBA, 0xA7, 0x04, 0xA0, 0xE3, 
	0x16, 0x07, 0x80, 0xE2, 0x43, 0x30, 0xE0, 0xE3, 0x06, 0x0A, 0x80, 0xE2, 0x0D, 0x10, 0xA0, 0xE1, 
	0x07, 0x30, 0xCD, 0xE5, 0xB1, 0xFF, 0xFF, 0xEB, 0x0C, 0xD0, 0x8D, 0xE2, 0xF0, 0x40, 0xBD, 0xE8, 
	0x1E, 0xFF, 0x2F, 0xE1, 0xF0, 0x40, 0x2D, 0xE9, 0x00, 0x70, 0x51, 0xE2, 0x04, 0xD0, 0x4D, 0xE2, 
	0x00, 0x50, 0xA0, 0xE1, 0x0A, 0x00, 0x00, 0x0A, 0x02, 0x40, 0xA0, 0xE1, 0x00, 0x60, 0xA0, 0xE3, 
	0x85, 0x04, 0xA0, 0xE1, 0x04, 0x10, 0xA0, 0xE1, 0x01, 0x60, 0x86, 0xE2, 0x80, 0x20, 0xA0, 0xE3, 
	0xB8, 0xFF, 0xFF, 0xEB, 0x06, 0x00, 0x57, 0xE1, 0x01, 0x50, 0x85, 0xE2, 0x02, 0x4C, 0x84, 0xE2, 
	0xF6, 0xFF, 0xFF, 0x1A, 0x01, 0x00, 0xA0, 0xE3, 0x04, 0xD0, 0x8D, 0xE2, 0xF0, 0x40, 0xBD, 0xE8, 
	0x1E, 0xFF, 0x2F, 0xE1, 0x04, 0xE0, 0x2D, 0xE5, 0xA7, 0x04, 0xA0, 0xE3, 0x14, 0xD0, 0x4D, 0xE2, 
	0x16, 0x07, 0x80, 0xE2, 0x00, 0xC0, 0xA0, 0xE3, 0x4F, 0xE0, 0xE0, 0xE3, 0x06, 0x0A, 0x80, 0xE2, 
	0x0C, 0x10, 0x8D, 0xE2, 0x01, 0x20, 0xA0, 0xE3, 0x04, 0x30, 0x8D, 0xE2, 0x0B, 0xE0, 0xCD, 0xE5, 
	0x04, 0xC0, 0xCD, 0xE5, 0x0A, 0xC0, 0xCD, 0xE5, 0x09, 0xC0, 0xCD, 0xE5, 0x08, 0xC0, 0xCD, 0xE5, 
	0x07, 0xC0, 0xCD, 0xE5, 0x06, 0xC0, 0xCD, 0xE5, 0x05, 0xC0, 0xCD, 0xE5, 0x38, 0xFF, 0xFF, 0xEB, 
	0x0C, 0x00, 0x9D, 0xE5, 0x14, 0xD0, 0x8D, 0xE2, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 
	0x04, 0xE0, 0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0xE5, 0xFF, 0xFF, 0xEB, 0x07, 0x00, 0x00, 0xE2, 
	0x04, 0x00, 0x50, 0xE3, 0x00, 0x00, 0xA0, 0x13, 0x01, 0x00, 0xA0, 0x03, 0x04, 0xD0, 0x8D, 0xE2, 
	0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x04, 0xE0, 0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 
	0xDB, 0xFF, 0xFF, 0xEB, 0x07, 0x00, 0x00, 0xE2, 0x04, 0x00, 0x50, 0xE3, 0x00, 0x00, 0xA0, 0x13, 
	0x01, 0x00, 0xA0, 0x03, 0x04, 0xD0, 0x8D, 0xE2, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 
	0xF0, 0x41, 0x2D, 0xE9, 0x00, 0xC0, 0xA0, 0xE1, 0xA7, 0x04, 0xA0, 0xE3, 0x08, 0xD0, 0x4D, 0xE2, 
	0x16, 0x07, 0x80, 0xE2, 0x2C, 0x58, 0xA0, 0xE1, 0x01, 0x70, 0xA0, 0xE1, 0x00, 0x40, 0xA0, 0xE3, 
	0x2C, 0xEC, 0xA0, 0xE1, 0x2C, 0x64, 0xA0, 0xE1, 0x46, 0x30, 0xE0, 0xE3, 0x06, 0x0A, 0x80, 0xE2, 
	0x0D, 0x10, 0xA0, 0xE1, 0x07, 0x30, 0xCD, 0xE5, 0x05, 0x50, 0xCD, 0xE5, 0x03, 0xC0, 0xCD, 0xE5, 
	0x02, 0x50, 0xA0, 0xE1, 0x06, 0xE0, 0xCD, 0xE5, 0x04, 0x60, 0xCD, 0xE5, 0x00, 0x40, 0xCD, 0xE5, 
	0x02, 0x40, 0xCD, 0xE5, 0x01, 0x40, 0xCD, 0xE5, 0x58, 0xFF, 0xFF, 0xEB, 0xA1, 0x04, 0xA0, 0xE3, 
	0x16, 0x07, 0x80, 0xE2, 0x45, 0xC0, 0xE0, 0xE3, 0x03, 0x00, 0x17, 0xE3, 0x0D, 0x80, 0xA0, 0xE1, 
	0x06, 0x0A, 0x80, 0xE2, 0x07, 0x10, 0xA0, 0xE1, 0x05, 0x20, 0xA0, 0xE1, 0x0D, 0x30, 0xA0, 0xE1, 
	0x07, 0xC0, 0xCD, 0xE5, 0x03, 0x00, 0x00, 0x0A, 0x2F, 0xFF, 0xFF, 0xEB, 0x08, 0xD0, 0x8D, 0xE2, 
	0xF0, 0x41, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0xA1, 0x04, 0xA0, 0xE3, 0x16, 0x07, 0x80, 0xE2, 
	0x06, 0x0A, 0x80, 0xE2, 0x07, 0x10, 0xA0, 0xE1, 0x05, 0x20, 0xA0, 0xE1, 0x0D, 0x30, 0xA0, 0xE1, 
	0xF3, 0xFE, 0xFF, 0xEB, 0xF4, 0xFF, 0xFF, 0xEA, 0xF0, 0x40, 0x2D, 0xE9, 0x00, 0x70, 0x51, 0xE2, 
	0x04, 0xD0, 0x4D, 0xE2, 0x00, 0x50, 0xA0, 0xE1, 0x0A, 0x00, 0x00, 0x0A, 0x02, 0x40, 0xA0, 0xE1, 
	0x00, 0x60, 0xA0, 0xE3, 0x85, 0x04, 0xA0, 0xE1, 0x04, 0x10, 0xA0, 0xE1, 0x01, 0x60, 0x86, 0xE2, 
	0x80, 0x20, 0xA0, 0xE3, 0xC5, 0xFF, 0xFF, 0xEB, 0x06, 0x00, 0x57, 0xE1, 0x01, 0x50, 0x85, 0xE2, 
	0x02, 0x4C, 0x84, 0xE2, 0xF6, 0xFF, 0xFF, 0x1A, 0x01, 0x00, 0xA0, 0xE3, 0x04, 0xD0, 0x8D, 0xE2, 
	0xF0, 0x40, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x10, 0xB5, 0x40, 0x23, 0x05, 0x4A, 0x5B, 0x42, 
	0x05, 0x4C, 0x13, 0x70, 0x00, 0x21, 0x43, 0x5C, 0x62, 0x1A, 0x01, 0x31, 0x13, 0x70, 0x08, 0x29, 
	0xF9, 0xD1, 0x10, 0xBD, 0xA1, 0x01, 0x00, 0x04, 0xAF, 0x01, 0x00, 0x04, 0x70, 0xB5, 0x05, 0x1C, 
	0x18, 0x1C, 0x0E, 0x1C, 0x14, 0x1C, 0xFF, 0xF7, 0xE7, 0xFF, 0x0A, 0x4B, 0xA4, 0x00, 0x80, 0x22, 
	0x09, 0x48, 0x1D, 0x60, 0xA4, 0x19, 0x19, 0x1C, 0x12, 0x04, 0x0B, 0x68, 0x13, 0x42, 0x04, 0xD0, 
	0x03, 0x68, 0xA6, 0x42, 0x00, 0xD2, 0x33, 0x60, 0x04, 0x36, 0x0B, 0x68, 0x00, 0x2B, 0xF4, 0xDB, 
	0x70, 0xBD, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x04, 0x10, 0x00, 0x10, 0x04, 0x70, 0xB5, 0x0D, 0x1C, 
	0x14, 0x1C, 0x1E, 0x1C, 0xFF, 0xF7, 0xC8, 0xFF, 0x63, 0x00, 0x1B, 0x19, 0x07, 0x4A, 0x9B, 0x00, 
	0x99, 0x18, 0x07, 0x4A, 0x0A, 0x60, 0x07, 0x49, 0x5A, 0x18, 0x15, 0x60, 0x06, 0x4A, 0x9B, 0x18, 
	0x06, 0x4A, 0x1A, 0x60, 0x06, 0x4B, 0x1E, 0x60, 0x70, 0xBD, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x04, 
	0x10, 0x00, 0x10, 0x04, 0xB4, 0x00, 0x00, 0x04, 0xB8, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0xAF, 
	0xA4, 0x01, 0x00, 0x04, 0x10, 0xB5, 0x0C, 0x1C, 0xFF, 0xF7, 0xA6, 0xFF, 0x06, 0x4B, 0x80, 0x22, 
	0x1C, 0x43, 0x06, 0x4B, 0x12, 0x04, 0x1C, 0x60, 0x19, 0x1C, 0x0B, 0x68, 0x13, 0x42, 0xFC, 0xD0, 
	0x03, 0x4B, 0x18, 0x68, 0x10, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xA4, 0x01, 0x00, 0x04, 
	0x10, 0x00, 0x10, 0x04, 0x70, 0xB5, 0x82, 0xB0, 0x1E, 0x1C, 0x04, 0x0E, 0x6B, 0x46, 0x9C, 0x71, 
	0x04, 0x0C, 0x00, 0x25, 0x5C, 0x71, 0x04, 0x0A, 0xDD, 0x71, 0xD8, 0x70, 0x9D, 0x70, 0x5D, 0x70, 
	0x1D, 0x70, 0x30, 0x1C, 0x1C, 0x71, 0xFF, 0xF7, 0x91, 0xFF, 0x02, 0xB0, 0x70, 0xBD, 0x00, 0x00, 
	0x00, 0xB5, 0x80, 0x22, 0x81, 0xB0, 0x01, 0x1C, 0x92, 0x00, 0x00, 0x20, 0x02, 0x4B, 0xFF, 0xF7, 
	0xE1, 0xFF, 0x01, 0xB0, 0x00, 0xBD, 0x00, 0x00, 0xFF, 0x1F, 0x3F, 0xA9, 0x30, 0xB5, 0x83, 0xB0, 
	0x05, 0x1C, 0x08, 0x22, 0x04, 0x49, 0x68, 0x46, 0xFF, 0xF7, 0x2A, 0xFD, 0x29, 0x1C, 0x68, 0x46, 
	0xFF, 0xF7, 0xB8, 0xFF, 0x03, 0xB0, 0x30, 0xBD, 0xC8, 0x08, 0x80, 0xBF, 0xF0, 0xB5, 0x5F, 0x46, 
	0x56, 0x46, 0x4D, 0x46, 0x44, 0x46, 0xF0, 0xB4, 0x12, 0x18, 0x83, 0xB0, 0x94, 0x46, 0x04, 0x1C, 
	0x0F, 0x1C, 0x01, 0x93, 0x60, 0x45, 0x63, 0xD2, 0x38, 0x4A, 0x39, 0x4B, 0x90, 0x46, 0x9B, 0x46, 
	0x02, 0x32, 0x80, 0x23, 0x92, 0x46, 0x99, 0x46, 0x5B, 0x46, 0x42, 0x46, 0x13, 0x80, 0x06, 0x23, 
	0x52, 0x46, 0x13, 0x70, 0x42, 0x46, 0x13, 0x88, 0x4A, 0x46, 0x13, 0x42, 0xFA, 0xD1, 0x43, 0x46, 
	0x40, 0x22, 0x1A, 0x80, 0x5A, 0x46, 0x1A, 0x80, 0x01, 0x9B, 0x01, 0x2B, 0x4F, 0xD0, 0x02, 0x23, 
	0x52, 0x46, 0x2A, 0x49, 0x13, 0x70, 0x80, 0x22, 0x0B, 0x88, 0x13, 0x42, 0xFC, 0xD1, 0x01, 0x9B, 
	0x01, 0x2B, 0x08, 0xD9, 0x23, 0x04, 0x52, 0x46, 0x1B, 0x0E, 0x24, 0x49, 0x13, 0x70, 0x80, 0x22, 
	0x0B, 0x88, 0x13, 0x42, 0xFC, 0xD1, 0x23, 0x06, 0x52, 0x46, 0x1B, 0x0E, 0x1F, 0x49, 0x13, 0x70, 
	0x80, 0x22, 0x0B, 0x88, 0x13, 0x42, 0xFC, 0xD1, 0x1E, 0x4D, 0x1C, 0x4A, 0x00, 0x20, 0x80, 0x21, 
	0x3B, 0x78, 0x01, 0x37, 0x2B, 0x70, 0x13, 0x88, 0x0B, 0x42, 0xFC, 0xD1, 0x01, 0x34, 0xA4, 0x45, 
	0x02, 0xD9, 0x01, 0x30, 0x20, 0x28, 0xF3, 0xD1, 0x40, 0x23, 0x13, 0x80, 0x5B, 0x46, 0x13, 0x80, 
	0x12, 0x49, 0x52, 0x46, 0x05, 0x23, 0x13, 0x70, 0x80, 0x22, 0x0B, 0x88, 0x13, 0x42, 0xFC, 0xD1, 
	0x10, 0x48, 0x0E, 0x49, 0x00, 0x26, 0x80, 0x22, 0x01, 0x25, 0x06, 0x70, 0x0B, 0x88, 0x13, 0x42, 
	0xFC, 0xD1, 0x03, 0x78, 0x2B, 0x42, 0xF8, 0xD1, 0x40, 0x23, 0x0B, 0x80, 0xA4, 0x45, 0xA3, 0xD8, 
	0x03, 0xB0, 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x23, 0x0A, 
	0xDB, 0x00, 0x02, 0x22, 0x13, 0x43, 0x1B, 0x06, 0x1B, 0x0E, 0xA9, 0xE7, 0xA0, 0x01, 0x00, 0x04, 
	0x40, 0xA0, 0xFF, 0xFF, 0xA2, 0x01, 0x00, 0x04, 0x70, 0xB5, 0x14, 0x1C, 0x1E, 0x1C, 0x22, 0x4A, 
	0x22, 0x4B, 0x0D, 0x1C, 0x1A, 0x80, 0x01, 0x2E, 0x31, 0xD0, 0x03, 0x22, 0x20, 0x4B, 0x1F, 0x49, 
	0x1A, 0x70, 0x80, 0x22, 0x0B, 0x88, 0x13, 0x42, 0xFC, 0xD1, 0x03, 0x2E, 0x2E, 0xD0, 0x01, 0x2E, 
	0x03, 0xD9, 0x03, 0x04, 0x1A, 0x4A, 0x1B, 0x0E, 0x13, 0x70, 0x18, 0x49, 0x0B, 0x88, 0x1A, 0x06, 
	0xFB, 0xD4, 0x03, 0x06, 0x16, 0x4A, 0x1B, 0x0E, 0x13, 0x70, 0x08, 0x1C, 0x80, 0x22, 0x03, 0x88, 
	0x13, 0x42, 0xFC, 0xD1, 0x00, 0x2C, 0x0E, 0xD0, 0x11, 0x49, 0x10, 0x48, 0x00, 0x26, 0x80, 0x22, 
	0x0E, 0x70, 0x03, 0x88, 0x13, 0x42, 0xFC, 0xD1, 0x0B, 0x78, 0x01, 0x3C, 0x2B, 0x70, 0x00, 0x2C, 
	0x01, 0xD0, 0x01, 0x35, 0xF4, 0xE7, 0x09, 0x4B, 0x40, 0x22, 0x1A, 0x80, 0x70, 0xBD, 0x03, 0x0A, 
	0x03, 0x22, 0xDB, 0x00, 0x13, 0x43, 0x1B, 0x06, 0x1A, 0x0E, 0xC7, 0xE7, 0x03, 0x02, 0x04, 0x4A, 
	0x1B, 0x0E, 0x13, 0x70, 0xD1, 0xE7, 0x00, 0x00, 0x40, 0xA0, 0xFF, 0xFF, 0xA0, 0x01, 0x00, 0x04, 
	0xA2, 0x01, 0x00, 0x04, 0x0F, 0x00, 0x52, 0xE3, 0x04, 0xE0, 0x2D, 0xE5, 0x00, 0xC0, 0xA0, 0xE1, 
	0x02, 0xE0, 0xA0, 0xE1, 0x02, 0x00, 0x00, 0x9A, 0x00, 0x30, 0x81, 0xE1, 0x03, 0x00, 0x13, 0xE3, 
	0x09, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x5E, 0xE3, 0x05, 0x00, 0x00, 0x0A, 0x00, 0x20, 0xA0, 0xE3, 
	0x01, 0x30, 0xD1, 0xE4, 0x0C, 0x30, 0xC2, 0xE7, 0x01, 0x20, 0x82, 0xE2, 0x0E, 0x00, 0x52, 0xE1, 
	0xFA, 0xFF, 0xFF, 0x1A, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x30, 0x91, 0xE5, 
	0x00, 0x30, 0x8C, 0xE5, 0x04, 0x20, 0x91, 0xE5, 0x04, 0x20, 0x8C, 0xE5, 0x08, 0x30, 0x91, 0xE5, 
	0x08, 0x30, 0x8C, 0xE5, 0x10, 0xE0, 0x4E, 0xE2, 0x0C, 0x30, 0x91, 0xE5, 0x0F, 0x00, 0x5E, 0xE3, 
	0x0C, 0x30, 0x8C, 0xE5, 0x10, 0x10, 0x81, 0xE2, 0x10, 0xC0, 0x8C, 0xE2, 0xF2, 0xFF, 0xFF, 0x8A, 
	0x03, 0x00, 0x5E, 0xE3, 0xE6, 0xFF, 0xFF, 0x9A, 0x04, 0xE0, 0x4E, 0xE2, 0x04, 0x30, 0x91, 0xE4, 
	0x03, 0x00, 0x5E, 0xE3, 0x04, 0x30, 0x8C, 0xE4, 0xFA, 0xFF, 0xFF, 0x8A, 0xE0, 0xFF, 0xFF, 0xEA, 
	0x0D, 0xC0, 0xA0, 0xE1, 0xF8, 0xDF, 0x2D, 0xE9, 0x04, 0xB0, 0x4C, 0xE2, 0x28, 0xD0, 0x4B, 0xE2, 
	0xF0, 0x6F, 0x9D, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 
	0xFC, 0x00, 0x80, 0xBF, 0xB8, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00
};

bool tryPatch(void* data, size_t size, unsigned int device)
{
	// Find the DSDI reserved space in the file
	addr_t patchOffset = quickFind ((data_t*)data, dldiMagicString, size, sizeof(dldiMagicString)/sizeof(char));

	//no DLDI section
	if (patchOffset < 0)
		return false;

	data_t *pDH = device == 0?mpcf_dldi:r4_dldi;
	data_t *pAH = (data_t*)data + patchOffset;

	if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) {
		printf ("Not enough space for patch. Available %d bytes, need %d bytes\n", ( 1 << pAH[DO_allocatedSpace]), ( 1 << pDH[DO_driverSize]) );
		return false;
	}

	if(memcmp(&pAH[DO_friendlyName],"Default (No interface)",22))
	{
		printf("Would have been a candidate for auto-patch DLDI, but there was already a patch installed.");
		return false;
	}

	//----should be able to patch OK-----

	addr_t memOffset;			// Offset of DLDI after the file is loaded into memory
	addr_t relocationOffset;	// Value added to all offsets within the patch to fix it properly
	addr_t ddmemOffset;			// Original offset used in the DLDI file
	addr_t ddmemStart;			// Start of range that offsets can be in the DLDI file
	addr_t ddmemEnd;			// End of range that offsets can be in the DLDI file
	addr_t ddmemSize;			// Size of range that offsets can be in the DLDI file

	addr_t addrIter;


	memOffset = readAddr (pAH, DO_text_start);
	if (memOffset == 0) {
			memOffset = readAddr (pAH, DO_startup) - DO_code;
	}
	ddmemOffset = readAddr (pDH, DO_text_start);
	relocationOffset = memOffset - ddmemOffset;

	printf ("AUTO-PATCHING DLDI to MPCF! Lucky you!\n\n");
	printf ("Old driver:          %s\n", &pAH[DO_friendlyName]);
	printf ("New driver:          %s\n", &pDH[DO_friendlyName]);
	printf ("\n");
	printf ("Position in file:    0x%08X\n", patchOffset);
	printf ("Position in memory:  0x%08X\n", memOffset);
	printf ("Patch base address:  0x%08X\n", ddmemOffset);
	printf ("Relocation offset:   0x%08X\n", relocationOffset);
	printf ("\n");

	ddmemStart = readAddr (pDH, DO_text_start);
	ddmemSize = (1 << pDH[DO_driverSize]);
	ddmemEnd = ddmemStart + ddmemSize;

	// Remember how much space is actually reserved
	pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace];
	// Copy the DLDI patch into the application
	memcpy (pAH, pDH, device == 0?sizeof(mpcf_dldi):sizeof(r4_dldi));

	// Fix the section pointers in the header
	writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset);
	writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset);
	writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset);
	writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset);
	writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset);
	writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset);
	writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset);
	writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset);
	// Fix the function pointers in the header
	writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset);
	writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset);
	writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset);
	writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset);
	writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset);
	writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset);

	if (pDH[DO_fixSections] & FIX_ALL) { 
		// Search through and fix pointers within the data section of the file
		for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) {
			if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
				writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
			}
		}
	}

	if (pDH[DO_fixSections] & FIX_GLUE) { 
		// Search through and fix pointers within the glue section of the file
		for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) {
			if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
				writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
			}
		}
	}

	if (pDH[DO_fixSections] & FIX_GOT) { 
		// Search through and fix pointers within the Global Offset Table section of the file
		for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) {
			if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
				writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
			}
		}
	}

	if (pDH[DO_fixSections] & FIX_BSS) { 
		// Initialise the BSS to 0
		memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start));
	}

	return true;
}

} //namespace DLDI
