#use 8x10l.lib
#use 8x10l.lib
#use 12x16l.lib
#use engfontl.lib
#use engfnt2l.lib
#use op71l.lib
#use op71hw.lib
#use kp_op71.lib
#use kp.lib
#use vdriver.lib

#memmap xmem

#define BUTTON_CORNER 3

#define VMAX 240
#define HMAX 320

#define BTN_VNUM 8
#define BTN_HNUM 8

#define BTN_VSPACE (VMAX/BTN_VNUM)
#define BTN_HSPACE (HMAX/BTN_HNUM)

/*
Automatic output from Font Converter
bitmap file is nwbutt.bmp.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnNW {
'\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.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnNE {
'\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.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnSW {
'\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.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnSE {
'\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 */

/*
Automatic output from Font Converter
bitmap file is nwbuttm.bmp.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnNWX {
'\x00','\x00','\x00',
'\x00','\x00','\x00',
'\x03','\xff','\xf0',
'\x0f','\xff','\xf0',
'\x1e','\x00','\x00',
'\x18','\x00','\x00',
'\x38','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is nebuttm.bmp.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnNEX {
'\x00','\x00','\x00',
'\x00','\x00','\x00',
'\xff','\xf8','\x00',
'\xff','\xfc','\x00',
'\x00','\x06','\x00',
'\x00','\x01','\x00',
'\x00','\x01','\x80',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0',
'\x00','\x00','\xc0'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is swbuttm.bmp.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnSWX {
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x30','\x00','\x00',
'\x18','\x00','\x00',
'\x08','\x00','\x00',
'\x06','\x00','\x00',
'\x03','\xff','\xf0',
'\x01','\xff','\xf0',
'\x00','\x00','\x00',
'\x00','\x00','\x00'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is sebuttm.bmp.
bfSize = 122
horizontal size is 20 pixels.
vertical size is 15 pixels.
*/
xdata btnSEX {
'\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','\x01','\xc0',
'\x00','\x01','\x80',
'\x00','\x07','\x80',
'\xff','\xff','\x00',
'\xff','\xfc','\x00',
'\x00','\x00','\x00',
'\x00','\x00','\x00'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is K:\COMMON\4ALL\ZLOGOS\LOGO128.BMP.
bfSize = 926
horizontal size is 127 pixels.
vertical size is 54 pixels.
*/
xdata zlogo128 {
'\xff','\xff','\xfc','\x7f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xfe','\x3f','\xff','\xfe',
'\xff','\xff','\xef','\xc0','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x03','\xf3','\xff','\xfe',
'\xff','\xff','\x70','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x0e','\xff','\xfe',
'\xff','\xfd','\xc0','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x03','\xbf','\xfe',
'\xff','\xf3','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\xcf','\xfe',
'\xff','\xec','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x37','\xfe',
'\xff','\xd0','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x1b','\xfe',
'\xff','\xa0','\x01','\x95','\x80','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x0d','\xfe',
'\xff','\x40','\x08','\x81','\x10','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x02','\xfe',
'\xfe','\x80','\x20','\x60','\x44','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x01','\x7e',
'\xfd','\x00','\x80','\x10','\x25','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\xbe',
'\xfb','\x01','\x91','\x08','\x08','\x80','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\xde',
'\xfe','\x02','\x0a','\x04','\x04','\x40','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x7e',
'\xf4','\x04','\x0f','\xff','\xff','\x20','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x2e',
'\xf8','\x08','\xdf','\xff','\xff','\x10','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x3e',
'\xe8','\x0c','\x9f','\x80','\xfe','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x16',
'\xf0','\x00','\x9e','\x01','\xfc','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x1e',
'\xd0','\x30','\x9d','\x03','\xfc','\x40','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x0a',
'\xd0','\x00','\x38','\x07','\xf8','\x04','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x0a',
'\xe0','\x00','\x30','\x9f','\xf0','\x24','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x0e',
'\xa0','\x40','\x30','\x3f','\xe8','\x02','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x04',
'\xa0','\x00','\x00','\x9f','\xc0','\x12','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x04',
'\xa0','\x00','\x44','\x3f','\x84','\x10','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x04',
'\xe0','\x00','\x20','\x7f','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x06',
'\xc0','\xfc','\x00','\xff','\x00','\xfd','\xff','\xc3','\xf0',
'\x7f','\xe0','\xff','\x03','\xff','\x00','\x06',
'\xc0','\x80','\x21','\xfe','\x02','\x70','\xe1','\x8e','\x18',
'\x1c','\x78','\x3c','\x00','\xf3','\x80','\x06',
'\xc0','\x90','\x01','\xfc','\x01','\x70','\xe1','\x1c','\x1c',
'\x1c','\x38','\x38','\x00','\xe1','\xc0','\x06',
'\xc0','\x80','\x13','\xfc','\x03','\x78','\xe3','\x3c','\x0e',
'\x3c','\x38','\x38','\x01','\xe0','\xe0','\x06',
'\xc0','\x80','\x07','\xf0','\x05','\x39','\xe2','\x38','\x0e',
'\x38','\x78','\x38','\x01','\xe0','\xe0','\x06',
'\xe0','\x08','\x0f','\xe2','\x1c','\x39','\x76','\x78','\x0e',
'\x38','\x70','\x78','\x01','\xc0','\xe0','\x06',
'\xa0','\x08','\x1f','\xe0','\x3c','\x3b','\x74','\x78','\x1e',
'\x7f','\xe0','\x70','\x01','\xc0','\xe0','\x04',
'\xa0','\x00','\x3f','\xc1','\x38','\xba','\x74','\x70','\x1e',
'\x79','\x80','\x70','\x03','\xc1','\xe0','\x04',
'\xa0','\x40','\x7f','\x82','\xb8','\xbe','\x78','\x70','\x1e',
'\x71','\xc0','\xf0','\x03','\x81','\xe0','\x04',
'\xe0','\x02','\xff','\x04','\x78','\x3c','\x78','\x70','\x3c',
'\x71','\xc0','\xe0','\x23','\x81','\xc0','\x0e',
'\xf0','\x20','\xff','\x21','\xf8','\x3c','\x70','\x70','\x3c',
'\xf1','\xe0','\xe0','\x67','\x83','\xc0','\x0e',
'\xd0','\x09','\xff','\x87','\xf0','\x38','\x70','\x70','\x78',
'\xe1','\xc8','\xe0','\xc7','\x87','\x80','\x0a',
'\xf0','\x13','\xff','\xff','\xf0','\x18','\x60','\x38','\xe0',
'\xe1','\xf9','\xe1','\xc7','\x0f','\x00','\x1e',
'\xe8','\x03','\xff','\xff','\xf0','\x50','\x20','\x0f','\x83',
'\xf8','\xe3','\xff','\xdf','\xf0','\x00','\x16',
'\xf8','\x00','\x20','\x10','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x3e',
'\xf4','\x04','\x00','\x08','\x0a','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x2e',
'\xfe','\x00','\x00','\x04','\x04','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x7e',
'\xfb','\x00','\x04','\x02','\x15','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\xde',
'\xfd','\x00','\x42','\x00','\x22','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\xbe',
'\xfe','\x80','\x10','\x01','\x48','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x01','\x7e',
'\xff','\xc0','\x04','\x58','\x20','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x03','\xfe',
'\xff','\xa0','\x00','\x7e','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x0f','\xfe',
'\xff','\xd8','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x1b','\xfe',
'\xff','\xec','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x37','\xfe',
'\xff','\xf7','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\xef','\xfe',
'\xff','\xfd','\xc0','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x03','\xbf','\xfe',
'\xff','\xff','\x78','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x1e','\x7f','\xfe',
'\xff','\xff','\xcf','\xf0','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x0f','\xf3','\xff','\xfe',
'\xff','\xff','\xf8','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\x1f','\xff','\xfe',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfe'
}; /* end of char *bitMap */

/*
Automatic output from Font Converter
bitmap file is M:\SWBIN\WINJPEG\LOGO270.BMP.
bfSize = 4202
horizontal size is 268 pixels.
vertical size is 115 pixels.
*/
xdata zlogo268 {
'\x00','\x00','\x00','\x00','\x00','\x00','\x07','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\x80','\x00','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x00','\x01','\xff','\xc0','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x1f','\xfc','\x00','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x00','\x3f','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x07','\xe0','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x01','\xf0','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x7c','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x07','\x00','\x7f','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xf0','\x07','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x18','\x0f','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\x00','\xe0','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\xe0','\x7f','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xf0','\x38','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x03','\x83','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xfc','\x0e','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x0e','\x0f','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\x83','\x80','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x3c','\x3f','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xe0','\xe0','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x70','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xf8','\x70','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\xc3','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xfe','\x18','\x00','\x00',
'\x00',
'\x00','\x00','\x03','\x87','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\x0e','\x00','\x00',
'\x00',
'\x00','\x00','\x07','\x1f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xc7','\x00','\x00',
'\x00',
'\x00','\x00','\x0c','\x3f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xe1','\x80','\x00',
'\x00',
'\x00','\x00','\x18','\xff','\xff','\xff','\xfc','\x01','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xf0','\xc0','\x00',
'\x00',
'\x00','\x00','\x31','\xff','\xff','\xff','\x0f','\xb9','\x87',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xf8','\x60','\x00',
'\x00',
'\x00','\x00','\x63','\xff','\xff','\xf8','\x7f','\xbe','\x7c',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xfe','\x30','\x00',
'\x00',
'\x00','\x00','\xc7','\xff','\xff','\xc7','\x9f','\x7f','\x9f',
'\x1f','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\x18','\x00',
'\x00',
'\x00','\x01','\x8f','\xff','\xff','\x3f','\xee','\xff','\xcf',
'\xe7','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\x8c','\x00',
'\x00',
'\x00','\x03','\x1f','\xff','\xfc','\xff','\xf1','\xff','\xf3',
'\xf9','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xc6','\x00',
'\x00',
'\x00','\x02','\x3f','\xff','\xf2','\xff','\xf9','\xff','\xfd',
'\xfe','\x7f','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xe2','\x00',
'\x00',
'\x00','\x04','\x7f','\xff','\xee','\xff','\xf2','\x7f','\xfe',
'\x7d','\xbf','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xe1','\x00',
'\x00',
'\x00','\x0c','\xff','\xff','\x9f','\x7f','\xe7','\xbf','\xff',
'\xb9','\xdf','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xf1','\x80',
'\x00',
'\x00','\x18','\xff','\xff','\x5f','\x7f','\xdf','\xdf','\xff',
'\xcb','\xe7','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xf8','\xc0',
'\x00',
'\x00','\x11','\xff','\xfe','\x9f','\xbf','\xbf','\xe7','\xff',
'\xe7','\xf3','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfc','\x40',
'\x00',
'\x00','\x23','\xff','\xfd','\xbf','\x9e','\x7f','\xf3','\xff',
'\xe3','\xfd','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfc','\x20',
'\x00',
'\x00','\x23','\xff','\xfb','\xbf','\xff','\xff','\xff','\xff',
'\xcd','\xfe','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfe','\x20',
'\x00',
'\x00','\x47','\xff','\xf7','\xbf','\x80','\x00','\x00','\x00',
'\x00','\x0f','\x7f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\x10',
'\x00',
'\x00','\xcf','\xff','\xef','\xbf','\x80','\x00','\x00','\x00',
'\x00','\x0f','\x3f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\x18',
'\x00',
'\x00','\x8f','\xff','\xdf','\xde','\x80','\x00','\x00','\x00',
'\x00','\x0f','\x9f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\x88',
'\x00',
'\x01','\x9f','\xff','\xbf','\xc3','\x00','\x00','\x00','\x00',
'\x00','\x0f','\xdf','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xcc',
'\x00',
'\x01','\x1f','\xff','\xbc','\x1f','\x00','\x00','\x7f','\xe0',
'\x00','\x1f','\xef','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xc4',
'\x00',
'\x03','\x3f','\xff','\x07','\xdf','\x00','\x0f','\xff','\xc0',
'\x00','\x2f','\xf7','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xe6',
'\x00',
'\x02','\x3f','\xfe','\x7f','\xdf','\x00','\x3f','\xff','\x80',
'\x00','\x77','\xf7','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xe2',
'\x00',
'\x06','\x7f','\xfe','\xff','\xde','\x00','\x7f','\xff','\x80',
'\x00','\x7b','\xfb','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xf3',
'\x00',
'\x04','\x7f','\xfc','\xff','\xde','\x00','\xff','\xff','\x00',
'\x00','\xf9','\xfd','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xf1',
'\x00',
'\x04','\xff','\xfc','\xff','\xde','\x01','\x7f','\xfe','\x00',
'\x01','\xfd','\xfd','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xf1',
'\x00',
'\x0c','\xff','\xfa','\xff','\xdc','\x03','\xbf','\xfc','\x00',
'\x03','\xfe','\xfe','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xf9',
'\x80',
'\x08','\xff','\xfa','\xff','\xfc','\x07','\xbf','\xf8','\x00',
'\x07','\xfe','\x7e','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xf8',
'\x80',
'\x09','\xff','\xf7','\xff','\xfc','\x0f','\xdf','\xf0','\x00',
'\x0f','\xff','\x7f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xf8',
'\x80',
'\x19','\xff','\xf7','\xff','\xec','\x1f','\xdf','\xd0','\x00',
'\x0f','\xff','\xbf','\x7f','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfc',
'\x40',
'\x11','\xff','\xfd','\xff','\xe8','\x1f','\xef','\xa0','\x00',
'\x0f','\xff','\xbe','\x7f','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfc',
'\x40',
'\x13','\xff','\xed','\xff','\xe8','\x3f','\xe6','\x40','\x00',
'\x2f','\xff','\xdd','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfc',
'\x40',
'\x13','\xff','\xed','\xff','\xe8','\x7f','\xf5','\x80','\x00',
'\x77','\xff','\xd9','\xbf','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfe',
'\x60',
'\x33','\xff','\xfd','\xff','\xf0','\x7f','\xf3','\x00','\x00',
'\xf7','\xff','\xeb','\xbf','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfe',
'\x20',
'\x33','\xff','\xdd','\xff','\xff','\xff','\x9a','\x00','\x01',
'\xfb','\xff','\xe7','\xbf','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfe',
'\x20',
'\x27','\xff','\xdd','\xff','\xf7','\xfe','\x7c','\x00','\x01',
'\xfb','\xff','\xef','\xdf','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfe',
'\x20',
'\x27','\xff','\xdd','\xff','\xf7','\xf3','\xfc','\x00','\x03',
'\xfd','\xff','\xd7','\xdf','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfe',
'\x20',
'\x27','\xff','\xdd','\xff','\xf7','\x8f','\xf8','\x00','\x07',
'\xfd','\xff','\xb7','\xdf','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xfe',
'\x20',
'\x67','\xff','\xfd','\xff','\xf8','\xff','\xf0','\x00','\x0f',
'\xfe','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\x30',
'\x67','\xff','\xbd','\xff','\x0b','\xff','\xe0','\x00','\x1f',
'\xfe','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\x30',
'\x67','\xff','\x80','\x00','\xfb','\xff','\xc0','\x00','\x3f',
'\xfe','\xf0','\x00','\xc0','\x03','\x00','\x3f','\xe0',
'\x03','\xff','\x80','\x00','\x03','\xff','\xc0','\x00',
'\x7f','\xfe','\x00','\x00','\x3f','\xff','\xff','\xff',
'\x30',
'\x67','\xff','\xbd','\xff','\xfd','\xff','\xc0','\x00','\x7f',
'\xff','\x70','\x00','\xc0','\x03','\x00','\x3f','\x80',
'\xc0','\xff','\x80','\x00','\x00','\xff','\xc0','\x00',
'\x7f','\xfe','\x00','\x00','\x07','\xff','\xff','\xff',
'\x30',
'\x47','\xff','\xbd','\xff','\xfd','\xff','\x80','\x00','\x7f',
'\xff','\x78','\x07','\xf0','\x0f','\xc0','\xfe','\x07',
'\xf0','\x7f','\xf8','\x07','\x80','\x3f','\xf8','\x03',
'\xff','\xff','\xc0','\x00','\x01','\xff','\xff','\xff',
'\x10',
'\x47','\xff','\xbe','\xff','\xfd','\xff','\x00','\x00','\xff',
'\xff','\xbc','\x07','\xf0','\x1f','\xe1','\xfc','\x0f',
'\xf8','\x1f','\xf8','\x0f','\xe0','\x1f','\xfc','\x07',
'\xff','\xff','\xe0','\x3f','\x80','\xff','\xff','\xff',
'\x10',
'\x47','\xff','\xbe','\xff','\xfe','\xfe','\x00','\x01','\xff',
'\xff','\xac','\x07','\xf8','\x1f','\xe3','\xf8','\x1f',
'\xfc','\x0f','\xf8','\x0f','\xf0','\x1f','\xf8','\x0f',
'\xff','\xff','\xc0','\x3f','\xc0','\x7f','\xff','\xff',
'\x10',
'\x47','\xff','\xbe','\xff','\xfe','\xfc','\x00','\x03','\xff',
'\xff','\x9c','\x07','\xf8','\x0f','\xc7','\xf0','\x1f',
'\xfc','\x0f','\xf0','\x0f','\xf0','\x1f','\xf8','\x0f',
'\xff','\xff','\xc0','\x7f','\xc0','\x7f','\xff','\xff',
'\x10',
'\x47','\xff','\xbe','\xff','\xff','\x7c','\x00','\x07','\xff',
'\xff','\x1e','\x07','\xf0','\x0f','\xc7','\xe0','\x3f',
'\xfc','\x07','\xf0','\x1f','\xf0','\x1f','\xf8','\x0f',
'\xff','\xff','\xc0','\x7f','\xe0','\x3f','\xff','\xff',
'\x10',
'\x47','\xff','\xbf','\x7f','\xff','\x78','\x00','\x0b','\xff',
'\xfe','\x5e','\x07','\xf0','\x0f','\xcf','\xc0','\x7f',
'\xfc','\x07','\xf0','\x1f','\xf0','\x1f','\xf8','\x0f',
'\xff','\xff','\xc0','\x7f','\xe0','\x3f','\xff','\xff',
'\x10',
'\x67','\xff','\xbf','\x7f','\xff','\xb0','\x00','\x09','\xff',
'\xfd','\xfe','\x07','\xe0','\x0f','\x8f','\x80','\x7f',
'\xfc','\x07','\xf0','\x1f','\xf0','\x1f','\xf0','\x1f',
'\xff','\xff','\x80','\xff','\xe0','\x3f','\xff','\xff',
'\x30',
'\x67','\xff','\xbf','\x7f','\xff','\xa0','\x00','\x1d','\xff',
'\xf3','\xee','\x03','\xe0','\x0f','\x9f','\x80','\xff',
'\xfc','\x07','\xe0','\x1f','\xe0','\x1f','\xf0','\x1f',
'\xff','\xff','\x80','\xff','\xe0','\x1f','\xff','\xff',
'\x30',
'\x67','\xff','\xff','\xbf','\xff','\xc0','\x00','\x3e','\xff',
'\xf0','\xee','\x03','\xc4','\x0f','\x1f','\x00','\xff',
'\xfc','\x07','\xe0','\x3f','\xe0','\x1f','\xf0','\x1f',
'\xff','\xff','\x80','\xff','\xe0','\x1f','\xff','\xff',
'\x30',
'\x67','\xff','\xdf','\xbf','\xff','\x80','\x00','\x7e','\xff',
'\xc1','\xee','\x03','\xc4','\x0f','\x1f','\x00','\xff',
'\xfc','\x03','\xe0','\x3f','\xc0','\x3f','\xf0','\x1f',
'\xff','\xff','\x80','\xff','\xe0','\x1f','\xff','\xff',
'\x30',
'\x27','\xff','\xdf','\xbf','\xff','\x80','\x00','\xff','\x7f',
'\x81','\xfe','\x03','\x8c','\x0f','\x3f','\x00','\xff',
'\xfc','\x03','\xe0','\x3f','\x00','\xff','\xe0','\x3f',
'\xff','\xff','\x01','\xff','\xe0','\x1f','\xff','\xfe',
'\x30',
'\x27','\xff','\xdf','\xdf','\xff','\x00','\x01','\xff','\x7f',
'\x41','\xf7','\x03','\x8c','\x06','\x3e','\x01','\xff',
'\xfc','\x07','\xc0','\x00','\x03','\xff','\xe0','\x3f',
'\xff','\xff','\x01','\xff','\xe0','\x1f','\xff','\xfe',
'\x20',
'\x27','\xff','\xdf','\xdf','\xfe','\x00','\x01','\xff','\xbc',
'\x81','\xf7','\x03','\x9c','\x06','\x7e','\x01','\xff',
'\xf8','\x07','\xc0','\x01','\xff','\xff','\xe0','\x3f',
'\xff','\xff','\x01','\xff','\xc0','\x1f','\xff','\xfe',
'\x20',
'\x23','\xff','\xff','\xef','\xfc','\x00','\x03','\xff','\xd3',
'\x03','\xf7','\x03','\x1c','\x06','\x7e','\x01','\xff',
'\xf8','\x07','\xc0','\x78','\x3f','\xff','\xc0','\x3f',
'\xff','\xff','\x01','\xff','\xc0','\x3f','\xff','\xfe',
'\x20',
'\x33','\xff','\xef','\xef','\xf8','\x00','\x07','\xff','\xcf',
'\x03','\xff','\x03','\x3e','\x04','\xfe','\x03','\xff',
'\xf8','\x07','\xc0','\x7c','\x1f','\xff','\xc0','\x7f',
'\xff','\xfe','\x03','\xff','\xc0','\x3f','\xff','\xfe',
'\x20',
'\x13','\xff','\xef','\xf7','\xf0','\x00','\x0f','\xff','\xae',
'\x03','\xfb','\x00','\x3e','\x04','\xfe','\x03','\xff',
'\xf8','\x0f','\x80','\xfc','\x0f','\xff','\xc0','\x7f',
'\xff','\xfe','\x03','\xff','\xc0','\x3f','\xff','\xfe',
'\x60',
'\x13','\xff','\xef','\xf7','\xf0','\x00','\x1f','\xfc','\xe4',
'\x03','\xfb','\x00','\x7e','\x00','\xfe','\x03','\xff',
'\xf0','\x0f','\x80','\xfe','\x07','\xff','\xc0','\x7f',
'\xff','\xfe','\x03','\xff','\x80','\x3f','\xff','\xfc',
'\x40',
'\x11','\xff','\xf7','\xfb','\xe0','\x00','\x3f','\xf3','\xf8',
'\x07','\xfb','\x00','\x7e','\x01','\xfe','\x03','\xff',
'\xf0','\x0f','\x80','\xfe','\x07','\xff','\x80','\x7f',
'\xfc','\xfc','\x07','\xff','\x80','\x7f','\xff','\xfc',
'\x40',
'\x11','\xff','\xf7','\xfd','\xc0','\x00','\x3f','\xef','\xe0',
'\x07','\xfb','\x00','\xfe','\x01','\xfe','\x03','\xff',
'\xe0','\x1f','\x80','\xfc','\x03','\xff','\x80','\xff',
'\xf8','\xfc','\x07','\xff','\x00','\xff','\xff','\xfc',
'\x40',
'\x09','\xff','\xfb','\xfd','\x80','\x00','\x3e','\x3f','\xc0',
'\x07','\xfb','\x80','\xfe','\x03','\xfe','\x03','\xff',
'\xe0','\x1f','\x01','\xfc','\x03','\xff','\x80','\xff',
'\xf8','\xfc','\x07','\xff','\x00','\xff','\xff','\xf8',
'\xc0',
'\x08','\xff','\xfb','\xff','\x00','\x00','\x99','\xff','\x00',
'\x07','\xfb','\x80','\xfe','\x03','\xff','\x03','\xff',
'\xc0','\x3f','\x01','\xfc','\x03','\xff','\x80','\xff',
'\xf0','\xfc','\x07','\xfe','\x01','\xff','\xff','\xf8',
'\x80',
'\x08','\xff','\xfc','\xfe','\x00','\x01','\x87','\xfc','\x00',
'\x0f','\xfb','\x81','\xff','\x07','\xff','\x03','\xff',
'\xc0','\x7f','\x01','\xfc','\x07','\x9f','\x00','\xff',
'\xe1','\xf8','\x0f','\xfe','\x03','\xff','\xff','\xf8',
'\x80',
'\x0c','\xff','\xfd','\x84','\x00','\x03','\xff','\xe0','\x00',
'\x0f','\xfb','\x81','\xff','\x07','\xff','\x83','\xff',
'\x80','\xff','\x01','\xfc','\x07','\x9f','\x01','\xff',
'\x81','\xf8','\x0f','\xfc','\x03','\xff','\xff','\xf1',
'\x80',
'\x04','\x7f','\xfe','\xf8','\x00','\x00','\x00','\x00','\x00',
'\x0f','\xff','\x83','\xff','\x0f','\xff','\x81','\xff',
'\x01','\xfe','\x03','\xfc','\x03','\x3f','\x01','\xff',
'\x01','\xf8','\x0f','\xf0','\x07','\xff','\xff','\xf1',
'\x00',
'\x06','\x7f','\xfe','\xf8','\x00','\x00','\x00','\x00','\x00',
'\x0f','\xff','\x83','\xff','\x0f','\xff','\xc0','\xfc',
'\x07','\xfe','\x01','\xfe','\x02','\x3e','\x01','\xf8',
'\x01','\xf0','\x00','\x00','\x1f','\xff','\xff','\xf3',
'\x00',
'\x06','\x3f','\xff','\x78','\x00','\x00','\x00','\x00','\x00',
'\x1f','\xff','\x87','\xff','\x0f','\xff','\xf0','\x00',
'\x0f','\xf0','\x00','\x1e','\x00','\x70','\x00','\x00',
'\x03','\x80','\x00','\x00','\x7f','\xff','\xff','\xe3',
'\x00',
'\x02','\x3f','\xff','\xb8','\x00','\x00','\x00','\x00','\x00',
'\x1f','\xfd','\xc7','\xff','\x1f','\xff','\xf8','\x00',
'\x7f','\xe0','\x00','\x3f','\x00','\xf0','\x00','\x00',
'\x03','\x80','\x00','\x07','\xff','\xff','\xff','\xe2',
'\x00',
'\x03','\x1f','\xff','\xbf','\xff','\xff','\xff','\xff','\xff',
'\xdf','\xf9','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xc6',
'\x00',
'\x01','\x1f','\xff','\xdf','\xf9','\xff','\xff','\xbf','\xff',
'\xef','\xe5','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xc4',
'\x00',
'\x01','\x8f','\xff','\xef','\xfc','\xff','\xff','\xdf','\xff',
'\xef','\xcd','\x3f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\x8c',
'\x00',
'\x00','\x8f','\xff','\xf7','\xfe','\xff','\xff','\xef','\xff',
'\xf7','\xbd','\x7f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\x08',
'\x00',
'\x00','\x47','\xff','\xfb','\xff','\x7f','\xff','\xf7','\xff',
'\xf2','\x7c','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\x10',
'\x00',
'\x00','\x63','\xff','\xfd','\xff','\xbf','\xff','\xfb','\xff',
'\xf8','\xf9','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfe','\x30',
'\x00',
'\x00','\x23','\xff','\xfe','\xff','\xdf','\xff','\xfd','\xff',
'\xf1','\xf3','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfc','\x20',
'\x00',
'\x00','\x31','\xff','\xff','\x3f','\xe7','\xff','\xfe','\x7f',
'\xe5','\xe7','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xfc','\x60',
'\x00',
'\x00','\x10','\xff','\xff','\x9f','\xf3','\xff','\xff','\x3f',
'\x9e','\xdf','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xf8','\x40',
'\x00',
'\x00','\x08','\xff','\xff','\xe7','\xfd','\xff','\xff','\xde',
'\x7e','\x3f','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xf0','\x80',
'\x00',
'\x00','\x0c','\x7f','\xff','\xfb','\xfe','\x7f','\xff','\xe1',
'\xfe','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xe1','\x80',
'\x00',
'\x00','\x06','\x3f','\xff','\xfc','\xff','\x3f','\xff','\xe3',
'\xf9','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xe3','\x00',
'\x00',
'\x00','\x03','\x1f','\xff','\xff','\x3f','\xdf','\xff','\x3c',
'\xe7','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xc6','\x00',
'\x00',
'\x00','\x01','\x8f','\xff','\xff','\xc7','\xe7','\xf0','\xff',
'\x1f','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\x8c','\x00',
'\x00',
'\x00','\x00','\xc7','\xff','\xff','\xf9','\xf3','\x0f','\xfc',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\x18','\x00',
'\x00',
'\x00','\x00','\x63','\xff','\xff','\xff','\x04','\xff','\xc7',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xfe','\x30','\x00',
'\x00',
'\x00','\x00','\x31','\xff','\xff','\xff','\xf8','\x00','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xf8','\x20','\x00',
'\x00',
'\x00','\x00','\x18','\x7f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xf0','\x40','\x00',
'\x00',
'\x00','\x00','\x0c','\x3f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xe1','\x80','\x00',
'\x00',
'\x00','\x00','\x06','\x1f','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\x83','\x00','\x00',
'\x00',
'\x00','\x00','\x03','\x07','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\x06','\x00','\x00',
'\x00',
'\x00','\x00','\x01','\xc3','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xfc','\x1c','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x60','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xf8','\x30','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x38','\x3f','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xc0','\xe0','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x0e','\x0f','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\x01','\x80','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x03','\x01','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xfc','\x06','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\xe0','\x3f','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xe0','\x3c','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x38','\x07','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xfe','\x00','\xf0','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x0e','\x00','\x1f','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xc0','\x03','\x80','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x03','\xc0','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x1e','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x00','\x7c','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x01','\xf0','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x00','\x07','\xf8','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\xff','\x00','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x3f','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',
'\xff','\xff','\xc0','\x00','\x00','\x00','\x00','\x00',
'\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
'\x00'
}; /* end of char *bitMap */

/* the following function draws a button at an absolute location */

//void drawButtonAbs(unsigned x, unsigned y, unsigned w, unsigned h, unsigned long btnButton) {
//	glXPutBitmap(x,y,w,h,btnButton);
//}

/* START FUNCTION DESCRIPTION ********************************************
btnDrawBase

SYNTAX:			void btnDrawBase(int x, int y, int w, int h);

DESCRIPTION:	This function draws the outline of a button on the screen

PARAMETER1:		the x coordinate of the upper left corner of the button.
Note that this number is units of horizontal grid size (0 based).

PARAMETER2:		the y coordinate of the upper left corner of the button.
Note that this number is units of vertical grid size (0 based).

PARAMETER3:		the width of the button in units of horizontal grid size.

PARAMETER4:		the height of the button in units of vertical grid size.

RETURN VALUE:   N/A

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

void btnDrawBase(int x, int y, int w, int h) {
	glBuffLock();
	glXPutBitmap(x*BTN_HSPACE,y*BTN_VSPACE,BTN_HSPACE/2, BTN_VSPACE/2, btnNW);
	glXPutBitmap(x*BTN_HSPACE,(y+h)*BTN_VSPACE-BTN_VSPACE/2,BTN_HSPACE/2, BTN_VSPACE/2, btnSW);
	glXPutBitmap((x+w)*BTN_HSPACE-BTN_HSPACE/2,(y+h)*BTN_VSPACE-BTN_VSPACE/2,BTN_HSPACE/2, BTN_VSPACE/2, btnSE);
	glXPutBitmap((x+w)*BTN_HSPACE-BTN_HSPACE/2,y*BTN_VSPACE,BTN_HSPACE/2, BTN_VSPACE/2, btnNE);
	if (w > 1) {
		op71Block(x*BTN_HSPACE+BTN_HSPACE/2,y*BTN_VSPACE,(w-1)*BTN_HSPACE,2);
		op71Block(x*BTN_HSPACE+BTN_HSPACE/2,(y+h)*BTN_VSPACE-4,(w-1)*BTN_HSPACE,4);
	}
	if (h > 1) {
		op71Block(x*BTN_HSPACE,y*BTN_VSPACE+BTN_VSPACE/2,2,(h-1)*BTN_VSPACE);
		op71Block((x+w)*BTN_HSPACE-4,y*BTN_VSPACE+BTN_VSPACE/2,4,(h-1)*BTN_VSPACE);
	}
	glBuffUnlock();
}

/* START FUNCTION DESCRIPTION ********************************************
btnDrawMask

SYNTAX:			void btnDrawMask(int x, int y, int w, int h);

DESCRIPTION:	This function draws the mask that should be xor'ed with
the button to give the impression of depressed.

PARAMETER1:		the x coordinate of the upper left corner of the button.
Note that this number is units of horizontal grid size (0 based).

PARAMETER2:		the y coordinate of the upper left corner of the button.
Note that this number is units of vertical grid size (0 based).

PARAMETER3:		the width of the button in units of horizontal grid size.

PARAMETER4:		the height of the button in units of vertical grid size.

RETURN VALUE:   N/A

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

void btnDrawMask(int x, int y, int w, int h) {
	glBuffLock();
	glXPutBitmap(x*BTN_HSPACE,y*BTN_VSPACE,BTN_HSPACE/2, BTN_VSPACE/2, btnNWX);
	glXPutBitmap(x*BTN_HSPACE,(y+h)*BTN_VSPACE-BTN_VSPACE/2,BTN_HSPACE/2, BTN_VSPACE/2, btnSWX);
	glXPutBitmap((x+w)*BTN_HSPACE-BTN_HSPACE/2,(y+h)*BTN_VSPACE-BTN_VSPACE/2,BTN_HSPACE/2, BTN_VSPACE/2, btnSEX);
	glXPutBitmap((x+w)*BTN_HSPACE-BTN_HSPACE/2,y*BTN_VSPACE,BTN_HSPACE/2, BTN_VSPACE/2, btnNEX);
	if (w > 1) {
		op71Block(x*BTN_HSPACE+BTN_HSPACE/2,y*BTN_VSPACE+2,(w-1)*BTN_HSPACE,2);
		op71Block(x*BTN_HSPACE+BTN_HSPACE/2,(y+h)*BTN_VSPACE-4,(w-1)*BTN_HSPACE,2);
	}
	if (h > 1) {
		op71Block(x*BTN_HSPACE+2,y*BTN_VSPACE+BTN_VSPACE/2,2,(h-1)*BTN_VSPACE);
		op71Block((x+w)*BTN_HSPACE-4,y*BTN_VSPACE+BTN_VSPACE/2,2,(h-1)*BTN_VSPACE);
	}
	glBuffUnlock();
}

/* the following function displays caption text in a button. The coordinate
	and size of the button is given in grid units. On a QVGA display in
	landscape mode, a grid cell is 40x30 */

/* START FUNCTION DESCRIPTION ********************************************
btnCaption

SYNTAX:			void btnCaption(unsigned x, unsigned y,
						unsigned w, unsigned h,
						struct _fontInfo *pFi, char *caption);

DESCRIPTION:	This function prints the caption for a button.

PARAMETER1:		the x coordinate of the upper left corner of the button.
Note that this number is units of horizontal grid size (0 based).

PARAMETER2:		the y coordinate of the upper left corner of the button.
Note that this number is units of vertical grid size (0 based).

PARAMETER3:		the width of the button in units of horizontal grid size.

PARAMETER4:		the height of the button in units of vertical grid size.

PARAMETER5:		a pointer to the font info structure that describes the
font to use for the caption

PARAMETER6:		a null terminated string for the caption.

RETURN VALUE:   N/A

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

void btnCaption(unsigned x, unsigned y, unsigned w, unsigned h, struct _fontInfo *pFi, char *caption) {
	auto unsigned len;

	len = strlen(caption);
	glPrintf(
		x*BTN_HSPACE+(w*BTN_HSPACE-pFi->pixWidth*len)/2,
		y*BTN_VSPACE+(h*BTN_VSPACE-pFi->pixHeight)/2,
		pFi,
		caption
	);
}

/********************** BEGIN OF BUTTONS *******************************/

/* the following structure holds information about a button */

struct _Button {
	char x,y,w,h;					//	coordinate in grid cells
	char level;						//	level number to support push/pop
	struct _Button *next;		//	points to the next button in a chain
	struct _Button *prev;		//	points to the previous button in a chain
	char *caption;					//	the caption for this button
	int command;					//	a command code for the button
};

/* the following pointer points to the first free button, available
	to be allocated */

struct _Button *btnFirstFree;

/* the following pointer points to the first used button, actively
	being checked by the scanning routine */

struct _Button *btnFirstUsed;

/*	the following pointer points to a font information structure to
	describe the font used for button caption */

struct _fontInfo *btnFi;	//	declare struct to hold font information

/*	the following macro defines the maximum total number of buttons.
	this number can be increased to store more buttons */

#define BTN_TOTALNUM 40

/*	the following macro defines the bit-mask to indicate a button is
	released (instead of depressed). When a button is released, the
	original button code (command field) is ORed with BTN_RELEASED
	to generate the event number. This allows the interpretation code
	to handle both depression and release of buttons. */

#define BTN_RELEASED 0x4000

/* the following defines an array of button structures */

struct _Button buttonArray[BTN_TOTALNUM];

/* the following integer indicates the current "stack" level. The
	stack like structure allows more efficient implementation of a
	hierarchical button/menu scheme */

char btnLevel;

/* the following integer stores the current button event. It should
	be overwritten to a negative number once the event is handled. */

int btnEvent;

int btnSnapShotState;

/* the following integer keeps track of how many keys are being pressed
	so the beeper only turns off when there is no key pressed */

int btnBeepCount;

/* the following function handles the beeper. It keeps count of total
	number of beep requests so that multiple key presses can be handled */

/* START FUNCTION DESCRIPTION ********************************************
btnBeep

SYNTAX:			void btnBeep(int onOff);

DESCRIPTION:	This function beeps.

PARAMETER1:		If non-zero, turn the buzzer on and increment an internal
counter. If zero, decrements the internal counter and turns off the buzzer
only if the counter reaches zero.

RETURN VALUE:   N/A

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

void btnBeep(int onOff) {
	if ((btnBeepCount > 0) && !onOff) eioBeep(--btnBeepCount);
	else if (onOff) eioBeep(++btnBeepCount);
}

/* the following function stops beeping right away and reinitializes the
	beep count to zero */

/* START FUNCTION DESCRIPTION ********************************************
btnStopBeep

SYNTAX:			void btnStopBeep();

DESCRIPTION:	This function stops the buzzer and resets the internal
counter.

RETURN VALUE:   N/A

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

void btnStopBeep() {
	eioBeep(btnBeepCount = 0);
}

/*	the following function initializes the array of button structures so
	that all entries are in the free list. This function must be called
	before the first button is allocated */

/* START FUNCTION DESCRIPTION ********************************************
btnInitArray

SYNTAX:			void btnInitArray();

DESCRIPTION:	This function initializes objects in an internal array
so it becomes a chain of free objects.

RETURN VALUE:   N/A

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

void btnInitArray() {
	auto int i;

	buttonArray[0].next = &buttonArray[1];
	buttonArray[0].prev = NULL;
	buttonArray[BTN_TOTALNUM-1].prev = &buttonArray[BTN_TOTALNUM-2];
	buttonArray[BTN_TOTALNUM-1].next = NULL;
	
	for (i = 1; i < BTN_TOTALNUM-1; ++i) {
		buttonArray[i].next = &buttonArray[i+1];
		buttonArray[i].prev = &buttonArray[i-1];
	}

	btnFirstFree = &buttonArray[0];

	btnFirstUsed = NULL;
}

/* the following function allocates a button structure from the free
	list. If the operation is successful, a pointer to the just allocated
	button structure is returned. Otherwise, NULL is returned */

/* START FUNCTION DESCRIPTION ********************************************
btnAlloc

SYNTAX:			struct _Button *btnAlloc();

DESCRIPTION:	This function allocates a button object from the button
free pool.

RETURN VALUE:	Returns a pointer to a just-allocated button object if one
is available. Otherwise returns a NULL pointer.

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

struct _Button *btnAlloc() {
	auto struct _Button *pThis;

	pThis = btnFirstFree;
	if (pThis != NULL) {
		if (pThis->next) {
			pThis->next->prev = NULL;
		}
		btnFirstFree = pThis->next;			//	remove myself from the free list
		pThis->next = btnFirstUsed;			//	add myself to the used list
		if (btnFirstUsed != NULL) {
			btnFirstUsed->prev = pThis;
		}
		pThis->prev = NULL;
		btnFirstUsed = pThis;
	}
	return pThis;
}

/* the following function frees a button structure (currently in use)
	and attach the just freed button to the free list */

/* START FUNCTION DESCRIPTION ********************************************
btnFree

SYNTAX:			void btnFree(struct _Button *pThis);

DESCRIPTION:	This function deallocate (free) a button object, and add
the object to the free list.

PARAMETER1:		A pointer to the object to be deallocated (freed).

RETURN VALUE:	N/A

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

void btnFree(struct _Button *pThis) {
	//	first, detach myself from the used list
	if (pThis->next) {
		pThis->next->prev = pThis->prev;
	}
	if (pThis->prev) {
		pThis->prev->next = pThis->next;
	} else {
		//	I am the first
		btnFirstUsed = pThis->next;
	}

	//	then add myself to the free list
	pThis->next = btnFirstFree;
	pThis->prev = NULL;
	if (btnFirstFree != NULL) {
		btnFirstFree->prev = pThis;
	}
	btnFirstFree = pThis;
}

/*	the following function looks in the chain of used buttons and tries
	to find a button that matches the x-y coordinates (in grid units) as
	well as the stack level "l". If no such button is found, the function
	returns NULL. If a button is found, a pointer to the button is returned.
	Note that if multiple buttons match, only the first one encountered is
	returned. */

/* START FUNCTION DESCRIPTION ********************************************
btnSearchXY

SYNTAX:			struct _Button * btnSearchXY(char xx, char yy, char l);

DESCRIPTION:	This function searches the list of buttons in use for a
button that matches the criteria (coordinate and level).

PARAMETER1:		The x coordinate interested in.

PARAMETER2:		The y coordinate interested in.

PARAMETER3:		The level interested in.

RETURN VALUE:	A pointer to a button covering the x-y coordinate AND
matching the level number if such a button is found. Otherwise, returns
a NULL pointer.

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

struct _Button * btnSearchXY(char xx, char yy, char l) {
	auto struct _Button *pThis;

	pThis = btnFirstUsed;
	while (pThis) {
		if ((pThis->x <= xx) && (pThis->y <= yy) &&
			((pThis->x+pThis->w) > xx) && ((pThis->y+pThis->h) > yy) && (pThis->level == l)) {
			break;
		}
		pThis = pThis->next;
	}
	return pThis;
}

/* the following function adds a button of xx-yy coordinate (in grid units),
	with caption as pointed by "c" and command as indicated by "cmd" to the
	used list. The add is only performed if there is no button matching the
	coordinates and level and only if a button can be allocated. */

/* START FUNCTION DESCRIPTION ********************************************
btnSearchXY

SYNTAX:			int btnAdd(char xx, char yy, char ww, char hh,
						char *c, int cmd);

DESCRIPTION:	This function adds a new button

PARAMETER1:		The x coordinate of the upper left corner of the button in
units of horizontal grid size (0 based).

PARAMETER2:		The y coordinate of the upper left corner of the button in
units of vertical grid size (0 based).

PARAMETER3:		The width of the button in units of horizontal grid size.

PARAMETER4:		The height of the button in units of vertical grid size.

PARAMETER5:		The caption for the button.

PARAMETER6:		The command code of the button (less than 0x4000).

RETURN VALUE:	Returns 1 if a button is successfully created and added.
Otherwise returns 0.

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

int btnAdd(char xx, char yy, char ww, char hh, char *c, int cmd) {
	auto struct _Button *pThis;
	if (btnSearchXY(xx,yy,btnLevel) == NULL) {
		//	make sure no two buttons overlap with the same level
		pThis = btnAlloc();
		if (pThis) {
			pThis->x = xx;
			pThis->y = yy;
			pThis->h = hh;
			pThis->w = ww;
			pThis->level = btnLevel;
			pThis->caption = c;
			pThis->command = cmd;
		}
	}
	return pThis != NULL;
}

/* the following function pushes the level of buttons. It also
	disables the beeper. This function should be called before
	btnAdd when a new level of menu is being constructed. */

/* START FUNCTION DESCRIPTION ********************************************
btnPushLevel

SYNTAX:			void btnPushLevel();

DESCRIPTION:	This function pushes the button level by one. This
function calls btnStopBeep.

RETURN VALUE:	N/A

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

void btnPushLevel() {
	btnStopBeep();
	++btnLevel;
}

/* the following function pops the level of buttons. It also
	disables the beeper. All buttons of the popped level is
	freed automatically. This function should be called when
	the hierarchical menu returns to the previous level. */

/* START FUNCTION DESCRIPTION ********************************************
btnPopLevel

SYNTAX:			void btnPopLevel();

DESCRIPTION:	This function pops the button level by one. All buttons
belonging to the popped level are deallocated by this function. This
function calls btnStopBeep.

RETURN VALUE:	N/A

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

void btnPopLevel() {
	auto struct _Button *pThis, *pNext;

	btnStopBeep();
	pThis = btnFirstUsed;
	while (pThis) {
		pNext = pThis->next;
		if ((pThis->level >= btnLevel)) {
			btnFree(pThis);
		}
		pThis = pNext;
	}
	if (btnLevel > 0) --btnLevel;
}

/* the following function repaints all the buttons of the current
	level. The repaint is not destructive to other items on the
	screen, but does overwrite the current buttons */

/* START FUNCTION DESCRIPTION ********************************************
btnRepaint

SYNTAX:			void btnRepaint();

DESCRIPTION:	This function repaints all the button of the current
level.

RETURN VALUE:	N/A

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

void btnRepaint() {
	auto struct _Button *pThis;

	pThis = btnFirstUsed;
	glSetBrushType(GL_BLOCK);
	while (pThis) {
		if ((pThis->level == btnLevel)) {
			btnDrawBase(pThis->x, pThis->y, pThis->w, pThis->h);
			btnCaption(pThis->x, pThis->y, pThis->w, pThis->h, btnFi, pThis->caption);
		}
		pThis = pThis->next;
	}
}

char btnState[8], btnChange[8];

/* START FUNCTION DESCRIPTION ********************************************
btnChangeFn

SYNTAX:			int btnChangeFn(char *curState, char *xorTable);

DESCRIPTION:	This is the call-back function for the kp driver. This
function. If btnSnapShotState is zero, it copies the state and change
tables to a local buffer. This function also sets btnSnapShotState to 1.

PARAMETER1:		An array indicating the current state of buttons.

PARAMETER2:		An array indicating what buttons are different from the
last scan.

RETURN VALUE:	N/A.

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

int btnChangeFn(char *curState, char *xorTable) {
	if (!btnSnapShotState) {
		//	only copy over if the last snapshot is all dealt with
		memcpy(btnState,curState,sizeof(btnState));
		memcpy(btnChange, xorTable, sizeof(btnChange));
		btnSnapShotState = 1;			//	to indicate a snapshot is now valid
	}
}

/* the following function initializes the button array,  the current
	event, stack level and the beeper. */

/* START FUNCTION DESCRIPTION ********************************************
btnInit

SYNTAX:			void btnInit();

DESCRIPTION:	Initializes the btn driver.

RETURN VALUE:	N/A.

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

void btnInit() {
	btnEvent = -1;				//	no event
	btnSnapShotState = 0;	//	no snapshot valid
	btnInitArray();
	btnLevel = 0;
	kpInit(btnChangeFn);
	btnBeepCount = 0;
}

struct _Button *btnCurButton;

/* the following function interprets the key states and map key state
	changes to events. If no event is present, it returns -1. Otherwise,
	a positive number is returned corresponding to the command code of the
	button corresponding to the key event. Call kpScanState to actually
	sample the keypad. As a general rule, btnGet should be called repeatedly
	until it returns -1 before kpScanState is called again. This approach
	ensures that multiple events recorded by a sample are all taken care
	of before the keypad is sampled again. */

/* START FUNCTION DESCRIPTION ********************************************
btnGet

SYNTAX:			int btnGet();

DESCRIPTION:	This function interprets the keypad code and returns a
button command (if a button at the current level covers the key being
pressed). This function should be called repeatedly and the non-negative
number returned should be interpreted by a menu. If this function returns
a negative number, another keypad scan can be called (call kpScanState).
One keypad scan and produce multiple button commands.

RETURN VALUE:	The command code of the button corresponding to a button
in the current level. If no such button is found, returns a negative
number.

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

int btnGet() {
	auto int thisKey;
	
	//	call this function periodically to scan and update the button information
	//	1.		scan the keypad state, debounce
	//	2.		find the button being pushed corresponding to the current level
	//	3.		record the number associated with the button
	//	4.		no additional scan is possible until the number is cleared by btnGet

	if (btnSnapShotState) {
		//	only scan if the last event is not cleared
		do {
			kpDefStChgFn(btnState, btnChange);	//	interpret one key
			thisKey = kpDefGetKey();
			//	does it match a button?
			if (thisKey == -1) {
				btnCurButton = NULL;
			} else {
				btnCurButton = btnSearchXY(thisKey & 7, ~(thisKey >> 3) & 7, btnLevel);
			}
		} while ((thisKey != -1) && (btnCurButton == NULL));
		if (btnCurButton != NULL) {
			//	we do have a key pressed
			//	yes, the key matches a button
			if (btnCurButton != NULL) {
				glSetBrushType(GL_XOR);
				btnDrawMask(btnCurButton->x, btnCurButton->y, btnCurButton->w, btnCurButton->h);
				btnEvent = btnCurButton->command;
				if (thisKey < 256) {
					// it is pressed now
					btnBeep(1);
				} else {
					//	it is depressed now
					btnBeep(0);
					btnEvent += BTN_RELEASED;	//	indicate depression
				}
			}
		} else {
			//	no key interpreted, we're done
			btnEvent = -1;		//	so we can re-register another snapshot
			btnSnapShotState = 0;	//	indicate snapshot is done with
		}
	}
	return btnEvent;
}

#define BTN_INCSEC	1
#define BTN_DECSEC	2
#define BTN_INCMIN	3
#define BTN_DECMIN	4
#define BTN_INCHOUR	5
#define BTN_DECHOUR	6
#define BTN_INCDAY	7
#define BTN_DECDAY	8
#define BTN_INCMON	9
#define BTN_DECMON	10
#define BTN_INCYEAR	11
#define BTN_DECYEAR	12

#define BTN_OKAY		1
#define BTN_QUIT		2

#define BTN_INC		1
#define BTN_DEC		2

#define BTN_INCPER	2000		//	every 2000ms, increment the delta
#define BTN_REPEATPER 100		//	every 100ms, make another auto repeat

/* the following function changes the time based on the button event.
	If the event is processed, the function returns -1. Otherwise, the
	event is returned. Note that this function does not directly deal
	with the keypad or the screen, just using the key code to change
	the time. The time changed is reflected by the struct tm pointed
	to by "pTm". */

/* START FUNCTION DESCRIPTION ********************************************
btnSetTime

SYNTAX:			int btnSetTime(struct tm *pTm, int keypressed);

DESCRIPTION:	This function interprets a button command and updates a
time structure accordingly. The recognized button command are as follows:

	BTN_INCSEC to increment second
	BTN_DECSEC to decrement second
	BTN_INCMIN to increment minute
	BTN_DECMIN to decrement minute
	BTN_INCHOUR to increment hour
	BTN_DECHOUR to decrement hour

PARAMETER1:		A pointer to the time structure to be modified.

PARAMETER2:		The button command.

RETURN VALUE:	If the button code is indeed one of the commands recognized,
the function returns -1 to indicate the command is interpreted. Otherwise,
the button code is returned.

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

int btnSetTime(struct tm *pTm, int keypressed) {
	//	returns -1 if the key is processed
	//	otherwise returns the key itself
	auto unsigned long iTime;
	auto int result;

	result = -1;
	iTime = mktime(pTm);
	switch (keypressed) {
		case BTN_INCSEC:
			++iTime;
			break;
		case BTN_DECSEC:
			--iTime;
			break;
		case BTN_INCMIN:
			iTime += 60UL;
			break;
		case BTN_DECMIN:
			iTime -= 60UL;
			break;
		case BTN_INCHOUR:
			iTime += 3600UL;
			break;
		case BTN_DECHOUR:
			iTime -= 3600UL;
			break;
		default:
			result = keypressed;
	}
	if (result == -1) {
		mktm(pTm, iTime);
	}
	return result;
}

/* the following function changes the date based on the button event.
	If the event is processed, the function returns -1. Otherwise, the
	event is returned. Note that this function does not directly deal
	with the keypad or the screen, just using the key code to change
	the date. The time changed is reflected by the struct tm pointed
	to by "pTm".*/

/* START FUNCTION DESCRIPTION ********************************************
btnSetDate

SYNTAX:			int btnSetDate(struct tm *pTm, int keypressed);

DESCRIPTION:	This function interprets a button command and updates a
time structure accordingly. The recognized button command are as follows:

	BTN_INCDAY to increment day
	BTN_DECDAY to decrement day
	BTN_INCMON to increment month
	BTN_DECMON to decrement month
	BTN_INCYEAR to increment year
	BTN_DECYEAR to decrement year

PARAMETER1:		A pointer to the time structure to be modified.

PARAMETER2:		The button command.

RETURN VALUE:	If the button code is indeed one of the commands recognized,
the function returns -1 to indicate the command is interpreted. Otherwise,
the button code is returned.

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

int btnSetDate(struct tm *pTm, int keypressed) {
	//	returns -1 if the key is processed
	//	otherwise returns the key itself
	auto unsigned long iTime;
	auto int result;

	result = -1;
	iTime = mktime(pTm);
	switch (keypressed) {
		case BTN_INCDAY:
			iTime += 3600UL*24;
			mktm(pTm, iTime);
			break;
		case BTN_DECDAY:
			iTime -= 3600UL*24;
			mktm(pTm, iTime);
			break;
		case BTN_INCMON:
			if (pTm->tm_mon >= 12) {
				if (pTm->tm_year < 179) {
					pTm->tm_mon = 1;
					++pTm->tm_year;
				}
			} else {
				++pTm->tm_mon;
			}
			break;
		case BTN_DECMON:
			if (pTm->tm_mon <= 1) {
				if (pTm->tm_year > 80) {
					pTm->tm_mon = 12;
					--pTm->tm_year;
				}
			} else {
				--pTm->tm_mon;
			}
			break;
		case BTN_INCYEAR:
			if (pTm->tm_year < 179) ++pTm->tm_year;
			break;
		case BTN_DECYEAR:
			if (pTm->tm_year > 80) --pTm->tm_year;
			break;
		default:
			result = keypressed;
			break;
	}
	return result;
}

int btnSetInt(int *pInt, int keypressed, int max, int min) {
	//	returns -1 if the key is processed
	//	otherwise returns the key itself
}

int btnSetBool(int *pBoolean, int keypressed) {
	//	returns -1 if the key is processed
	//	otherwise returns the key itself
}

/********************* END OF BUTTONS ****************************/

/********************* BEGIN OF DISPLAY **************************/

/* menuFi keeps track of the font used for menu items */

struct _fontInfo fi, menuFi;	//	declare struct to hold font information

/* names for the months */

char *monthName[] = {
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec"
};

/* the following function displays the date (in DD MMM, YYYY format) on the
	screen. coordinates are in pixels. */

/* START FUNCTION DESCRIPTION ********************************************
dpDate

SYNTAX:			void dpDate(int x, int y, struct tm *pTm);

DESCRIPTION:	This function displays a date. The font info structure
menuFi is used and the date format is expressed as YYYY mmm, DD.

PARAMETER1:		the x coordinate of the upper left corner of text in pixels.

PARAMETER2:		the y coordinate of the upper left corner of text in pixels.

PARAMETER3:		a pointer to the time structure to be displayed.

RETURN VALUE:	N/A

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

void dpDate(int x, int y, struct tm *pTm) {
	glPrintf(x,y,&menuFi,"%04d %s, %02d",
		pTm->tm_year + 1900, monthName[pTm->tm_mon-1], pTm->tm_mday);
}

/* the following function displays the time (in HH : MM : SS format) on the
	screen. coordinates are in pixels. */

/* START FUNCTION DESCRIPTION ********************************************
dpTime

SYNTAX:			void dpTime(int x, int y, struct tm *pTm);

DESCRIPTION:	This function displays a time. The font info structure
menuFi is used and the date format is expressed as HH : MM : SS.

PARAMETER1:		the x coordinate of the upper left corner of text in pixels.

PARAMETER2:		the y coordinate of the upper left corner of text in pixels.

PARAMETER3:		a pointer to the time structure to be displayed.

RETURN VALUE:	N/A

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

void dpTime(int x, int y, struct tm *pTm) {
	glPrintf(x,y,&menuFi,"%02d : %02d : %02d",
		pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
}

/* the following function displays an integer in decimal form on the screen,
	coordinates are in pixels. */

/* START FUNCTION DESCRIPTION ********************************************
dpIntegerD

SYNTAX:			void dpIntegerD(int x, int y, int integer);

DESCRIPTION:	This function displays an integer is decimal digits. The
font info structure menuFi is used.

PARAMETER1:		the x coordinate of the upper left corner of text in pixels.

PARAMETER2:		the y coordinate of the upper left corner of text in pixels.

PARAMETER3:		the integer value to display.

RETURN VALUE:	N/A

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

void dpIntegerD(int x, int y, int integer) {
	glPrintf(x,y,&menuFi,"%5d",integer);
}

/********************* END OF DISPLAY ****************************/


/********************* BEGIN OF MENUS ****************************/

/* constant to indicate a key is processed */

#define MNU_KEYPROCESSED -1

/* constant to indicate okay is pressed for a menu */

#define MNU_OKAY -2

/* constant to indicate quit is pressed for a menu */

#define MNU_QUIT -3

/* this is a structure for a generic menu */

struct _mnuGeneric {
	int x,y;				//	the "home" (north west) corner of a menu
//	CoData instance;
	int cmdOffset;		//	the offset of commands. All commands should
							//	have this constant subtracted before being
							//	interpreted. With the offset, multiple menus
							//	can be active at the same time.
};

/* this is a structure for a date menu */

struct _mnuDate {
	struct _mnuGeneric menu;		//	a date menu is a generic menu
	struct tm *pTm;					//	plus it keeps track of a pointer to
											//	a struct tm that stores the date
											//	being displayed/edited
};

/* a time menu has the same fields as a date menu */

#define _mnuTime _mnuDate

/* this is a struct for a set time menu. A set time menu is a generic
	menu, but has a date menu and time menu embedded in it. localTm is
	the local storage for the time/date being edited. "okay" indicates
	whether the user has pressed the okay button. */

struct _mnuSetTime {
	struct _mnuGeneric menu;
	struct _mnuDate menuDate;
	struct _mnuTime menuTime;
	struct tm localTm;
	int okay;				//	was okay pressed
};

/* this is a struct for a set integer menu. A set integer menu is a
	generic menu, but it needs to maintain additional information */

struct _mnuInteger {
	struct _mnuGeneric menu;
	unsigned int lastRepeatTime;	//	stores the ms mark of the last
											//	auto repeat instance time
	unsigned int lastIncTime;		//	stores the ms mark of the last
											//	auto repeat count increment time
	int delta;							//	stores the current delta for auto
											//	in/decrement
	int *pValue;						//	stores the pointer to the integer
											//	being modified
	int *pMax;							//	stores the pointer to the integer
											//	indicating the maximum
	int *pMin;							//	stores the pointer to the integer
											//	indicating the minimum
};

/* a set contrast menu is a generic menu with a built-in integer
	menu and an okay button */

struct _mnuSetContr {
	struct _mnuGeneric menu;
	struct _mnuInteger menuContrast;
	int okay;				//	was okay pushed?
};

/* a demo menu is a generic menu with an okay button */

struct _mnuDemo {
	struct _mnuGeneric menu;
	int okay;				//	was okay pushed?
};

/* the following function constructs the buttons needed for a set date
	menu */

void mnuDateInit(struct _mnuDate *pmd, int cmdOffset, int x, int y, struct tm *t) {
	pmd->menu.x = x;
	pmd->menu.y = y;
	pmd->menu.cmdOffset = cmdOffset;

	++y;

	pmd->pTm = t;
	
	btnAdd(x,y,1,1,"+yr",BTN_INCYEAR+pmd->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-yr",BTN_DECYEAR+pmd->menu.cmdOffset);
	btnAdd(++x,y,1,1,"+mon",BTN_INCMON+pmd->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-mon",BTN_DECMON+pmd->menu.cmdOffset);
	btnAdd(++x,y,1,1,"+day",BTN_INCDAY+pmd->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-day",BTN_DECDAY+pmd->menu.cmdOffset);
}

/* the following function displays the date for a set date menu */

void mnuDateUpdate(struct _mnuDate *pmd) {
	dpDate(pmd->menu.x*BTN_HSPACE,(pmd->menu.y+1)*BTN_VSPACE-menuFi.pixHeight,pmd->pTm);
}

/* the following function processes the key event to a set date menu. If the
	key event is not processed, it is returned as is. Otherwise, the function
	returns -1. Note that this function does interact with the display. */

int mnuDateRun(struct _mnuDate *pmd, int key) {
	auto int result;

	glSetBrushType(GL_BLOCK);
	mnuDateUpdate(pmd);
	if (btnSetDate(pmd->pTm, key-pmd->menu.cmdOffset) == -1) {
		glSetBrushType(GL_BLOCK);
		mnuDateUpdate(pmd);
		result = -1;
	} else {
		result = key;
	}
	return result;
}

/* the following function constructs buttons for a set time menu */

void mnuTimeInit(struct _mnuTime *pmt, int cmdOffset, int x, int y, struct tm *t) {
	pmt->menu.x = x;
	pmt->menu.y = y;
	pmt->menu.cmdOffset = cmdOffset;

	++y;

	pmt->pTm = t;
	
	btnAdd(x,y,1,1,"+hr",BTN_INCHOUR+pmt->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-hr",BTN_DECHOUR+pmt->menu.cmdOffset);
	btnAdd(++x,y,1,1,"+min",BTN_INCMIN+pmt->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-min",BTN_DECMIN+pmt->menu.cmdOffset);
	btnAdd(++x,y,1,1,"+sec",BTN_INCSEC+pmt->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-sec",BTN_DECSEC+pmt->menu.cmdOffset);
}

/* the following function displays the time for a set time menu */

void mnuTimeUpdate(struct _mnuTime *pmt) {
	dpTime(pmt->menu.x*BTN_HSPACE,(pmt->menu.y+1)*BTN_VSPACE-menuFi.pixHeight,pmt->pTm);
}

/* the following function processes the key event to a set time menu. If the
	key event is not processed, it is returned as is. Otherwise, the function
	returns -1. Note that this function does interact with the display. */

int mnuTimeRun(struct _mnuTime *pmt, int key) {
	auto int result;

	glSetBrushType(GL_BLOCK);
	mnuTimeUpdate(pmt);
	if (btnSetTime(pmt->pTm, key-pmt->menu.cmdOffset) == -1) {
		glSetBrushType(GL_BLOCK);
		mnuTimeUpdate(pmt);
		result = -1;
	} else {
		result = key;
	}
	return result;
}

/* the following function displays an integer for a set integer menu */

void mnuIntDUpdate(struct _mnuInteger *pmi) {
	dpIntegerD(pmi->menu.x*BTN_HSPACE,(pmi->menu.y+1)*BTN_VSPACE-menuFi.pixHeight,*pmi->pValue);
}

/* the following function sets up the buttons for a set integer menu */

//void mnuIntDInit(struct _mnuInteger *pmi) {
//}

/* the following function sets up a integer menu */

void mnuIntDInit(struct _mnuInteger *pmi, int cmdOffset, int x, int y, int *pValue, int *pMax, int *pMin) {
	pmi->menu.x = x;
	pmi->menu.y = y;
	pmi->menu.cmdOffset = cmdOffset;
	pmi->pMax = pMax;
	pmi->pMin = pMin;
	pmi->pValue = pValue;
	pmi->delta = 0;

	x = pmi->menu.x;
	y = pmi->menu.y+1;
	
	btnAdd(x,y,1,1,"+",BTN_INC+pmi->menu.cmdOffset);
	btnAdd(x,y+1,1,1,"-",BTN_DEC+pmi->menu.cmdOffset);
}

/* the following function processes the key event to a set integer menu. If the
	key event is not processed, it is returned as is. Otherwise, the function
	returns -1. Note that this function does interact with the display. */

int mnuIntDRun(struct _mnuInteger *pmi, int key) {
	auto int result;

	glSetBrushType(GL_BLOCK);
	mnuIntDUpdate(pmi);
	switch (key - pmi->menu.cmdOffset) {
		case BTN_INC:
			pmi->delta = 1;
			result = -1;
			break;
		case BTN_DEC:
			pmi->delta = -1;
			result = -1;
			break;
		case BTN_INC+BTN_RELEASED:
			pmi->delta = 0;
			result = -1;
			break;
		case BTN_DEC+BTN_RELEASED:
			pmi->delta = 0;
			result = -1;
			break;
		default:
			result = key;
			break;
	}
	if ((result != key) || (pmi->delta != 0)) {
		//	we are in the middle of something
		if ((unsigned)MS_TIMER - pmi->lastIncTime > BTN_INCPER) {
			//	need to adjust the increment value
			pmi->delta *= 2;
			pmi->lastIncTime = (unsigned)MS_TIMER;
		}
		if ((result != key) || ((unsigned)MS_TIMER - pmi->lastRepeatTime > BTN_REPEATPER)) {
			*pmi->pValue += pmi->delta;
			pmi->lastRepeatTime = (unsigned)MS_TIMER;
			if ((*pmi->pValue > *pmi->pMax) || (*pmi->pValue < *pmi->pMin)) {
				//	if we are out of range, readjust
				*pmi->pValue -= pmi->delta;
			} else {
				//	if the change didn't make us out of range, update on screen
				mnuIntDUpdate(pmi);
			}
		}
	}
	return result;
}

/********************* END OF MENUS ******************************/

#define NUM_PLAYBUTTON 5

char *playButtonNames[NUM_PLAYBUTTON] = {
	"clock",
	"ctrst",
	"bklit",
	"beep",
	"demo"
//	"exit"
};

#define CMD_CLOCK 11
#define CMD_CONTRAST 12
#define CMD_BACKLIGHT 13
#define CMD_BEEPER 14
#define CMD_DEMO 15
//#define CMD_EXIT 16

int playButtonCmd[NUM_PLAYBUTTON] = {
	CMD_CLOCK,
	CMD_CONTRAST,
	CMD_BACKLIGHT,
	CMD_BEEPER,
	CMD_DEMO
//	CMD_EXIT
};

#define CMD_MENU 1

void setTopButton() {
	btnAdd(4,7,1,1,"menu",CMD_MENU);
}

void setPlayButtons() {
	auto int i;

	for (i = 0; i < NUM_PLAYBUTTON; ++i) {
		btnAdd(7,i,1,1,playButtonNames[i],playButtonCmd[i]);
	}
}

#define MNU_CONFIRM 40

/* the following function initializes a set time menu */

void mnuSetTimeInit(struct _mnuSetTime *pmst, int cmdOffset, int x, int y, struct tm *pt) {
	pmst->menu.cmdOffset = cmdOffset;
	pmst->menu.x = x;
	pmst->menu.y = y;
	
	pmst->localTm = *pt;
	
//	CoBegin(&menuTime.menu.instance);
	mnuDateInit(&pmst->menuDate, cmdOffset, x, y, &pmst->localTm);
	mnuDateUpdate(&pmst->menuDate);
	mnuTimeInit(&pmst->menuTime, cmdOffset, x+3, y, &pmst->localTm);
	mnuTimeUpdate(&pmst->menuTime);
	btnAdd(x,y+3,1,1,"okay",BTN_OKAY+MNU_CONFIRM+cmdOffset);
	btnAdd(x+5,y+3,1,1,"quit",BTN_QUIT+MNU_CONFIRM+cmdOffset);
//	btnRepaint();
}

/* the following function interprets key events for a set time menu. Note that
	the screen is updated by this function */

int mnuSetTimeRun(struct _mnuSetTime *pmst, int thisKey) {
	//	one scan of the keypad may return multiple key events
	//	handle all key events reported by this scan
	if ((thisKey = mnuTimeRun(&pmst->menuTime,thisKey)) == -1) {
		mnuDateUpdate(&pmst->menuDate);
	} else if ((thisKey = mnuDateRun(&pmst->menuDate,thisKey)) == -1) {
	} else {
		switch (thisKey - MNU_CONFIRM - pmst->menu.cmdOffset) {
			case BTN_OKAY:
				thisKey = MNU_OKAY;
				pmst->okay = 1;
				break;
			case BTN_QUIT:
				thisKey = MNU_QUIT;
				pmst->okay = 0;
				break;
			default:
				break;
		}
	}
	return thisKey;
}

void mnuSetContrInit(struct _mnuSetContr *pmsc, int cmdOffset, int x, int y, int *pContrast) {
	static int maxContrast = 63;
	static int minContrast = 0;
	
	pmsc->menu.cmdOffset = cmdOffset;
	pmsc->menu.x = x;
	pmsc->menu.y = y;
	
	mnuIntDInit(&pmsc->menuContrast,cmdOffset,x,y,pContrast,&maxContrast,&minContrast);
	
	btnAdd(x+1,y,1,1,"okay",BTN_OKAY+MNU_CONFIRM+cmdOffset);
	btnAdd(x+1,y+2,1,1,"quit",BTN_QUIT+MNU_CONFIRM+cmdOffset);
}

int mnuSetContrRun(struct _mnuSetContr *pmsc, int thisKey) {
	
	//	one scan of the keypad may return multiple key events
	//	handle all key events reported by this scan
	thisKey = mnuIntDRun(&pmsc->menuContrast,thisKey);
	op71SetContrast(*pmsc->menuContrast.pValue);
	if (thisKey >= 0) {
		switch (thisKey - MNU_CONFIRM - pmsc->menu.cmdOffset) {
			case BTN_OKAY:
				thisKey = MNU_OKAY;
				pmsc->okay = 1;
				break;
			case BTN_QUIT:
				thisKey = MNU_QUIT;
				pmsc->okay = 0;
				break;
			default:
				break;
		}
	}
	return thisKey;
}

CoData demoCD;

void mnuDemoInit(struct _mnuDemo *pmd, int cmdOffset, int x, int y) {
	static int maxContrast = 63;
	static int minContrast = 0;
	
	pmd->menu.cmdOffset = cmdOffset;
	pmd->menu.x = x;
	pmd->menu.y = y;

	CoBegin(&demoCD);
	
	btnAdd(x,y,1,1,"quit",BTN_QUIT+MNU_CONFIRM+cmdOffset);
}

void demoTask() {
	static int x,y,cnt,i;
	static struct _fontInfo custFont;
	
	costate demoCD {
		while (1) {
			//	display bitmap
			glBuffLock();
			glSetBrushType(GL_CLEAR);
			op71Block(BTN_HSPACE,0,320-BTN_HSPACE,BTN_VSPACE);

			op71Block(0,BTN_VSPACE,320,240-BTN_VSPACE);

			glSetBrushType(GL_SET);
			glPrintf(BTN_HSPACE,0,&fi,"display bitmaps");
			glBuffUnlock();
			for (y = BTN_VSPACE; y < 240-54; y += 54) {
				for (x = 0; x < 320-127; x += 127) {
					glXPutBitmap(x,y,127,54,zlogo128);
					yield;
				}
			}
			for (cnt = 0; cnt < 3; ++cnt) {
				for (y = BTN_VSPACE; y < 240-54; y += 54) {
					for (x = 0; x < 320-127; x += 127) {
						glSetBrushType(GL_XOR);
						op71Block(x,y,127,54);
						waitfor(DelayMs(300));
					}
				}
			}
			
			//	display text
			glSetBrushType(GL_CLEAR);
			glBuffLock();
			op71Block(BTN_HSPACE,0,320-BTN_HSPACE,BTN_VSPACE);

			op71Block(0,BTN_VSPACE,320,240-BTN_VSPACE);
			
			glSetBrushType(GL_SET);
			glPrintf(BTN_HSPACE,0,&fi,"variable fonts");
			glPrintf(0,BTN_VSPACE,&fi,"6x8");
			glPrintf(0,BTN_VSPACE+8,&menuFi,"8x10");
			glXFontInit(	//	initialize the font info structure needed later
				&custFont,	//	pointer to the font info structure to fill
				12,				//	horizontal size (in pixels) of each character
				16,				//	vertical size (in pixels) of each character
				32,			//	beginning code of printable characters
				127,			//	ending code of printable characters
				engFont12x16	//	address of font bitmap in xmem
				);
			glPrintf(0,BTN_VSPACE+8+10,&custFont,"12x16");
			glXFontInit(	//	initialize the font info structure needed later
				&custFont,	//	pointer to the font info structure to fill
				16,				//	horizontal size (in pixels) of each character
				32,				//	vertical size (in pixels) of each character
				32,			//	beginning code of printable characters
				127,			//	ending code of printable characters
				engFont16x32	//	address of font bitmap in xmem
				);
			glPrintf(0,BTN_VSPACE+8+10+16,&custFont,"16x32");
			glXFontInit(	//	initialize the font info structure needed later
				&custFont,	//	pointer to the font info structure to fill
				17,				//	horizontal size (in pixels) of each character
				35,				//	vertical size (in pixels) of each character
				32,			//	beginning code of printable characters
				127,			//	ending code of printable characters
				engFont17x35a	//	address of font bitmap in xmem
				);
			glPrintf(0,BTN_VSPACE+8+10+16+32,&custFont,"17x35");
			glBuffUnlock();
			waitfor(DelayMs(3000));
			
			//	draw lines
			glSetBrushType(GL_CLEAR);
			glBuffLock();
			op71Block(BTN_HSPACE,0,320-BTN_HSPACE,BTN_VSPACE);

			op71Block(0,BTN_VSPACE,320,240-BTN_VSPACE);

			glSetBrushType(GL_SET);			
			glPrintf(BTN_HSPACE,0,&fi,"draw lines");
			glBuffUnlock();

			for (i = 0; i < 40; ++i) {
				glBuffLock();
				glPlotLine(i*8,BTN_VSPACE,319,BTN_VSPACE+i*5);
				glPlotLine(319,BTN_VSPACE+i*5,319-i*8,BTN_VSPACE+199);
				glPlotLine(319-i*8,BTN_VSPACE+199,0,BTN_VSPACE+199-i*5);
				glPlotLine(0,BTN_VSPACE+199-i*5,i*8,BTN_VSPACE);
				glBuffUnlock();
				yield;
			}
			
			waitfor(DelayMs(3000));
			
			//	draw polygons
			
			//	draw circles
			glSetBrushType(GL_CLEAR);
			glBuffLock();
			op71Block(BTN_HSPACE,0,320-BTN_HSPACE,BTN_VSPACE);

			op71Block(0,BTN_VSPACE,320,240-BTN_VSPACE);

			glSetBrushType(GL_SET);			
			glPrintf(BTN_HSPACE,0,&fi,"draw circles");
			glBuffUnlock();

			for (i = 0; i < 20; ++i) {
				glPlotCircle(159,120+BTN_VSPACE/2,i*5);
				yield;
			}
			
			waitfor(DelayMs(3000));
			
			//	clear screen
		}
	}
}

int mnuDemoRun(struct _mnuDemo *pmsc, int thisKey) {
	//	one scan of the keypad may return multiple key events
	//	handle all key events reported by this scan
	demoTask();
	if (thisKey >= 0) {
		switch (thisKey - MNU_CONFIRM - pmsc->menu.cmdOffset) {
			case BTN_OKAY:
				thisKey = MNU_OKAY;
				pmsc->okay = 1;
				break;
			case BTN_QUIT:
				thisKey = MNU_QUIT;
				pmsc->okay = 0;
				break;
			default:
				break;
		}
	}
	return thisKey;
}

#define SCR_SETTIME 1
#define SCR_ENTRY 2
#define SCR_MAIN 3
#define SCR_SETCONTR 4
#define SCR_DEMO 5

void main() {
	auto int i;
	auto struct tm t, t1;
	auto struct _mnuSetTime mst;
	auto struct _mnuSetContr msc;
	auto struct _mnuDemo md;
	auto int thisKey;
	auto int screen, prevScreen;
	auto int contrast;
	auto int prevContrast;
	
	VdInit();
	glInit();

	glBlankScreen();
	op71BackLight(1);
	op71SetContrast(30);
	glSetBrushType(GL_XOR);
	glXFontInit(	//	initialize the font info structure needed later
		&fi,			//	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
		);
	btnFi = &fi;
	btnInit();
	glXFontInit(	//	initialize the font info structure needed later
		&menuFi,		//	pointer to the font info structure to fill
		8,				//	horizontal size (in pixels) of each character
		10,				//	vertical size (in pixels) of each character
		32,			//	beginning code of printable characters
		127,			//	ending code of printable characters
		engFont8x10	//	address of font bitmap in xmem
		);
	setPlayButtons();
	screen = SCR_MAIN;
	prevScreen = SCR_MAIN+1;
//	setTopButton();
//	screen = SCR_ENTRY;
//	btnRepaint();

	contrast = 30;
	op71SetContrast(contrast);
	
	while (1) {
		costate {
			kpScanState();
			waitfor(IntervalMs(50));
			thisKey = btnGet();
			do {
				if (screen != prevScreen) {
					switch (screen) {
						case SCR_MAIN:
							glBlankScreen();
							btnRepaint();
							glXPutBitmap(0,(240-115)/2,268,115,zlogo268);
							break;
						default:
							break;
					}
				}
				prevScreen = screen;
				switch (screen) {
					case SCR_SETTIME:
						switch (mnuSetTimeRun(&mst, thisKey)) {
							case MNU_KEYPROCESSED: //	key is processed, but not done
								break;
							case MNU_OKAY:	//	key is processed, and okay
								tm_wr(&mst.localTm);	//	save the result
								btnPopLevel();
								screen = SCR_MAIN;
								break;
							case MNU_QUIT:	//	key is processed, and quit
								btnPopLevel();
								screen = SCR_MAIN;
								break;
						}
						break;
					case SCR_SETCONTR:
						switch (mnuSetContrRun(&msc, thisKey)) {
							case MNU_KEYPROCESSED: //	key is processed, but not done
								break;
							case MNU_OKAY:	//	key is processed, and okay
								glBlankScreen();
								btnPopLevel();
								btnRepaint();
								screen = SCR_MAIN;
								break;
							case MNU_QUIT:	//	key is processed, and quit
								contrast = prevContrast;		//	since we are quitting
								op71SetContrast(contrast);		//	we need to restore the
								btnPopLevel();						//	prev. constrast
								screen = SCR_MAIN;
								break;
						}
						break;
					case SCR_DEMO:
						switch (mnuDemoRun(&md, thisKey)) {
							case MNU_KEYPROCESSED: //	key is processed, but not done
								break;
							case MNU_QUIT:	//	key is processed, and quit
								btnPopLevel();
								screen = SCR_MAIN;
								break;
						}
						break;
					case SCR_MAIN:
						switch (thisKey) {
							case CMD_CLOCK:
								glBlankScreen();
								btnPushLevel();
								tm_rd(&t);
								mnuSetTimeInit(&mst, 0, 0, 0, &t);
								btnRepaint();
								screen = SCR_SETTIME;
								break;
							case CMD_BACKLIGHT:
								op71BackLight(0);
								break;
							case (CMD_BACKLIGHT+BTN_RELEASED):
								op71BackLight(1);
								break;
							case CMD_CONTRAST:
								glBlankScreen();
								btnPushLevel();
								mnuSetContrInit(&msc, 0, 0, 0, &contrast);
								btnRepaint();
								screen = SCR_SETCONTR;
								prevContrast = contrast;
								break;
							case CMD_DEMO:
								glBlankScreen();
								btnPushLevel();
								mnuDemoInit(&md, 0, 0, 0);
								btnRepaint();
								screen = SCR_DEMO;
								break;
//							case CMD_EXIT:
//								glBlankScreen();
//								btnPopLevel();
//								btnRepaint();
//								screen = SCR_ENTRY;
								break;
							default:
								break;
						}
						break;
//					case SCR_ENTRY:
//						switch (thisKey) {
//							case CMD_MENU:
//								btnPushLevel();
//								setPlayButtons();
//								glBlankScreen();
//								btnRepaint();
//								screen = SCR_MAIN;
//								break;
//						}
						break;
				}
				thisKey = btnGet();
			} while (thisKey >=  0);
		}
	}
}
