/*M****************************************************************************
**
** SOURCE FILE:		GREET.C
**
******************************************************************************/
//#define ADD_QVGA_DEMO	// define to add QVGA demo (requires qvgademo.lib)

#nodebug

xdata greet1 { "Graphics Engine" };

#ifdef ADD_QVGA_DEMO
xdata greet2 { "Ver. 2.60 w/ QVGA Demo" };
#else
xdata greet2 { "Ver. 2.60" };
#endif

xdata greet3 { "08/27/2001" };

char ourCopyRight[] =
"Copyright (@)Z-World, Inc. 1999-2001, \
(@)WOODLEY ASSOCIATES 1999\r\n";

#makechain _OP7100GE_INIT

/*M******************************************************************
**
** SOURCE FILE:		DEFINE.H
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					Definitions, Structures, global storage
**					This is the 1st module concatenated
**
** FUNCTION LIST:	none
**
** CREATION DATE: 	04/27/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
#define PK2600				// undefine to get OP7100
#define LANDSCAPE			// undefine to get PORTRAIT
#define ANIMATION_MODE	// undefine to get "non-shimmery" slower display speed

#use "vdriver.lib"

// The same fonts are used in both LANDSCAPE and PORTRAIT !!!
#use "8x10l.lib"		// engFont8x10
#use "12x16l.lib"		// engFont12x16
#use "engfnt2l.lib"	// engFont16x32, engFont17x35a
#use "engfontl.lib"	// engFont6x8

#ifdef	LANDSCAPE
#use "op71l.lib"
#else
#use "op71p.lib"
#endif

#use "op71hw.lib"
#use "kp_op71.lib"
#use "kp.lib"

#use "aasc.lib"
#use "aascz0.lib"
#use "aascz1.lib"

#ifdef ADD_QVGA_DEMO
#use "qvgademo.lib"
#endif


/*****************************************************************
	OP7100GE definitions
*****************************************************************/
#define BUFFSIZE		256		// buffer has room for 1 packets
#define BAUDMULT		8		// multiples of 1200 baud
#define SHAKE			1		// set to 1 to implement RTS/CTS handshake

#define MIN_FONT		4		// lowest allowable font index for a new font
#define MAX_FONT		20		// highest allowable font index
#define MAX_STRING		24		// longest allowable string (used in vk)
#define MAX_MACRO		1000	// longest allowable macro size
#define MAX_VERTEX		32		// maximum number of vertices in a polygon
#define PLAY_QUE_SIZE	100		// number of command pointers in the display que
#define MACRO_QUE_SIZE	50		// number of command pointers in the macro que
#define FILLED			0xFF	// if shape is filled

#ifdef LANDSCAPE
#define VMAX 240
#define HMAX 320
#else
#define VMAX 320
#define HMAX 240
#endif

#define BTN_VNUM 8				// the number of buttons (i.e. cells)
#define BTN_HNUM 8

#define BTN_VSPACE (VMAX/BTN_VNUM)	// the space for each button
#define BTN_HSPACE (HMAX/BTN_HNUM)

/*****************************************************************
	MISCELLANEOUS DEFINITIONS
*****************************************************************/
#define FALSE		0
#define TRUE		1
#define FOREVER		for(;;)
#define XX			0		// don't care
#define NUL			0
#define NONE

#define OFF			0
#define ON			1

#define LOW			0
#define HIGH		1

#define	BOOL	unsigned char
#define	BYTE	unsigned char
#define	WORD	unsigned int
#define	UINT	unsigned int
#define	ULONG	unsigned long
#define	ADDR20	unsigned long
#define	FNULL	(ADDR20)0

#define	SOH		0x01
#define	ACK		0x06
#define	BS		0x08
#define	LF		0x0A
#define	CR		0x0D
#define	SI		0x0F
#define	NAK		0x15
//#define	ESC	0x1B

// bit-encoded fields in lastStatus
#define	DATA_ENTERED	0x01
#define	CELL_HIT		0x02
#define	BUTTON_HIT		0x04
#define	ERR_OCCURRED	0x80

// offsets in msg packet
#define	ADDR	0
#define	LEN		1
#define	CMD		2
#define	FXN		3
#define	SEQ		4
#define	DATA0	5	// the 1st data byte

// offsets in BITMAP_LIST, BUTTON_LIST, and REGION_LIST
#define	FP_FWD		(ADDR20)0
#define	BITMAP_ID	(ADDR20)(2*sizeof(ADDR20))	// in BITMAP_LIST
#define	REGION_ID	BITMAP_ID					// in REGION_LIST
#define	BUTTON_ID	(ADDR20)(4*sizeof(ADDR20))	// in BUTTON_LIST
#define	FP_TEXT		(ADDR20)sizeof(ADDR20)
#define	FP_REGION	FP_TEXT
#define	FP_SAVE		(ADDR20)(2*sizeof(ADDR20))

// offsets in MACRO_LIST
//#define	FP_FWD		(ADDR20)0
#define	MACRO_ID		(ADDR20)sizeof(ADDR20)
#define	MACRO_MYADDR	MACRO_ID + (ADDR20)sizeof(int)
#define	MACRO_OFFSET	MACRO_MYADDR + (ADDR20)sizeof(ADDR20)
#define	MACRO_RETAD		MACRO_OFFSET + (ADDR20)sizeof(int)
#define	MACRO_XX		MACRO_RETAD + (ADDR20)sizeof(ADDR20)
#define	MACRO_YY		MACRO_XX + (ADDR20)sizeof(int)

// Virtual Keyboard Text Entry parameters
#define	VK_PX	0	// x start of text entry line (cell relative coords)
#define	VK_PY	2	// y start of text entry line (cell relative coords)
#define	VK_PW	7	// width of text entry line (cells)
#define	VK_PH	1	// height of text entry line (cells)
// The following parameters define the dimensions of the space above the vk.
// This space is saved and cleared when the vk is put up, then restored
// when it's removed.
#define	VK_PX0	0
#define	VK_PY0	0
#define	VK_PW0	7	// width = 7 cells
#define	VK_PH0	3	// height = 3 lines

/*****************************************************************
	COMMANDS
*****************************************************************/
/* Control Commands */
#define INIT					10
#define SET_MODE				11
#define SEND_STATUS				12
#define SEND_LAST_PUSH			13
#define SEND_STRING				14
#define SEND_LONG_INT			15
#define SEND_FLOAT				16
#define SEND_CHAR				17
#define SEND_TOD				18
#define RESEND_LAST_MSG			19
#define CLEAR_STRING_BUFF		20
#define BIT_MAP					21
#define FONT					22
#define REPLACE_DEFAULT_FONT	23
#define DISABLE_CELLS			24
#define ENABLE_CELLS			25
#define SUPER_RESET				26

/* Macro Commands */
#define START_MACRO			30
#define END_MACRO			31

/* Graphics Primitives Commands */
#define CLEAR_SCREEN		40
#define SET_BRUSH_TYPE		41
#define PIXEL				42
#define LINE				43
#define CIRCLE				44
#define RECTANGLE			45
#define POLYGON				46
#define BLANK_REGION		47
#define INVERT_REGION		48
#define STORE_REGION		49
#define RESTORE_REGION		50
#define PUT_BIT_MAP			51
#define SCROLL_REGION		52

/* Text Commands */
#define SET_FONT  			60
#define SET_CURSOR_MODE		61
#define SET_CURSOR			62
#define PUT_TEXT  			63
#define SET_TEXT_DIR		64

/* Miscellaneous Commands */
#define BACK_LIGHT			70
#define SET_CONTRAST		71
#define BEEP				72
#define NULL_LOOP			73
#define SET_CELL_ACTIVE		74
#define DEFINE_BUTTON		75
#define DELETE_BUTTON		76
#define DISPLAY_BUTTON		77
#define REMOVE_BUTTON		78
#define DIS_ENA_BUTTON		79
#define LINK_CELL_TO_MACRO	80
#define LINK_BUTTON_TO_MACRO	81
#define STOP_MACRO_LOOP		82
#define RESET_FSM			83
#define SET_STRING			84
#define SET_LONG_INTEGER	85
#define SET_FLOAT			86
#define SET_CHAR			87
#define SET_TOD				88
#define PLAY_KEYBOARD_MACRO	89

/* Scripting Commands */
#define DRAW_MACRO			100
#define SHIFT_DRAW_MACRO	101
#define DELETE_MACRO		102
#define DELETE_MACRO_ITEM	103
#define INSERT_MACRO_ITEM	104
#define DELAY_PLAY			105
#define LOOP_MACRO			106

/* Special Commands */
#define DISPLAY_BUTTON_Q	107

/*****************************************************************
	STRUCTURES and TYPEDEFs
*****************************************************************/
typedef int	(*FUNPTR)();	// pointer to a fxn returning an int

typedef	struct	{
	unsigned xMax;		// display area maximum X coordinate
	unsigned xMin;		// display area minimum X coordinate
	unsigned yMax;		// display area maximum Y coordinate
	unsigned yMin;		// display area minimum Y coordinate
	} XYBOUNDS;

typedef	struct	{
	BYTE	len;		// number of bytes (including 5 bytes of overhead)
	BYTE	cmd;		// command
	BYTE	fxn;		// subfunction
	BYTE	seq;		// sequence
	BYTE	data[1];	// open-ended
	} COMMAND;

typedef	struct	{
	ADDR20		fpFwd;				// far ptr to forward node
	ADDR20		fpBitmap;			// far pointer to bitmap data in xmem ROM
	int			bitmapId;			// identifier (room for expansion)
	int			dx, dy;				// size of bitmap
	} BITMAP_LIST;

typedef	struct	{
	ADDR20		fpFwd;				// far ptr to forward node
	ADDR20		fpText;				// Far pointer to ASCIIZ text assoc with button, NULL if none
	ADDR20		fpSave;				// Far pointer to saved background in xmem RAM.  NULL if none
	ADDR20		fpMyaddr;			// Far pointer to this block (my address)
	int			buttonId;			// identifier
	int			bitmapId;			// id of bitmap associated with button, 0 if none
	int			macroId;				// id of macro associated with button, 0 if none
	BYTE		flags;					// bit flags
	BYTE		nwCell, seCell;		// index of North West and South East corner cell
	BYTE		pushCount;				// number of cells currently pushed in button (must be last item)
	} BUTTON_LIST;

typedef	struct	{
	ADDR20		fpFwd;				// far ptr to forward node
	ADDR20		fpRegion;			// far pointer to bitmap data in xmem RAM
	int			regionId;			// identifier (room for expansion)
	int			x0, y0;				// coordinates of NW corner
	int			dx, dy;				// size of bitmap
	} REGION_LIST;

typedef	struct	{
	ADDR20		fpFwd;				// far ptr to forward node
	int			macroId;			// identifier
	ADDR20		fpMyaddr;			// Far pointer to this block (my address)
	int			offset;				// offset from fpMyaddr to the currently executing command
	ADDR20		fpReturn;			// return address, used when a macro is called by another macro
	int			xx, yy;				// drawing offset
	COMMAND		command[1];
	} MACRO_LIST;

typedef	struct	{				// structure of data block in flash
	BYTE		cmd;				// command
	ADDR20		fpData;				// pointer to data
	int			id;					// bitmapId or fontId
	int			dx, dy;				// size of bitmap or size of font letter
	BYTE		startChar, endChar;	// not used for bitmap
	} BLOCK_STRUCT;

union	CMD_DATA	{
	COMMAND	cmdStruc;
	BYTE	data[255];
	};

union	LONG_FLOAT	{
	long	longMem;
	float	floatMem;
	};

/* Flash-related definitions */
#define	FLASH_SEGS	3
#define	FLASH_INUSE	0x5A5A5A5AL
#define	FLASH_AVAIL	0xA5A5A5A5L

typedef	struct {
	ULONG	size;
	ADDR20  fpAddr;
	}  FREE_LIST;

typedef	struct {
	ULONG	flag;
	ULONG	size;
	ADDR20  fpAddr;
	}  FLASH_HDR;

/*****************************************************************
	GLOBAL STORAGE
*****************************************************************/
BOOL		enaAckNak;		// TRUE to enable ACK/NAK
int			contrast;		// screen contrast
int			brushType;		// last specified brush type
int			fontId;			// current font ID
int			cursorX, cursorY;		// cursor position
int			curType;		// cursor type
int			curBlink;		// cursor blink time (msec); 0 = don't blink
int			textDir;		// text direction	0 = left-to-right
							//					1 = right-to-left
							//					2 = bottom-to-top
							//					3 = top-to-bottom
BYTE		lastStatus;		// bit-encoded status
BYTE		lastCell;		// Last cell pushed
WORD		lastButton;		// Last button pushed (buttonId)
BYTE		lastError;		// last decode error
BYTE		okBitmapId;		// it's OK to continue loading this bitmap
BYTE		okFontId;		// it's OK to continue loading this font
BYTE		packet0[255];	// current packet, chan 0
BYTE		packet0u[255];	// unsolicited response packet, chan 0
BOOL		first;			// flag set after restart
int			macroChain1st;	// the 1st macro in the macro chain
struct	_Channel	*pChan0;	// channel pointer 0
union	CMD_DATA	cmdData;// temp usage

ADDR20		fpBitmapList;	// far pointer to bit map linked list
ADDR20		fpButtonList;	// far pointer to button linked list
ADDR20		fpRegionList;	// far pointer to region linked list

// virtual keyboard items
char	vkBuff[MAX_STRING];	// virtual keyboard string buffer
char	vkPrompt[MAX_STRING];	// virtual keyboard prompt line buffer
BOOL	vkActive;			// flag set if vk is active
BOOL	vkShift;			// flag set if shift lock
BYTE	vkFlags;			// as set by PLAY_KEYBOARD_MACRO command
char	vkLastChar;			// Last character entered
int		vkTimeout;			// keyboard timeout value
union	LONG_FLOAT vkLowLimit;
union	LONG_FLOAT vkHighLimit;
BOOL	vkResShow;			// flag TRUE if result is showing

// font information array
// [0] = filler, 1 to 3 = default font, 4 to MAX_FONT = user defined
struct _fontInfo	fontInfo[MAX_FONT + 1];

// This array links a cell to a button. It contains the buttonId if the cell is
// associated with a button; 0 if not. In order of cellId, 1 to 64. 0 = filler.
int cellToButton[65];

// The vk uses this array to save/restore cell to button links.
int vkCellToButton[65];

// The disable/enable area buttons commands use this array to save/restore cell
// to button links.
int areaButtons[65];

// this array links a cell to a macro.  In order of cellId, 1 to 64. 0 = filler.
int		cellToMacro[65];

// this array has a TRUE entry if a cell is enabled.
// In order of cellId, 1 to 64. 0 = filler.
BOOL	cellEnabled[65];

// this array has a bit-encoded entry if a cell is active.
// In order of cellId, 1 to 64. 0 = filler.
BYTE	cellActive[65];

// Macro-related global variables
BOOL	buildingMacro;	// TRUE if we're building a macro
BOOL	playingMacro;	// TRUE if we're playing a macro
int		macroX, macroY;	// offsets applied to macro commands (ShiftDrawMacro)
ADDR20	fpMacroList;	// RAM pointer to start of macro list structure
ADDR20	fpPlayMacro;	// pointer to currently displaying macro

// this should be in supermal; we'll put it there later
FREE_LIST	flashFreeList[FLASH_SEGS];

//
// file:	LIB.H
//			procedure declarations
//
/*** BeginHeader InitPlayQue, PutPlayQue */
void InitPlayQue(void);
BOOL PutPlayQue (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader GetPlayQue */
BOOL GetPlayQue (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader CheckPlayQue */
BOOL CheckPlayQue (int which);
/*** endHeader */
/*** BeginHeader XStrlen, MyFtoa */
int	 XStrlen(ADDR20 fpStr);
char *MyFtoa (float fvalue, char *pBuff);
/*** endHeader */
/*** BeginHeader Srand, Rand */
void Srand (UINT seed);
int	 Rand (void);
/*** endHeader */
/*** BeginHeader Xlate */
int	 Xlate (int object, int *pTable);
/*** endHeader */
/*** BeginHeader PlayTask */
void PlayTask (void);
/*** endHeader */
/*** BeginHeader TestTask */
void TestTask (void);
/*** endHeader */
/*** BeginHeader AddBitmapList, DelBitmapList, FindBitmapList, PlayBitmap */
BOOL AddBitmapList (COMMAND *pCmd, ADDR20 pBitmap);
BOOL DelBitmapList (int bitmapId);
BOOL FindBitmapList (int bitmapId, BITMAP_LIST *pBitmapList);
BOOL PlayBitmap (int bitmapId, int xx, int yy);
/*** endHeader */
/*** BeginHeader cellButt, cellEnter, cellBs, cellEsc, cellDot,
	allClear, allSet */
extern ADDR20 cellButt;
extern ADDR20 cellEnter;
extern ADDR20 cellBs;
extern ADDR20 cellEsc;
extern ADDR20 cellDot;
extern ADDR20 allClear;
extern ADDR20 allSet;
/*** EndHeader */
/*** BeginHeader btnFrameNw, btnFrameSw, btnFrameNe, btnFrameSe */
extern ADDR20 btnFrameNw;
extern ADDR20 btnFrameSw;
extern ADDR20 btnFrameNe;
extern ADDR20 btnFrameSe;
/*** EndHeader */
/*** BeginHeader PlayString, CenterXString */
void PlayString (int xx0, int yy0, XYBOUNDS *xyBounds, char *pChar);
void CenterXString (int px, int py, XYBOUNDS *xyBounds, ADDR20 fpChar);
/*** endHeader */
/*** BeginHeader AddButtonList, DelButtonList, FindButtonList,
 PlayButton, EnaButton */
BOOL AddButtonList (COMMAND *pCmd);
BOOL DelButtonList (int buttonId);
BOOL FindButtonList (int buttonId, BUTTON_LIST *pButtonList);
BOOL PlayButton (int buttonId, int fxn);
BOOL EnaButton (int buttonId, int fxn);
/*** endHeader */
/*** BeginHeader AbsToRel */
int	 AbsToRel (BYTE absCoord, BOOL x);
/*** endHeader */
/*** BeginHeader DrawOvalFrame, DrawRectFrame */
void DrawOvalFrame (int x, int y, int w, int h);
void DrawRectFrame (int x, int y, int w, int h);
/*** endHeader */
/*** BeginHeader MemoryDevice, A24to20,
	XramMalloc, XramClear, XramFree, XramPack */
int 	MemoryDevice(ADDR20 fpAddr);
ADDR20	XramMalloc(ULONG nBytes);
BOOL	XramBfree(ADDR20 lo, ADDR20 hi);
void	XramClear(void);
BOOL	XramFree(ADDR20 fpAddr);
ULONG	XramPack(void);
ADDR20	A24to20(ULONG a24);
/*** EndHeader */
/*** BeginHeader InitFlash, FlashClear, FlashMalloc, FlashAvail, FlashGenWrite */
void	InitFlash(void);
void	FlashClear (void);
ADDR20	FlashMalloc (ULONG rsize);
BOOL	FlashAvail (ADDR20 fpAddr);
int		FlashGenWrite (ADDR20 fpDst, void *pSrc, int nbytes);
/*** EndHeader */
/*** BeginHeader Decode */
BYTE Decode (COMMAND *pCmd, BOOL *pDelta);
/*** endHeader */
/*** BeginHeader InitChan0, SendReply */
BOOL InitChan0 (void);
void SendReply(struct _Channel *pChan, BYTE *pPacket);
/*** endHeader */
/*** BeginHeader Init, SuperReset, InitGlobalVars */
void Init (void);
void SuperReset (void);
void InitGlobalVars (void);
/*** endHeader */
/*** BeginHeader InitVirtKbd, PlayVirtKbd, SetString, PlayPrompt,
	PlayResult, PlayVkBuff */
BOOL InitVirtKbd (void);
BOOL PlayVirtKbd (COMMAND *pCmd, int fxn);
void SetString (COMMAND *pCmd);
void PlayPrompt(void);
void PlayResult(char *pChar);
void PlayVkBuff(void);
/*** endHeader */
/*** BeginHeader Rs232Task, InitChan0, SendReply */
void Rs232Task (void);
BOOL InitChan0 (void);
void SendReply(struct _Channel *pChan, BYTE *pPacket);
/*** endHeader */
/*** BeginHeader InitButtons, CellTask */
void InitButtons (void);
void CellTask (void);
/*** endHeader */
/*** BeginHeader DeleteBitmap, InitLoadBitmap, ConueLoadBitmap */
BOOL DeleteBitmap (int bitmapId);
BOOL InitLoadBitmap (int bitmapId, int dx, int dy);
BOOL ConueLoadBitmap (int bitmapId, int len, BYTE *pByte);
/*** endHeader */
/*** BeginHeader DeleteFont, InitLoadFont, ConueLoadFont */
BOOL DeleteFont (int font);
BOOL InitLoadFont (int font, BYTE *pByte);
BOOL ConueLoadFont (int font, int len, BYTE *pByte);
/*** endHeader */
/*** BeginHeader CheckIfAllowed, StartBuildingMacro, AddCommandToList,
 DelMacroList, FindMacroList, StartPlayingMacro, StopPlayingMacro,
 PlayNextMacroStep */
BOOL CheckIfAllowed (COMMAND *pCmd);
BOOL StartBuildingMacro (COMMAND *pCmd);
BOOL AddCommandToList (COMMAND *pCmd);
BOOL DelMacroList (int myMacroId);
BOOL FindMacroList (int macroId, MACRO_LIST *pMacroList);
BOOL StartPlayingMacro (int macroId, int xx, int yy);
void StopPlayingMacro (void);
void PlayNextMacroStep (void);
/*** endHeader */
/*** BeginHeader InitMacroQue, PutMacroQue, PutMacroIdQue */
void InitMacroQue(void);
BOOL PutMacroQue (COMMAND *pCmd);
BOOL PutMacroIdQue (int macroId);
/*** endHeader */
/*** BeginHeader GetMacroQue */
BOOL GetMacroQue (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader CheckMacroQue */
BOOL CheckMacroQue (int which);
/*** endHeader */
/*** BeginHeader AddRegionList,	DelRegionList, FindRegionList,
	BlankRegion, InvertRegion */
BOOL AddRegionList (COMMAND *pCmd);
BOOL DelRegionList (int myRegionId, int xOvr, int yOvr);
BOOL FindRegionList (int regionId, REGION_LIST *pRegionList);
BOOL BlankRegion (COMMAND *pCmd);
BOOL InvertRegion (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader min, PlayGreeting */
int	 min (int int1, int int2);
void PlayGreeting (void);
/*** endHeader */
/*M******************************************************************
**
** SOURCE FILE:		MAIN.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					Main program entry
**
** FUNCTION LIST:	main
**						Program entry
**					MacroTask
**						Plays a macro
**					InitGlobalVars
**						init global variables
**					Init
**						Reset board, clear screen, init global variables
**					SuperReset
**						Clear all bitmap, macro, and font lists
**					FlashClear
**						Clear possible bitmaps and fonts info in flash
**					FlashRebuild
**						Rebuild bitmaps and fonts from info in flash
**
** CREATION DATE: 	04/27/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
void MacroTask(void);
void InitGlobalVars(void);
void Init(void);
void SuperReset(void);
void FlashClear(void);
void FlashRebuild(void);

/*****************************************************************
	main program is here
*****************************************************************/
#memmap root
nodebug
main()
{
	segchain _GLOBAL_INIT { _OP7100GE_INIT(); }
	segchain _OP7100GE_INIT { first = TRUE; }
/*--initialize-------------------------------------------------*/
	_sysIsSuperReset();	// check for 1st time power up!
// set up wait states for a 90 ns flash memory
	outport(DCNTL, ((inport(DCNTL) & 0x0F) | 0x60));
	VdInit();
// Initialize communications
	InitChan0();
	Init();					// order is critical
	if(sysIsSuperReset())
	{
// only if 1st time power up!
		SuperReset();
		FlashClear();		// make Flash available for user bitmaps and fonts
#ifdef ADD_QVGA_DEMO
		skipQvgaDemo = 0;	//	quarter VGA demo initialization stuff
#endif
	}
	else
	{
// subsequent power up or reset
		FlashRebuild();	// rebuild user bitmaps and fonts
	}
	InitVirtKbd();			// initialize the virtual keyboard
	InitButtons();			// initialize scanning of buttons

#ifdef ADD_QVGA_DEMO
//	skip QVGA demo after 1st communication is received
	if(!skipQvgaDemo)
	{
		QvgaDemo(pChan0, engFont6x8, engFont8x10, engFont12x16, engFont16x32,
		         engFont17x35a);
	}
#endif

/*---------------------------------------------------------------
	loop
---------------------------------------------------------------*/
	FOREVER
	{
		PlayTask();
		Rs232Task();
		CellTask();
		MacroTask();
		TestTask();
		hitwd();	// ensure the watchdog gets hit during long bitmap or font DLs
	}
}

/* START FUNCTION DESCRIPTION ********************************************
MacroTask

SYNTAX:			void	MacroTask (void);

DESCRIPTION:	Display macros

GLOBALS & USE:	playingMacro

END DESCRIPTION **********************************************************/
nodebug
void MacroTask(void)
{
	// a SHIFT_DRAW_MACRO command can fit into the buffer
#define	SHIFT_SIZE	10	// sizeof(COMMAND) + sizeof(int) + sizeof(int) - 1
	BYTE	buff[SHIFT_SIZE];
	BYTE	rc;
	static int state;

	segchain _OP7100GE_INIT { state = 0; }

// check if other macros are qued if not playing a macro
	if (!playingMacro)
		{
		state = 0;
		rc = GetMacroQue ((COMMAND *)&buff[0]);
		if (rc)				// start playing the next macro
			rc = Decode ((COMMAND *)&buff[0], NULL);
		}

// already playing a macro - play the next step
	else
	switch (state)
		{
// Wait for the display que empty
	case 0:
		if (CheckPlayQue (0))
			state++;
		break;

// Play this macro step
	case 1:
		PlayNextMacroStep();	// may have set 'playingMacro' = FALSE
		state--;
		break;
		}
	}

#memmap xmem
/* START FUNCTION DESCRIPTION ********************************************
InitGlobalVars

SYNTAX:			void InitGlobalVars (void);

DESCRIPTION:	Init global variables

RETURN VALUE:	none

END DESCRIPTION **********************************************************/
nodebug
void InitGlobalVars(void)
{
	auto int ix;

	for(ix = 0; ix <= 64; ix++)
	{
		cellEnabled[ix] = FALSE;
		cellToMacro[ix] = 0;
		cellToButton[ix] = 0;
		cellActive[ix] = 0;
		vkCellToButton[ix] = 0;
		areaButtons[ix] = 0;
	}
	vkResShow = FALSE;		// Result is not showing
	fontId = 2;				// Medium font is the default
	cursorX = cursorY = 0;	// initial cursor position
	enaAckNak = TRUE;		// enable ACK/NAK
	curType = 0;			// cursor type = invisible
	curBlink = 0;			// cursor blink time (msec); 0 = don't blink
	textDir = 0;			// text direction = left-to-right
	macroChain1st = 0;		// no macros in the chain
	lastStatus = lastError = 0;
	lastButton = lastCell = vkLastChar = 0;
	vkActive = FALSE;
	vkBuff[0] = NUL;		// no string entered as yet
	okBitmapId = okFontId = 0;

	buildingMacro = FALSE;
	playingMacro = FALSE;
	macroX = 0; macroY = 0;
	fpMacroList = FNULL;
	fpPlayMacro = FNULL;
}

/* START FUNCTION DESCRIPTION ********************************************
Init

SYNTAX:			void Init (void);

DESCRIPTION:	Reset board, clear screen, init global variables

RETURN VALUE:	none

END DESCRIPTION **********************************************************/
nodebug
void Init(void)
{
	int		rc;

	glInit();

	contrast = 35;		// full scale = 63
	brushType = OP71BLACK;

	glBlankScreen();
	op71BackLight(1);
	op71SetContrast(contrast);

	glSetBrushType(brushType);

// Initialize flash subsystem
	InitFlash();
}

/* START FUNCTION DESCRIPTION ********************************************
SuperReset

SYNTAX:			void SuperReset (void);

DESCRIPTION:	Clear all bitmap, macro, and font lists except for default
				fonts.

RETURN VALUE:	none

END DESCRIPTION **********************************************************/
nodebug
void SuperReset(void)
{
	BOOL	ok;
	int		ix;

	InitGlobalVars();

	fpButtonList = FNULL;
	fpBitmapList = FNULL;
	fpRegionList = FNULL;
// There are two XRAM areas in the OP7100 available for allocation
	XramClear ();	// startHeapXram = FNULL;
	XramBfree(/*lo=*/0xA0000ul, /*hi=*/phy_adr((void*)prog_param.stkB));
	XramBfree(/*lo=*/A24to20(prog_param.XDE.l), /*hi=*/0xBFFFF);

// we assume that no font has a startChar of zero
// we'll use that as a "font not inited" flag
	for (ix = 0; ix <= MAX_FONT; ix++)
		{
		fontInfo[ix].startChar = 0;
		}
// small font
	glXFontInit(	//	initialize the font info structure needed later
		&fontInfo[1],	//	pointer to the font info structure to fill
		6,				//	horizontal size (in pixels) of each character
		8,				//	vertical size (in pixels) of each character
		32,				//	beginning code of printable characters
		255,			//	ending code of printable characters
		engFont6x8		//	address of font bitmap in xmem
		);

// medium font
	glXFontInit(
		&fontInfo[2],
		12,
		16,
		32,
		127,
		engFont12x16
		);
// large font
	glXFontInit(
		&fontInfo[3],
		17,
		35,
		32,
		127,
		engFont17x35a
		);
}

/* START FUNCTION DESCRIPTION ********************************************
FlashRebuild

SYNTAX:			void	FlashRebuild (void);

DESCRIPTION:	Rebuild bitmaps and fonts from info in flash

GLOBALS & USE:	fontInfo[4] onwards

RETURN VALUE:	n/a

END DESCRIPTION **********************************************************/
nodebug
void FlashRebuild(void)
{
	BOOL			ok;
	int				ix, id, *pInt;
	ULONG			size, blockSize, dataSize, flag;
	ADDR20			fpAddr, addr1st, blockAddr, hdrAddr;
	FLASH_HDR		flashHdr;
	BLOCK_STRUCT	blockStruct;

	ix = 0;
	while (flashFreeList[ix].fpAddr)
		{
	// here for each segment
		fpAddr = flashFreeList[ix].fpAddr;	// the last address of this segment + 1
		size = flashFreeList[ix++].size;	// the size of this segment
		addr1st = fpAddr - size;			// the 1st address in this segment
	// here for each data block; fpAddr points past the last byte of the block
		FOREVER
			{
			hdrAddr	= fpAddr - sizeof(FLASH_HDR);
			xmem2root (/*fpSrc=*/hdrAddr, /*pDst=*/&flashHdr,
						/*len=*/sizeof(FLASH_HDR));
			blockSize = flashHdr.size;
			blockAddr = flashHdr.fpAddr;
			flag = flashHdr.flag;

			ok = ((flag == FLASH_INUSE)
				&& (blockAddr <= (fpAddr - 32))	// at least 32 bytes in block
				&& (blockAddr >= addr1st)
				&& (blockSize >= 32)
				&& (blockSize <= size));
			if (!ok)
				break;	// this header is not reasonable, and the rest of the
						// flash must be unused
		// this header is reasonable
		// read the block structure into memory
			xmem2root (/*fpSrc=*/blockAddr, /*pDst=*/&blockStruct,
						/*len=*/sizeof(BLOCK_STRUCT));
/*---------------------**
** rebuild bitmap list **
**---------------------*/
			if (blockStruct.cmd == BIT_MAP)
				{
				id = blockStruct.id;
				dataSize = (((ULONG) blockStruct.dx + 7L) / 8L) *
				           (ULONG) blockStruct.dy;	// in bytes
				ok = ((id >= 1) && (id < 251));		// vk uses 251 to 255
				if (ok)
					ok = ((dataSize <= blockSize)
						&& (blockStruct.dx >= 4)
						&& (blockStruct.dx <= HMAX)
						&& (blockStruct.dy > 4)
						&& (blockStruct.dy <= VMAX)
						&& (blockStruct.fpData ==
								(blockAddr + sizeof(BLOCK_STRUCT))));
				cmdData.cmdStruc.seq = (BYTE)id;
				pInt = (int *)&cmdData.data[4];
				*pInt++ = blockStruct.dx;	// dx
				*pInt++ = blockStruct.dy;	// dy
				if (ok)
					ok = AddBitmapList ((COMMAND *)&cmdData, blockStruct.fpData);
				}
/*--------------**
** rebuild font **
**--------------*/
			else if (blockStruct.cmd == FONT)
				{
				id = blockStruct.id;
				dataSize = (((ULONG) blockStruct.dx + 7L) / 8L) *
				           (ULONG) blockStruct.dy *
				           ((ULONG) blockStruct.endChar -
				            (ULONG) blockStruct.startChar + 1L);	// in bytes
				ok = ((id >= MIN_FONT) && (id <= MAX_FONT));
				if (ok)
					ok = ((dataSize <= blockSize)
						&& (blockStruct.dx > 4)
						&& (blockStruct.dx <= 32)
						&& (blockStruct.dy > 4)
						&& (blockStruct.dy <= 32)
						&& (blockStruct.fpData ==
								(blockAddr + sizeof(BLOCK_STRUCT))));
				if (ok)
					glXFontInit(
						&fontInfo[id],
						(char)blockStruct.dx,
						(char)blockStruct.dy,
						blockStruct.startChar,
						blockStruct.endChar,
						blockStruct.fpData);
				}

			size -= blockSize;
			fpAddr -= blockSize;			// ready for the next iteration
			if (size <= 0)
				break;
			}
		}
	}
/*M******************************************************************
**
** SOURCE FILE:		PLAYTASK.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**				   	Display Task
**
** FUNCTION LIST:	PlayTask
**						Display Task
**					Shift
**						Shift a coordinate
**
** CREATION DATE: 	04/27/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/

#memmap xmem
/*** BeginHeader PlayTask */
void PlayTask (void);
/*** endHeader */
int Shift (int coord, BOOL doy);

/* START FUNCTION DESCRIPTION ********************************************
PlayTask

SYNTAX:			void	PlayTask(void);

DESCRIPTION:
	This is a costatement task in charge of display.

RETURN VALUE:
	None

END DESCRIPTION **********************************************************/
nodebug
void PlayTask(void)
{
	auto XYBOUNDS xyBounds;
	BOOL ok;
	BYTE	btemp, *pByte;
	int		itemp, vertices, bitmapId, buttonId, tfontId, regionId,
			xx0, yy0, xx1, yy1, rad, dx, dy, len, dir, num;
	long	lTemp;
	float	fTemp, *pFloat;

	static	char	*pChar;
	static	int		state, *pInt;
	static	ULONG	*pUlong;
	static	union	CMD_DATA	cmdData;
	static	int		brushTypeT[] =	{
		OP71WHITE,
		OP71BLACK,
		OP71XOR,
		OP71BLACK};
	static	int		*pVertex, vertex[MAX_VERTEX * 2];	// shifted vertices

	segchain _OP7100GE_INIT { state = 0; }

	xyBounds.xMax = HMAX;
	xyBounds.xMin = 0;
	xyBounds.yMax = VMAX;
	xyBounds.yMin = 0;
	costate
	{
		ok = TRUE;
		switch (state)
		{
/*----------------------------**
** Get a command from the que **
**----------------------------*/
		case 0:
			ok = GetPlayQue ((COMMAND *)&cmdData);
			if (ok)
				{
				pByte = &cmdData.data[4];
				pInt = (int *)pByte;
				pUlong = (ULONG *)pByte;
				state = cmdData.cmdStruc.cmd;	// no command is numbered 0
				}
			break;

		case CLEAR_SCREEN:
			if (vkActive)
				{
				// We have to XramFree the area saved by vk buttons
				// in the next call, pCmd is a don't care
				PlayVirtKbd (/*pCmd=*/NULL, /*fxn=*/0);
				}
			glBlankScreen();
			state = 0;
			break;

		case SET_BRUSH_TYPE:
			brushType = brushTypeT[cmdData.cmdStruc.fxn];
			glSetBrushType(brushType);
			state = 0;
			break;

		case PIXEL:
			xx0 = *pInt++;
			yy0 = *pInt;
			glPlotDot (Shift(xx0, FALSE), Shift(yy0, TRUE));
			state = 0;
			break;

		case LINE:
			xx0 = *pInt++;
			yy0 = *pInt++;
			xx1 = *pInt++;
			yy1 = *pInt;
			glPlotLine (Shift(xx0, FALSE), Shift(yy0, TRUE),
						Shift(xx1, FALSE), Shift(yy1, TRUE));
			state = 0;
			break;

		case CIRCLE:
			xx0 = Shift(*pInt++, FALSE);
			yy0 = Shift(*pInt++, TRUE);
			rad = *pInt;
			if (cmdData.cmdStruc.fxn == FILLED)
				glFillCircle (xx0, yy0, rad);
			else
				glPlotCircle (xx0, yy0, rad);
			state = 0;
			break;

		case RECTANGLE:
			xx0 = Shift(*pInt++, FALSE);
			yy0 = Shift(*pInt++, TRUE);
			xx1 = Shift(*pInt++, FALSE);
			yy1 = Shift(*pInt, TRUE);
			if (cmdData.cmdStruc.fxn == FILLED)
				glFillPolygon (4, 	xx0, yy0,
								xx1, yy0,
								xx1, yy1,
								xx0, yy1);
			else
				 glPlotPolygon (4, xx0, yy0,
								xx1, yy0,
								xx1, yy1,
								xx0, yy1);
			state = 0;
			break;

		case POLYGON:
			vertices = cmdData.cmdStruc.seq;
			if (vertices > MAX_VERTEX)
				vertices = MAX_VERTEX;
			itemp = vertices;
			pVertex = vertex;
			while (itemp--)
				{
				*pVertex++ = Shift (*pInt++, FALSE);
				*pVertex++ = Shift (*pInt++, TRUE);
				}
			if (cmdData.cmdStruc.fxn == FILLED)
				glFillVPolygon (vertices, vertex);
			else
				glPlotVPolygon (vertices, vertex);
			state = 0;
			break;

		case BLANK_REGION:
			BlankRegion ((COMMAND *)&cmdData);
			state = 0;
			break;

		case INVERT_REGION:
			InvertRegion ((COMMAND *)&cmdData);
			state = 0;
			break;

		case STORE_REGION:
			AddRegionList ((COMMAND *)&cmdData);
			state = 0;
			break;

		case RESTORE_REGION:
			regionId = (int)cmdData.cmdStruc.seq;
			xx0 = *pInt++;
			yy0 = *pInt;
			if (xx0 > 0)
				xx0 = Shift(xx0, FALSE);
			if (yy0 > 0)
				yy0 = Shift(yy0, TRUE);
			DelRegionList (regionId, xx0, yy0);
			state = 0;
			break;

		case PUT_BIT_MAP:
			bitmapId = (int)cmdData.cmdStruc.seq;
			xx0 = Shift(*pInt++, FALSE);
			yy0 = Shift(*pInt, TRUE);
		// the caller should use FindBitmapList before
		// stuffing command into que
			ok = PlayBitmap (bitmapId, xx0, yy0);
			state = 0;
			break;

		case SCROLL_REGION:
			dir = (int)cmdData.cmdStruc.fxn;
			num = *pInt++;
			xx0 = Shift(*pInt++, FALSE);
			yy0 = Shift(*pInt++, TRUE);
			xx1 = Shift(*pInt++, FALSE);
			yy1 = Shift(*pInt++, TRUE);
			dx = xx1 - xx0;
			dy = yy1 - yy0;
			if (dx < 0)
				{
				dx = -dx;
				xx0 = xx1;
				}
			if (dy < 0)
				{
				dy = -dy;
				yy0 = yy1;
				}
			glSetBrushType ( OP71WHITE );
			glBuffLock ();
			while (num--)
				{
				switch (dir)
					{
					case 1:
						op71Up1   (xx0, yy0, dx, dy);
						break;
					case 2:
						op71Down1 (xx0, yy0, dx, dy);
						break;
					case 3:
						op71Right1(xx0, yy0, dx, dy);
						break;
					case 4:
						op71Left1 (xx0, yy0, dx, dy);
						break;
					}
				}
			glBuffUnlock ();
			glSetBrushType(brushType);
			state = 0;
			break;

		case SET_FONT:
		// the caller must do the checking before
		// stuffing command into que
			fontId = (int)cmdData.cmdStruc.seq;
			state = 0;
			break;

		case PUT_TEXT:
			xx0 = Shift(*pInt++, FALSE);
			yy0 = Shift(*pInt++, TRUE);
			pChar = (char *)pInt;
			PlayString(xx0, yy0, &xyBounds, pChar);
			state = 0;
			break;

		case SET_TEXT_DIR:
			itemp = (int) cmdData.cmdStruc.fxn;
			if((itemp >= 0) && (itemp <= 3))
			{
				textDir = itemp;
			}
			state = 0;
			break;

		case BACK_LIGHT:
			op71BackLight(cmdData.cmdStruc.fxn);
			state = 0;
			break;

		case SET_CONTRAST:
			itemp = (int) cmdData.cmdStruc.data[0];
			if((itemp >= 0) && (itemp <= 63))
			{
				contrast = itemp;
				op71SetContrast (contrast);
			}
			state = 0;
			break;

		case BEEP:
			itemp = *pInt;
			if (itemp == 0)
				itemp = 100;	// default value
			eioBeep (1);
			waitfor (DelayMs((ULONG)itemp));
			eioBeep (0);
			state = 0;
			break;

		case DISPLAY_BUTTON:
			buttonId = *pInt;
			ok = PlayButton (buttonId, /*fxn=*/1);
			state = 0;
			break;

		case DISPLAY_BUTTON_Q:
			buttonId = *pInt;
			ok = PlayButton (buttonId, /*fxn=*/cmdData.cmdStruc.fxn);
			state = 0;
			break;

		case REMOVE_BUTTON:
			buttonId = *pInt;
			ok = PlayButton (buttonId, /*fxn=*/0);
			state = 0;
			break;

		case SET_STRING:
			SetString ((COMMAND *)&cmdData);
			state = 0;
			break;

		case SET_LONG_INTEGER:
			lTemp = *pUlong;
			ltoa (lTemp, &cmdData.data[4]);	// store ASCIIZ in command
			SetString ((COMMAND *)&cmdData);
			state = 0;
			break;

		case SET_FLOAT:
			pFloat = (float *)&cmdData.data[4];
			fTemp = *pFloat;
			MyFtoa (fTemp, &cmdData.data[4]);	// store ASCIIZ in command
			SetString ((COMMAND *)&cmdData);
			state = 0;
			break;

		case SET_CHAR:
		// the char is in data[4]
			cmdData.data[5] = NUL;				// terminate the string
			if(strlen(vkBuff) < (MAX_STRING - 1))
				strcat (vkBuff, &cmdData.data[4]);	// append char to vk buffer
			strcpy (&cmdData.data[4], vkBuff);	// copy it back to the command
			SetString ((COMMAND *)&cmdData);	// there's probably an easier way
			state = 0;
			break;

		case PLAY_KEYBOARD_MACRO:
			PlayVirtKbd ((COMMAND *)&cmdData, cmdData.cmdStruc.fxn);
			state = 0;
			break;

		case DELAY_PLAY:
			waitfor(DelayMs(*pUlong));
			state = 0;
			break;

		case CLEAR_STRING_BUFF:
			SetString (NULL);	// to clear the string buffer
			state = 0;
			break;

		case BIT_MAP:
			switch (cmdData.cmdStruc.fxn)
				{
				case 0:
					bitmapId = (int)cmdData.cmdStruc.seq;
					ok = DeleteBitmap (bitmapId);
					break;

				case 1:
					bitmapId = (int)cmdData.cmdStruc.seq;
					dx = *pInt++;
					dy = *pInt;
					ok = InitLoadBitmap (bitmapId, dx, dy);
					break;

				case 2:
					len = cmdData.cmdStruc.len - 5;	// addr, len, cmd, fxn, seq
					ok = ConueLoadBitmap (/*bitmapId=*/cmdData.cmdStruc.seq,
								len, pByte);
					break;

				default:
					ok = FALSE;
					break;
				}
			state = 0;
			break;

		case FONT:
			switch (cmdData.cmdStruc.fxn)
				{
				case 0:
					tfontId = (int)cmdData.cmdStruc.seq;
					ok = DeleteFont (tfontId);
					break;

				case 1:
					tfontId = (int)cmdData.cmdStruc.seq;
					ok = InitLoadFont (tfontId, pByte);
					break;

				case 2:
					len = cmdData.cmdStruc.len - 5;	// addr, len, cmd, fxn, seq
					ok = ConueLoadFont (/*font=*/cmdData.cmdStruc.seq,
								len, pByte);
					break;

				default:
					ok = FALSE;
					break;
				}
			state = 0;
			break;

		default:
			state = 0;
			break;
		}
	}
}

/* START FUNCTION DESCRIPTION ********************************************
Shift

SYNTAX:			int Shift (
					int		coord,	// the coordinate to shift
					BOOL	doy);	// FALSE = do x-coord
									// TRUE  = do y-coord

DESCRIPTION:	Shift the coordinate by macroX or macroY, clamp to max

RETURN VALUE:	The shifted coordinate.

END DESCRIPTION **********************************************************/
nodebug
int Shift (int coord, BOOL doy)
{
	int		max;

	if (playingMacro)		// don't shift outside of the macro
		{
		if (doy)
			{
			max = VMAX;
			coord += macroY;
			}
		else
			{
			max = HMAX;
			coord += macroX;
			}
		if (coord < 0)
			coord = 0;
		else if (coord > max)
			coord = max;
		}

	return (coord);
}

/********************************************************************
**
** SOURCE FILE:		MACROS.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					Procedures to process macros
**
** FUNCTION LIST:	InitMacroQue
**						Initialize the macro que
**					PutMacroQue
**						Put a command into the macro que
**					PutMacroIdQue
**						Put a macro specified by id into macro que
**					GetMacroQue
**						Get a command from the macro que
**					CheckMacroQue
**						Check if que is empty or full
**					CheckIfAllowed
**						Check if this command is allowed in a macro
**					StartBuildingMacro
**						Start building a macro
**					AddCommandToList
**						Add a command to the Macro List
**						Includes StopBuildingMacro code
**					DelMacroList
**						Delete a Macro List structure from the chain
**					FindMacroList
**						Return a far ptr to a Macro List in XRAM
**					StartPlayingMacro
**						Start displaying a macro
**					StopPlayingMacro
**						Stop playing the current macro
**					PlayNextMacroStep
**						Play the next step in the current macro
**
** CREATION DATE: 	09/14/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*		GLOBALS & USE:
*	BOOL	buildingMacro;	// TRUE if we're building a macro
*	BOOL	playingMacro;	// TRUE if we're playing a macro
*	int		macroX, macroY;	// offsets applied to macro commands (ShiftDrawMacro)
*	ADDR20	fpMacroList;	// RAM pointer to start of macro list structure
*	ADDR20	fpPlayMacro;	// pointer to currently displaying macro
*
*********************************************************************
**$Log$
**
**/
/* Local variables */
int	macroQueInix,	// input index into the que
		macroQueOutix,	// output index from the que
		macroQueUsed;	// number of slots used
ADDR20	macroQue[MACRO_QUE_SIZE];
#memmap	xmem

/*** BeginHeader CheckIfAllowed, StartBuildingMacro, AddCommandToList,
 DelMacroList, FindMacroList, StartPlayingMacro, StopPlayingMacro,
 PlayNextMacroStep */
BOOL CheckIfAllowed (COMMAND *pCmd);
BOOL StartBuildingMacro (COMMAND *pCmd);
BOOL AddCommandToList (COMMAND *pCmd);
BOOL DelMacroList (int myMacroId);
BOOL FindMacroList (int macroId, MACRO_LIST *pMacroList);
BOOL StartPlayingMacro (int macroId, int xx, int yy);
void StopPlayingMacro (void);
void PlayNextMacroStep (void);
/*** endHeader */
/*** BeginHeader InitMacroQue, PutMacroQue, PutMacroIdQue */
void InitMacroQue(void);
BOOL PutMacroQue (COMMAND *pCmd);
BOOL PutMacroIdQue (int macroId);
/*** endHeader */
/*** BeginHeader GetMacroQue */
BOOL GetMacroQue (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader CheckMacroQue */
BOOL CheckMacroQue (int which);
/*** endHeader */

// Variables local to MACROS.C
void	*pMacro;		// pointer to the macro being built in root RAM
int		macroSize;		// size of ditto
int		macroId;		// macro identifier

/* START FUNCTION DESCRIPTION ********************************************
InitMacroQue

SYNTAX:			void InitMacroQue(void);

DESCRIPTION:	Initialize the macro que

END DESCRIPTION **********************************************************/
nodebug
void InitMacroQue(void)
{
	macroQueInix = 0;
	macroQueOutix = 0;
	macroQueUsed = 0;
	playingMacro = FALSE;
}

/* START FUNCTION DESCRIPTION ********************************************
PutMacroQue

SYNTAX:			BOOL	PutMacroQue (
					COMMAND	*pCmd);		// Pointer to command
DESCRIPTION:
				The caller constructs the command in local root RAM,
				and calls PutMacroQue with a (near) pointer to that command.
				PutMacroQue allocates an area for the command in XRAM,
				copies the command to XRAM, and stores a (far) pointer
				to the area in the playQue.

				Macros are qued only if they come in as an external command
				via Decode().  Macros which are part of another macro are
				handled in PlayNextMacroStep().

				CAUTION: the 'len' member is used to allocate space.  Make
				sure it's initialized prior to calling PutMacroQue.

RETURN VALUE:	TRUE if successful
				FALSE if que full (call CheckMacroQue() to eliminate this)
				or XramMalloc fails.

END DESCRIPTION **********************************************************/
nodebug
BOOL PutMacroQue(COMMAND *pCmd)
{
	BOOL	ok;
	ADDR20	fpCmd;

	segchain _OP7100GE_INIT { InitMacroQue(); }

	ok = macroQueUsed < MACRO_QUE_SIZE;
	if (ok)
		{
		fpCmd = XramMalloc ((ULONG)pCmd->len);
		if (fpCmd)
			{
		// continue if allocation successful
			root2xmem (/*pSrc=*/(void *)pCmd, /*fpDst=*/fpCmd,
						(UINT)pCmd->len);	// copy to XRAM
			macroQue[macroQueInix] = fpCmd;	// store command in que
			macroQueUsed++;					// one more item in the que
		// postincrement the input index
			if (++macroQueInix == MACRO_QUE_SIZE)
				macroQueInix = 0;
			}
		else
			ok = FALSE;
		}

	return (ok);
	}

/* START FUNCTION DESCRIPTION ********************************************
PutMacroIdQue

SYNTAX:			BOOL	PutMacroIdQue (
					int		macroId);	// the macro identifier

DESCRIPTION:	Put a macro specified by id into macro que

RETURN VALUE:	TRUE if macro exists
				FALSE if not found

END DESCRIPTION **********************************************************/
nodebug
BOOL PutMacroIdQue(int macroId)
{
	BOOL	ok;
	COMMAND	cmd;

	ok = FindMacroList (macroId, NULL);

// synthesize command
	if (ok)
		{
		cmd.len = sizeof(COMMAND);
		cmd.cmd = DRAW_MACRO;			// command
		cmd.fxn = (BYTE)macroId;		// subfunction
		cmd.seq = (BYTE)(macroId >> 8);	// sequence
		ok = PutMacroQue (&cmd);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
GetMacroQue

SYNTAX:			BOOL	GetMacroQue (
					COMMAND *pCmd);		// the command will be copied here

DESCRIPTION:
				GetMacroQue is called with a (near) pointer to local root RAM.
				GetMacroQue retrieves the (far) pointer from the macroQue,
				copies the command from XRAM to the caller's storage,
				and XramFree's the area occupied by the command.

RETURN VALUE:	TRUE if an item was in the que.
				FALSE if que is empty

END DESCRIPTION **********************************************************/
nodebug
BOOL GetMacroQue(COMMAND *pCmd)
{
	BOOL	ok;
	BYTE	len;
	ADDR20	fpCmd;

	ok = FALSE;		// assume que is empty
	if (macroQueUsed)	// if there are commands in the que
		{
		ok = TRUE;
		fpCmd = macroQue[macroQueOutix];
		len = xgetchar (fpCmd);		// get the length from XMEM
		xmem2root (/*fpSrc=*/fpCmd, /*pDst=*/(void *)pCmd,
					(UINT)len);		// copy command from XMEM to user's buffer
		XramFree (fpCmd);			// free XMEM storage
		macroQueUsed--;
	// postincrement the output index
		if (++macroQueOutix == MACRO_QUE_SIZE)
			macroQueOutix = 0;
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
CheckMacroQue

SYNTAX:			BOOL CheckMacroQue (
					int which);		// 0 = check if que is empty
									// 1 = check if que is full

DESCRIPTION:	Check if que is empty or full

RETURN VALUE:	TRUE if requested state is TRUE
				FALSE if it's not

END DESCRIPTION **********************************************************/
nodebug
BOOL CheckMacroQue(int which)
{
	BOOL	ok;

	if (which)
		{		// check if que is full
		ok = (macroQueUsed == MACRO_QUE_SIZE);
		}
	else
		{		// check if que is empty
		ok = (macroQueUsed == 0);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
CheckIfAllowed

SYNTAX:			BOOL CheckIfAllowed (
					COMMAND *pCmd);	// the pointer to a command.

DESCRIPTION:	Check if this command is allowed in a macro

RETURN VALUE:	TRUE if allowed

END DESCRIPTION **********************************************************/
nodebug
BOOL CheckIfAllowed(COMMAND *pCmd)
{
	BOOL	found;
	BYTE	lcmd, *pAllowed;
	BYTE	allowed[] =	{
		SEND_STATUS,
		SEND_LAST_PUSH,
		SEND_STRING,
		SEND_LONG_INT,
		SEND_FLOAT,
		SEND_CHAR,
		SEND_TOD,
		CLEAR_STRING_BUFF,
		DISABLE_CELLS,
		ENABLE_CELLS,
		END_MACRO,
		CLEAR_SCREEN,
		SET_BRUSH_TYPE,
		PIXEL,
		LINE,
		CIRCLE,
		RECTANGLE,
		POLYGON,
		BLANK_REGION,
		INVERT_REGION,
		STORE_REGION,
		RESTORE_REGION,
		PUT_BIT_MAP,
		SCROLL_REGION,
		SET_FONT,
		SET_CURSOR_MODE,
		SET_CURSOR,
		PUT_TEXT,
		SET_TEXT_DIR,
		BACK_LIGHT,
		SET_CONTRAST,
		BEEP,
		NULL_LOOP,
		SET_CELL_ACTIVE,
		DISPLAY_BUTTON,
		DISPLAY_BUTTON_Q,
		REMOVE_BUTTON,
		DIS_ENA_BUTTON,
		STOP_MACRO_LOOP,
		SET_STRING,
		SET_LONG_INTEGER,
		SET_FLOAT,
		SET_CHAR,
		SET_TOD,
		PLAY_KEYBOARD_MACRO,
		DRAW_MACRO,
		SHIFT_DRAW_MACRO,
		DELAY_PLAY,
		LOOP_MACRO,
		LINK_CELL_TO_MACRO,
		LINK_BUTTON_TO_MACRO,
		NUL
		};

	found = FALSE;
	lcmd = pCmd->cmd;
	pAllowed = allowed;
	while (*pAllowed)
	{
		if (lcmd == *pAllowed++)
		{
			found = TRUE;
			break;
		}
	}
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
StartBuildingMacro

SYNTAX:			BOOL StartBuildingMacro (
					COMMAND *pCmd);	// the pointer to a START_MACRO command.

DESCRIPTION:	Start building a macro.

RETURN VALUE:	TRUE if successful
				FALSE if:
				1. command not START_MACRO
				2. duplicate macro

END DESCRIPTION **********************************************************/
nodebug
BOOL StartBuildingMacro(COMMAND *pCmd)
{
	MACRO_LIST	tempMacro;
	BYTE		macroBuild[MAX_MACRO];

	if (pCmd->cmd != START_MACRO)
		return (FALSE);				// command not START_MACRO

	macroId = (int)pCmd->fxn + ((int)pCmd->seq << 8);
	if (FindMacroList(macroId, &tempMacro))
		return (FALSE);				// duplicate macro

	pMacro = macroBuild;

	tempMacro.macroId = macroId;
	tempMacro.offset = tempMacro.xx = tempMacro.yy = 0;
	tempMacro.fpReturn = FNULL;

	macroSize = sizeof(MACRO_LIST) - sizeof(COMMAND);
	memcpy (/*pDst=*/pMacro, /*pSrc=*/&tempMacro, macroSize);

	buildingMacro = TRUE;
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
AddCommandToList

SYNTAX:			BOOL AddCommandToList (
					COMMAND *pCmd);	// the pointer to a command to add

DESCRIPTION:	Add a command to the Macro List.

				Called by Decode if buildingMacro.

				END_MACRO command terminates the building process.
				We have been keeping 2 bytes in reserve for len & cmd,
				so that we're sure to have the space.

				The user should first call CheckIfAllowed() to insure that
				this command is allowed in a macro.

RETURN VALUE:	TRUE if successful
				FALSE if:
				This command is not allowed in a macro
				Cannot XramMalloc sufficient storage
				Will exceed allocated root memory

END DESCRIPTION **********************************************************/
nodebug
BOOL AddCommandToList(COMMAND *pCmd)
{
	BOOL		ok;
	char		*pNext;	// next storage addr in macro being built
	int			myMacroId, hisMacroId, ilen;
	MACRO_LIST	*pMacroList;
	ADDR20		new,	// storage for the new block
				p,		// pointer to the next block
				q;		// saved pointer (pointer to the current block)

	if (!CheckIfAllowed(pCmd))		// just to make sure
		return (FALSE);
/*-------------------------------**
** Process the END_MACRO command **
**-------------------------------*/
	if (pCmd->cmd == END_MACRO)
		{
// allocate the storage
		pNext = (char *) pMacro + macroSize;
		*pNext++ = 2;				// this command has only 2 bytes
		*pNext = END_MACRO;
		macroSize += 2;

		new = XramMalloc ((ULONG)macroSize);
		ok = (new != FNULL);

		if (!ok)
			return (FALSE);		// Cannot XramMalloc sufficient storage
	// the chain is in the order of macroId
		p = fpMacroList;		// pointer to the 1st block
		q = FNULL;				// init pointer
		myMacroId = (int)pCmd->fxn + ((int)pCmd->seq << 8);
	// look for the spot for this new block
		if (p)
			{
			hisMacroId = xgetint (p + MACRO_ID);
			while ((hisMacroId < myMacroId) && (p != FNULL))
				{
				q = p;						// save pointer to the current block
				p = xgetlong (p + FP_FWD);	// point to the next block
				hisMacroId = xgetint (p + MACRO_ID);
				}
			}
	// we found the spot
		if (q == FNULL)			// at the head of the chain
			fpMacroList = new;
		else 					// at the middle (or end) of the chain
			xputlong ((q + FP_FWD), new);
								// link to next block may be NULL
		pMacroList = (MACRO_LIST *)pMacro;
		pMacroList->fpFwd = p;
		pMacroList->fpMyaddr = new;
	// copy new macro list to XRAM and free the one we're building
		root2xmem (/*pSrc=*/(void *)pMacro, /*fpDst=*/new, macroSize);
		//free (pMacro);
		buildingMacro = FALSE;
		}
/*---------------------------**
** Process other commands	 **
**---------------------------*/
	else
		{
		ilen = pCmd->len;
	// save 2 bytes for the END_MACRO command
		if ((ilen + 2) > (MAX_MACRO - macroSize))	// = is ok
			return (FALSE);

		memcpy (/*pDst=*/(void *)((char *) pMacro + macroSize),
				/*pSrc=*/(void *)pCmd, ilen);
		macroSize += ilen;
		}
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
DelMacroList

SYNTAX:
	BOOL DelMacroList (
		int	macroId);		// Macro identifier

DESCRIPTION:
	Delete Macro List.

	Finds the referenced macro in the macro chain and readjusts
	forward link of its neighbor.  Frees the memory
	allocated to the MACRO_LIST structure.

RETURN VALUE:
	TRUE if successful.
	FALSE if failed to find the macroId.

END DESCRIPTION **********************************************************/
nodebug
BOOL DelMacroList(int myMacroId)
{
	BOOL		found;
	int			hisMacroId;
	ADDR20		p,		// pointer to the next block
				r,		// pointer to the block after that one
				q;		// saved pointer (pointer to the current block)

	if (fpMacroList == FNULL)
		return (FALSE);	// nothing at the list

	found = FALSE;
// the chain is in the order of macroId
	q = FNULL;					// init pointer
	p = fpMacroList;			// pointer to the 1st block
	r = xgetlong (p + FP_FWD);	// ptr to the 2nd block
	hisMacroId = xgetint (p + MACRO_ID);
// look for the spot for this block
	while ((hisMacroId < myMacroId) && (p != FNULL))
		{
		q = p;						// save pointer to the current block
		p = r;						// point to the next block
		r = xgetlong (p + FP_FWD);	// ptr to the block after that
		hisMacroId = xgetint (p + MACRO_ID);
		}
// we found the spot (maybe)
	found = (hisMacroId == myMacroId);	// could also be '>'
	if (found)
		{		// p is deleted
		if (q == FNULL)			// at the head of the chain
			fpMacroList = r;
		else 					// at the middle (or end) of the chain
			xputlong ((q + FP_FWD), r);
								// link to next block may be NULL
		XramFree (p);			// free memory allocated to p
		}
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
FindMacroList

SYNTAX:			BOOL	FindMacroList (
					int			macroId,		// the macro identifier
				// the following structure is filled in if the macro is found
					MACRO_LIST	*pMacroList);	// address of structure in root RAM
												// NULL if we just want to find macro

DESCRIPTION:	Find a macro in the Macro list.

RETURN VALUE:	TRUE if the macro is found

END DESCRIPTION **********************************************************/
nodebug
BOOL FindMacroList(int macroId, MACRO_LIST *pMacroList)
{
	BOOL		found;
	int			lmacroId;
	ADDR20		fpSearch;

	found = FALSE;
	fpSearch = fpMacroList;	// point to start of list
	while (fpSearch)
		{
		lmacroId = xgetint (fpSearch + MACRO_ID);
		if (lmacroId == macroId)
			{
			found = TRUE;
			break;
			}
		if (lmacroId > macroId)
			break;			// they're arranged numerically

		fpSearch = xgetlong(fpSearch + FP_FWD);
		}

	if (found)
		{
		if (pMacroList)	// copy data to user's buffer if valid ptr
			xmem2root (/*fpSrc=*/fpSearch, /*pDst=*/(void *)pMacroList,
						(UINT)sizeof(MACRO_LIST));
		}

	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
StartPlayingMacro

SYNTAX:			BOOL StartPlayingMacro (
					int		macroId,	// the macro identifier
					int		xx,
					int 	yy);		// offset to be used for all macro commands

DESCRIPTION:	Start playing a macro.  This can be executed under the following
				circumstances:
					1. A DRAW_MACRO or SHIFT_DRAW_MACRO is received from the link.
					   This can only occur if we're not 'playingMacro' (else it
					   would be illegal (the caller must STOP_MACRO_LOOP first).
					2. A DRAW_MACRO is received from a button or cell push.
					   The caller must stop any executing macros by setting
					   'playingMacro' FALSE before calling this procedure.
					3. A DRAW_MACRO or SHIFT_DRAW_MACRO is encountered in an
					   executing macro block.  The caller must adjust the
					   command offset to point past the command before calling
					   this procedure.

RETURN VALUE:	TRUE if successful
				FALSE if:
				cannot find macro

END DESCRIPTION **********************************************************/
nodebug
BOOL StartPlayingMacro(int macroId, int xx, int yy)
{
	ADDR20		fpNewMacro;
	MACRO_LIST	macroList;

	if (!FindMacroList(macroId, &macroList))
		return (FALSE);		// cannot find macro

// the address of the new macro is in macroList.fpMyaddr
// and if the old (current) macro exists, its address is in fpPlayMacro
	fpNewMacro = macroList.fpMyaddr;
// if this command is executed while we're playing a macro
// then the command offset is taken care of by the caller
	if (playingMacro)
		{
	// save the current offsets in the old block
		xputint ((fpPlayMacro + MACRO_XX), macroX);
		xputint ((fpPlayMacro + MACRO_YY), macroY);
	// save the return address in the new block
		xputlong ((fpNewMacro + MACRO_RETAD), fpPlayMacro);
		}
// Else we init the return address
	else
		{
		xputlong ((fpNewMacro + MACRO_RETAD), FNULL);
		}
	xputint ((fpNewMacro + MACRO_OFFSET),
			(sizeof(MACRO_LIST) - sizeof(COMMAND)));
	macroX = xx;
	macroY = yy;
	fpPlayMacro = fpNewMacro;
	playingMacro = TRUE;
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
StopPlayingMacro

SYNTAX:			void StopPlayingMacro (void);

DESCRIPTION:	Stop playing the current macro.  Usually called when the
				END_MACRO command is encountered.

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void StopPlayingMacro(void)
{
	ADDR20		fpOldMacro;

	fpOldMacro = xgetlong (fpPlayMacro + MACRO_RETAD);
	if (fpOldMacro)
	{
		fpPlayMacro = fpOldMacro;
		macroX = xgetint (fpPlayMacro + MACRO_XX);
		macroY = xgetint (fpPlayMacro + MACRO_YY);
	}
	else
	{
		playingMacro = FALSE;
		macroX = 0;
		macroY = 0;
	}
}

/* START FUNCTION DESCRIPTION ********************************************
PlayNextMacroStep

SYNTAX:				void PlayNextMacroStep (void);

DESCRIPTION:		Play the next step in the current macro

					Make sure that the que is not full, and
					playingMacro is TRUE before calling this.

END DESCRIPTION **********************************************************/
nodebug
void PlayNextMacroStep(void)
{
	int			llen, offset, macroId;
	int			xx, yy, *pInt;
	COMMAND		*pCmd;
	ADDR20		fpMacroStep;
	union CMD_DATA	cmdData;	// COMMAND cmdStruc;	BYTE data[255];

// copy the next command from the macro to cmdData
	offset = xgetint (fpPlayMacro + MACRO_OFFSET);
	fpMacroStep = fpPlayMacro + (ADDR20)offset;
// len is the 1st byte since the items in a macro list are commands
	llen = (int)xgetchar (fpMacroStep);
	xmem2root (/*src=*/fpMacroStep, /*dst=*/(void *)&cmdData, llen);
// update the offset
	xputint ((fpPlayMacro + MACRO_OFFSET), (offset + llen));
// execute the macro step
	pCmd = (COMMAND *)&cmdData;
	pInt = (int *)&pCmd->data[0];
	switch (pCmd->cmd)
		{
/*--------------------------------------------------------**
** The following commands require an unsolicited response **
** We assume it's channel 0, but how can we tell?		  **
**--------------------------------------------------------*/
		case SEND_STATUS:
		case SEND_LAST_PUSH:
		case SEND_STRING:
		case SEND_LONG_INT:
		case SEND_FLOAT:
		case SEND_CHAR:
		case SEND_TOD:
			Decode (pCmd, NULL);
			SendReply (pChan0, (BYTE *)&cmdData);
			break;

/*------------------------------------------------**
** The following commands are handled by Decode() **
**------------------------------------------------*/
		case DISABLE_CELLS:
		case ENABLE_CELLS:
		case DIS_ENA_BUTTON:
		case SET_FONT:
		case SET_CURSOR_MODE:
		case SET_CURSOR:
		case NULL_LOOP:
		case SET_CELL_ACTIVE:
		case STOP_MACRO_LOOP:
		case SET_TOD:
		case LOOP_MACRO:
		case LINK_CELL_TO_MACRO:
		case LINK_BUTTON_TO_MACRO:
			Decode (pCmd, NULL);
			break;

/*-----------------------------------------**
** The following commands are handled here **
**-----------------------------------------*/
		case END_MACRO:
		 	StopPlayingMacro();
		 	break;

		case DRAW_MACRO:
			macroId = (int)pCmd->fxn + ((int)pCmd->seq << 8);
			StartPlayingMacro (macroId, /*xx=*/0, /*yy=*/0);
			break;

		case SHIFT_DRAW_MACRO:
			macroId = (int)pCmd->fxn + ((int)pCmd->seq << 8);
			xx = *pInt++;
			yy = *pInt++;
			StartPlayingMacro (macroId, xx, yy);
			break;
/*--------------------------------**
** Commands processed by PlayTask **
**--------------------------------*/
		case BLANK_REGION:
		case INVERT_REGION:
		case STORE_REGION:
		case RESTORE_REGION:
		case CLEAR_STRING_BUFF:
		case CLEAR_SCREEN:
		case SET_BRUSH_TYPE:
		case PIXEL:
		case LINE:
		case CIRCLE:
		case RECTANGLE:
		case POLYGON:
		case PUT_BIT_MAP:
		case PUT_TEXT:
		case SET_TEXT_DIR:
		case BACK_LIGHT:
		case SET_CONTRAST:
		case BEEP:
		case DISPLAY_BUTTON:
		case DISPLAY_BUTTON_Q:
		case REMOVE_BUTTON:
		case DELAY_PLAY:
		case PLAY_KEYBOARD_MACRO:
		case SET_STRING:
		case SET_LONG_INTEGER:
		case SET_FLOAT:
		case SET_CHAR:
		case BIT_MAP:
		case SCROLL_REGION:
			PutPlayQue ((COMMAND *)&cmdData.cmdStruc);
			break;
		}
}

/*M******************************************************************
**
** SOURCE FILE:		RS232TASK.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					RS-232 communications
**
** FUNCTION LIST:	InitChan0
**						Initialize Channel 0 (RS-232 channel)
**					SendReply
**						Send reply to master
**					Rs232Task
**						Handle RS232 Communications
**
** CREATION DATE: 	06/18/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
#memmap xmem
/*** BeginHeader Rs232Task, InitChan0, SendReply */
void Rs232Task (void);
BOOL InitChan0 (void);
void SendReply(struct _Channel *pChan, BYTE *pPacket);
/*** endHeader */

BYTE	readBuff0[BUFFSIZE], writeBuff0[BUFFSIZE];

/* START FUNCTION DESCRIPTION ********************************************
InitChan0

SYNTAX:			BOOL InitChan0 (void);

DESCRIPTION:	Perform complete initialization of channel 0
				Actually channel 1 if PK2600 (don't get confused)

RETURN VALUE:	TRUE if initialization successful
				FALSE if channel not available

END DESCRIPTION **********************************************************/
nodebug
BOOL InitChan0(void)
{
	BOOL	ok;

#ifdef	PK2600
	pChan0 = aascOpen(
				/*Type=*/		DEV_Z1,
				/*CTS/RTS=*/	0,
				/*Param=*/		ASCI_PARAM_8N1	// 8 data bits, 1 stop, no parity
								| (BAUDMULT * ASCI_PARAM_1200),
				/*brqfnc()=*/	NULL);			// use standard ISR (_z0Int)
#else
	pChan0 = aascOpen(
				/*Type=*/		DEV_Z0,
				/*CTS/RTS=*/	0,
				/*Param=*/		ASCI_PARAM_8N1	// 8 data bits, 1 stop, no parity
								| (BAUDMULT * ASCI_PARAM_1200),
				/*brqfnc()=*/	NULL);			// use standard ISR (_z0Int)
#endif
	ok = (pChan0 != NULL);
	if (ok)
		{
		aascSetReadBuf (pChan0, readBuff0, BUFFSIZE);
		aascSetWriteBuf (pChan0, writeBuff0, BUFFSIZE);
		aascTxSwitch(pChan0, 1);
		aascRxSwitch(pChan0, 1);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
SendReply

SYNTAX:			void	SendReply(
					struct _Channel	*pChan,		// pointer to the channel
					BYTE			*pPacket);	// pointer to the complete packet

DESCRIPTION:
	Send a reply to the master.  The packet is complete, except for the CRC.

RETURN VALUE:
	None

END DESCRIPTION **********************************************************/
nodebug
void SendReply(struct _Channel *pChan, BYTE *pPacket)
{
	int			crc, len;

	pPacket[ADDR] = 0;		// reply to the master
	len = (int)pPacket[LEN];
    crc = getcrc (pPacket, len, 0);
    pPacket[len] = (crc >> 8) & 0xff;     // Tail in crc hi
    pPacket[len + 1] = crc & 0xff;        // Tail in crc lo
	aascWriteBlk (pChan, (void *)pPacket, (len + 2), /*flags=*/0);
}

/* START FUNCTION DESCRIPTION ********************************************
Rs232Task

SYNTAX:			void	Rs232Task(void);

DESCRIPTION:
	This is a costatement task to handle RS232 communications

RETURN VALUE:
	None

END DESCRIPTION **********************************************************/
nodebug
void Rs232Task(void)
{
	BOOL			ok, deltaLen;
	BYTE			ch, error;
	BYTE			nChars, len, cmd;

	int				crc;
	static	BYTE	*pCmd0;		// pointer to command buffer 0
	static	int		state;

	segchain _GLOBAL_INIT { state = 0; }

	costate
	{
	nChars = aascReadChar (pChan0, &ch);
	if (nChars)
	switch (state)
		{
/*------------------------**
** state 0 = look for SOH **
**------------------------*/
		case 0:
			if (ch == SOH)
				{
				pCmd0 = packet0;	// init command pointer
				*pCmd0++ = SOH;		// store the SOH in the buffer
				state++;
				}
			break;
/*--------------------------**
** state 1 = get the length **
**--------------------------*/
		case 1:
			len = ch;
			if (len > 253)
				len = 253;			// in case of xmission error
			*pCmd0++ = ch;			// store the length in the buffer
			state++;
			break;
/*----------------------------------------------------------**
** state 2 = get the rest of the packet (including the CRC) **
**----------------------------------------------------------*/
		case 2:
			*pCmd0++ = ch;			// store the rest of the msg
			if (--len == 0)
				{
/*-------------------------**
** check the CRC 		   **
** decode msg if CRC is ok **
**-------------------------*/
				error = 0;
				ok = TRUE;
				len = packet0[LEN];		// the header is not included in len
										// so the count of bytes excludes the crc itself
				
				if (len < DATA0)
					{
					error = 2;			// Record too short
					ok = FALSE;
					}
				if (ok)
					{
					crc = getcrc (packet0, len, 0);
					ok = ((((crc >> 8) & 0xff) == packet0[len])
					&& ((crc & 0xff) == packet0[len + 1]));
					if (!ok)
						error = 1;				// CRC error
					}
				if (ok)
					{
				// clear the screen if 1st time
					if (first)
						{
						first = FALSE;
						glBlankScreen();
						}
				// Reject command if we're playing macro
				// unless command is STOP_MACRO_LOOP
					cmd = packet0[CMD];
					if (playingMacro
					&& (cmd != STOP_MACRO_LOOP))
						error = 14;
				// Decode may change len (deltaLen will be set)
					deltaLen = FALSE;
					if (!error)
						error = Decode ((COMMAND *)&packet0[LEN], &deltaLen);
					if (!deltaLen)
						packet0[LEN] = 5;		// ADDR, LEN, CMD, FXN, SEQ
					ok = (error == 0);
					}
				if (ok)
					{
					packet0[FXN] = ACK;
					packet0[SEQ] = lastStatus;
					lastStatus = 0;
					// if there is any other data, it was set up by Decode()
					}
				else 	// not ok
					{
					packet0[LEN] = 6;		// ADDR, LEN, CMD, FXN, SEQ, data[0]
					packet0[FXN] = NAK;
					packet0[SEQ] = ERR_OCCURRED;	// error occurred since last msg
					packet0[DATA0] = error;
					}
				SendReply (pChan0, packet0);
				state = 0;
				}
			break;
		}	// end of 'switch (state)
	}
}

/*M******************************************************************
**
** SOURCE FILE:		OP71UTIL.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					Utilities
**
**					This entire module is located in xmem
**
** FUNCTION LIST:	min
**						Return the smallest of two ints
**					InitPlayQue
**						Initialize the display que
**					PutPlayQue
**						Put a command into the display que
**					GetPlayQue
**						Get a command from the display que
**					CheckPlayQue
**						Check if que is empty or full
**					XStrlen
**						Determine length of a string in xmem
**					MyFtoa
**						My own version of ftoa()
**					Srand
**						Seed the random-number generator
**					Rand
**						Get a pseudo-random number
**					AddBitmapList
**						Add a BITMAP_LIST structure to the bitmap list.
**					DelBitmapList
**						Delete a BITMAP_LIST structure from the bitmap list.
**					FindBitmapList
**						Find a BITMAP_LIST structure in the bitmap list.
**					PlayBitmap
**						Find and display a BITMAP_LIST structure
**					AddRegionList
**						Add a REGION_LIST structure to the region list.
**					DelRegionList
**						Delete a REGION_LIST structure from the region list.
**					FindRegionList
**						Find a REGION_LIST structure in the region list.
**					BlankRegion
**						Fill a region with all 0's or all 1's
**					InvertRegion
**						Invert a region
**					PlayString
**						Display an ASCIIZ string
**					CenterXString
**						Center a string in a rectangular area
**					AddButtonList
**						Add a BUTTON_LIST structure to the button list.
**					DelButtonList
**						Delete a BUTTON_LIST structure from the button list.
**					FindButtonList
**						Find a BUTTON_LIST structure in the button list.
**					PlayButton
**						Find and display (or remove) a BUTTON_LIST structure
**					EnaButton
**						Enable or disable a button
**					AbsToRel
**						Convert absolute cell coordinates to relative cell coords
**					DrawOvalFrame
**						Draw an oval button frame
**					DrawRectFrame
**						Draw an rectangular button frame
**					DeleteBitmap
**						Delete the bitmap from the bitmap list, and make the
**						flash block available.
**					InitLoadBitmap
**						Initialize the loading of a bitmap
**					ConueLoadBitmap
**						Continue the loading of a bitmap
**					DeleteFont
**						Delete the font from the font list, and make the
**						flash block available.
**					InitLoadFont
**						Initialize the loading of a font
**					ConueLoadFont
**						Continue the loading of a font
**					PlayGreeting
**						Displays the greeting
**					AutoBaud
**						Automatically determine Baud Rate
**
** CREATION DATE: 	05/14/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/

#memmap xmem
/*** BeginHeader min, PlayGreeting */
int	 min (int int1, int int2);
void PlayGreeting (void);
/*** endHeader */
/*** BeginHeader InitPlayQue, PutPlayQue */
void InitPlayQue(void);
BOOL PutPlayQue (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader GetPlayQue */
BOOL GetPlayQue (COMMAND *pCmd);
/*** endHeader */
/*** BeginHeader CheckPlayQue */
BOOL CheckPlayQue (int which);
/*** endHeader */
/*** BeginHeader XStrlen, MyFtoa */
int	 XStrlen(ADDR20 fpStr);
char *MyFtoa (float fvalue, char *pBuff);
/*** endHeader */
/*** BeginHeader Srand, Rand */
void Srand (UINT seed);
int	 Rand (void);
/*** endHeader */
/*** BeginHeader Xlate */
int	 Xlate (int object, int *pTable);
/*** endHeader */
/*** BeginHeader AddBitmapList, DelBitmapList, FindBitmapList, PlayBitmap */
BOOL AddBitmapList (COMMAND *pCmd, ADDR20 fpBitmap);
BOOL DelBitmapList (int bitmapId);
BOOL FindBitmapList (int bitmapId, BITMAP_LIST *pBitmapList);
BOOL PlayBitmap (int bitmapId, int xx, int yy);
/*** endHeader */
/*** BeginHeader PlayString, CenterXString */
void PlayString(int xx0, int yy0, XYBOUNDS *xyBounds, char *pChar);
void CenterXString (int px, int py, XYBOUNDS *xyBounds, ADDR20 fpChar);
/*** endHeader */
/*** BeginHeader AddButtonList, DelButtonList, FindButtonList,
 PlayButton, EnaButton */
BOOL AddButtonList (COMMAND *pCmd);
BOOL DelButtonList (int buttonId);
BOOL FindButtonList (int buttonId, BUTTON_LIST *pButtonList);
BOOL PlayButton (int buttonId, int fxn);
BOOL EnaButton (int buttonId, int fxn);
/*** endHeader */
/*** BeginHeader AbsToRel */
int	 AbsToRel (BYTE absCoord, BOOL x);
/*** endHeader */
/*** BeginHeader DrawOvalFrame, DrawRectFrame */
void DrawOvalFrame (int x, int y, int w, int h);
void DrawRectFrame (int x, int y, int w, int h);
/*** endHeader */
/*** BeginHeader DeleteBitmap, InitLoadBitmap, ConueLoadBitmap */
BOOL DeleteBitmap (int bitmapId);
BOOL InitLoadBitmap (int bitmapId, int dx, int dy);
BOOL ConueLoadBitmap (int bitmapId, int len, BYTE *pByte);
/*** endHeader */
/*** BeginHeader DeleteFont, InitLoadFont, ConueLoadFont */
BOOL DeleteFont (int font);
BOOL InitLoadFont (int font, BYTE *pByte);
BOOL ConueLoadFont (int font, int len, BYTE *pByte);
/*** endHeader */
/*** BeginHeader AddRegionList,	DelRegionList, FindRegionList,
	BlankRegion, InvertRegion */
BOOL AddRegionList (COMMAND *pCmd);
BOOL DelRegionList (int myRegionId, int xOvr, int yOvr);
BOOL FindRegionList (int regionId, REGION_LIST *pRegionList);
BOOL BlankRegion (COMMAND *pCmd);
BOOL InvertRegion (COMMAND *pCmd);
/*** endHeader */

/* Local variables */
int	playQueInix,	// input index into the que
		playQueOutix,	// output index from the que
		playQueUsed;	// number of slots used
ADDR20	playQue[PLAY_QUE_SIZE];
long	lholdRand;		// holds the random number
ULONG	xxSize;			// size of flash block left to write
ADDR20	xxfpAddr;		// current address of flash block
ADDR20	xxfpAddr0;		// original address of flash block

/* START FUNCTION DESCRIPTION ********************************************
min

SYNTAX:			int	min (
					int	int1, int int2);

DESCRIPTION:	Return the smallest of two ints

END DESCRIPTION **********************************************************/
nodebug
int min(int int1, int int2)
{
	if (int1 <= int2)
		return (int1);
	/* else */
		return (int2);
}


/* START FUNCTION DESCRIPTION ********************************************
InitPlayQue

SYNTAX: void InitPlayQue(void);

DESCRIPTION: Initialize the display que

END DESCRIPTION **********************************************************/
nodebug
void InitPlayQue(void)
{
	playQueInix = 0;
	playQueOutix = 0;
	playQueUsed = 0;
	lholdRand = 1;
}

/* START FUNCTION DESCRIPTION ********************************************
PutPlayQue

SYNTAX:			BOOL	PutPlayQue (
					COMMAND	*pCmd);		// Pointer to command
DESCRIPTION:
				The caller constructs the command in local root RAM,
				and calls PutPlayQue with a (near) pointer to that command.
				PutPlayQue allocates an area for the command in XRAM,
				copies the command to XRAM, and stores a (far) pointer
				to the area in the playQue.

				CAUTION: the 'len' member is used to allocate space.  Make
				sure it's initialized prior to calling PutPlayQue.

RETURN VALUE:	TRUE if successful
				FALSE if que full (call CheckPlayQue() to eliminate this)
				or XramMalloc fails.

END DESCRIPTION **********************************************************/
nodebug
BOOL PutPlayQue(COMMAND *pCmd)
{
	BOOL	ok;
	ADDR20	fpCmd;

	segchain _OP7100GE_INIT { InitPlayQue(); }

	ok = playQueUsed < PLAY_QUE_SIZE;
	if (ok)
		{
		fpCmd = XramMalloc ((ULONG)pCmd->len);
		if (fpCmd)
			{
		// continue if allocation successful
			root2xmem (/*pSrc=*/(void *)pCmd, /*fpDst=*/fpCmd,
						(UINT)pCmd->len);	// copy to XRAM
			playQue[playQueInix] = fpCmd;	// store command in que
			playQueUsed++;					// one more item in the que
		// postincrement the input index
			if (++playQueInix == PLAY_QUE_SIZE)
				playQueInix = 0;
			}
		else
			ok = FALSE;
		}

	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
GetPlayQue

SYNTAX:			BOOL	GetPlayQue (
					COMMAND *pCmd);		// the command will be copied here

DESCRIPTION:
				GetPlayQue is called with a (near) pointer to local root RAM.
				GetPlayQue retrieves the (far) pointer from the playQue,
				copies the command from XRAM to the caller's storage,
				and XramFree's the area occupied by the command.

RETURN VALUE:	TRUE if an item was in the que.
				FALSE if que is empty

END DESCRIPTION **********************************************************/
nodebug
BOOL GetPlayQue(COMMAND *pCmd)
{
	BOOL	ok;
	BYTE	len;
	ADDR20	fpCmd;

	ok = FALSE;		// assume que is empty
	if (playQueUsed)	// if there are commands in the que
		{
		ok = TRUE;
		fpCmd = playQue[playQueOutix];
		len = xgetchar (fpCmd);		// get the length from XMEM
		xmem2root (/*fpSrc=*/fpCmd, /*pDst=*/(void *)pCmd,
					(UINT)len);		// copy command from XMEM to user's buffer
		XramFree (fpCmd);			// free XMEM storage
		playQueUsed--;
	// postincrement the output index
		if (++playQueOutix == PLAY_QUE_SIZE)
			playQueOutix = 0;
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
CheckPlayQue

SYNTAX:			BOOL CheckPlayQue (
					int which);		// 0 = check if que is empty
									// 1 = check if que is full

DESCRIPTION:	Check if que is empty or full

RETURN VALUE:	TRUE if requested state is TRUE
				FALSE if it's not

END DESCRIPTION **********************************************************/
nodebug
BOOL CheckPlayQue(int which)
{
	BOOL	ok;

	if (which)
		{		// check if que is full
		ok = (playQueUsed == PLAY_QUE_SIZE);
		}
	else
		{		// check if que is empty
		ok = (playQueUsed == 0);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
XStrlen

SYNTAX:		int	 XStrlen(
				ADDR20 fpStr);	// 20-bit address of ASCIIZ string in xmem

DESCRIPTION:
			Determine length of a string in xmem

RETURN VALUE:
			Number of chars in string, excluding the terminating NUL

END DESCRIPTION **********************************************************/
nodebug
int XStrlen(ADDR20 fpStr)
{
	char	ch;
	int		len;

	len = 0;
	FOREVER
		{
		ch = xgetchar (fpStr++);
		if (!ch)
			break;

		len++;
		}
	return (len);
}

/* START FUNCTION DESCRIPTION ********************************************
MyFtoa

SYNTAX:		char	*MyFtoa (
				float	fvalue,		// the value to be converted
				char	*pBuff);	// pointer to storage buffer

CAUTION:
			This is not debuggged!
DESCRIPTION:
			My own version of ftoa() converts a floating-pt number to
			a properly-formatted ASCII representation thereof.  The number
			itself will take up 12 spaces at most, plus 1 for the DP (if
			any), plus the terminating NUL for a max total of 14 spaces.

RETURN VALUE:
			Pointer to the trminating NUL.

END DESCRIPTION **********************************************************/
nodebug
char *MyFtoa(float fvalue, char *pBuff)
{
	char	ch;
	int		m, n, t, ix, jx;

	m = ftoa (fvalue, &pBuff[1]);
	t = strlen (&pBuff[1]);	// total number of chars
	n = t + m;					// really t - m, but m is negative

	ix = 0;
	jx = 1;
	FOREVER
		{
		ch = pBuff[jx];
		pBuff[ix++] = ch;
		if (!ch)
			break;		// the NUL was transferred

		if (--n == 0)
			pBuff[ix++] = '.';		// insert the decimal point
		}
	return (&pBuff[ix]);
}

/* START FUNCTION DESCRIPTION ********************************************
Srand

SYNTAX:			void	Srand (
					UINT	seed);	// random-number generator seed

DESCRIPTION:	This seeds the random-number generator.  To reinitialize
				the generator, use 1 as the seed.  Any other value sets the
				generator to a random starting point.  The seed is inited
				to 1.

RETURN VALUE:	none

END DESCRIPTION **********************************************************/
nodebug
void Srand(UINT seed)
{
	lholdRand = (long) seed;
}

/* START FUNCTION DESCRIPTION ********************************************
Rand

SYNTAX:			int	Rand (void);

DESCRIPTION:	This function returns a pseudorandom int in the range of
				0 to 0x7FFF.  The Srand routine can be used to seed the
				generator before calling Rand().

RETURN VALUE:	The pseudorandom number

END DESCRIPTION **********************************************************/
nodebug
int Rand(void)
{
	int		result;

	lholdRand = lholdRand * 214013L + 2531011L;
	result = (int)((lholdRand >> 16) & 0x7fff);

	return (result);
}

/* START FUNCTION DESCRIPTION ********************************************
Xlate

SYNTAX:			int	Xlate (
					int		object,		// value to be translated
					int		pTable);	// pointer to a table in the form
											int	value, int translated value
											...
											NUL sentinel
DESCRIPTION:	Translate according to a table


RETURN VALUE:	Translated value
				0 if not in table

END DESCRIPTION **********************************************************/
nodebug
int Xlate(int object, int *pTable)
{
	int	result;

	result = NUL;
	while (*pTable)
		{
		if (*pTable++ == object)
			{
			result = *pTable;
			break;
			}
		else
			pTable++;
		}
	return (result);
}

/* START FUNCTION DESCRIPTION ********************************************
AddBitmapList

SYNTAX:
	BOOL AddBitmapList (
		COMMAND *pCmd, 		// pCmd is the pointer to a
							// load BIT_MAP command, FXN = 1.
		ADDR20 fpBitmap);	// Bitmap storage must have been allocated and
							// used prior to call.
DESCRIPTION:
	Allocates storage in XRAM for a BITMAP_LIST structure, and inserts
	into the chain in order of bitmapId.

RETURN VALUE:
	TRUE if successful.
	FALSE if:
		a. failed to allocate storage.
		b. dupe bitmapId (use FindBitmapList 1st to avoid this possibility)

END DESCRIPTION **********************************************************/
nodebug
BOOL AddBitmapList(COMMAND *pCmd, ADDR20 fpBitmap)
{
	BOOL		ok, found;
	int			myBitmapId, hisBitmapId, *pInt;
	ADDR20		new,	// storage for the new block
				p,		// pointer to the next block
				q;		// saved pointer (pointer to the current block)
	BITMAP_LIST bitmapList;

	myBitmapId = (int)pCmd->seq;
// look for dupes 1st
	ok = (!FindBitmapList(myBitmapId, NULL));
// allocate the storage
	if (ok)
		{
		new = XramMalloc ((ULONG)sizeof(BITMAP_LIST));
		ok = (new != FNULL);
		}
	if (!ok)
		return (FALSE);
// fill in the list structure
	pInt = (int *)&pCmd->data[0];
	bitmapList.bitmapId = myBitmapId;
	bitmapList.dx = *pInt++;
	bitmapList.dy = *pInt;
	bitmapList.fpBitmap = fpBitmap;
// the chain is in the order of bitmapId
	p = fpBitmapList;		// pointer to the 1st block
	q = FNULL;				// init pointer
// look for the spot for this new block
	if (p)
		{
		hisBitmapId = xgetint (p + BITMAP_ID);
		while ((hisBitmapId < myBitmapId) && (p != FNULL))
			{
			q = p;						// save pointer to the current block
			p = xgetlong (p + FP_FWD);	// point to the next block
			hisBitmapId = xgetint (p + BITMAP_ID);
			}
		}
// we found the spot
	if (q == FNULL)			// at the head of the chain
		fpBitmapList = new;
	else 					// at the middle (or end) of the chain
		xputlong ((q + FP_FWD), new);
							// link to next block may be NULL
	bitmapList.fpFwd = p;
// copy new bitmap list to XRAM
	root2xmem (/*pSrc=*/(void *)&bitmapList, /*fpDst=*/new,
					(UINT)sizeof(BITMAP_LIST));
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
DelBitmapList

SYNTAX:
	BOOL DelBitmapList (
		int	bitmapId);		// Bitmap identifier

DESCRIPTION:
	Finds the referenced bitmap in the bitmap chain and readjusts
	forward and reverse links of its neighbors.  Frees the memory
	allocated to the BITMAP_LIST structure.

RETURN VALUE:
	TRUE if successful.
	FALSE if failed to find the bitmapId.

END DESCRIPTION **********************************************************/
nodebug
BOOL DelBitmapList(int myBitmapId)
{
	BOOL		found;
	int			hisBitmapId;
	ADDR20		p,		// pointer to the next block
				r,		// pointer to the block after that one
				q;		// saved pointer (pointer to the current block)

	if (fpBitmapList == FNULL)
		return (FALSE);	// nothing at the list

	found = FALSE;
// the chain is in the order of bitmapId
	q = FNULL;					// init pointer
	p = fpBitmapList;			// pointer to the 1st block
	r = xgetlong (p + FP_FWD);	// ptr to the 2nd block
	hisBitmapId = xgetint (p + BITMAP_ID);
// look for the spot for this block
	while ((hisBitmapId < myBitmapId) && (p != FNULL))
		{
		q = p;						// save pointer to the current block
		p = r;						// point to the next block
		r = xgetlong (p + FP_FWD);	// ptr to the block after that
		hisBitmapId = xgetint (p + BITMAP_ID);
		}
// we found the spot (maybe)
	found = (hisBitmapId == myBitmapId);	// could also be '>'
	if (found)
		{		// p is deleted
		if (q == FNULL)			// at the head of the chain
			fpBitmapList = r;
		else 					// at the middle (or end) of the chain
			xputlong ((q + FP_FWD), r);
								// link to next block may be NULL
		XramFree (p);			// free memory allocated to p
		}
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
FindBitmapList

SYNTAX:
	BOOL FindBitmapList (
		int			bitmapId,		// Bitmap identifier
		BITMAP_LIST *pBitmapList);	// Bitmap List is copied here
									// NULL if don't wish to copy

DESCRIPTION:
	Finds the referenced bitmap in the bitmap chain, and copies from XRAM
	to caller's buffer if found (unless storage ptr is NULL).

RETURN VALUE:
	TRUE if found
	FALSE if not found.

END DESCRIPTION **********************************************************/
nodebug
BOOL FindBitmapList(int bitmapId, BITMAP_LIST *pBitmapList)
{
	BOOL		found;
	int			lbitmapId;
	ADDR20		fpSearch;

	found = FALSE;
	fpSearch = fpBitmapList;	// point to start of list
	while (fpSearch)
		{
		lbitmapId = xgetint (fpSearch + BITMAP_ID);
		if (lbitmapId == bitmapId)
			{
			found = TRUE;
			break;
			}
		if (lbitmapId > bitmapId)
			break;			// they're arranged numerically

		fpSearch = xgetlong(fpSearch + FP_FWD);
		}

	if (found)
		{
		if (pBitmapList)	// copy data to user's buffer if valid ptr
			xmem2root (/*fpSrc=*/fpSearch, /*pDst=*/(void *)pBitmapList,
						(UINT)sizeof(BITMAP_LIST));
		}

	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
PlayBitmap

SYNTAX:
	BOOL	PlayBitmap (
		int	bitmapId,		// Bitmap identifier
		int	xx, yy);		// Pixel coordinates of upper left-hand corner

DESCRIPTION:
	Finds the referenced bitmap in the bitmap chain,
	displays if found. The bitmap itself must reside in xmem.

RETURN VALUE:
	TRUE if bitmapId is found
	NULL if not found.

END DESCRIPTION **********************************************************/
nodebug
BOOL PlayBitmap(int bitmapId, int xx, int yy)
{
	BOOL		found;
	BITMAP_LIST	bitmapList;

	found = FindBitmapList (bitmapId, &bitmapList);
	if (found)
		{
		glXPutBitmap (xx, yy, bitmapList.dx, bitmapList.dy, bitmapList.fpBitmap);
		}
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
AddRegionList

SYNTAX:
	BOOL AddRegionList (
		COMMAND *pCmd);		// pCmd is the pointer to a
							// STORE_REGION command
DESCRIPTION:
	Allocates storage in XRAM for region data.  If successful,
	allocates storage in XRAM for a REGION_LIST structure, and inserts
	into the chain in order of regionId.  Saves the region data.

RETURN VALUE:
	TRUE if successful.
	FALSE if:
		a. failed to allocate storage.
		b. dupe regionId (use FindRegionList 1st to avoid this possibility)

END DESCRIPTION **********************************************************/
nodebug
BOOL AddRegionList(COMMAND *pCmd)
{
	BOOL		ok, found;
	int			myRegionId, hisRegionId, *pInt;
	int			x0, y0, x1, y1, dx, dy;
	ADDR20		new,	// storage for the new block
				p,		// pointer to the next block
				q;		// saved pointer (pointer to the current block)
	ADDR20		fpRegion;
	REGION_LIST regionList;

	myRegionId = (int)pCmd->seq;
	pInt = (int *)&pCmd->data[0];
	x0 = *pInt++;
	y0 = *pInt++;
	x1 = *pInt++;
	y1 = *pInt++;
	dx = x1 - x0;
	dy = y1 - y0;
	ok = ((dx > 0) && (dx <= HMAX)
		&& (dy > 0) && (dy <= VMAX));
// look for dupes 1st
	if (ok)
		ok = (!FindRegionList(myRegionId, NULL));
// allocate the storage for the region data
	if (ok)
		{
		fpRegion = XramMalloc ((ULONG)FONTOFFSET(dx, dy));
		ok = (fpRegion != FNULL);
		}
// save the contents of the region
	if (ok)
		{
		glXGetBitmap (x0, y0, dx, dy, fpRegion);
		}
// allocate the storage for the REGION_LIST structure
	if (ok)
		{
		new = XramMalloc ((ULONG)sizeof(REGION_LIST));
		ok = (new != FNULL);
		if (!ok)
			XramFree (fpRegion);
		}
	if (!ok)
		return (FALSE);
// fill in the list structure
	regionList.fpRegion = fpRegion;
	regionList.regionId = myRegionId;
	regionList.x0 = x0;
	regionList.y0 = y0;
	regionList.dx = dx;
	regionList.dy = dy;
// the chain is in the order of regionId
	p = fpRegionList;		// pointer to the 1st block
	q = FNULL;				// init pointer
// look for the spot for this new block
	if (p)
		{
		hisRegionId = xgetint (p + REGION_ID);
		while ((hisRegionId < myRegionId) && (p != FNULL))
			{
			q = p;						// save pointer to the current block
			p = xgetlong (p + FP_FWD);	// point to the next block
			hisRegionId = xgetint (p + REGION_ID);
			}
		}
// we found the spot
	if (q == FNULL)			// at the head of the chain
		fpRegionList = new;
	else 					// at the middle (or end) of the chain
		xputlong ((q + FP_FWD), new);
							// link to next block may be NULL
	regionList.fpFwd = p;
// copy new region list to XRAM
	root2xmem (/*pSrc=*/(void *)&regionList, /*fpDst=*/new,
					(UINT)sizeof(REGION_LIST));
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
DelRegionList

SYNTAX:
	BOOL DelRegionList (
		int	regionId,		// Region identifier
		int xOvr, yOvr);	// When restoring region data:
							// Use coordinates stored in REGION_LIST
							// if the override value is -1.
							// Else use override value.

DESCRIPTION:
	Finds the referenced region in the region chain and readjusts
	forward and reverse links of its neighbors.  Restores the region data
	and frees the allocated memory.  Frees the memory allocated to the
	REGION_LIST structure.

RETURN VALUE:
	TRUE if successful.
	FALSE if failed to find the regionId.

END DESCRIPTION **********************************************************/
nodebug
BOOL DelRegionList(int myRegionId, int xOvr, int yOvr)
{
	BOOL		found;
	int			hisRegionId, x0, y0, dx, dy;
	ADDR20		p,		// pointer to the next block
				r,		// pointer to the block after that one
				q;		// saved pointer (pointer to the current block)
	REGION_LIST regionList;
	ADDR20		fpRegion;

	if (fpRegionList == FNULL)
		return (FALSE);	// nothing at the list

	found = FALSE;
// the chain is in the order of regionId
	q = FNULL;					// init pointer
	p = fpRegionList;			// pointer to the 1st block
	r = xgetlong (p + FP_FWD);	// ptr to the 2nd block
	hisRegionId = xgetint (p + REGION_ID);
// look for the spot for this block
	while ((hisRegionId < myRegionId) && (p != FNULL))
		{
		q = p;						// save pointer to the current block
		p = r;						// point to the next block
		r = xgetlong (p + FP_FWD);	// ptr to the block after that
		hisRegionId = xgetint (p + REGION_ID);
		}
// we found the spot (maybe): p is a pointer to it
	found = (hisRegionId == myRegionId);	// could also be '>'
	if (found)
		{		// p is deleted
		if (q == FNULL)			// at the head of the chain
			fpRegionList = r;
		else 					// at the middle (or end) of the chain
			xputlong ((q + FP_FWD), r);
								// link to next block may be NULL

		xmem2root (/*fpSrc=*/p, /*pDst=*/(void *)&regionList,
					(UINT)sizeof(REGION_LIST));
		fpRegion = regionList.fpRegion;
		x0 = (xOvr == -1)	?	regionList.x0	: xOvr;
		y0 = (yOvr == -1)	?	regionList.y0	: yOvr;
		dx = regionList.dx;
		dy = regionList.dy;
		x0 = min (x0, (HMAX - dx));
		y0 = min (y0, (VMAX - dy));
		glXPutBitmap (x0, y0, dx, dy, fpRegion);
		XramFree (fpRegion);
		XramFree (p);			// free memory allocated to p
		}
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
FindRegionList

SYNTAX:
	BOOL FindRegionList (
		int			regionId,		// Region identifier
		REGION_LIST *pRegionList);	// Region List is copied here
									// NULL if don't wish to copy

DESCRIPTION:
	Finds the referenced region in the region chain, and copies from XRAM
	to caller's buffer if found (unless storage ptr is NULL).

RETURN VALUE:
	TRUE if found
	FALSE if not found.

END DESCRIPTION **********************************************************/
nodebug
BOOL FindRegionList(int regionId, REGION_LIST *pRegionList)
{
	BOOL		found;
	int			lregionId;
	ADDR20		fpSearch;

	found = FALSE;
	fpSearch = fpRegionList;	// point to start of list
	while (fpSearch)
		{
		lregionId = xgetint (fpSearch + REGION_ID);
		if (lregionId == regionId)
			{
			found = TRUE;
			break;
			}
		if (lregionId > regionId)
			break;			// they're arranged numerically

		fpSearch = xgetlong(fpSearch + FP_FWD);
		}

	if (found)
		{
		if (pRegionList)	// copy data to user's buffer if valid ptr
			xmem2root (/*fpSrc=*/fpSearch, /*pDst=*/(void *)pRegionList,
						(UINT)sizeof(REGION_LIST));
		}

	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
BlankRegion

SYNTAX:
	BOOL	BlankRegion (
		COMMAND *pCmd);		// Pointer to a BLANK_REGION command

DESCRIPTION:
	Fills the specified region with all 0's or all 1's

RETURN VALUE:
	TRUE if region boundaries are within limits of screen
	Else FALSE

END DESCRIPTION **********************************************************/
nodebug
BOOL BlankRegion(COMMAND *pCmd)
{
	BOOL	ok;
	int		x0, y0, x1, y1, dx, dy, *pInt;

	pInt = (int *)&pCmd->data[0];
	x0 = *pInt++;
	y0 = *pInt++;
	x1 = *pInt++;
	y1 = *pInt++;
	dx = x1 - x0;
	dy = y1 - y0;
	ok = ((dx > 0) && (dx <= HMAX)
		&& (dy > 0) && (dy <= VMAX));

	if (ok)
		{
		if (pCmd->fxn == 0)
// fill the area of the region with all 0's
			glXPutBitmap (x0, y0, dx, dy, allClear);
		else
// fill the area of the region with all 1's
			glXPutBitmap (x0, y0, dx, dy, allSet);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
InvertRegion

SYNTAX:
	BOOL	InvertRegion (
		COMMAND *pCmd);		// Pointer to a BLANK_REGION command

DESCRIPTION:
	Inverts the specified region

RETURN VALUE:
	TRUE if region boundaries are within limits of screen
	Else FALSE

END DESCRIPTION **********************************************************/
nodebug
BOOL InvertRegion(COMMAND *pCmd)
{
	BOOL	ok;
	int		x0, y0, x1, y1, dx, dy, *pInt;
	ADDR20	fpRegion;

	pInt = (int *)&pCmd->data[0];
	x0 = *pInt++;
	y0 = *pInt++;
	x1 = *pInt++;
	y1 = *pInt++;
	dx = x1 - x0;
	dy = y1 - y0;
	ok = ((dx > 0) && (dx <= HMAX)
		&& (dy > 0) && (dy <= VMAX));

	if (ok)
		{
		fpRegion = XramMalloc ((ULONG)FONTOFFSET(dx, dy));
		ok = (fpRegion != FNULL);
		}
// save the contents of the region
	if (ok)
		{
		glXGetBitmap (x0, y0, dx, dy, fpRegion);
// fill the area of the region with all 1's
		glBuffLock();
		glXPutBitmap (x0, y0, dx, dy, allSet);
// redraw the region with an XOR brush
		glSetBrushType (OP71XOR);
		glXPutBitmap (x0, y0, dx, dy, fpRegion);
		glBuffUnlock();
// restore the brush and free the memory for the region
		glSetBrushType (brushType);
		XramFree (fpRegion);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
PlayString

SYNTAX:
	void	PlayString (
				int		xx0,			// x left pixel coordinate
				int		yy0,			// y top pixel coordinate
				XYBOUNDS *xyBounds,	// do not exceed these dimensions
				char	*pChar);			// pointer to ASCIIZ string
											// must not include chars not in font

DESCRIPTION:	Displays the string starting at xx0, yy0.  Stops if
				screen dimensions exceeded.

GLOBALS & USE:	fontId identifies the current font
				textDir determines the direction of writing

RETURN VALUE:	none

END DESCRIPTION **********************************************************/
nodebug
void PlayString(int xx0, int yy0, XYBOUNDS *xyBounds, char *pChar)
{
	char ch, vch;
	int pixWidth, pixHeight;

	pixWidth = (int) fontInfo[fontId].pixWidth;
	pixHeight = (int) fontInfo[fontId].pixHeight;
	
	glBuffLock();
	do
	{
		ch = *pChar++;
		vch = (vkActive && ((vkFlags & 0x04) != 0)) ? '*' : ch;
		if(ch)
		{
	// ch is not the string terminator
			if((xx0 >= xyBounds->xMin) && ((xx0 + pixWidth) <= xyBounds->xMax) &&
			   (yy0 >= xyBounds->yMin) && ((yy0 + pixHeight) <= xyBounds->yMax))
			{
		// within bounds
				glPutFont(xx0, yy0, &fontInfo[fontId], (unsigned) vch);
			}
			switch(textDir)
			{
		// advance for the next time
				default:
				case 0:	xx0 += pixWidth;	break;
				case 1:	xx0 -= pixWidth;	break;
				case 2:	yy0 -= pixHeight;	break;
				case 3:	yy0 += pixHeight;	break;
			}
		}
	} while(ch);
	glBuffUnlock();
	cursorX = xx0;
	cursorY = yy0;
}

/* START FUNCTION DESCRIPTION ********************************************
CenterXString

SYNTAX:
	void	CenterXString (
				int		px,			// x left pixel coordinate
				int		py,			// y top pixel coordinate
				XYBOUNDS *xyBounds,	// do not exceed these dimensions
				ADDR20	fpChar);		// XRAM address of ASCIIZ string
											// must not include chars not in font

DESCRIPTION:	Displays the string centered in a rectangular area.
				Gives up if font is too large to display within area.
				Truncates string if area dimensions exceeded.

GLOBALS & USE:	fontId identifies the current font
				textDir determines the direction of writing

RETURN VALUE:	none

END DESCRIPTION **********************************************************/
nodebug
void CenterXString(int px, int py, XYBOUNDS *xyBounds, ADDR20 fpChar)
{
	auto char ch;
	auto int len, maxLen, pixWidth, pixHeight;
	auto int ph, pw;

	pixWidth = (int) fontInfo[fontId].pixWidth;
	pixHeight = (int) fontInfo[fontId].pixHeight;

	ph = xyBounds->yMax - xyBounds->yMin;
	pw = xyBounds->xMax - xyBounds->xMin;
	len = XStrlen(fpChar);
	if((textDir == 0) || (textDir == 1))
	{
// horizontal text
		maxLen = (xyBounds->xMax - xyBounds->xMin) / pixWidth;
	}
	else
	{
// vertical text
		maxLen = (xyBounds->yMax - xyBounds->yMin) / pixHeight;
	}
	if(len > maxLen)
	{
// truncate string if bounds exceeded
		len = maxLen;
	}
// Calculate starting point
	if((textDir == 0) || (textDir == 1))
	{
// horizontal text
		py = py + ((ph - pixHeight) / 2);
		px = px + ((pw - (len * pixWidth)) / 2);
		if(textDir == 1)
		{
	// right-to-left
			px += ((len - 1) * pixWidth);
		}
	}
	else
	{
// vertical text
		px = px + ((pw - pixWidth) / 2);
		py = py + ((ph - (len * pixHeight)) /2);
		if(textDir == 2)
		{
	// bottom-to-top
			py += ((len - 1) * pixHeight);
		}
	}
// Display the centered text
	glBuffLock();
	do
	{
		ch = xgetchar(fpChar++);
		if((ch != '\0') && len)
		{
	// ch is not the string terminator and length hasn't been exceeded
			if((px >= xyBounds->xMin) && ((px + pixWidth) <= xyBounds->xMax) &&
			   (py >= xyBounds->yMin) && ((py + pixHeight) <= xyBounds->yMax))
			{
		// within bounds
				glPutFont(px, py, &fontInfo[fontId], (unsigned) ch);
			}
			switch(textDir)
			{
		// advance for the next time
				default:
				case 0:	px += pixWidth;	break;
				case 1:	px -= pixWidth;	break;
				case 2:	py -= pixHeight;	break;
				case 3:	py += pixHeight;	break;
			}
		}
	} while((ch != '\0') && len--);
	glBuffUnlock();
}

/* START FUNCTION DESCRIPTION ********************************************
AddButtonList

SYNTAX:
	BOOL AddButtonList (
		COMMAND *pCmd);		// pCmd is the pointer to a DEFINE_BUTTON command

DESCRIPTION:
	Allocates storage in XRAM for a BUTTON_LIST structure, and inserts
	into the chain in order of buttonId.

RETURN VALUE:
	TRUE if successful.
	FALSE if:
		a. failed to allocate storage.
		b. cannot find bitmapId (use FindBitmapList 1st to avoid this possibility)
		c. dupe buttonId (use FindButtonList 1st to avoid this possibility)

END DESCRIPTION **********************************************************/
nodebug
BOOL AddButtonList(COMMAND *pCmd)
{
	BOOL		ok, found;
	ADDR20		fpText;
	BYTE		*pByte;
	int			myButtonId, hisButtonId, bitmapId, *pInt, len;
	ULONG		flags;
	ADDR20		new,	// storage for the new block
				p,		// pointer to the next block
				q;		// saved pointer (pointer to the current block)
	BUTTON_LIST buttonList;

	pInt = (int *)&pCmd->data[0];
	myButtonId = *pInt++;
// look for dupes 1st
	ok = (!FindButtonList (myButtonId, NULL));
// allocate the storage
	if (ok)
		{
		new = XramMalloc ((ULONG)sizeof (BUTTON_LIST));
		ok = (new != FNULL);
		}
	if (!ok)
		return (FALSE);
// fill in the list structure
	buttonList.buttonId = myButtonId;
	buttonList.macroId = 0;
	buttonList.flags = pCmd->fxn;
	buttonList.fpMyaddr = new;
	flags = (ULONG)pCmd->fxn;

	pByte = (BYTE *)pInt;
	buttonList.nwCell = *pByte++;
	buttonList.seCell = *pByte++;
	buttonList.pushCount = 0;

	bitmapId = 0;
	if (bit(&flags, 7))	// button bitmap index follows
		{
		bitmapId = (int)*pByte++;
		if (!FindBitmapList (bitmapId, NULL))
			{		// error if bitmap does not exist
			XramFree (new);
			return (FALSE);
			}
		}
	buttonList.bitmapId = bitmapId;

	fpText = FNULL;
	if (bit(&flags, 6))	// button text follows
		{				// pByte is pointing to the text
						// which is guaranteed to be ASCIIZ less than 255 bytes
		len = strlen(pByte) + 1;
		fpText = XramMalloc ((ULONG)len);
		if (!fpText)
			{		// error if cannot allocate storage
			XramFree (new);
			return (FALSE);
			}
		//else copy string to storage
		root2xmem (/*pSrc=*/(void *)pByte, /*dst=*/fpText,
					(UINT)(strlen(pByte) + 1));
		}
	buttonList.fpText = fpText;
	buttonList.fpSave = FNULL;	// no background saved yet
// the chain is in the order of buttonId
	p = fpButtonList;
	q = FNULL;				// init pointer
// look for the spot for this new block
	if (p)
		{
		hisButtonId = xgetint (p + BUTTON_ID);
		while ((hisButtonId < myButtonId) && (p != FNULL))
			{
			q = p;						// save pointer to the current block
			p = xgetlong (p + FP_FWD);	// point to the next block
			hisButtonId = xgetint (p + BUTTON_ID);
			}
		}
// we found the spot
	if (q == FNULL)			// at the head of the chain
		fpButtonList = new;
	else 					// at the middle (or end) of the chain
		xputlong ((q + FP_FWD), new);
							// link to next block may be NULL
	buttonList.fpFwd = p;
// copy new button list to XRAM
	root2xmem (/*pSrc=*/(void *)&buttonList, /*fpDst=*/new,
					(UINT)sizeof(BUTTON_LIST));
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
DelButtonList

SYNTAX:
	BOOL DelButtonList (
		int	buttonId);		// Button identifier

DESCRIPTION:
	Finds the referenced button in the button chain and readjusts
	forward and reverse links of its neighbors.  Frees the memory
	allocated to:
		1. the BUTTON_LIST structure
		2. background storage, if allocated
		3. button text, if allocated

RETURN VALUE:
	TRUE if successful.
	FALSE if failed to find the buttonId.

END DESCRIPTION **********************************************************/
nodebug
BOOL DelButtonList(int myButtonId)
{
	BOOL		found;
	int			hisButtonId;
	ADDR20		fpText;
	ADDR20		p,		// pointer to the next block
				r,		// pointer to the block after that one
				q;		// saved pointer (pointer to the current block)

	if (fpButtonList == FNULL)
		return (FALSE);	// nothing at the list

	found = FALSE;
// the chain is in the order of buttonId
	q = FNULL;					// init pointer
	p = fpButtonList;			// pointer to the 1st block
	r = xgetlong (p + FP_FWD);	// ptr to the 2nd block
	hisButtonId = xgetint (p + BUTTON_ID);
// look for the spot for this block
	while ((hisButtonId < myButtonId) && (p != FNULL))
		{
		q = p;						// save pointer to the current block
		p = r;						// point to the next block
		r = xgetlong (p + FP_FWD);	// ptr to the block after that
		hisButtonId = xgetint (p + BITMAP_ID);
		}
// we found the spot (maybe)
	found = (hisButtonId == myButtonId);	// could also be '>'
	if (found)
		{		// p is deleted
		if (q == FNULL)			// at the head of the chain
			fpButtonList = r;
		else 					// at the middle (or end) of the chain
			xputlong ((q + FP_FWD), r);
								// link to next block may be NULL

		PlayButton (myButtonId, /*fxn=*/0);	// remove the button
								// restore the background, and free background storage
		fpText = xgetlong (p + FP_TEXT);
		if (fpText)		// free button text memory
			XramFree (fpText);

		XramFree (p);			// free memory allocated to p
		}
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
FindButtonList

SYNTAX:
	BOOL	FindButtonList (
		int			buttonId,		// Button identifier
		BUTTON_LIST *pButtonList);	// Button List is copied here
									// NULL if don't wish to copy

DESCRIPTION:
	Finds the referenced button in the button chain, and copies from XRAM
	to caller's buffer if found (unless storage ptr is NULL).

RETURN VALUE:
	TRUE if found
	FALSE if not found.

END DESCRIPTION **********************************************************/
nodebug
BOOL FindButtonList(int buttonId, BUTTON_LIST *pButtonList)
{
	auto BOOL found;
	auto int lbuttonId;
	auto ADDR20 fpSearch;

	found = FALSE;
	fpSearch = fpButtonList;	// point to start of list
	while(fpSearch)
	{
		lbuttonId = xgetint(fpSearch + BUTTON_ID);
		if(lbuttonId == buttonId)
		{
			found = TRUE;
			break;
		}
		if(lbuttonId > buttonId)
		{
			break;			// they're numerically sorted
		}
		fpSearch = xgetlong(fpSearch + FP_FWD);
	}
	if (found)
	{
		if (pButtonList)	// copy data to user's buffer if valid ptr
			xmem2root(fpSearch, (void *) pButtonList, sizeof(BUTTON_LIST));
	}
	return(found);
}

/* START FUNCTION DESCRIPTION ********************************************
PlayButton

SYNTAX:
	BOOL	PlayButton (
		int	buttonId,	// Button identifier
		int	fxn);		// function can be:
						// 0 = remove button, restore background
						//	   and XramFree the xmem RAM
						// 1 = display button, bitmap, and text (in that order)
						// 2 = same a 1, but inverted

DESCRIPTION:
	Finds the referenced button in the button chain, displays if found.
	The button is automatically disabled (fxn = 0) or enabled (fxn != 0)
	after display. If there is button text, it is centered and subject
	to SET_TEXT_DIR.

RETURN VALUE:
	TRUE if buttonId is found
	FALSE if:
		a. buttonId not found
		b. cannot XramMalloc memory to store background

END DESCRIPTION **********************************************************/
nodebug
BOOL PlayButton(int buttonId, int fxn)
{
	int type, bitmapId,
	    cx, cy, cw, ch,		// cell coords
	    px, py, pw, ph;		// pixel coords
	ULONG flags;
	ADDR20 fpText;
	ADDR20 fpSave;
	ADDR20 fpMyaddr;
	BUTTON_LIST buttonList;
	auto int currentFontId, maxLen;
	auto XYBOUNDS xyBounds;

	if(!FindButtonList(buttonId, &buttonList))
	{
		return (FALSE);
	}
// continue if found
// compute rel cell coords
	cx = AbsToRel (buttonList.nwCell, TRUE);
	cy = AbsToRel (buttonList.nwCell, FALSE);
	cw = AbsToRel (buttonList.seCell, TRUE) - cx + 1;		// inclusive
	ch = AbsToRel (buttonList.seCell, FALSE) - cy + 1;	// inclusive
// compute pixel coords
	px = cx * BTN_HSPACE;
	py = cy * BTN_VSPACE;
	pw = (cw * BTN_HSPACE);
	ph = (ch * BTN_VSPACE);

	glSetBrushType (OP71BLACK);
	fpSave = buttonList.fpSave;
	fpMyaddr = buttonList.fpMyaddr;
	if (fxn == 0)
	{
/*------------------------------------------------**
** fxn = 0	remove button by restoring background **
**			disable the button					  **
**------------------------------------------------*/
		if (fpSave)
		{
	// restore background
			glXPutBitmap (px, py, pw, ph, fpSave);
			XramFree (fpSave);
			xputlong ((fpMyaddr + FP_SAVE), FNULL);	// fpSave = FNULL
		}
		EnaButton (buttonId, 0);
		return (TRUE);
	}
/*-----------------------**
** continue if fxn not 0 **
**-----------------------*/
	if (fpSave == FNULL)	// if bitmap not saved already
	{
	// allocate space for the bitmap
		fpSave = XramMalloc ((ULONG)FONTOFFSET(pw, ph));
		if (!fpSave)
		{
			return (FALSE);	// cannot allocate memory
		}
		xputlong ((fpMyaddr + FP_SAVE), fpSave);
	// save the area underneath the bitmap
		glXGetBitmap (px, py, pw, ph, fpSave);
	}
	flags = (ULONG)buttonList.flags;
// invert logic for a checkbox
	if (bit(&flags, 5))
	{
		fxn = 3 - fxn;	// 1 becomes 2, and 2 becomes 1
	}
	glBuffLock();
	if (fxn == 1)
	{
// display normal
// fill the area of the button with all 0's
		glXPutBitmap (px, py, pw, ph, allClear);
	}
	else
	{
// display inverted
// fill the area of the button with all 1's
		glXPutBitmap (px, py, pw, ph, allSet);
		glSetBrushType (OP71XOR);
	}
// test if button is to be framed
	if (bit(&flags, 2))
	{
		if (bit(&flags, 3))
		{
			// if rounded corners
			DrawOvalFrame (cx, cy, cw, ch);
		}
		else
		{
			// square corners
			DrawRectFrame (cx, cy, cw, ch);
		}
	}
// test if there is a bitmap to display
	if (bit(&flags, 7))
	{
		bitmapId = buttonList.bitmapId;
		PlayBitmap (bitmapId, px, py);	// doesn't display if not found
	}
// test if there is button text to display
	fpText = buttonList.fpText;
	if (fpText)
	{
		currentFontId = fontId;	// save current font ID
		fontId = 2;					// try medium default font first
		if((textDir == 0) || (textDir == 1))
		{
	// horizontal text
			maxLen = pw / fontInfo[fontId].pixWidth;
		}
		else
		{
	// vertical text
			maxLen = ph / fontInfo[fontId].pixHeight;
		}
		if(XStrlen(fpText) > maxLen)
		{
			fontId = 1;				// use small default font instead
		}
		xyBounds.xMax = (unsigned) (px + pw);
		xyBounds.xMin = (unsigned) px;
		xyBounds.yMax = (unsigned) (py + ph);
		xyBounds.yMin = (unsigned) py;
		CenterXString(px, py, &xyBounds, fpText);
		fontId = currentFontId;	// restore previous font ID
	}
	glBuffUnlock();
// enable the button
	EnaButton (buttonId, 1);
// restore brush type
	glSetBrushType (brushType);
	return (TRUE);
}

/* START FUNCTION DESCRIPTION ********************************************
EnaButton

SYNTAX:	BOOL EnaButton (
				int buttonId,	// button identifier
				int fxn);		// 1 = enable
								// 0 = disable
DESCRIPTION:
		Enables or disables a button by setting or clearing the appropriate
		entries in the cellToButton array.

GLOBALS & USE:	cellToButton[] contains buttonId if that cell is enabled
				and associated with a button.  Else it contains 0.

RETURN VALUE:	TRUE if successful
				FALSE if buttonId cannot be found

END DESCRIPTION **********************************************************/
nodebug
BOOL EnaButton(int buttonId, int fxn)
{
	auto int row, col;
	auto BOOL result;
	auto BYTE cx0, cy0, cx1, cy1;
	auto BUTTON_LIST buttonList;

	result = FALSE;	// default to button not found
	if(FindButtonList(buttonId, &buttonList))
	{
		result = TRUE;
		cx0 = AbsToRel(buttonList.nwCell, TRUE);
		cx1 = AbsToRel(buttonList.seCell, TRUE);
		cy0 = AbsToRel(buttonList.nwCell, FALSE);
		cy1 = AbsToRel(buttonList.seCell, FALSE);
		for (row = cy0; row <= cy1; row++)
		{
			for (col = cx0; col <= cx1; col++)
			{
				cellToButton[(row * 8) + col + 1] = (fxn ? buttonId : 0);
			}
		}
		if(fxn == 0)
		{
			// zero the button list's push count in XRAM
			xputchar(buttonList.fpMyaddr + sizeof(BUTTON_LIST) - sizeof(BYTE),
			         (char) 0);
		}
	}
	return(result);
}

/* START FUNCTION DESCRIPTION ********************************************
AbsToRel

SYNTAX:
	int	AbsToRel (
		BYTE	absCoord,	// absolute cell coordinate
		BOOL	x);			// TRUE to convert x coordinate
							// FALSE to convert y coordinate

DESCRIPTION:
	convert absolute cell coordinate in the form 1, 2, 3, ..., 64
	to relative x or y cell coordinate in the form	0, 1, 2, ..., 7

RETURN VALUE:
	relative x or y coordinate

END DESCRIPTION **********************************************************/
nodebug
int AbsToRel(BYTE absCoord, BOOL x)
{
	return((int) ((x ? (absCoord - 1) : ((absCoord - 1) >> 3)) & 0x7));
}

/* START FUNCTION DESCRIPTION ********************************************
DrawOvalFrame

SYNTAX:	void DrawOvalFrame (
			int x,	// x-cell coord, 0 to 7 (0 = west side)
			int y,	// y-cell coord, 0 to 7 (0 = north side)
			int w,	// width in cells
			int h);	// height in cells

DESCRIPTION:
			Draws an oval frame with	22222
									   2     4
									   2     4
									    44444	pixels
RETURN VALUE:
			 none

END DESCRIPTION **********************************************************/
nodebug
void DrawOvalFrame(int x, int y, int w, int h)
{
	glBuffLock();
											// North-West corner
	glXPutBitmap(	(x * BTN_HSPACE),
					(y * BTN_VSPACE),
					(BTN_HSPACE / 2), (BTN_VSPACE / 2),
					btnFrameNw);
											// South-West corner
	glXPutBitmap(	(x * BTN_HSPACE),
					(((y + h) * BTN_VSPACE) - (BTN_VSPACE / 2)),
					(BTN_HSPACE / 2), (BTN_VSPACE / 2),
					btnFrameSw);
											// South-East corner
	glXPutBitmap(	((((x + w) * BTN_HSPACE) - (BTN_HSPACE / 2)) - 1),
					(((y + h) * BTN_VSPACE) - (BTN_VSPACE / 2)),
					(BTN_HSPACE / 2), (BTN_VSPACE / 2),
					btnFrameSe);
											// North-East corner
	glXPutBitmap(	((((x + w) * BTN_HSPACE) - (BTN_HSPACE / 2)) - 1),
					(y * BTN_VSPACE),
					(BTN_HSPACE / 2), (BTN_VSPACE / 2),
					btnFrameNe);
	if (w > 1)
		{									// top bar
		op71Block(	((x * BTN_HSPACE) + (BTN_HSPACE / 2)),
					(y * BTN_VSPACE),
					((w - 1) * BTN_HSPACE),
					2);
											// bottom bar
		op71Block(	((x * BTN_HSPACE) + (BTN_HSPACE / 2)),
					(((y + h) * BTN_VSPACE) - 4),
					((w - 1) * BTN_HSPACE),
					4);
		}
	if (h > 1)
		{									// left bar
		op71Block(	(x * BTN_HSPACE),
					((y * BTN_VSPACE) + (BTN_VSPACE / 2)),
					2,
					((h - 1) * BTN_VSPACE));
											// right bar
		op71Block(	(((x + w) * BTN_HSPACE) - 5),
					((y * BTN_VSPACE) + (BTN_VSPACE / 2)),
					4,
					((h - 1) * BTN_VSPACE));
		}
	glBuffUnlock();
}

/* START FUNCTION DESCRIPTION ********************************************
DrawRectFrame

SYNTAX:	void DrawRectFrame (
			int x,	// x-cell coord, 0 to 7 (0 = west side)
			int y,	// y-cell coord, 0 to 7 (0 = north side)
			int w,	// width in cells
			int h);	// heght in cells

DESCRIPTION:
			Draws a rectangular frame with 2222222
										   2     2
										   2     2
										   2222222	pixels
RETURN VALUE:
			 none

END DESCRIPTION **********************************************************/
nodebug
void DrawRectFrame(int x, int y, int w, int h)
{
	glBuffLock();
	op71Block(	(x * BTN_HSPACE),				// the top bar
				(y * BTN_VSPACE),
				((w * BTN_HSPACE) - 1),
				2);
	op71Block(	(x * BTN_HSPACE),				// the bottom bar
				(((y + h) * BTN_VSPACE) - 2),
				((w * BTN_HSPACE) - 1),
				2);
	op71Block(	(x * BTN_HSPACE),				// the left bar
				(y * BTN_VSPACE),
				2,
				(h * BTN_VSPACE));
	op71Block(	(((x + w) * BTN_HSPACE) - 3),	// the right bar
				(y * BTN_VSPACE),
				2,
				(h * BTN_VSPACE));
	glBuffUnlock();
}

/* START FUNCTION DESCRIPTION ********************************************
DeleteBitmap

SYNTAX:			BOOL DeleteBitmap (
					int bitmapId);		// the id of the bitmap

DESCRIPTION:	Delete the bitmap from the bitmap list, and make the
				flash block available.

RETURN VALUE:	TRUE if successful
				FALSE if not sucessful

END DESCRIPTION **********************************************************/
nodebug
BOOL DeleteBitmap(int bitmapId)
{
	BOOL			ok, ok1, ok2;
	BITMAP_LIST		bitmapList;

	ok = FindBitmapList (bitmapId, &bitmapList);
	if (ok)
		{
		ok1 = DelBitmapList (bitmapId);			// delete the bitmap from the list
		ok2 = FlashAvail (bitmapList.fpBitmap);	// make the flash block available
		ok = ok1 && ok2;
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
InitLoadBitmap

SYNTAX:			BOOL	InitLoadBitmap (
					int	bitmapId, 		// the id of the bitmap
					int	dx, int dy);	// dimensions of the bitmap (pixels)

DESCRIPTION:	Initialize the loading of a bitmap by writing the block header
				and setting up global vars.

GLOBALS & USE:	xxSize, xxfpAddr

RETURN VALUE:	TRUE if successful
				FALSE if not sucessful

END DESCRIPTION **********************************************************/
nodebug
BOOL InitLoadBitmap(int bitmapId, int dx, int dy)
{
	BOOL			ok;
	int				rc;
	ULONG			rsize;
	ADDR20			fpAddr;
	BLOCK_STRUCT	blockStruct;
	BITMAP_LIST		bitmapList;

	xxSize = 0;		// none allocated as yet
	okBitmapId = 0;
	xxfpAddr = xxfpAddr0 = FNULL;

	ok = (bitmapId != 0) 								// 0 bitmap ID is illegal
		 && (FindBitmapList(bitmapId, &bitmapList) == 0);	// look for dupes

	rsize = (((ULONG) dx + 7L) / 8L) * (ULONG) dy;	// need that many bytes
	if (ok)
		ok = ((dx > 0) && (dy > 0));
	if (ok)
		ok = (rsize <= (((ULONG)VMAX * (ULONG)HMAX) / 8L));

	rsize += (ULONG)sizeof(BLOCK_STRUCT);	// add the overhead for BLOCK_STRUCT
	if (ok)
		{
		fpAddr = FlashMalloc (rsize);
		ok = (fpAddr != FNULL);
		}
	blockStruct.cmd = BIT_MAP;
	blockStruct.fpData = fpAddr + (ULONG)sizeof(BLOCK_STRUCT);
	blockStruct.id = bitmapId;
	blockStruct.dx = dx;
	blockStruct.dy = dy;
	if (ok)
		{
		rc = FlashGenWrite (/*fpDst=*/fpAddr, /*pSrc=*/&blockStruct,
								/*len=*/sizeof(BLOCK_STRUCT));
		xxSize = rsize - (ULONG)sizeof(BLOCK_STRUCT);
		xxfpAddr = fpAddr + (ULONG)sizeof(BLOCK_STRUCT);
		xxfpAddr0 = fpAddr;
		okBitmapId = bitmapId;
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
ConueLoadBitmap

SYNTAX:			BOOL	ConueLoadBitmap (
					int	 bitmapId, 	// must be same as before to continue
					int	 len,		// number of bytes to load
					BYTE *pByte);	// pointer to bitmap data

DESCRIPTION:	Continue the loading of a bitmap by writing the data
				and adjusting global vars. Loading of the bitmap is
				complete when xxSize becomes zero.  At this point the
				bitmap is registered.

GLOBALS & USE:	xxSize, xxfpAddr

RETURN VALUE:	TRUE if successful
				FALSE if not sucessful

END DESCRIPTION **********************************************************/
nodebug
BOOL ConueLoadBitmap(int bitmapId, int len, BYTE *pByte)
{
	BOOL			ok;
	int				rc, *pInt;
	BLOCK_STRUCT	blockStruct;

	ok = ((bitmapId != 0) && (bitmapId == okBitmapId));
	if (ok)
		ok = (len <= xxSize);
	if (ok)
		{
		rc = FlashGenWrite (/*fpDst=*/xxfpAddr, /*pSrc=*/pByte, len);
		xxSize -= (ULONG)len;
		xxfpAddr += (ULONG)len;
	// register the bitmap when all bytes have been loaded
		if (xxSize == 0)
			{
			xmem2root (/*fpSrc=*/xxfpAddr0, /*pDst=*/&blockStruct,
						/*len=*/sizeof(BLOCK_STRUCT));
			cmdData.cmdStruc.seq = (BYTE)bitmapId;
			pInt = (int *)&cmdData.data[4];
			*pInt++ = blockStruct.dx;	// dx
			*pInt++ = blockStruct.dy;	// dy
			ok = AddBitmapList ((COMMAND *)&cmdData, blockStruct.fpData);
			okBitmapId = 0;
			}
		}

	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
DeleteFont

SYNTAX:			BOOL DeleteFont (
					int font);		// the id of the font

DESCRIPTION:	Delete the font from the font list, and make the
				flash block available.

RETURN VALUE:	TRUE if successful
				FALSE if not sucessful

END DESCRIPTION **********************************************************/
nodebug
BOOL DeleteFont(int font)
{
	BOOL	ok;
	ADDR20	fpFont;

	ok = ((font >= MIN_FONT) && (font <= MAX_FONT));
	if (ok)
		ok = (fontInfo[font].startChar != 0);
	if (ok)
		{
		fontInfo[font].startChar = 0;	// mark fontInfo as "available"
		fpFont = fontInfo[font].where.xmemBuffer;
		ok = FlashAvail (fpFont);
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
InitLoadFont

SYNTAX:			BOOL	InitLoadFont (
					int		font, 		// the id of the font
					BYTE	*pByte):	// ptr to width, height, startChar, endChar

DESCRIPTION:	Initialize the loading of a font by writing the block header
				and setting up global vars.

GLOBALS & USE:	xxSize, xxfpAddr

RETURN VALUE:	TRUE if successful
				FALSE if not sucessful

END DESCRIPTION **********************************************************/
nodebug
BOOL InitLoadFont(int font, BYTE *pByte)
{
	BOOL			ok;
	BYTE			width, height, startChar, endChar;
	int				rc;
	ULONG			rsize;
	ADDR20			fpAddr;
	BLOCK_STRUCT	blockStruct;

	xxSize = 0;		// none allocated as yet
	okFontId = 0;
	xxfpAddr = xxfpAddr0 = FNULL;

	ok = ((font >= MIN_FONT) && (font <= MAX_FONT));
	if (ok)
		ok = (fontInfo[font].startChar == 0);
	width = *pByte++;
	height = *pByte++;
	startChar = *pByte++;
	endChar = *pByte++;

	rsize = (((ULONG) width + 7L) / 8L) * (ULONG) height *
	        ((ULONG) endChar - (ULONG) startChar + 1L);	// in bytes
	rsize += (ULONG) sizeof(BLOCK_STRUCT);	// add the overhead for BLOCK_STRUCT
	if (ok)
		{
		fpAddr = FlashMalloc (rsize);
		ok = (fpAddr != FNULL);
		}
	blockStruct.cmd = FONT;
	blockStruct.fpData = fpAddr + (ULONG)sizeof(BLOCK_STRUCT);
	blockStruct.id = font;
	blockStruct.dx = (int)width;
	blockStruct.dy = (int)height;
	blockStruct.startChar = startChar;
	blockStruct.endChar = endChar;
	if (ok)
		{
		rc = FlashGenWrite (/*fpDst=*/fpAddr, /*pSrc=*/&blockStruct,
							/*len=*/sizeof(BLOCK_STRUCT));
		xxSize = rsize - (ULONG)sizeof(BLOCK_STRUCT);
		xxfpAddr = fpAddr + (ULONG)sizeof(BLOCK_STRUCT);
		xxfpAddr0 = fpAddr;
		okFontId = font;
		}

	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
ConueLoadFont

SYNTAX:			BOOL	ConueLoadFont (
					int	 font,		// must be same as before to continue loading
					int	 len,		// number of bytes to load
					BYTE *pByte);	// pointer to font data

DESCRIPTION:	Continue the loading of a font by writing the data
				and adjusting global vars. Loading of the font is
				complete when xxSize becomes zero.  At this point the
				font is registered.

GLOBALS & USE:	xxSize, xxfpAddr

RETURN VALUE:	TRUE if successful
				FALSE if not sucessful

END DESCRIPTION **********************************************************/
nodebug
BOOL ConueLoadFont(int font, int len, BYTE *pByte)
{
	BOOL			ok;
	int				rc;
	BLOCK_STRUCT	blockStruct;

	ok = ((font != 0) && (font == okFontId));
	if (ok)
		ok = (len <= xxSize);
	if (ok)
		{
		rc = FlashGenWrite (/*fpDst=*/xxfpAddr, /*pSrc=*/pByte, len);
		xxSize -= (ULONG)len;
		xxfpAddr += (ULONG)len;
	// register the font when all bytes have been loaded
		if (xxSize == 0)
			{
			xmem2root (/*fpSrc=*/xxfpAddr0, /*pDst=*/&blockStruct,
						/*len=*/sizeof(BLOCK_STRUCT));
			glXFontInit(	//	initialize the font info structure needed later
				&fontInfo[font],	//	pointer to the font info structure to fill
				blockStruct.dx,		//	horizontal size (in pixels) of each character
				blockStruct.dy,		//	vertical size (in pixels) of each character
				blockStruct.startChar,	//	beginning code of printable characters
				blockStruct.endChar,	//	ending code of printable characters
				blockStruct.fpData		//	address of font bitmap in xmem
				);
			okFontId = 0;
			}
		}
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
PlayGreeting

SYNTAX:			void PlayGreeting (void);

DESCRIPTION:	Displays greeting centered in VGA screen

GLOBALS & USE:	greet1, greet2, greet3

END DESCRIPTION **********************************************************/
nodebug
void PlayGreeting(void)
{
	auto int y, total, leeway, pixHeight[2];
	auto int currentFontId;
	auto XYBOUNDS xyBounds;

	currentFontId = fontId;	// save current font ID
	xyBounds.xMax = HMAX;
	xyBounds.xMin = 0;
	leeway = 2;
	pixHeight[0] = (int)fontInfo[3].pixHeight + (2 * leeway);
	pixHeight[1] = (int)fontInfo[2].pixHeight + (2 * leeway);
	total = pixHeight[0] + (2 * pixHeight[1]);
	y = ((VMAX - total) / 2);
	textDir = 0;
	fontId = 3;		// large font
	xyBounds.yMax = (unsigned) (y + pixHeight[0]);
	xyBounds.yMin = (unsigned) y;
	glBuffLock();
	CenterXString (/*px=*/0, /*py=*/y, &xyBounds, greet1);

	fontId = 2;		// medium font
	y += pixHeight[0];
	xyBounds.yMax = (unsigned) (y + pixHeight[1]);
	xyBounds.yMin = (unsigned) y;
	CenterXString (/*px=*/0, /*py=*/y, &xyBounds, greet2);

	y += pixHeight[1];
	xyBounds.yMax = (unsigned) (y + pixHeight[1]);
	xyBounds.yMin = (unsigned) y;
	CenterXString (/*px=*/0, /*py=*/y, &xyBounds, greet3);
	glBuffUnlock();
	fontId = currentFontId;	// restore previous font ID
}

/* START FUNCTION DESCRIPTION ********************************************
AutoBaud

SYNTAX:			int		AutoBaud (void);

DESCRIPTION:	Automatically determine Baud Rate
				; baud rate starts set at 57.6K
				; loop until a character is recieved (an A2h is sent at 57.6k)

RETURN VALUE:

END DESCRIPTION **********************************************************/

//#asm root nodebug
//check_baud:
//	xor      a                 ; check for the first byte for autobaud
//	ld       hl, (hzNrbuf)     ; check if there is data from zNRS232 port
//	ld       de, (tzNrbuf)
//	sbc      hl, de
//	jr       z, check_baud     ; continue to check for data
//
//	ld       hl, (tzNrbuf)
//	ld       a, (hl)           ; get data from the zNRS232 receive buffer
//
//check_9600:
//	cp       0x00              ; is it 0x00 for 9600 baud ?
//	jr       nz, check_19200
//	ld       a, BAUDDIV1
//	ld       (baudratediv), a
//	jp       autobauded
//
//check_19200:
//	cp       0xe0              ; is it 0xe0 for 19200 baud ?
//	jr       nz, check_28800
//	ld       a, BAUDDIV2
//	ld       (baudratediv), a
//	jp       autobauded
//
//check_28800:
//	cp       0x18              ; is it 0x18 for 28800 baud ?
//	jr       nz, check_57600
//	ld       a, BAUDDIV3
//	ld       (baudratediv), a
//	jp       autobauded
//
//check_57600:
//	cp       0xa2              ; is it 0xa2 for 57600 baud ?
//	jr       nz, restart
//	ld       a, BAUDDIV4
//	ld       (baudratediv), a
//
//autobauded:
//#endasm

/*M******************************************************************
**
** SOURCE FILE:		VIRTKBD.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**				   	Display Virtual Keyboard and utilities
**
** FUNCTION LIST:	InitVirtKbd
**						Initialize Virtual Keyboard
**					PlayVirtKbd
**						Display or Remove Virtual Keyboard
**					SetString
**						Store the string in the command data in vkBuff.
**						Display if vk active.
**					PlayVkBuff
**						Display contents of vkBuff
**
** CREATION DATE: 	06/22/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
#memmap xmem

/*** BeginHeader InitVirtKbd, PlayVirtKbd, SetString, PlayPrompt,
	PlayResult, PlayVkBuff */
BOOL InitVirtKbd (void);
BOOL PlayVirtKbd (COMMAND *pCmd, int fxn);
void SetString (COMMAND *pCmd);
void PlayPrompt(void);
void PlayResult(char *pChar);
void PlayVkBuff(void);
/*** endHeader */

typedef	struct	{
	int		buttonId;
	BYTE	flags;
	BYTE	cell;
	BYTE	bitmapId;	// none if 0
	char	*pText;
	}	BUTTON_INIT_DATA;
BUTTON_INIT_DATA	buttonInitData[] =	{
// Note: Character translation is done in ProcessVK() based on buttonID.
// partial rows have special buttons (CE, CAP, BS)
	{0x7FD5, 0xD2,		//  = CE	beep, invert, text, bitmap
		8,	255, "CE"},
	{0x7FD6, 0xF2,		//  = CAP	beep, invert, checkbox, text, bitmap
		16,	255, "CAP"},
	{0x7FD7, 0x92,		//  = BS	beep, invert, bitmap
		24,	254, XX},
// 1st full row
	{0x7FD8, 0xD2,		//  = A	beep, invert, text, bitmap
		25,	255, "A"},
	{0x7FD9, 0xD2,		//  = B	beep, invert, text, bitmap
		26,	255, "B"},
	{0x7FDA, 0xD2,		//  = C	beep, invert, text, bitmap
		27,	255, "C"},
	{0x7FDB, 0xD2,		//  = D	beep, invert, text, bitmap
		28,	255, "D"},
	{0x7FDC, 0xD2,		//  = E	beep, invert, text, bitmap
		29,	255, "E"},
	{0x7FDD, 0xD2,		//  = 7	beep, invert, text, bitmap
		30,	255, "7"},
	{0x7FDE, 0xD2,		//  = 8	beep, invert, text, bitmap
		31,	255, "8"},
	{0x7FDF, 0xD2,		//  = 9	beep, invert, text, bitmap
		32,	255, "9"},
// 2nd full row
	{0x7FE0, 0xD2,		//  = F	beep, invert, text, bitmap
		33,	255, "F"},
	{0x7FE1, 0xD2,		//  = G	beep, invert, text, bitmap
		34,	255, "G"},
	{0x7FE2, 0xD2,		//  = H	beep, invert, text, bitmap
		35,	255, "H"},
	{0x7FE3, 0xD2,		//  = I	beep, invert, text, bitmap
		36,	255, "I"},
	{0x7FE4, 0xD2,		//  = J	beep, invert, text, bitmap
		37,	255, "J"},
	{0x7FE5, 0xD2,		//  = 4	beep, invert, text, bitmap
		38,	255, "4"},
	{0x7FE6, 0xD2,		//  = 5	beep, invert, text, bitmap
		39,	255, "5"},
	{0x7FE7, 0xD2,		//  = 6	beep, invert, text, bitmap
		40,	255, "6"},
// 3rd full row
	{0x7FE8, 0xD2,		//  = K	beep, invert, text, bitmap
		41,	255, "K"},
	{0x7FE9, 0xD2,		//  = L	beep, invert, text, bitmap
		42,	255, "L"},
	{0x7FEA, 0xD2,		//  = M	beep, invert, text, bitmap
		43,	255, "M"},
	{0x7FEB, 0xD2,		//  = N	beep, invert, text, bitmap
		44,	255, "N"},
	{0x7FEC, 0xD2,		//  = O	beep, invert, text, bitmap
		45,	255, "O"},
	{0x7FED, 0xD2,		//  = 1	beep, invert, text, bitmap
		46,	255, "1"},
	{0x7FEE, 0xD2,		//  = 2	beep, invert, text, bitmap
		47,	255, "2"},
	{0x7FEF, 0xD2,		//  = 3	beep, invert, text, bitmap
		48,	255, "3"},
// 4th full row has one special button (dot)
	{0x7FF0, 0xD2,		//  = P	beep, invert, text, bitmap
		49,	255, "P"},
	{0x7FF1, 0xD2,		//  = Q	beep, invert, text, bitmap
		50,	255, "Q"},
	{0x7FF2, 0xD2,		//  = R	beep, invert, text, bitmap
		51,	255, "R"},
	{0x7FF3, 0xD2,		//  = S	beep, invert, text, bitmap
		52,	255, "S"},
	{0x7FF4, 0xD2,		//  = T	beep, invert, text, bitmap
		53,	255, "T"},
	{0x7FF5, 0xD2,		//  = 0	beep, invert, text, bitmap
		54,	255, "0"},
	{0x7FF6, 0x92,		//  = dot beep, invert, bitmap
		55,	253, XX},
	{0x7FF7, 0xD2,		//  = -	beep, invert, text, bitmap
		56,	255, "-"},
// 5th and last full row has one special button (CR)
	{0x7FF8, 0xD2,		//  = U	beep, invert, text, bitmap
		57,	255, "U"},
	{0x7FF9, 0xD2,		//  = V	beep, invert, text, bitmap
		58,	255, "V"},
	{0x7FFA, 0xD2,		//  = W	beep, invert, text, bitmap
		59,	255, "W"},
	{0x7FFB, 0xD2,		//  = X	beep, invert, text, bitmap
		60,	255, "X"},
	{0x7FFC, 0xD2,		//  = Y	beep, invert, text, bitmap
		61,	255, "Y"},
	{0x7FFD, 0xD2,		//  = Z	beep, invert, text, bitmap
		62,	255, "Z"},
	{0x7FFE, 0xD2,		//  = Spc	beep, invert, text, bitmap
		63,	255, "Spc"},
	{0x7FFF, 0x92,		//  = CR	beep, invert, bitmap
		64,	252, XX},
	{0, XX, XX, XX, XX}};

/* START FUNCTION DESCRIPTION *****************************************
InitVirtKbd

SYNTAX: BOOL InitVirtKbd(void);

DESCRIPTION: Initialize (but do not display) the virtual keyboard by
registering the bitmaps and buttons. This should be called during
initialization only.

RETURN VALUE: TRUE if OK, FALSE if cannot allocate memory (which should
never happen).
END DESCRIPTION ******************************************************/
nodebug
BOOL InitVirtKbd(void)
{
	BOOL ok;
	BYTE *pByte;
	int ix, bitmapId, buttonId, *pInt;
	ADDR20 fpBitmap;
	int bitmapIdData[] = { 251, 252, 253, 254, 255, 0 };

// register the bitmaps used here
	ix = 0;
	FOREVER
	{
		bitmapId = bitmapIdData[ix];
		if (!bitmapId)
		{
			break;
		}
		cmdData.cmdStruc.seq = bitmapId;
		pInt = (int *)&cmdData.data[4];
		*pInt++ = BTN_HSPACE;	// dx
		*pInt++ = BTN_VSPACE;	// dy

	// Dynamic C seems to have a problem assigning ADDR20 items in an array
		fpBitmap = ix == 0	?	cellEsc		:
				   ix == 1	?	cellEnter	:
				   ix == 2	?	cellDot		:
				   ix == 3	?	cellBs		:
				 /*ix == 4  ?*/	cellButt;

		ok = AddBitmapList ((COMMAND *)&cmdData, fpBitmap);
		ix++;
		if (!ok)
		{
			break;
		}
	}
// register the buttons used here
	ix = 0;
	FOREVER
	{
		buttonId = buttonInitData[ix].buttonId;
		if (!buttonId)
		{
			break;
		}
		cmdData.cmdStruc.fxn = buttonInitData[ix].flags;
		pInt = (int *)&cmdData.data[4];
		*pInt++ = buttonId;				// in sequence
		pByte = (BYTE *)pInt;
		*pByte++ = buttonInitData[ix].cell;
		*pByte++ = buttonInitData[ix].cell;
		if (buttonInitData[ix].bitmapId)
		{
			*pByte++ = buttonInitData[ix].bitmapId;
		}
		if (buttonInitData[ix].pText)
		{
			strcpy (pByte, buttonInitData[ix].pText);
		}
		ok = AddButtonList ((COMMAND *)&cmdData);
		ix++;
		if (!ok)
		{
			break;
		}
	}
	vkActive = FALSE;
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
PlayVirtKbd

SYNTAX:			BOOL PlayVirtKbd (
					COMMAND	*pCmd,	// pointer to PLAY_KEYBOARD_MACRO if fxn = 1
									// NULL if fxn = 0
					int		fxn};	// function: 1 = Display Virtual Keyboard
									// 			 0 = Remove Virtual Keyboard

DESCRIPTION:	Display or Remove the Virtual Keyboard

RETURN VALUE:	TRUE if OK
				FALSE if Display Queue is full
				or cannot allocate memory for the saved area

END DESCRIPTION **********************************************************/
nodebug
BOOL PlayVirtKbd(COMMAND *pCmd, int fxn)
{
	BOOL ok;
	int ix;
	int px, py, pw, ph;	// pixel coords
	int buttonId;
	auto int currentFontId, currentTextDir;
	BYTE *pByte;
	long *pLong;
	static ADDR20 fpSave;

	segchain _OP7100GE_INIT { fpSave = FNULL; }

	currentFontId = fontId;		// save current font ID
	fontId = 2;						// use medium font for the keyboard
	currentTextDir = textDir;	// save current text direction
	if(textDir != 1)
	{
		textDir = 0;	// enforce horizontal text diplay
	}
	if (fxn)
	{
		fxn = 1;			// force fxn to be 0 or 1
	}
	if (fxn == 1)
	{
		if(!vkActive)
		{
	// save, then disconnect the current cell-to-button mapping
			for(ix = 0; ix < 65; ix++)
			{
				vkCellToButton[ix] = cellToButton[ix];
				cellToButton[ix] = 0;
			}
		}
		glSetBrushType(OP71BLACK);
	// fill in the vk items from pCmd
		vkFlags = pCmd->seq;
		pByte = &pCmd->data[0];
		vkTimeout = (int)*pByte++;
		pLong = (long *)pByte;
		vkLowLimit.longMem = *pLong++;		// floatMem will follow
		vkHighLimit.longMem = *pLong++;		// floatMem will follow
		pByte = (BYTE *)pLong;
		strncpy (/*dst=*/vkPrompt, /*src=*/pByte, MAX_STRING);
		vkPrompt[MAX_STRING - 1] = NUL;		// make sure its terminated
		vkActive = TRUE;
		vkShift = TRUE;
	}
	else	// if (fxn == 0)
	{	// pCmd is not used if fxn == 0
		vkActive = FALSE;
		vkBuff[0] = NUL;					// so as not to show up old msg
	}
// display (or remove) the buttons
	glBuffLock();
	ix = 0;
	FOREVER
	{
		buttonId = buttonInitData[ix].buttonId;
		if (!buttonId)
		{
			break;
		}
		ok = PlayButton (buttonId, fxn);
		ix++;
		if (!ok)
		{
			break;
		}
	}
	px = VK_PX0 * BTN_HSPACE;
	py = VK_PY0 * BTN_VSPACE;
	pw = VK_PW0 * BTN_HSPACE;
	ph = VK_PH0 * BTN_VSPACE;		// pixel coords
	if (ok && (fxn == 1))
	{
		if(!fpSave)	// check for multiple vk requests
		{
			if(fpSave = XramMalloc ((ULONG)FONTOFFSET(pw, ph)))
			{
		// save the area underneath the bitmap
				glXGetBitmap (px, py, pw, ph, fpSave);
			}
			else
			{
				ok = FALSE;	// cannot allocate memory
			}
		}
		if (ok)
		{
	// fill the area of the bitmap with all 0's
			glXPutBitmap (px, py, pw, ph, allClear);
	// draw	a rectangular box around the text entry line
			DrawRectFrame (/*x-cell=*/VK_PX, /*y-cell=*/VK_PY, /*width=*/VK_PW,
			               /*height=*/VK_PH);
			PlayVkBuff();
			vkFlags &= ~0x04;	// temporarily ensure not password mode
			PlayPrompt();
			vkFlags = pCmd->seq;	// restore vk flags from pCmd
		}
	}
	if ((fxn == 0) && fpSave)
	{
// restore background
		glXPutBitmap (px, py, pw, ph, fpSave);
		XramFree (fpSave);
		fpSave = FNULL;
// also restore the previous cell-to-button mapping
		for(ix = 0; ix < 65; ix++)
		{
			cellToButton[ix] = vkCellToButton[ix];
		}
	}
	glBuffUnlock();
	textDir = currentTextDir;	// restore previous text direction
	fontId = currentFontId;		// restore previous font ID
	return (ok);
}

/* START FUNCTION DESCRIPTION ********************************************
SetString

SYNTAX:			VOID SetString (
					COMMAND	*pCmd);	// pointer to SET_STRING command
				// special case:
					NULL);			// to clear the String Buffer

DESCRIPTION:	Store the string in the command data in vkBuff.
				Display if vk active.

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void SetString(COMMAND *pCmd)
{
	if(pCmd)
	{
		strncpy (vkBuff, &pCmd->data[0], (MAX_STRING - 1));
	}
	else
	{
		vkBuff[0] = NUL;		// clear the String Buffer
	}
	vkBuff[MAX_STRING - 1] = NUL;	// just in case
	if (vkActive)
	{
		PlayVkBuff();
	}
}

/* START FUNCTION DESCRIPTION ********************************************
PlayPrompt

SYNTAX:			VOID PlayPrompt (void);

DESCRIPTION:	Display Prompt line

GLOBALS & USE:	vkPrompt contains the prompt

END DESCRIPTION **********************************************************/
nodebug
void PlayPrompt(void)
{
	auto int delta,				// offset to the line we want
	     pixHeight, pixWidth;
	auto int px, py, pw, ph;		// pixel coords
	auto int currentFontId, currentTextDir;
	auto XYBOUNDS xyBounds;

	currentFontId = fontId;		// save current font ID
	fontId = 2;						// use medium default font
	currentTextDir = textDir;	// save current text direction
	if(textDir != 1)
	{
		textDir = 0;	// enforce horizontal text diplay
	}
	delta = 1;					// prompt line
// the box is drawn with 2 pixels on each side
	pixHeight = (int)fontInfo[fontId].pixHeight;
	pixWidth = (int)fontInfo[fontId].pixWidth;
	// px = (VK_PX * BTN_HSPACE) + (pixWidth / 2);		// 1/2 char space over
	px = (VK_PX * BTN_HSPACE) + 2;
	ph = (VK_PH * BTN_VSPACE) - 4;
	py = ((VK_PY - delta) * BTN_VSPACE) + 2;
	pw = (VK_PW * BTN_HSPACE) - 4;
	xyBounds.xMax = (unsigned) (px + pw);
	xyBounds.xMin = (unsigned) px;
	xyBounds.yMax = (unsigned) (py + ph);
	xyBounds.yMin = (unsigned) py;
	glBuffLock();
	glXPutBitmap(px, py, pw, ph, allClear);
	if(textDir == 1)
	{
		px += (pw - pixWidth);
	}
	py = ((VK_PY - delta) * BTN_VSPACE) + ((BTN_VSPACE - pixHeight) / 2);
	PlayString(px, py, &xyBounds, vkPrompt);
	glBuffUnlock();
	textDir = currentTextDir;	// restore previous text direction
	fontId = currentFontId;		// restore previous font ID
}

/* START FUNCTION DESCRIPTION ********************************************
PlayResult

SYNTAX:			VOID PlayResult (
					char *pResult);	// to display result line
					NULL);			// to clear result line

DESCRIPTION:	Display Result line
				Make sure Result line does not exceed (MAX_STRING - 1) = 23 chars

END DESCRIPTION **********************************************************/
nodebug
void PlayResult(char *pResult)
{
	auto int delta,				// offset to the line we want
	     pixHeight, pixWidth;
	auto int px, py, pw, ph;		// pixel coords
	auto int currentFontId, currentTextDir;
	auto XYBOUNDS xyBounds;

	currentFontId = fontId;		// save current font ID
	fontId = 2;						// use medium default font
	currentTextDir = textDir;	// save current text direction
	if(textDir != 1)
	{
		textDir = 0;	// enforce horizontal text diplay
	}
	delta = 2;					// result line
// the box is drawn with 2 pixels on each side
	pixHeight = (int) fontInfo[fontId].pixHeight;
	pixWidth = (int) fontInfo[fontId].pixWidth;
	// px = (VK_PX * BTN_HSPACE) + (pixWidth / 2);		// 1/2 char space over
	px = (VK_PX * BTN_HSPACE) + 2;
	ph = (VK_PH * BTN_VSPACE) - 4;
	py = ((VK_PY - delta) * BTN_VSPACE) + 2;
	pw = (VK_PW * BTN_HSPACE) - 4;
	xyBounds.xMax = (unsigned) (px + pw);
	xyBounds.xMin = (unsigned) px;
	xyBounds.yMax = (unsigned) (py + ph);
	xyBounds.yMin = (unsigned) py;
	glBuffLock();
	glXPutBitmap(px, py, pw, ph, allClear);
	if(textDir == 1)
	{
		px += (pw - pixWidth);
	}
	py = ((VK_PY - delta) * BTN_VSPACE) + ((BTN_VSPACE - pixHeight) / 2);
	if(pResult)
	{
		PlayString(px, py, &xyBounds, pResult);
	}
	glBuffUnlock();
	textDir = currentTextDir;	// restore previous text direction
	fontId = currentFontId;		// restore previous font ID
}

/* START FUNCTION DESCRIPTION ********************************************
PlayVkBuff

SYNTAX:			void PlayVkBuff(void);

DESCRIPTION:	Display the contents of vkBuff (or asterisks) in the
standard location.

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void PlayVkBuff(void)
{
	auto int len, pixWidth, pixHeight;
	auto int px, py, pw, ph;	// pixel coords
	auto char *pTemp;
	auto int addCursor, maxLen;
	auto int currentFontId, currentTextDir;
	auto XYBOUNDS xyBounds;

	currentFontId = fontId;		// save current font ID
	fontId = 2;						// use medium default font
	currentTextDir = textDir;	// save current text direction
	if(textDir != 1)
	{
		textDir = 0;	// enforce horizontal text diplay
	}
	addCursor = ((len = strlen(vkBuff)) < (MAX_STRING - 1)) ? 1 : 0;
	pixWidth = (int) fontInfo[fontId].pixWidth;
	pixHeight = (int) fontInfo[fontId].pixHeight;
	
	px = (VK_PX * BTN_HSPACE) + 2;
	py = (VK_PY * BTN_VSPACE) + 2;
	pw = (VK_PW * BTN_HSPACE) - 4;
	ph = (VK_PH * BTN_VSPACE) - 4;
	xyBounds.xMax = (unsigned) (px + pw);
	xyBounds.xMin = (unsigned) px;
	xyBounds.yMax = (unsigned) (py + ph);
	xyBounds.yMin = (unsigned) py;
	
	glBuffLock();
	glXPutBitmap(px, py, pw, ph, allClear);
	px = (VK_PX * BTN_HSPACE) + (pixWidth / 2);				// +1/2 char spaces
	py = py + ((ph - pixHeight) / 2);							// vertically centered
	switch(textDir)
	{
	case 1:	// right to left
		px = ((VK_PX + VK_PW) * BTN_HSPACE) - (pixWidth * 3 / 2);		// -3/2 chars
	default:
	case 0:	// left to right
		maxLen = VK_PW * BTN_HSPACE / pixWidth - addCursor - 1;
		pTemp = vkBuff;
		while(strlen(pTemp) > maxLen)
		{
			pTemp++;
		}
		break;
	case 2:	// bottom to top
	case 3:	// top to bottom
		pTemp = &vkBuff[len - 1];
		addCursor = FALSE;
		break;
	}
	PlayString(px, py, &xyBounds, pTemp);
	if(addCursor)
	{
// visually append an underscore "cursor"
		glPutFont(cursorX, cursorY, &fontInfo[fontId], (unsigned) '_');
	}
	glBuffUnlock();
	textDir = currentTextDir;	// restore previous text direction
	fontId = currentFontId;		// restore previous font ID
}

/*M******************************************************************
**
** SOURCE FILE:		DECODE.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					Decode command
**
** FUNCTION LIST:	Decode
**						Decode command
**
** CREATION DATE: 	06/18/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
#memmap xmem

/*** BeginHeader Decode */
BYTE Decode (COMMAND *pCmd, BOOL *pDelta);
/*** endHeader */

/* START FUNCTION DESCRIPTION ********************************************
Decode

SYNTAX:			BYTE Decode (
					COMMAND *pCmd,		// pointer to command to decode
				// indirect output
					BOOL	*pDelta);	// flag set if we changed len
										// NULL if we don't care

DESCRIPTION:	Decode command. Set up command fields when required.

RETURN VALUE:	error 0 = none
				1 = CRC error (actually not returned here)
				2 = Record less than 5 bytes (actually not returned here)
				3 = Command not recognized
				4 = Command not implemented as yet
				5 = Option not recognized
				6 = RTC has failed or is not installed
				7 = Command que full
				8 = This command not allowed in a macro
				9 = Error adding a macro to the list
				10 = END_MACRO command when we're not building a macro
				11 = A command target (add, delete) does not exist
				12 = Memory allocation error
				13 = Parameter out of range, or object not found
				14 = We're playing a macro and this command is not
					 STOP_MACRO_LOOP. (not returned here).

END DESCRIPTION **********************************************************/
nodebug
BYTE Decode(COMMAND *pCmd, BOOL *pDelta)
{
	auto BOOL ok, delta;
	auto BYTE error;
	auto BYTE cmd, fxn, seq, *pByte;
	auto BYTE cx0, cy0, cx1, cy1;
	auto int row, col;
	auto int *pInt, ix, rc, xx, yy, macroId, cellId, buttonId;
	auto long *pLong;
	auto float *pFloat;
	auto struct tm	tm;
	auto BUTTON_LIST buttonList;

	error = 0;
	delta = FALSE;			// most commands do not change len
	cmd = (int)pCmd->cmd;
	fxn = (int)pCmd->fxn;
	seq = (int)pCmd->seq;
	pByte = &(pCmd->data[0]);
	pInt = (int *)pByte;
	pLong = (long *)pByte;
	pFloat = (float *)pByte;

/*-------------------------------------------------------------**
** Add the command to the Macro List if we're building a macro **
**-------------------------------------------------------------*/
	if (buildingMacro)
		{
		if (!CheckIfAllowed(pCmd))
			error = 8;
		else if (!AddCommandToList(pCmd))
			error = 9;
		}
	else switch (cmd)
		{
/*------------------**
** Control Commands **
**------------------*/
		case INIT:
			if (fxn <= 1)
				{
				Init();
				enaAckNak = pCmd->fxn;
				}
			else if (fxn == 2)
				{
				//qq need more code
				}
			break;

		case SEND_STATUS:
			pCmd->seq = lastStatus;
			pCmd->data[0] = lastError;
			lastStatus = lastError = 0;
			break;

		case SEND_LAST_PUSH:
			if (fxn == 1)
				{					// return last cell pushed
				*pByte = lastCell;
				lastCell = 0;
				pCmd->len = DATA0 + sizeof(BYTE);
				delta = TRUE;
				}
			else if (fxn == 2)
				{					// return last button pushed
				*pInt = lastButton;
				lastButton = 0;
				pCmd->len = DATA0 + sizeof(int);
				delta = TRUE;
				}
			else
				error = 5;			// option not recognized
			break;

		case SEND_STRING:
			strcpy (pByte, vkBuff);	// copy string to the command buffer
			pCmd->len = DATA0 + strlen(vkBuff) + 1;	// don't forget the NUL
			delta = TRUE;
			break;

		case SEND_LONG_INT:
			*pLong = atol(vkBuff);
			pCmd->len = DATA0 + sizeof(long);
			delta = TRUE;
			break;

		case SEND_FLOAT:
			*pFloat = atof(vkBuff);
			pCmd->len = DATA0 + sizeof(float);
			delta = TRUE;
			break;

		case SEND_CHAR:
			*pByte = vkLastChar;
			vkLastChar = NUL;
			pCmd->len = DATA0 + sizeof(char);
			delta = TRUE;
			break;

		case SEND_TOD:
			rc = tm_rd (&tm);
			if (rc < 0)
				error = 6;
			else
				{
				memcpy ((void *)pByte, (void *)&tm, sizeof(tm));
				pCmd->len = DATA0 + sizeof(tm);
				delta = TRUE;
				}
			break;

		case REPLACE_DEFAULT_FONT:
			break;

		case DISABLE_CELLS:
			ok = (fxn >= 0) && (fxn <= 64);
			if (ok)
				{
				if (fxn == 0)		// disable all cells
					{
					for (ix = 1; ix <= 64; ix++)
						{
						cellEnabled[ix] = FALSE;
						}
					}
				else 			// disable specific cell
					cellEnabled[fxn] = FALSE;
				}
			else
				error = 13;
			break;

		case ENABLE_CELLS:
			ok = (fxn >= 0) && (fxn <= 64);
			if (ok)
				{
				if (fxn == 0)		// enable all cells
					{
					for (ix = 1; ix <= 64; ix++)
						{
						cellEnabled[ix] = TRUE;
						}
					}
				else 			// enable specific cell
					cellEnabled[fxn] = TRUE;
				}
			else
				error = 13;
			break;

		case SET_FONT:
			// seq is prospective fontId
			ok = ((seq >= 1) && (seq <= MAX_FONT));
			if (ok)
				ok = (fontInfo[seq].startChar != 0);
			if (ok)
				fontId = seq;
			break;

/* Macro Commands */
		case START_MACRO:
			if (!StartBuildingMacro(pCmd))
				error = 9;
			break;

	// if we're buildingMacro, then we should not see the END_MACRO command here
	// else the command is an error
		case END_MACRO:
			error = 10;
			break;

		case DEFINE_BUTTON:
			ok = AddButtonList (pCmd);
			if(!ok)
			{
				error = 13;
			}
			break;

		case DIS_ENA_BUTTON:
			ok = FALSE;				// initially default to not OK
			error = 13;				// default to object not found
			if((fxn == 0) || (fxn == 1))
			{
				// single button disable/enable
				ok = EnaButton(*pInt, fxn);
			}
			else if((fxn == 2) || (fxn == 3))
			{
				// touch screen area buttons disable/enable
				ok = TRUE;			// switch default to OK for compound result
				cx0 = AbsToRel(*pByte, TRUE);
				cy0 = AbsToRel(*pByte++, FALSE);
				cx1 = AbsToRel(*pByte, TRUE);
				cy1 = AbsToRel(*pByte, FALSE);
				if(fxn == 2)
				{
					// touch screen area buttons disable
					for(row = cy0; row <= cy1; row++)
					{
						for(col = cx0; col <= cx1; col++)
						{
							if(buttonId = cellToButton[ix = (row * 8) + col + 1])
							{
								// disable every button that is either . . .
								// completely or partially in the region
								ok &= EnaButton(buttonId, 0);
								// copy cellToButton[] mapping for area enable later
								areaButtons[ix] = buttonId;
							}
						}
					}
				}
				else	// fxn == 3
				{
					// touch screen area buttons enable
					for(row = cy0; row <= cy1; row++)
					{
						for(col = cx0; col <= cx1; col++)
						{
							if(buttonId = areaButtons[ix = (row * 8) + col + 1])
							{
								// enable every button that is either . . .
								// completely or partially in the region
								ok &= EnaButton(buttonId, 1);
								// clear areaButtons[] copy of cellToButton[] mapping
								areaButtons[ix] = 0;
							}
						}
					}
				}
			}
			else
			{
				error = 5;	// option (fxn) is not recognized
			}
			if(ok)
			{
				error = 0;	// is OK, report no error
			}
			break;

/*--------------------------------**
** Commands processed by PlayTask **
**--------------------------------*/
		case BLANK_REGION:			// check
		case INVERT_REGION:			// check
		case STORE_REGION:			// check
		case RESTORE_REGION:			// check
		case CLEAR_STRING_BUFF:		// check
		case CLEAR_SCREEN:			// check
		case SET_BRUSH_TYPE:			// check
		case PIXEL:						// check
		case LINE:						// check
		case CIRCLE:					// check
		case RECTANGLE:				// check
		case POLYGON:					// check
		case PUT_BIT_MAP:				// check
		case PUT_TEXT:					// check
		case SET_TEXT_DIR:			// check
		case BACK_LIGHT:				// check
		case SET_CONTRAST:			// check
		case BEEP:						// check
		case DISPLAY_BUTTON:			// check
		case DISPLAY_BUTTON_Q:		// check
		case REMOVE_BUTTON:			// check
		case DELAY_PLAY:				// check
		case PLAY_KEYBOARD_MACRO:	// check
		case SET_STRING:				// check
		case SET_LONG_INTEGER:		// check
		case SET_FLOAT:				// check
		case SET_CHAR:					// check
		case BIT_MAP:					// check
		case FONT:						// check
		case SCROLL_REGION:			// check

			if (!PutPlayQue (pCmd))
				error = 7;		// command que full
			break;

/* Commands moved from PlayTask */
		case DELETE_BUTTON:
			buttonId = *pInt;
			ok = PlayButton(buttonId, /*fxn=*/0);
			if(ok)
			{
				ok = DelButtonList(buttonId);
			}
			break;

		case SUPER_RESET:
			_OP7100GE_INIT();
			InitFlash();
			SuperReset();
			FlashClear();
		// the following code is necessary because we do a SuperReset().
			InitVirtKbd();		// initialize the virtual keyboard
			InitButtons();
			break;

/* Miscellaneous Commands */
		case SET_CELL_ACTIVE:
			ok = (fxn >= 1) && (fxn <= 64);
			if (ok)
				{
				cellActive[fxn] = *pByte;
				}
			else
				error = 13;
			break;

		case LINK_CELL_TO_MACRO:
			cellId = *pInt++;
			macroId = *pInt;
			ok = ((cellId >= 1) && (cellId <= 64));
			if (ok)
				{
				if (fxn)
					{		// link cell to macro
					ok = FindMacroList (macroId, NULL);
					if (ok)
						cellToMacro[cellId] = macroId;
					}
				else 		// unlink cell to macro
					cellToMacro[cellId] = 0;
				}
			if (!ok)
				error = 13;
			break;

		case LINK_BUTTON_TO_MACRO:
			buttonId = *pInt++;
			macroId = *pInt;
			ok = FindButtonList (buttonId, &buttonList);
			if (ok)
				{
				if (fxn)
					{		// link button to macro
					ok = FindMacroList (macroId, NULL);
					if (ok)
						{
						buttonList.macroId = macroId;
						root2xmem (/*pSrc=*/(void *)&buttonList,
								/*fpDst=*/buttonList.fpMyaddr,
								(UINT)sizeof(BUTTON_LIST));
						}
					}
				else 		// unlink button to macro
					{
					buttonList.macroId = 0;
					root2xmem (/*pSrc=*/(void *)&buttonList,
							/*fpDst=*/buttonList.fpMyaddr,
							(UINT)sizeof(BUTTON_LIST));
					}
				}
			if (!ok)
				error = 13;
			break;

		case STOP_MACRO_LOOP:
			InitMacroQue();
			macroX = 0;
			macroY = 0;
			break;

		case SET_TOD:
			memcpy ((void *)&tm, (void *)pByte, sizeof(tm));
			rc = 0;
			//if (fxn)			// non-zero fxn
				rc = tm_wr (&tm);
			// else ?			// don't know what "load the s/w" means
			if (rc < 0)
				error = 6;
			break;

/* Scripting Commands */
		case DRAW_MACRO:
			xx = yy = 0;
			goto MACRO_COM;
			break;

		case SHIFT_DRAW_MACRO:	// processed by PlayTask
			xx = *pInt++;
			yy = *pInt++;
		MACRO_COM:
			macroId = (int)pCmd->fxn + ((int)pCmd->seq << 8);
			if (!FindMacroList (macroId, NULL))
				error = 11;		// this macro does not exist
			else if (!playingMacro)
				{
				macroChain1st = macroId;		// this macro is 1st in the chain
				StartPlayingMacro (macroId, xx, yy);
				}
			else
				{				// que this macro if we're playing another one
				if (CheckMacroQue(1))
					error = 7;	// que is full
				else if (!PutMacroQue(pCmd))
					error = 12;	// memory allocation error
				}
			break;

		case DELETE_MACRO:
			macroId = (int)pCmd->fxn + ((int)pCmd->seq << 8);
			if (!DelMacroList(macroId))
				error = 11;
			break;

		case LOOP_MACRO:
			if (macroChain1st)
				{
				PutMacroIdQue (macroChain1st);
				macroChain1st = 0;
				playingMacro = FALSE;
				macroX = 0;
				macroY = 0;
				}
			break;

		default:
			error = 3;
			break;
		}
	if (pDelta)
		*pDelta = delta;	// return the flag
	return (error);
}

/*M******************************************************************
**
** SOURCE FILE:		BUTTONS.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**					Supports Cells and Buttons
**
** FUNCTION LIST:	InitButtons
**						Init buttons processing
**					CellTask
**						Task to detect keypushes
**					ProcessVk
**						Translates the buttonId into the equivalent char
**
** CREATION DATE: 	07/20/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
#memmap xmem

/*** BeginHeader InitButtons, CellTask */
void InitButtons (void);
void CellTask (void);
/*** endHeader */
int	 ProcessVk (int buttonId);
void Append (char ch);
void BackSpace (void);
BOOL EntryOk (void);

/* START FUNCTION DESCRIPTION ********************************************
InitButtons

SYNTAX:			void	InitButtons (void);

DESCRIPTION:	Initialize button processing

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void InitButtons(void)
{
	kpMultiInit();
	kpScanState();	// 1st snapshot of the keyboard
}

/* START FUNCTION DESCRIPTION ********************************************
CellTask

SYNTAX:			void	CellTask (void);

DESCRIPTION:	Process Cell and Button pushes.

				A key is not processed until it's released.
				When key is pushed (edge = 0):
					Translate cell push to button push
					We beep if flags call for it.
					Invert image if flags call for it
				When key is released (edge = 1):
					Translate cell push to button push
					We display normal image if flags call for it
					Process virtual keyboard if vkActive
					Set lastButton and lastStatus if appropriate
					Request RS232 task to send unsolicited response
						if flags call for it


RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void CellTask (void)
{
	BOOL edge, conue;
	int key, buttonId, macroId, *pInt, row, col;
	int state;
	BUTTON_LIST buttonList;
#ifndef	LANDSCAPE
	BYTE keyXlate[] =	{	// key translation table in PORTRAIT mode
		64, 56, 48, 40, 32, 24, 16, 8,	// 0 thru 7
		63, 55, 47, 39, 31, 23, 15, 7,	// 8 thru 15
		62, 54, 46, 38, 30, 22, 14, 6,	// 16 thru 23
		61, 53, 45, 37, 29, 21, 13, 5,	// 24 thru 31
		60, 52, 44, 36, 28, 20, 12, 4,	// 32 thru 39
		59, 51, 43, 35, 27, 19, 11, 3, 	// 40 thru 47
		58, 50, 42, 34, 26, 18, 10, 2, 	// 48 thru 55
		57, 49, 41, 33, 25, 17, 9,  1};	// 56 thru 63
#endif

	segchain _OP7100GE_INIT { state = 0; }

	costate
	{
		switch (state)
		{
/*------------------------**
** Get the next cell push **
**------------------------*/
		case 0:
			key = kpMultiGet();
			conue = TRUE;
			if (key == -1)
			{
				kpScanState();	// get snapshot of the keyboard
				conue = FALSE;	// we'll get the key the next time
			}
			if (conue)
			{				// we got a key
				edge = ((key & 0x100) != 0);
				key = (key & 0x00FF);	// clear "edge"
				if (key > 63)
					key = 63;			// clamp to max
#ifdef	LANDSCAPE
			// bottom row = 0; we need to make it 7
			// left column = 0
				row = 7 - (key / 8);
				col = key & 0x07;			// modulo 8
				key = (row * 8) + col + 1;	// nw corner key = 1
#else	//------------------------------------------------------
				key = (int)keyXlate[key];
#endif	//------------------------------------------------------
				buttonId = cellToButton[key];
				conue = (buttonId != 0);
				if (conue)
					conue = FindButtonList (buttonId, &buttonList);
				state++;
			}
			break;
/*-----------------------**
** Process the button	 **
**-----------------------*/
		case 1:
			if (edge)		// key has been released
			{
				if (vkResShow)
				{
					vkResShow = FALSE;
					PlayResult(NULL);	// erase result if any showing
				}
				if (cellEnabled[key])
				{
					lastCell = key;
					lastStatus |= CELL_HIT;
				}
/*---------------------------------------------------------------------------**
** At this point, 'conue' means that a button is associated with this cell.  **
** Cells are automatically enabled if they are associated with a button or   **
** if the vk is active (can you imagine?).                                   **
** We do not continue if the cell is not enabled.                            **
**---------------------------------------------------------------------------*/
				if (!(cellEnabled[key] || conue || vkActive))
				{
					state = 0;
					break;			// abort if not enabled
				}
				if(conue)
				{
			// we have a button-cell release
					if(buttonList.pushCount > (BYTE) 0)
					{
				// button has a positive push count, decrement it and update XRAM
						xputchar(buttonList.fpMyaddr + sizeof(BUTTON_LIST) -
						         sizeof(BYTE), --buttonList.pushCount);
						if(buttonList.pushCount == (BYTE) 0)
						{
							if(buttonList.flags & 0x10)
							{
						// b4 set = was inverted on press, now redraw button normal
								PlayButton(buttonId, /*fxn=*/1);
							}
							if(vkActive)
							{
						// here to process the vk
								vkLastChar = (char) (key = ProcessVk(buttonId));
								if(key == CR)
								{
									if(!EntryOk())
									{
										state = 0;
										break;			// abort if entry not OK
									}
									if(vkFlags & 0x01)
									{
								// send unsolicited response in the form of SEND_STRING
										packet0u[LEN] = 5 + strlen(vkBuff) + 1;
										// ADDR, LEN, CMD, FXN, SEQ, string data, NUL
										packet0u[CMD] = SEND_STRING;
										packet0u[FXN] = 0;
										packet0u[SEQ] = 0;
										strcpy(&packet0u[DATA0], vkBuff);
										SendReply(pChan0, packet0u);
									}
									else
									{
										lastStatus |= DATA_ENTERED;
									}
									if(vkFlags & 0x02)
									{
								// remove the keyboard, which turns off vkActive
										PlayVirtKbd(/*pCmd=*/NULL, /*fxn=*/0);
									}
								}
							}
							else	// !vkActive
							{
/*-----------------------------------------------------------------**
** the vk is not active, but there is a button associated with key **
**-----------------------------------------------------------------*/
								lastButton = buttonId;
								lastStatus |= BUTTON_HIT;
								if(buttonList.flags & 0x01)
								{
							// send unsolicited response as SEND_LAST_PUSH, fxn=2
									packet0u[LEN] = 5 + sizeof(int);
									// ADDR, LEN, CMD, FXN, SEQ, buttonId
									packet0u[CMD] = SEND_LAST_PUSH;
									packet0u[FXN] = 2;	// send button Id
									packet0u[SEQ] = 0;
									pInt = (int *) &packet0u[DATA0];
									*pInt = buttonId;
									SendReply(pChan0, packet0u);
								}
								if(macroId = buttonList.macroId)
								{
							// play a macro if there is one associated with button
							// a button-based macro supercedes a cell-based macro
									PutMacroIdQue(macroId);
								}
							}
						}
					}
				}
				else
				{
			// this cell does not have an associated button, but it may
			// trigger a macro and it may send unsolicited response to host
					macroId = cellToMacro[key];
					if(macroId)
					{
						PutMacroIdQue(macroId);
					}
					if(cellActive[key] & 0x01)
				// send unsolicited response in the form of SEND_LAST_PUSH, fxn=1
					{
						packet0u[LEN] = 5 + sizeof(int);
						// ADDR, LEN, CMD, FXN, SEQ, buttonId
						packet0u[CMD] = SEND_LAST_PUSH;
						packet0u[FXN] = 1;	// send cell Id
						packet0u[SEQ] = 0;
						pInt = (int *) &packet0u[DATA0];
						*pInt = key;
						SendReply(pChan0, packet0u);
					}
				}
			}
/*---------------------------**
** key has just been pushed	 **
**---------------------------*/
			else // if (!edge)
			{
				if(conue)
				{
			// we have a button push, increment the push count and update XRAM
					xputchar(buttonList.fpMyaddr + sizeof(BUTTON_LIST) -
					         sizeof(BYTE), ++buttonList.pushCount);
					if(buttonList.pushCount == (BYTE) 1)
					{
				// only do this once, in case it is a multi-cell button
						if(buttonList.flags & 0x02)
						{				// b1 set = Beep on cell-hit
							eioBeep(1);
							waitfor(DelayMs(100L));
							eioBeep(0);
						}
						if(buttonList.flags & 0x10)
						{
					// b4 set = draw button inverted on press
							PlayButton(buttonId, /*fxn=*/2);
						}
					}
				}
				else
				{
					if(cellActive[key] & 0x02)
					{				// b1 set = Beep on cell-hit
						eioBeep(1);
						waitfor(DelayMs(100L));
						eioBeep(0);
					}
				}
			}
		default:
			state = 0;
			break;
		}
	}
}

/* START FUNCTION DESCRIPTION ********************************************
ProcessVk

SYNTAX:			int	ProcessVk (
						int	buttonId);	// the id assigned by InitVirtKbd

DESCRIPTION:	Translates the buttonId into the equivalent char
				and processes the chars according to classes:
					space, dot	stored in vkBuff
					0 to 9		stored in vkBuff
					a to z		converted to upper case if vkShift
								stored in vkBuff
					SI			toggles vkShift, redisplays CL
					ESC			erases vkBuff
					BS			erases the last char in vkBuff
					CR			performs the 'enter' function

GLOBALS & USE:	vkBuff[]- virtual keyboard string buffer
				vkShift	- letters are translated to upper case
				vkFlags - b2 set if password mode

RETURN VALUE:	translated char (returned as an int)
				0 if special char (SI, ESC, BS)

END DESCRIPTION **********************************************************/
nodebug
int ProcessVk(int buttonId)
{
	char	ch;
	int		fxn;

// the following table is arranged in order of buttonId,
// starting with 0x7FD5 and ending with 0x7FFF
	char	xlate[] = {
	ESC, SI, BS,
	'a', 'b', 'c', 'd', 'e', '7', '8', '9',
	'f', 'g', 'h', 'i', 'j', '4', '5', '6',
	'k', 'l', 'm', 'n', 'o', '1', '2', '3',
	'p', 'q', 'r', 's', 't', '0', '.', '-',
	'u', 'v', 'w', 'x', 'y', 'z', ' ', CR };

// Old key translations:
//	SI, '-', '.', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
//	'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
//	't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
//	'4', '5', '6', '7', '8', '9', CR, ESC, BS, ' '};

	ch = xlate[buttonId - 0x7fd5];
	if(ch == SI)
	{
		vkShift = !vkShift;
		fxn = vkShift	?	1	:	2;
		PlayButton(buttonId, fxn);
		ch = 0;
	}
	else if(ch == ESC)
	{
		SetString(NULL);
		ch = 0;
	}
	else if(ch == BS)
	{
		BackSpace();
		ch = 0;
	}
	else
	{
		if((ch >= 'a') && (ch <= 'z') && vkShift)
		{
			ch &= 0xDF;		// clear b5 to turn into cap
		}
		Append(ch);
	}
	return(ch);
}

/* START FUNCTION DESCRIPTION ********************************************
Append

SYNTAX:		void	Append (
						(char	ch);	// the character to append

DESCRIPTION:	Physically append char to vkBuff
				Visually append char (or '*' in password mode)

GLOBALS & USE:	vkBuff	- character buffer
				vkFlags	- b2 set if password mode
				textDir	- 0 or 1

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void Append(char ch)
{
	auto int len;

	if((len = strlen (vkBuff)) < (MAX_STRING - 1))
	{
		vkBuff[len++] = ch;
		vkBuff[len] = NUL;	// physically append char to vkBuff
		PlayVkBuff();			// redisplay the whole thing
	}
}

/* START FUNCTION DESCRIPTION ********************************************
BackSpace

SYNTAX:		void	BackSpace (void);

DESCRIPTION:	Physically delete char from end of vkBuff
				Visually delete char

GLOBALS & USE:	vkBuff	- character buffer
				textDir	- 0 or 1

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug
void BackSpace(void)
{
	auto int len;

	len = strlen(vkBuff);
	if (len)
	{
		len--;
	}
	vkBuff[len] = NUL;
	PlayVkBuff();	// redisplay the whole thing
}

/* START FUNCTION DESCRIPTION ********************************************
EntryOk

SYNTAX:				BOOL	EntryOk (void);

DESCRIPTION:		Check if entry is OK

GLOBALS & USE:		vkBuff, vkFlags, vkXxxLimit, vkResShow

RETURN VALUE:		TRUE if entry is OK, or no checking to be done
					Else we return FALSE and put up appropriate message

END DESCRIPTION **********************************************************/
nodebug
BOOL EntryOk(void)
{
	BOOL ok;
	BYTE enType,		// data entry type
	     chkLims;	// check limits
	long lValue, lHigh, lLow;
	float fValue, fHigh, fLow;
	char buff[40],
	     *pMsg[] =	{ "",							// 0
	                 "Too low (lim= %ld)",	// 1
	                 "Too high(lim= %ld)",	// 2
	                 "Too low (lim= %f)",	// 3
	                 "Too high(lim= %f)",	// 4
	               };

	ok = TRUE;
	chkLims = vkFlags & 0xC0;
	if(chkLims)		// checking is to be performed
	{
		enType = vkFlags & 0x18;
	// check if data entry type = long int
		if(enType & 0x08)
		{
			lHigh = vkHighLimit.longMem;
			lLow = vkLowLimit.longMem;
			lValue = atol(vkBuff);
			if(_xtoxErr)
			{
				strcpy(buff, __dcErrBadAtoI);
				ok = FALSE;
			}
			else
			{
				if(chkLims & 0x40)
				{		// check LOW limits
					if(lValue < lLow)
					{
						sprintf(buff, pMsg[1], lLow);
						ok = FALSE;
					}
				}
				if(chkLims & 0x80)
				{		// check HIGH limits
					if(lValue > lHigh)
					{
						sprintf(buff, pMsg[2], lHigh);
						ok = FALSE;
					}
				}
			}
		}
	// check if data entry type = float
		else if(enType & 0x10)
		{
			fHigh = vkHighLimit.floatMem;
			fLow = vkLowLimit.floatMem;
			fValue = atof(vkBuff);
			if(_xtoxErr)
			{
				strcpy(buff, __dcErrBadAtoF);
				ok = FALSE;
			}
			else
			{
				if(chkLims & 0x40)
				{		// check LOW limits
					if(fValue < fLow)
					{
						sprintf(buff, pMsg[3], fLow);
						ok = FALSE;
					}
				}
				if(chkLims & 0x80)
				{		// check HIGH limits
					if(fValue > fHigh)
					{
						sprintf(buff, pMsg[4], fHigh);
						ok = FALSE;
					}
				}
			}
		}
		if (!ok)
		{
			PlayResult(buff);
			vkResShow = TRUE;
		}
	}
	return (ok);
}

/*M******************************************************************
**
** SOURCE FILE:		SUPERMAL.LIB
**
** DESCRIPTION:		Memory Allocation Routines for XRAM and FLASH
**
** FUNCTION LIST:	MemoryDevice
**						Determine which memory device a physical address is in.
**					FlashGenWrite
**						General write to flash (1st flash or 2nd flash)
**					XramBfree
**						Make a block of Xram available for memory allocation.
**					XramClear
**						Call this before calling XramBfree
**					XramFree
**						Returns block of allocated XRAM back to the free list.
**					XramPack
**						Reduces fragmentation of XRAM by linking adjacent blocks.
**					XramMalloc
**						Allocates a XRAM block of "size" bytes.
**					InitFlash
**						Initialize Flash subsystem
**					FlashClear
**						Release all flash memory to allocation
**					FlashMalloc
**						Allocate a block of flash memory
**					FlashAvail
**						Make a block of flash memory available for reuse.
**					A24to20
**						Converts a segmented address into a 20-bit physical address
**
** CREATION DATE: 	06/10/99
** PROGRAMMER:		BPMurtha, GVWoodley
**
*********** NARRATIVE ***********************************************
*
	XRAM is the area in the (nominally 128Kbyte) RAM between the top of
	the stack and the top of the RAM.  It does not have to be declared
	to the compiler.
*
*********************************************************************
**$Log$
**
**/

#ifndef _SUPERMAL_LIB
#define _SUPERMAL_LIB

#use vdriver.lib

#define FALSE		0
#define TRUE		1
#define FOREVER		for(;;)
#define XX			0		// don't care

#define	BOOL	unsigned char
#define	BYTE	unsigned char
#define	WORD	unsigned int
#define	UINT	unsigned int
#define	ULONG	unsigned long
#define	ADDR20	unsigned long
#define	FNULL	(ADDR20)0

#define	XSIZE		(ADDR20)0
#define	XNEXT		(ADDR20)sizeof(ULONG)

#ifndef	FLASH_SEGS
#define	FLASH_SEGS	3
#define	FLASH_INUSE	0x5A5A5A5AL
#define	FLASH_AVAIL	0xA5A5A5A5L

typedef	struct {
	ULONG	size;
	ADDR20  fpAddr;
	}  FREE_LIST;

typedef	struct {
	ULONG	flag;
	ULONG	size;
	ADDR20  fpAddr;
	}  FLASH_HDR;
FREE_LIST	flashFreeList[FLASH_SEGS];
#endif

ADDR20		startHeapXram;
struct		_flashInfo flashInfo;

/*** BeginHeader MemoryDevice, A24to20,
	XramMalloc, XramClear, XramFree, XramPack */
int 	MemoryDevice(ADDR20 fpAddr);
ADDR20	XramMalloc(ULONG nBytes);
BOOL	XramBfree(ADDR20 lo, ADDR20 hi);
void	XramClear(void);
BOOL	XramFree(ADDR20 fpAddr);
ULONG	XramPack(void);
ADDR20	A24to20(ULONG a24);
/*** EndHeader */
/*** BeginHeader InitFlash, FlashClear, FlashMalloc, FlashAvail, FlashGenWrite */
void	InitFlash(void);
void	FlashClear (void);
ADDR20	FlashMalloc (ULONG rsize);
BOOL	FlashAvail (ADDR20 fpAddr);
int		FlashGenWrite (ADDR20 fpDst, void *pSrc, int nbytes);
/*** EndHeader */

/* START FUNCTION DESCRIPTION ********************************************
MemoryDevice                    <OP7100.LIB>

SYNTAX:			int	MemoryDevice(
					ADDR20 fpAddr);	// physical address

DESCRIPTION:	Determine which memory device a physical address is in.
				Hard coded for the default configuration of the OP7100.

RETURN VALUE:	1 - first flash, 2 - 2nd flash, 3 - XRAM, 0 - out of range

END DESCRIPTION **********************************************************/
nodebug xmem
int MemoryDevice(ADDR20 fpAddr)
{
	int	which;

	which = 0;
	if (fpAddr < 0x3F000ul)
		which = 1;				// 1st flash
	// there is a hole between 3F000 and 40000 (used for EEPROM sim)
	else if (fpAddr < 0x40000ul)
		which = 0;				// in the hole
	else if (fpAddr < 0x80000ul)
		which = 2;				// 2nd flash
	else if (fpAddr < 0xA0000ul)
		which = 0;				// nothing there
	else if (fpAddr < 0xC0000ul)
		which = 3;				// RAM
	return (which);
}

/* START FUNCTION DESCRIPTION ********************************************
FlashGenWrite

SYNTAX:			int		FlashGenWrite (
							ADDR20	fpDst,	// physical destination addr in flash
							void	*pSrc,	// logical root addres
							int		nbytes);// number of bytes to write

DESCRIPTION:	General write to flash (1st flash or 2nd flash)

GLOBALS & USE:	flashInfo describes 2nd flash

RETURN VALUE:	result of WriteFlash (write to 1st flash)
				or 0 (write to 2nd flash)

END DESCRIPTION **********************************************************/
nodebug
int FlashGenWrite(ADDR20 fpDst, void *pSrc, int nbytes)
{
	int		rc, which;

	which = MemoryDevice(fpDst);
	if (which == 2)
		{
		sysRoot2FXmem(&flashInfo, pSrc, fpDst, nbytes);
		rc = 0;
		}
	else if (which == 1)
		rc = WriteFlash(fpDst, (char *)pSrc, nbytes);

	return (rc);
}

/* START _FUNCTION DESCRIPTION ********************************************
XramBfree				<SUPERMAL.LIB>

SYNTAX: 	BOOL	XramBfree(
						ADDR20 lo,		// the low "address" of the block
						ADDR20 hi);		// the high "address" of the block

DESCRIPTION:
	Xram is the area of the extended RAM available to free-block allocation.
	ADDR20 is a 20-bit (1Mbyte) physical address expressed as an unsigned long.
	It is not a pointer, but acts like one, because the operand is at that
	extended location.

	XramBfree is used to make a block of Xram available for memory allocation.

RETURN VALUE:	TRUE if successful.
				FALSE if block area is too small

END DESCRIPTION **********************************************************/
nodebug root
BOOL XramBfree(ADDR20 lo, ADDR20 hi)
{
	BOOL	ok;
	ULONG	nBytes;

	nBytes = hi - lo + 1;		// make it inclusive
	ok = nBytes > 8ul;		// the overhead is 8 bytes
	if (ok)
		{
		xputlong(lo, nBytes);		// store the size at beginning of block
		ok = XramFree (lo + XNEXT);	// put block on free list
		}
	return (ok);
}

/* START _FUNCTION DESCRIPTION ********************************************
XramClear				<SUPERMAL.LIB>

SYNTAX: 	void	XramClear(void);

DESCRIPTION:
	Call this before calling XramBfree

END DESCRIPTION **********************************************************/
nodebug
void XramClear(void)
{
	startHeapXram = FNULL;
}

/* START FUNCTION DESCRIPTION ********************************************
XramFree                         <SYS.LIB>

SYNTAX: 	BOOL XramFree(
				ADDR20	fpAddr);	// A 20-bit "pointer" to area to free.
								// Points to the "next" member of the FREE_LIST.
								// This is preceded by the ULONG size member.

DESCRIPTION:
	Returns block of dynamically allocated XRAM back to the free list.
	(See XramBfree comments).  The size of the block is given at start of block.

RETURN VALUE:	TRUE if successful.
				FALSE if block area is too small

END DESCRIPTION **********************************************************/
nodebug root
BOOL XramFree(ADDR20 fpAddr)
{
	BOOL	ok;
	ADDR20	p,		// pointer to the next block
			q;		// saved pointer (pointer to the current block)

	fpAddr -= sizeof(ULONG);		// point to size of block
	ok = xgetlong(fpAddr) > 8ul;	// the overhead is 8 bytes
// the chain is in the order of physical addresses
	if (ok)
		{
		p = startHeapXram;		// pointer to the first block
		q = FNULL;				// init pointer
// look for the spot for this new block
		while ((p < fpAddr) && (p != FNULL))
			{
			q = p;				// save pointer to the current block
			p = xgetlong(p + XNEXT);	// pointer to the next block
			}
// we found the spot
		if (q == FNULL)			// at the head of the chain
			startHeapXram = fpAddr;
		else					// in the middle (or end) of the chain
			xputlong ((q + XNEXT), fpAddr);
								// link to next block may be NULL
		xputlong ((fpAddr + XNEXT), p);
		XramPack();
		}
	return (ok);
}

/* START FUNCTION _DESCRIPTION ********************************************
XramPack                         <SYS.LIB>

SYNTAX: 	ULONG XramPack(void);

DESCRIPTION:
	Reduces fragmentation of Extended Ram by linking adjacent blocks.

RETURN VALUE:
	The total amount of bytes in the free memory chain

END DESCRIPTION **********************************************************/
nodebug root
ULONG XramPack(void)
{
	ULONG	tsize, qsize, psize;
	ADDR20	p,		// pointer to the next block
			q;		// pointer to the current block

	tsize = 0;
	q = startHeapXram;					// init ptr to current block
	p = xgetlong(q + sizeof(ULONG));	// init ptr to next block
	while (q != FNULL)
		{
		qsize = xgetlong(q + XSIZE);
		psize = (p == FNULL)	?	0	:
									xgetlong(p + XSIZE);
		if ((q + qsize) >= (p - 1ul))
	// q and p are adjacent, put them together
			{
			qsize = p + psize - q;
			xputlong((q + XSIZE), qsize);
			p = xgetlong(p + XNEXT);
			xputlong ((q + XNEXT), p);
			}
		else
			{
			tsize += qsize;
			q = p;					// save p in q
			p = xgetlong(p + XNEXT);
			}
		}
	return (tsize);
}

/* START FUNCTION DESCRIPTION ********************************************
XramMalloc                      <SYS.LIB>

SYNTAX:		ADDR20 XramMalloc(
				ULONG size);	// number of bytes desired

DESCRIPTION:
	Allocates a dynamic block of "size" bytes.  Must call XramBfree
	before using XramMalloc.

RETURN VALUE:
			20-bit address of beginning of block.
			'size' is stored before that and the 'next' ptr will
			be overwritten by the user.

			FNULL, if space is unavailable.

END DESCRIPTION **********************************************************/
nodebug root
ADDR20 XramMalloc(ULONG nBytes)
{
	ADDR20	p,		// pointer to the next block
			q;		// pointer to the current block
	ADDR20	pnext;
	ULONG	psize;

	if (startHeapXram == FNULL)
		return (FNULL);

	nBytes += sizeof(ULONG);		// to allow for FREE_LIST.size
	q = FNULL;
	p = startHeapXram;
// search for a block large enough
	FOREVER
		{
		psize = xgetlong(p + XSIZE);
		if (psize >= nBytes)
			break;				// found it (p points to it)

		q = p;					// save ptr to current block
		p = xgetlong(p + XNEXT);// point to next block
		if (p == FNULL)
			return (FNULL);
		}
// we found a block; p is a pointer to it, and psize = it's size
	if (psize <= (nBytes + 8ul))
		{
	// the balance is too small - give them the rest
		psize = nBytes + 8ul;
		xputlong((p + XSIZE), psize);
		pnext = xgetlong(p + XNEXT);	// could be NULL

		if (q == FNULL)
			startHeapXram = pnext;		// the chain starts with next block
		else
			xputlong((q + XNEXT), pnext);

		return (p + sizeof(ULONG));		// return ptr to 1st usable byte
		}
// take a piece out of the end of the block
	psize -= nBytes;						// what's left
	xputlong((p + XSIZE), psize);		// store at beginning of block
	q = p + psize;						// point to the top block
	xputlong((q + XSIZE), nBytes);		// store size of newly allocated block
	q += sizeof(ULONG);					// point above stored size

	return (q);
}

/* START FUNCTION DESCRIPTION ********************************************
InitFlash

SYNTAX:			void	InitFlash (void);

DESCRIPTION:	Initialize Flash subsystem: check for presence of 2nd flash,
				set up flashFreeList[].

GLOBALS & USE:	flashInfo - flash information for 2nd flash

RETURN VALUE:	N/A

END DESCRIPTION **********************************************************/
nodebug xmem
void InitFlash(void)
{
	BOOL	have2ndFlash;
	int		rc, ix;

	rc = sysChk2ndFlash (&flashInfo);
	have2ndFlash = (rc == 0);
	ix = 0;
// allocate flash storage space from the top down
// there are 3 segments of memory which can be pooled
	if (have2ndFlash)
		{
		flashFreeList[ix].fpAddr = 0x80000;	// past the top of 2nd flash
		flashFreeList[ix++].size = 0x40000;	// all of 2nd flash
		}
// there seems to be a problem with XCE, so we won't use that, either
//	flashFreeList[ix].fpAddr = 0x3F000;
//	flashFreeList[ix++].size = 0x3F000 - A24to20(prog_param.XCE.l);
// there is a bug determining XCB, so we don't use it yet
//	flashFreeList[ix].fpAddr = A24to20(prog_param.XCB.l);
//	flashFreeList[ix++].size = A24to20(prog_param.XCB.l)
//								- A24to20(prog_param.RCE.l);
// store the sentinel
	flashFreeList[ix].fpAddr = FNULL;
	flashFreeList[ix].size = FNULL;
}

/* START FUNCTION DESCRIPTION ********************************************
FlashClear

SYNTAX:			void	FlashClear (void);

DESCRIPTION:	Release all flash memory to allocation by clearing
				all reasonable FLASH_HDRs.

GLOBALS & USE:	flashFreeList must have been set up prior to entry

RETURN VALUE:	n/a

END DESCRIPTION **********************************************************/
nodebug
void FlashClear(void)
{
	BOOL		reasonable;
	int			ix, rc;
	ULONG		segSize, blockSize, flag;
	ADDR20		fpAddr, addr1st, blockAddr, hdrAddr;
	FLASH_HDR	flashHdr;

	ix = 0;
// we look for reasonable FLASH_HDRs, and clear them if found
	while (flashFreeList[ix].fpAddr)
		{
	// here for each segment
		fpAddr = flashFreeList[ix].fpAddr;	// the last address in this segment + 1
		segSize = flashFreeList[ix++].size;	// the total size of the segment
		addr1st = fpAddr - segSize;			// the 1st address in this segment
	// here for each data block; fpAddr points past the last byte of the block
		FOREVER
			{
			hdrAddr	= fpAddr - sizeof(FLASH_HDR);
			xmem2root (/*fpSrc=*/hdrAddr, /*pDst=*/&flashHdr,
						/*len=*/sizeof(FLASH_HDR));
			blockSize = flashHdr.size;		// possibly size of the block
			blockAddr = flashHdr.fpAddr;	// possibly address of the block
			flag = flashHdr.flag;
		// check if size and fpAddr are reasonable
			reasonable = ((blockAddr <= (fpAddr - 32))	// at least 32 bytes in block
				&& (blockAddr >= addr1st)
				&& (blockSize >= 32)
				&& (blockSize <= segSize)
				&& ((flag == FLASH_AVAIL) || (flag == FLASH_INUSE)));
		// quit if this header is not reasonable
		// (the rest of the segment has not been allocated)
			if (!reasonable)
				break;

		// clear this header if resonable and continue searching for other headers
			if (reasonable)
				{
				flashHdr.size = 0L;
				flashHdr.fpAddr = 0L;
				flashHdr.flag = 0L;
				rc = FlashGenWrite (/*fpDst=*/hdrAddr, /*pSrc=*/&flashHdr,
								/*len=*/sizeof(FLASH_HDR));
				}
		// The block was reasonable so blocksize is valid
			segSize -= blockSize;
			fpAddr -= blockSize;			// ready for the next iteration
			if (segSize <= 0)
				break;			// out of the FOREVER
			}	// end of 'here for each data block'
		break;	// out of 'while (flashFreeList[ix].fpAddr)'
		}	// end of 'here for each segment'
}

/* START FUNCTION DESCRIPTION ********************************************
FlashMalloc

SYNTAX:			ADDR20	FlashMalloc (
					ULONG size);		// desired net area

DESCRIPTION:	Allocate a block of memory in flash.  Allocation order is
				from the top down.  We depend upon the "reasonability"
				criterion to determine if a block has already been allocated.
				A block will be reused if it's marked FLASH_AVAIL, and the
				size is at least the desired size.  We do not partition
				reused blocks.


				The total allocation will be increased by the size of the
				flash block header (FLASH_HDR), and the flash header will
				be written at the top of the block (flag = FLASH_INUSE).
				Minimum allocation is a total of 32 bytes.  Be sure not to
				use more than 'size' bytes.

RETURN VALUE:	Far pointer to the allocated data area
				FNULL if not enough memory available

END DESCRIPTION **********************************************************/
nodebug
ADDR20 FlashMalloc(ULONG rsize)
{
	BOOL		reasonable, found;
	int			ix, rc;
	ULONG		segSize, blockSize, flag;
	ADDR20		fpAddr, addr1st, blockAddr, hdrAddr;
	FLASH_HDR	flashHdr;

	rsize += sizeof(FLASH_HDR);	// include the overhead
	if (rsize < 32)
		rsize = 32;					// minimum allocation size

	found = FALSE;
	ix = 0;
	while (flashFreeList[ix].fpAddr)
		{
	// here for each segment
		fpAddr = flashFreeList[ix].fpAddr;	// the last address in this segment + 1
		segSize = flashFreeList[ix++].size;	// the total size of the segment
		addr1st = fpAddr - segSize;			// the 1st address in this segment
	// here for each data block; fpAddr points past the last byte of the block
		FOREVER
			{
			hdrAddr	= fpAddr - sizeof(FLASH_HDR);
			xmem2root (/*fpSrc=*/hdrAddr, /*pDst=*/&flashHdr,
						/*len=*/sizeof(FLASH_HDR));
			blockSize = flashHdr.size;		// possibly size of the block
			blockAddr = flashHdr.fpAddr;	// possibly address of the block
			flag = flashHdr.flag;
		// check if size and fpAddr are reasonable
			reasonable = ((blockAddr <= (fpAddr - 32))	// at least 32 bytes in block
				&& (blockAddr >= addr1st)
				&& (blockSize >= 32)
				&& (blockSize <= segSize)
				&& ((flag == FLASH_AVAIL) || (flag == FLASH_INUSE)));
		// this block is usable if the block is reasonable,
		//		the flag is "available" and the size is ok
		// or the header is not reasonable
			if (reasonable
			&& (flag == FLASH_AVAIL)
			&& (rsize <= blockSize))
				{
				found = TRUE;
				rsize = blockSize;	// take all of available area in the block
				}
			if (!reasonable)
				{
				found = TRUE;
				}
			if (found)
				break;
	// We're here if we did not find a usable block.
	// The block was reasonable (and therefore already used),
	// so blocksize is valid
			segSize -= blockSize;
			fpAddr -= blockSize;			// ready for the next iteration
			if (segSize <= 0)
				break;			// out of the FOREVER
			}	// end of 'here for each data block'
	// we may have found an unused (or available) block, but it may be too small
	// fpAddr points past the last byte of the block.
	// segSize is the size of the block if it's a virgin block,
	// and 'blockSize' is its size if it's a reusable block.
	// blockSize is <= segSize
		if (found && (rsize <= segSize))
			{
			flashHdr.size = rsize;
			flashHdr.fpAddr = fpAddr - rsize;
			flashHdr.flag = FLASH_INUSE;
		// write the block header and quit
			rc = FlashGenWrite (/*fpDst=*/hdrAddr, /*pSrc=*/&flashHdr,
							/*len=*/sizeof(FLASH_HDR));
			break;	// out of 'while (flashFreeList[ix].fpAddr)'
			}
		}	// end of 'here for each segment'
	return (flashHdr.fpAddr);
}

/* START FUNCTION DESCRIPTION ********************************************
FlashAvail

SYNTAX:			BOOL	FlashAvail (
					ADDR20 fpAddr);		// assigned address of the block

DESCRIPTION:	Make a block of flash memory available for reuse.

				This searches the block headers for the specified address
				and sets the flag to FLASH_AVAIL;

RETURN VALUE:	TRUE if fpAddr found.
				FALSE if not found

END DESCRIPTION **********************************************************/
nodebug
BOOL FlashAvail(ADDR20 fpAvail)
{
	BOOL		reasonable, found;
	int			ix, rc;
	ULONG		segSize, blockSize, flag;
	ADDR20		fpAddr, addr1st, blockAddr, hdrAddr;
	FLASH_HDR	flashHdr;

	found = FALSE;
	ix = 0;
	while (flashFreeList[ix].fpAddr)
		{
	// here for each segment
		fpAddr = flashFreeList[ix].fpAddr;	// the last address in this segment + 1
		segSize = flashFreeList[ix++].size;
		addr1st = fpAddr - segSize;			// the 1st address in this segment
	// here for each data block; fpAddr points past the last byte of the block
		FOREVER
			{
			hdrAddr	= fpAddr - sizeof(FLASH_HDR);
			xmem2root (/*fpSrc=*/hdrAddr, /*pDst=*/&flashHdr,
						/*len=*/sizeof(FLASH_HDR));
			blockSize = flashHdr.size;		// possibly size of the block
			blockAddr = flashHdr.fpAddr;	// possibly address of the block
			flag = flashHdr.flag;
		// check if size and fpAddr are reasonable
			reasonable = ((blockAddr <= (fpAddr - 32))	// at least 32 bytes in block
				&& (blockAddr >= addr1st)
				&& (blockSize >= 32)
				&& (blockSize <= segSize)
				&& ((flag == FLASH_AVAIL) || (flag == FLASH_INUSE)));
		// check the address if this header is reasonable
			if (reasonable
			&& (blockAddr == fpAvail))
				{
				found = TRUE;
				break;
				}
			if (!reasonable)
				break;					// no more data blocks in this segment

			segSize -= blockSize;			// we're here if block was reasonable
			fpAddr -= blockSize;			// ready for the next iteration
			if (segSize <= 0)
				break;			// out of the FOREVER
			}	// end of 'here for each data block'
	// we found the block; fpAddr points past the last byte of the block
		if (found)
			{
			flashHdr.flag = FLASH_AVAIL;	// the other members are ok
		// write the changed flag and quit
			rc = FlashGenWrite (/*fpDst=*/hdrAddr, /*pSrc=*/&flashHdr,
							/*len=*/sizeof(FLASH_HDR));
			break;	// out of 'while (flashFreeList[ix].fpAddr)'
			}
		}	// end of 'here for each segment'
	return (found);
}

/* START FUNCTION DESCRIPTION ********************************************
A24to20

SYNTAX: ADDR20 A24to20 (
			ULONG a24);	// ADDR24.l (the ULONG member of an ADDR24 union)

DESCRIPTION:
	Converts a segmented address into a 20-bit (1Mbyte) physical
	address (referred to as ADDR20).

RETURN VALUE: 	An unsigned long integer that is the physical equivalent
				address of the supplied extended logical address.

END DESCRIPTION **********************************************************/
nodebug xmem
ADDR20 A24to20(ULONG a24)
{
	ULONG	tmp1, tmp2;

	tmp1 = (ULONG)((int)a24);				// extract logical address
	tmp2 = (ULONG)(*((BYTE *)&a24 + 2));	// extract the base
	return (tmp1 + (tmp2 << 12));			// perform the addition
}

/*** beginheader */
#endif
/*** EndHeader */
/*M******************************************************************
**
** SOURCE FILE:		DATA.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**				   	Fonts and bitmaps
**
** FUNCTION LIST:	cellButt
**						Slightly oval border around a single cell
**					cellEnter, cellBs, cellEsc, cellDot
**						Special bitmaps used in Virtual Keyboard (vk)
**					allClear, allSet
**						All 0's and all 1's to cover the screen
**					btnFrameNw, btnFrameSw, btnFrameNe, btnFrameSe
**						Button frame corners (north-west, etc)
**
** CREATION DATE: 	05/19/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/
/*** BeginHeader cellButt, cellEnter, cellBs, cellEsc, cellDot,
	allClear, allSet */
extern ADDR20 cellButt;
extern ADDR20 cellEnter;
extern ADDR20 cellBs;
extern ADDR20 cellEsc;
extern ADDR20 cellDot;
extern ADDR20 allClear;
extern ADDR20 allSet;
/*** EndHeader */
/*** BeginHeader btnFrameNw, btnFrameSw, btnFrameNe, btnFrameSe */
extern ADDR20 btnFrameNw;
extern ADDR20 btnFrameSw;
extern ADDR20 btnFrameNe;
extern ADDR20 btnFrameSe;
/*** EndHeader */

#ifdef	LANDSCAPE
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellButt.bmp.
Slightly oval border around a single cell

bfSize = 302
horizontal size is 40 pixels.
vertical size is 30 pixels.
*/
xdata	cellButt {
'\x3f','\xff','\xff','\xff','\xf8','\x60','\x00','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x00','\x06','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\xc0','\x00','\x00','\x00','\x06','\x60','\x00','\x00','\x00','\x0e',
'\x3f','\xff','\xff','\xff','\xfc','\x1f','\xff','\xff','\xff','\xf8'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellEntr.bmp.
CellButt with an 'Enter' arrow

bfSize = 302
horizontal size is 40 pixels.
vertical size is 30 pixels.
*/
xdata	cellEnter {
'\x3f','\xff','\xff','\xff','\xf8','\x60','\x00','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x00','\x06','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x08','\x00','\x00','\x03','\x80','\x18','\x00','\x01','\xc3',
'\x80','\x38','\x00','\x01','\xc3','\x80','\x78','\x00','\x01','\xc3',
'\x80','\xf8','\x00','\x01','\xc3','\x81','\xff','\xff','\xff','\xc3',
'\x83','\xff','\xff','\xff','\xc3','\x81','\xff','\xff','\xff','\xc3',
'\x80','\xf8','\x00','\x00','\x03','\x80','\x78','\x00','\x00','\x03',
'\x80','\x38','\x00','\x00','\x03','\x80','\x18','\x00','\x00','\x03',
'\x80','\x08','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\xc0','\x00','\x00','\x00','\x06','\x60','\x00','\x00','\x00','\x0e',
'\x3f','\xff','\xff','\xff','\xfc','\x1f','\xff','\xff','\xff','\xf8'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellBS.bmp.
cellButt with a BackSpace arrow

bfSize = 302
horizontal size is 40 pixels.
vertical size is 30 pixels.
*/
xdata	cellBs {
'\x3f','\xff','\xff','\xff','\xf8','\x60','\x00','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x00','\x06','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x07','\x1c','\x03',
'\x80','\x00','\x04','\xa0','\x03','\x80','\x00','\x04','\xa0','\x03',
'\x80','\x00','\x07','\x38','\x03','\x80','\x00','\x04','\x84','\x03',
'\x80','\x00','\x04','\x84','\x03','\x80','\x08','\x04','\x84','\x03',
'\x80','\x18','\x07','\x38','\x03','\x80','\x38','\x00','\x00','\x03',
'\x80','\x7f','\xff','\xc0','\x03','\x80','\x7f','\xff','\xc0','\x03',
'\x80','\x38','\x00','\x00','\x03','\x80','\x18','\x00','\x00','\x03',
'\x80','\x08','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\xc0','\x00','\x00','\x00','\x06','\x60','\x00','\x00','\x00','\x0e',
'\x3f','\xff','\xff','\xff','\xfc','\x1f','\xff','\xff','\xff','\xf8'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellEsc.bmp.
cellButt with the text "Esc"

bfSize = 302
horizontal size is 40 pixels.
vertical size is 30 pixels.
*/
xdata	cellEsc {
'\x3f','\xff','\xff','\xff','\xf8','\x60','\x00','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x00','\x06','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x0f','\xc0','\x00','\x03','\x80','\x04','\x40','\x00','\x03',
'\x80','\x04','\x00','\x00','\x03','\x80','\x04','\x8e','\x70','\x03',
'\x80','\x07','\x92','\x90','\x03','\x80','\x04','\x98','\x80','\x03',
'\x80','\x04','\x06','\x80','\x03','\x80','\x04','\x12','\x90','\x03',
'\x80','\x0f','\xdc','\x60','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\xc0','\x00','\x00','\x00','\x06','\x60','\x00','\x00','\x00','\x0e',
'\x3f','\xff','\xff','\xff','\xfc','\x1f','\xff','\xff','\xff','\xf8'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellDot.bmp.
cellButt with a large dot in the middle

bfSize = 302
horizontal size is 40 pixels.
vertical size is 30 pixels.
*/
xdata	cellDot {
'\x3f','\xff','\xff','\xff','\xf8','\x60','\x00','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x00','\x06','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x18','\x00','\x03',
'\x80','\x00','\x3c','\x00','\x03','\x80','\x00','\x7e','\x00','\x03',
'\x80','\x00','\x7e','\x00','\x03','\x80','\x00','\x3c','\x00','\x03',
'\x80','\x00','\x18','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\x80','\x00','\x00','\x00','\x03','\x80','\x00','\x00','\x00','\x03',
'\xc0','\x00','\x00','\x00','\x06','\x60','\x00','\x00','\x00','\x0e',
'\x3f','\xff','\xff','\xff','\xfc','\x1f','\xff','\xff','\xff','\xf8'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is nwbutt.bmp.
Oval North West button corner

bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnFrameNw {
'\x03','\xff','\xff',
'\x0f','\xff','\xff',
'\x1c','\x00','\x00',
'\x30','\x00','\x00',
'\x60','\x00','\x00',
'\x60','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is nebutt.bmp.
Oval North East button corner
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnFrameNe {
'\xff','\xfc','\x00',
'\xff','\xff','\x00',
'\x00','\x07','\x80',
'\x00','\x03','\xc0',
'\x00','\x01','\xe0',
'\x00','\x01','\xe0',
'\x00','\x01','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is swbutt.bmp.
Oval South West button corner

bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnFrameSw {
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xc0','\x00','\x00',
'\xe0','\x00','\x00',
'\x70','\x00','\x00',
'\x7e','\x00','\x00',
'\x3f','\xff','\xf0',
'\x1f','\xff','\xf0',
'\x0f','\xff','\xf0',
'\x03','\xff','\xf0'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is sebutt.bmp.
Oval South East button corner

bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnFrameSe {
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x00','\xf0',
'\x00','\x01','\xf0',
'\x00','\x01','\xe0',
'\x00','\x07','\xe0',
'\xff','\xff','\xc0',
'\xff','\xff','\x80',
'\xff','\xff','\x00',
'\xff','\xfc','\x00'
}; /* end of char *bitMap */

#else		// PORTRAIT
/*
Automatic output from Font Converter (FNTSTRIP.exe)
bitmap file is C:\Projects\Zworld\Bitmaps\CellButP.bmp.
bfSize = 222
horizontal size is 30 pixels.
vertical size is 40 pixels.
*/
xdata	cellButt {
'\x3f','\xff','\xff','\xe0','\x60','\x00','\x00','\x30',
'\xc0','\x00','\x00','\x18','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x18','\x60','\x00','\x00','\x38',
'\x3f','\xff','\xff','\xf0','\x1f','\xff','\xff','\xe0'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellEntP.bmp.
bfSize = 222
horizontal size is 30 pixels.
vertical size is 40 pixels.
*/
xdata	cellEnter {
'\x3f','\xff','\xff','\xe0','\x60','\x00','\x00','\x30',
'\xc0','\x00','\x00','\x18','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x40','\x00','\x0c','\x80','\xc0','\x01','\xcc',
'\x81','\xc0','\x01','\xcc','\x83','\xc0','\x01','\xcc',
'\x87','\xc0','\x01','\xcc','\x8f','\xff','\xff','\xcc',
'\x9f','\xff','\xff','\xcc','\x8f','\xff','\xff','\xcc',
'\x87','\xc0','\x00','\x0c','\x83','\xc0','\x00','\x0c',
'\x81','\xc0','\x00','\x0c','\x80','\xc0','\x00','\x0c',
'\x80','\x40','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x18','\x60','\x00','\x00','\x38',
'\x3f','\xff','\xff','\xf0','\x1f','\xff','\xff','\xe0'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellBsP.bmp.
bfSize = 222
horizontal size is 30 pixels.
vertical size is 40 pixels.
*/
xdata	cellBs {
'\x3f','\xff','\xff','\xe0','\x60','\x00','\x00','\x30',
'\xc0','\x00','\x00','\x18','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\xe3','\x8c','\x80','\x00','\x94','\x0c',
'\x80','\x00','\x94','\x0c','\x80','\x00','\xe7','\x0c',
'\x80','\x00','\x90','\x8c','\x80','\x00','\x90','\x8c',
'\x81','\x00','\x90','\x8c','\x83','\x00','\xe7','\x0c',
'\x87','\x00','\x00','\x0c','\x8f','\xff','\xf8','\x0c',
'\x8f','\xff','\xf8','\x0c','\x87','\x00','\x00','\x0c',
'\x83','\x00','\x00','\x0c','\x81','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x18','\x60','\x00','\x00','\x38',
'\x3f','\xff','\xff','\xf0','\x1f','\xff','\xff','\xe0'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellEscP.bmp.
bfSize = 222
horizontal size is 30 pixels.
vertical size is 40 pixels.
*/
xdata	cellEsc {
'\x3f','\xff','\xff','\xe0','\x60','\x00','\x00','\x30',
'\xc0','\x00','\x00','\x18','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x83','\xf0','\x00','\x0c','\x81','\x10','\x00','\x0c',
'\x81','\x00','\x00','\x0c','\x81','\x23','\x9c','\x0c',
'\x81','\xe4','\xa4','\x0c','\x81','\x26','\x20','\x0c',
'\x81','\x01','\xa0','\x0c','\x81','\x04','\xa4','\x0c',
'\x83','\xf7','\x18','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x18','\x60','\x00','\x00','\x38',
'\x3f','\xff','\xff','\xf0','\x1f','\xff','\xff','\xe0'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\CellDotP.bmp.
bfSize = 222
horizontal size is 30 pixels.
vertical size is 40 pixels.
*/
xdata	cellDot {
'\x3f','\xff','\xff','\xe0','\x60','\x00','\x00','\x30',
'\xc0','\x00','\x00','\x18','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x03','\x00','\x0c','\x80','\x07','\x80','\x0c',
'\x80','\x0f','\xc0','\x0c','\x80','\x0f','\xc0','\x0c',
'\x80','\x07','\x80','\x0c','\x80','\x03','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\x80','\x00','\x00','\x0c','\x80','\x00','\x00','\x0c',
'\xc0','\x00','\x00','\x18','\x60','\x00','\x00','\x38',
'\x3f','\xff','\xff','\xf0','\x1f','\xff','\xff','\xe0'
}; /* end of char *bitMap */
/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\nw.bmp.
bfSize = 142
horizontal size is 15 pixels.
vertical size is 20 pixels.
*/
xdata btnFrameNw {
'\x00','\x1e','\x00','\xfe',
'\x01','\xfe','\x07','\xfe',
'\x0f','\x80','\x1c','\x00',
'\x18','\x00','\x38','\x00',
'\x70','\x00','\x70','\x00',
'\x60','\x00','\xe0','\x00',
'\xe0','\x00','\xc0','\x00',
'\xc0','\x00','\xc0','\x00',
'\xc0','\x00','\xc0','\x00',
'\xc0','\x00','\xc0','\x00'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\ne.bmp.
bfSize = 142
horizontal size is 15 pixels.
vertical size is 20 pixels.
*/
xdata btnFrameNe {
'\xe0','\x00','\xfc','\x00',
'\xfe','\x00','\xff','\x80',
'\x07','\xc0','\x01','\xe0',
'\x00','\xf0','\x00','\x70',
'\x00','\x78','\x00','\x38',
'\x00','\x3c','\x00','\x3e',
'\x00','\x3e','\x00','\x1e',
'\x00','\x1e','\x00','\x1e',
'\x00','\x1e','\x00','\x1e',
'\x00','\x1e','\x00','\x1e'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\sw.bmp.
bfSize = 142
horizontal size is 15 pixels.
vertical size is 20 pixels.
*/
xdata btnFrameSw {
'\xc0','\x00','\xc0','\x00',
'\xc0','\x00','\xc0','\x00',
'\xc0','\x00','\xc0','\x00',
'\xc0','\x00','\xe0','\x00',
'\xe0','\x00','\x70','\x00',
'\x70','\x00','\x78','\x00',
'\x38','\x00','\x1c','\x00',
'\x1e','\x00','\x0f','\x00',
'\x07','\xc0','\x01','\xf0',
'\x00','\xfe','\x00','\x3e'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is C:\Projects\Zworld\Bitmaps\se.bmp.
bfSize = 142
horizontal size is 15 pixels.
vertical size is 20 pixels.
*/
xdata btnFrameSe {
'\x00','\x1e','\x00','\x1e',
'\x00','\x1e','\x00','\x1e',
'\x00','\x1e','\x00','\x1e',
'\x00','\x1e','\x00','\x1e',
'\x00','\x1c','\x00','\x1c',
'\x00','\x38','\x00','\x38',
'\x00','\x78','\x00','\x70',
'\x01','\xf0','\x03','\xe0',
'\x0f','\xc0','\x3f','\x00',
'\xfc','\x00','\xf0','\x00'
}; /* end of char *bitMap */
#endif

/*
This bit map is all clear.  It has 9600 bytes = 76800 pixels
and is used to clear a rectangular area.
*/
xdata	allClear {
// 1
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 2
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 3
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 4
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 5
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 6
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 7
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 8
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 9
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 10
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 11
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 12
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 13
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 14
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 15
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 16
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 17
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 18
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 19
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 20
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 21
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 22
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 23
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 24
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 25
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 26
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 27
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 28
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 29
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 30
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 31
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 32
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 33
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 34
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 35
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 36
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 37
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 38
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 39
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 40
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 41
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 42
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 43
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 44
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 45
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 46
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 47
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 48
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 49
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 50
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 51
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 52
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 53
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 54
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 55
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 56
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 57
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 58
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 59
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 60
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 61
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 62
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 63
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',

// 64
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00'
}; /* nd of char *bitMap */

/*
This bit map is all set.  It has 9600 bytes = 76800 pixels
and is used to set a rectangular area.
*/
xdata	allSet {
// 1
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 2
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 3
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 4
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 5
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 6
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 7
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 8
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 9
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 10
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 11
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 12
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 13
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 14
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 15
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 16
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 17
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 18
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 19
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 20
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 21
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 22
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 23
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 24
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 25
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 26
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 27
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 28
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 29
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 30
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 31
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 32
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 33
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 34
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 35
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 36
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 37
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 38
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 39
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 40
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 41
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 42
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 43
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 44
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 45
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 46
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 47
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 48
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 49
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 50
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 51
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 52
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 53
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 54
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 55
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 56
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 57
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 58
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 59
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 60
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 61
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 62
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 63
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',

// 64
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff'
}; /* end of char *bitMap */

/*M******************************************************************
**
** SOURCE FILE:		TEST0.C
**
** DESCRIPTION:		Part of OP7100GE	ZWorld Graphics Engine
**				   	Test Task
**
** FUNCTION LIST:	TestTask
**						Dummy Test Task
**
** CREATION DATE: 	05/17/99
** PROGRAMMER:		GVWoodley
**
*********** NARRATIVE ***********************************************
*
*
*********************************************************************
**$Log$
**
**/

/*** beginHeader TestTask */
void TestTask (void);
/*** endHeader */

void TestTask(void)
{
	static	int		state;

	segchain _GLOBAL_INIT { state = 0; }

	costate
	{
	switch (state)
		{
		case 0:
			PlayGreeting();		// only the 1st time
			state++;
		default:
			break;
		}
	}
}
#memmap xmem
//#memmap	anymem
