/***************************************************************************

  vidhrdw.c

  Functions to emulate the video hardware of the machine.

***************************************************************************/

#include "driver.h"
#include "vidhrdw/generic.h"
#include "M6809.h"

/*  Stuff that work only in MS DOS (Color cycling)
 */

#define MS_DOS_ONLY

/*  The normal height for a Williams game is 256, but not all the
 *  lines are used. 240 lines is just enough and more compatible
 *  with the PC resolutions
 */

#define HEIGHT_240

/*  Skip some lines at the top of the screen because we lose bottom lines
 *  used only with HEIGHT_240
 */

#define START_OFFSET 4
#define VIDEO_RAM_SIZE 0x9800

extern int video_counter;
extern int defender_bank;
extern int bank_address;

/*  0 = I/O
 *  1 = BANK 1
 *  2 = BANK 2
 *  3 = BANK 3
 *  7 = BANK 4
 */


int Erase_screen_each_vbl;

void Williams_Palette_w(int offset,int data);

static unsigned char *williams_videoram;
static struct osd_bitmap *williams_bitmap;

static char BlasterRemapProm[];




void williams_vh_convert_color_prom(unsigned char *palette, unsigned char *colortable,const unsigned char *color_prom)
{
	int i;


	for (i = 0;i < 256;i++)
	{
		int bit0,bit1,bit2;


		bit0 = (i >> 0) & 0x01;
		bit1 = (i >> 1) & 0x01;
		bit2 = (i >> 2) & 0x01;
		palette[3*i + 0] = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
		bit0 = (i >> 3) & 0x01;
		bit1 = (i >> 4) & 0x01;
		bit2 = (i >> 5) & 0x01;
		palette[3*i + 1] = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
		bit0 = 0;
		bit1 = (i >> 6) & 0x01;
		bit2 = (i >> 7) & 0x01;
		palette[3*i + 2] = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
	}

	/* Colors for mame messages */
	colortable[0] = 0;
	colortable[1] = 0xff; /* White */
	colortable[2] = 0;
	colortable[3] = 0x3f; /* Yellow */
	colortable[4] = 0;
	colortable[5] = 0x07; /* Red */
}


/**************
 * Get a Pixel in the real bitmap
 */
inline int GetPix(int x,int y)
{
	return williams_bitmap->line[x][y];
}


/**************
 * Put a Pixel in the real bitmap
 */
inline void PutPix(int x,int y,int p)
{
	williams_bitmap->line[x][y] = p;
}



/**************
 *
 */
void williams_videoram_w(int offset,int data)
{
        int x,y;

        /* Put the byte in the videoram */
        williams_videoram[offset] = data;

        /* Put the pixels in our bitmap */
        x = offset % 256;
#ifdef HEIGHT_240
        x -= START_OFFSET;
        if (x<0)
          return;
        if (x>=240)
          return;
#endif
        y = offset / 256;
        PutPix(x, (y*2),   data>>4);
        PutPix(x, (y*2)+1, data & 0x0F);
}

/**************
 *
 */
void blaster_videoram_w(int offset,int data)
{
int x,y;


/*Put the byte in the videoram*/
	RAM[offset] = data;

/*Put the pixels in our bitmap*/
	x = offset % 256;
#ifdef HEIGHT_240
	x -= START_OFFSET;
	if(x<0)
		return;
	if(x>=240)
		return;
#endif
	y = offset / 256;
	PutPix(x,(y*2),data>>4);
	PutPix(x,(y*2)+1,data&0x0F);

}

/**************
 *
 */
int williams_videoram_r(int offset)
{
        /* Read the video ram or the ROM */
        if(RAM[0xc900] == 0){
            if(offset>>8 >= 0x98)
	           return RAM[offset];
            else
	           return williams_videoram[offset];
        }else
            return RAM[offset];
}


/**************
 *
 */
int blaster_videoram_r(int offset)
{

	if(offset>>8 < 0x40)
		if(RAM[0xc900] == 0){
			return RAM[offset];
	}else{
		return RAM[bank_address+offset];
	}


/*   Read the video ram or the ROM
 */

 if(RAM[0xc900] == 0){
	 return RAM[offset];
 }else
  if(offset>>8 >= 0x97)
	 return RAM[offset];
  else
	 return RAM[0x40000+offset];
}




/**************
 * Write in the video ram for the blitter
 */
void williams_videoram_blitter_w(int offset,int data,int flag)
{
int x,y;
int p1,p2,pb1,pb2;


/*  Calcul the real x-y
 */

  x = offset % 256;
  y = offset / 256;
#ifdef HEIGHT_240
  x -= START_OFFSET;
  if(x<0)
    return;
  if(x>=240)
    return;
#endif

/*   Source pixels
 */

 p1 = data >> 4;
 p2 = data & 0x0F;

/*
 1000 0000 Do not process half the byte 4-7
 0100 0000 Do not process half the byte 0-3
 0010 0000 Shift the shape one pixel right (to display a shape on an odd pixel)
 0001 0000 Remap, if shape != 0 then = mask
 0000 1000 Source  1 = take source 0 = take Mask only
 0000 0100
 0000 0010 Transparent
 0000 0001
*/

/*  Background pixels
 */

  if((flag & 0x20) == 0){
    pb1 = GetPix(x,(y*2));
    pb2 = GetPix(x,(y*2)+1);
  }else{
    pb1 = GetPix(x,(y*2)+1);
    pb2 = GetPix(x,(y*2)+2);
  }


/*  Not optimized yet, there must be a way to do that faster
 */
	if((flag & 0x08) == 0){
		if((flag & 0x10) == 0){
			if((flag & 0x80) == 0)
				pb1 = p1;
			if((flag & 0x40) == 0)
				pb2 = p2;
		}else{
			if((flag & 0x80) == 0)
				pb1 = RAM[0xCA01]>>4;
			if((flag & 0x40) == 0)
				pb2 = RAM[0xCA01]&0x0F;
		}
	}else{
		if((flag & 0x10) == 0){
			if(p1 != 0)
				if((flag & 0x80) == 0)
					pb1 = p1;
			if(p2 != 0)
				if((flag & 0x40) == 0)
					pb2 = p2;
		}else{
			if(p1 != 0)
				if((flag & 0x80) == 0)
					pb1 = RAM[0xCA01]>>4;
			if(p2 != 0)
				if((flag & 0x40) == 0)
					pb2 = RAM[0xCA01]&0x0f;
		}
	}


/*   Clip if outside the video then it is in RAM[]
 *   Bubble blit some code at $9800 +
 */

  if(offset>>8 >= 0x98){

/*   But do not write on ROM, Joust blit at $FXXX when a shape pass the
 *   left of the screen
 */

    if(offset>>8 >= 0xE0)
      return;
    RAM[offset] = data;
    return;
  }

/*  Put the byte in the videoram
 *  Not really good if flag & 0x20 != 0
 *  But the games seem to never read the video ram.
 */
	williams_videoram[offset] = (pb1<<4) + pb2;

/*  Put the pixels in our bitmap
 */

  if((flag & 0x20) == 0){
    PutPix(x,(y*2),pb1);
    PutPix(x,(y*2)+1,pb2);
  }else{
    PutPix(x,(y*2)+1,pb1);
    PutPix(x,(y*2)+2,pb2);
  }

}



/**************
 * Write in the video ram for the blitter
 * for Blaster only because this game use the Remap Prom
 */
void williams_videoram_blaster_blitter_w(int offset,int data,int flag)
{
int x,y;
int p1,p2,pb1,pb2;
int temp;

/*  Calcul the real x-y
 */

  x = offset % 256;
  y = offset / 256;
#ifdef HEIGHT_240
  x -= START_OFFSET;
  if(x<0)
    return;
  if(x>=240)
    return;
#endif

/*  For Blaster, Remap the byte with the Remap Prom
 */

temp = RAM[0xC940];
temp = temp * 16;
p1 = BlasterRemapProm[temp+(data>>4)];
p2 = BlasterRemapProm[temp+(data&0x0f)];

/*
 1000 0000 Do not process half the byte 4-7
 0100 0000 Do not process half the byte 0-3
 0010 0000 Shift the shape one pixel right (to display a shape on an odd pixel)
 0001 0000 Remap, if shape != 0 then = mask
 0000 1000 Source  1 = take source 0 = take Mask only
 0000 0100
 0000 0010 Transparent
 0000 0001
*/

/*  Background pixels
 */

  if((flag & 0x20) == 0){
    pb1 = GetPix(x,(y*2));
    pb2 = GetPix(x,(y*2)+1);
  }else{
    pb1 = GetPix(x,(y*2)+1);
    pb2 = GetPix(x,(y*2)+2);
  }


/*  Not optimized yet, there must be a way to do that faster
 */

	if((flag & 0x08) == 0){
		if((flag & 0x10) == 0){
			if((flag & 0x80) == 0)
				pb1 = p1;
			if((flag & 0x40) == 0)
				pb2 = p2;
		}else{
			if((flag & 0x80) == 0)
				pb1 = RAM[0xCA01]>>4;
			if((flag & 0x40) == 0)
				pb2 = RAM[0xCA01]&0x0F;
		}
	}else{
		if((flag & 0x10) == 0){
			if(p1 != 0)
				if((flag & 0x80) == 0)
					pb1 = p1;
			if(p2 != 0)
				if((flag & 0x40) == 0)
					pb2 = p2;
		}else{
			if(p1 != 0)
				if((flag & 0x80) == 0)
					pb1 = RAM[0xCA01]>>4;
			if(p2 != 0)
				if((flag & 0x40) == 0)
					pb2 = RAM[0xCA01]&0x0f;
		}
	}


/*  Clip if outside the video then it is in RAM[]
 *  Bubble blit some code at $9800 +
 */

  if(offset>>8 >= 0x98){

/*  But do not write on ROM, Joust blit at $FXXX when a shape pass the
 *  left of the screen
 */

    if(offset>>8 >= 0xE0)
      return;
    RAM[offset] = data;
    return;
  }


/*  Put the byte in the videoram
 *  Not really good if flag & 0x20 != 0
 *  But the games seem to never read the video ram.
 */

	RAM[offset] = (pb1<<4) + pb2;

/*  Put the pixels in our bitmap
 */

  if((flag & 0x20) == 0){
    PutPix(x,(y*2),pb1);
    PutPix(x,(y*2)+1,pb2);
  }else{
    PutPix(x,(y*2)+1,pb1);
    PutPix(x,(y*2)+2,pb2);
  }

}



/*
label CA01 blitter_mask
label CA02 blitter_source   hi
label CA03 blitter_source   lo
label CA04 blitter_dest     hi
label CA05 blitter_dest     lo
label CA06 blitter_w_h      H +1
label CA07 blitter_w_h      W +1
*/

#define SCREEN_WIDTH 256


/**************
 *
 */
void williams_StartBlitter(int offset,int data)
{
int i,j,offs;
unsigned short source,dest,start;

  offs = SCREEN_WIDTH - RAM[0xCA07];
  source = (RAM[0xCA02]<<8) + RAM[0xCA03];
  start = (RAM[0xCA04]<<8) + RAM[0xCA05];
  dest = start;


if((RAM[0xCA06]^4) == 0){

/*  Special case for Bubbles , will work correctly when my blitter routine
 *  will check the transparent flag
 *  Blit some code from rom to ram.
 */

  for(i=0;i<=(RAM[0xCA07]^4);i++){
    for(j=0;j<=(RAM[0xCA06]^4);j++){

/*      williams_videoram_blitter_w(dest,williams_videoram_r(source),data);
 */
      williams_videoram_blitter_w(dest,RAM[source],data);
      source++;
      dest+=SCREEN_WIDTH;
    }
    start += 1;
    dest = start;
  }
}else{
  for(i=0;i<(RAM[0xCA07]^4);i++){
    for(j=0;j<(RAM[0xCA06]^4);j++){
      williams_videoram_blitter_w(dest,williams_videoram_r(source),data);
      source++;
      dest+=SCREEN_WIDTH;
    }
    start += 1;
    dest = start;
  }
}

/*  Log blits
 */

	if (errorlog){
	 fprintf(errorlog,"---------- Blit %02X--------------PC: %04X\n",data,m6809_GetPC());
	 fprintf(errorlog,"Source : %02X %02X\n",RAM[0xCA02],RAM[0xCA03]);
	 fprintf(errorlog,"Dest   : %02X %02X\n",RAM[0xCA04],RAM[0xCA05]);
	 fprintf(errorlog,"W H    : %02X %02X (%d,%d)\n",RAM[0xCA06],RAM[0xCA07],RAM[0xCA06]^4,RAM[0xCA07]^4);
	 fprintf(errorlog,"Mask   : %02X\n",RAM[0xCA01]);
	}

}


/**************
 * Same as StartBlitter but call williams_videoram_blaster_blitter_w
 * instead of williams_videoram_blitter_w to remap with the Remap Prom
 */
void williams_BlasterStartBlitter(int offset,int data)
{
int i,j,offs;
unsigned short source,dest,start;

  offs = SCREEN_WIDTH - RAM[0xCA07];
  source = (RAM[0xCA02]<<8) + RAM[0xCA03];
  start = (RAM[0xCA04]<<8) + RAM[0xCA05];
  dest = start;

  for(i=0;i<RAM[0xCA07];i++){
    for(j=0;j<RAM[0xCA06];j++){
      williams_videoram_blaster_blitter_w(dest,blaster_videoram_r(source),data);
      source++;
      dest+=SCREEN_WIDTH;
    }
    start += 1;
    dest = start;
  }

/*  Log blits
 */
	if (errorlog){
	 fprintf(errorlog,"---------- Blit %02X--------------PC: %04X\n",data,m6809_GetPC());
	 fprintf(errorlog,"Source : %02X %02X\n",RAM[0xCA02],RAM[0xCA03]);
	 fprintf(errorlog,"Dest   : %02X %02X\n",RAM[0xCA04],RAM[0xCA05]);
	 fprintf(errorlog,"W H    : %02X %02X (%d,%d)\n",RAM[0xCA06],RAM[0xCA07],RAM[0xCA06]^4,RAM[0xCA07]^4);
	 fprintf(errorlog,"Mask   : %02X\n",RAM[0xCA01]);

	}
}

/**************
 * Same as StartBlitter but no ^ 4 with the Width and Length
 * For Splat or any game that use SC2 ships.
 */
void williams_StartBlitter2(int offset,int data)
{
int i,j,offs;
unsigned short source,dest,start;

  offs = SCREEN_WIDTH - RAM[0xCA07];
  source = (RAM[0xCA02]<<8) + RAM[0xCA03];
  start = (RAM[0xCA04]<<8) + RAM[0xCA05];
  dest = start;

  for(i=0;i<(RAM[0xCA07]);i++){
    for(j=0;j<(RAM[0xCA06]);j++){
      williams_videoram_blitter_w(dest,williams_videoram_r(source),data);
      source++;
      dest+=SCREEN_WIDTH;
    }
    start += 1;
    dest = start;
  }

/*  Log blits
 */
	if (errorlog){
	 fprintf(errorlog,"---------- Blit %02X--------------\n",data);
	 fprintf(errorlog,"Source : %02X %02X\n",RAM[0xCA02],RAM[0xCA03]);
	 fprintf(errorlog,"Dest   : %02X %02X\n",RAM[0xCA04],RAM[0xCA05]);
	 fprintf(errorlog,"W H    : %02X %02X (%d,%d)\n",RAM[0xCA06],RAM[0xCA07],RAM[0xCA06],RAM[0xCA07]);
	 fprintf(errorlog,"Mask   : %02X\n",RAM[0xCA01]);

	}
}


#ifdef MS_DOS_ONLY
#include <allegro.h>       /*  for RGB  */

/*
  This is not portable, it access the allegro library that is
   used on IBM.
*/
void Williams_Palette_w(int offset,int data)
{
	RGB rgb;

        RAM[offset+0xC000] = data;

	      rgb.r = ((data & 0x07)<<3);
        if(rgb.r != 0)
  	      rgb.r += 7;
	      rgb.g = (((data>>3) & 0x07)<<3);
        if(rgb.g != 0)
  	      rgb.g += 7;
	      rgb.b = (((data>>6) & 0x03)<<4);
        if(rgb.b != 0)
  	      rgb.b += 3;

	set_color(offset,&rgb);
}
#else
void Williams_Palette_w(int offset,int data)
{
  RAM[offset+0xC000] = data;
}
#endif


/********************* Defender ******************************/


/**************
 * Defender video ram Write
 * Same as the others but Write in RAM[]
 */
void defender_videoram_w(int offset,int data)
{
int x,y;

/*  defender only!!
 */

  RAM[offset] = data;

/*  Put the pixels in our bitmap
 */

  x = offset % 256;
#ifdef HEIGHT_240
  x -= START_OFFSET;
  if(x<0)
    return;
  if(x>=240)
    return;
#endif
  y = offset / 256;

  PutPix(x,(y*2),data>>4);
  PutPix(x,(y*2)+1,data&0x0F);

}






/***************************************************************************
  Start the video hardware emulation.
***************************************************************************/

int williams_vh_start(void)
{
	if (generic_vh_start() != 0)
		return 1;

        /*  Allocate space for video ram  */
	if ((williams_videoram = malloc(VIDEO_RAM_SIZE)) == 0)
	{
		generic_vh_stop();
		return 1;
	}
	memset(williams_videoram,0,VIDEO_RAM_SIZE);

	defender_bank = 0;
        Erase_screen_each_vbl = 0;

        williams_bitmap = tmpbitmap;

        return 0;
}

/***************************************************************************

  Stop the video hardware emulation.

***************************************************************************/
void williams_vh_stop(void)
{
	free(williams_videoram);
	generic_vh_stop();
}

/***************************************************************************

  Draw the game screen in the given osd_bitmap.
  Do NOT call osd_update_display() from this function, it will be called by
  the main emulation engine.

***************************************************************************/
void williams_vh_screenrefresh(struct osd_bitmap *bitmap)
{

#ifdef MS_DOS_ONLY
  copybitmap(bitmap,williams_bitmap,0,0,0,0,&Machine->drv->visible_area,TRANSPARENCY_NONE,0);
#else
int x,y;
  for(x=0;x<304;x++){
    for(y=0;y<240;y++){
      bitmap->line[y][x] = RAM[0xc000+williams_bitmap->line[y][x]];
    }
  }
#endif

}

void defender_vh_screenrefresh(struct osd_bitmap *bitmap)
{

#ifdef MS_DOS_ONLY
  copybitmap(bitmap,williams_bitmap,0,0,0,0,&Machine->drv->visible_area,TRANSPARENCY_NONE,0);
#else
int x,y;
  for(x=0;x<304;x++){
    for(y=0;y<240;y++){
      bitmap->line[y][x] = RAM[0x10000+williams_bitmap->line[y][x]];
    }
  }
#endif

}

void blaster_vh_screenrefresh(struct osd_bitmap *bitmap)
{

#ifdef MS_DOS_ONLY
  copybitmap(bitmap,williams_bitmap,0,0,0,0,&Machine->drv->visible_area,TRANSPARENCY_NONE,0);
#else
int x,y;
  for(x=0;x<304;x++){
    for(y=0;y<240;y++){
      bitmap->line[y][x] = RAM[0xc000+williams_bitmap->line[y][x]];
    }
  }
#endif


/*  Toggle the erase video ram each frames (for Blaster)
 */

if (osd_key_pressed(OSD_KEY_EQUALS)){
 Erase_screen_each_vbl ^= 1;
 while (osd_key_pressed(OSD_KEY_EQUALS));	/* wait for key release */
}

/*  Semi automatic erase video ram each frames (for Blaster)
 */

if(Erase_screen_each_vbl != 0)
#ifdef HEIGHT_240
	memset(williams_bitmap->line[20],0, 304*220);
#else
	memset(williams_bitmap->line[24],0, 304*(256-24));
#endif

}





/*
 *  Prom to remap the colors of the shapes of Blaster.
 *  There is two of this but they are exactly the same, so I put just one here
 *  A0-A3 of the prom is the data from the roms (4 bits)
 *  0xC940 bits 0-6 is plugged at A4-A10 of the Prom
 */

static char BlasterRemapProm[] = {
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x04,0x01,0x03,0x09,0x0A,0x01,0x0C,0x0D,0x0F,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x0C,0x0D,0x0A,0x09,0x0A,0x0C,0x0C,0x0D,0x0B,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x0C,0x0F,0x01,0x01,0x09,0x0A,0x07,0x0C,0x0D,0x06,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x01,0x09,0x0E,0x09,0x09,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x04,0x0C,0x0D,0x05,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x0C,0x09,0x0E,0x09,0x09,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x09,0x09,0x0E,0x01,0x0A,0x09,0x0C,0x0D,0x09,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x0C,0x0A,0x09,0x0C,0x0D,0x0B,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x05,0x0B,0x0E,0x0C,0x0B,0x06,0x0E,0x0D,0x07,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x05,0x06,0x0E,0x0C,0x06,0x01,0x0E,0x0D,0x03,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x05,0x01,0x0E,0x0C,0x01,0x0B,0x0E,0x0D,0x0D,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x05,0x0B,0x0E,0x0C,0x0B,0x0C,0x0E,0x0D,0x0D,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x04,0x0A,0x05,0x0C,0x0D,0x01,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x05,0x0C,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x05,0x01,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x06,0x03,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x0C,0x0B,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x0E,0x01,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x0E,0x0B,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x0B,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x0E,0x01,0x04,0x03,0x09,0x0B,0x0C,0x0C,0x0D,0x0B,0x0F,
     0x00,0x0F,0x02,0x0D,0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,
     0x00,0x03,0x02,0x07,0x09,0x0B,0x0D,0x0F,0x05,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x01,
     0x00,0x03,0x02,0x0E,0x07,0x01,0x0F,0x09,0x0D,0x06,0x08,0x0A,0x0C,0x05,0x04,0x0B,
     0x00,0x0B,0x02,0x05,0x0C,0x0A,0x04,0x06,0x0D,0x09,0x0F,0x01,0x07,0x0E,0x08,0x03,
     0x00,0x06,0x02,0x0A,0x0C,0x05,0x04,0x0B,0x03,0x08,0x0E,0x07,0x01,0x0F,0x09,0x0D,
     0x00,0x07,0x02,0x0D,0x0F,0x0C,0x04,0x0B,0x05,0x0A,0x06,0x09,0x01,0x03,0x08,0x0E,
     0x00,0x09,0x02,0x05,0x03,0x07,0x01,0x0D,0x0A,0x04,0x08,0x0F,0x06,0x0C,0x0B,0x0E,
     0x00,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x05,0x09,0x0C,0x01,0x0C,0x01,0x01,0x05,
     0x00,0x05,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x09,0x0C,0x01,0x0C,0x01,0x01,0x05,
     0x00,0x05,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x09,0x0C,0x01,0x0C,0x01,0x01,0x01,
     0x00,0x01,0x02,0x05,0x05,0x01,0x01,0x01,0x01,0x09,0x0C,0x01,0x0C,0x01,0x01,0x01,
     0x00,0x01,0x02,0x01,0x05,0x05,0x01,0x01,0x01,0x09,0x0C,0x01,0x0C,0x01,0x01,0x01,
     0x00,0x01,0x05,0x01,0x01,0x05,0x05,0x01,0x01,0x09,0x05,0x05,0x05,0x05,0x05,0x01,
     0x00,0x01,0x05,0x01,0x01,0x01,0x05,0x05,0x01,0x09,0x05,0x05,0x05,0x05,0x05,0x01,
     0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x05,0x05,0x09,0x05,0x05,0x05,0x05,0x05,0x01,
     0x00,0x00,0x02,0x03,0x0D,0x05,0x00,0x07,0x08,0x0D,0x00,0x0B,0x0C,0x0D,0x0D,0x0F,
     0x00,0x00,0x02,0x03,0x0D,0x05,0x09,0x07,0x08,0x09,0x00,0x0B,0x0C,0x0D,0x0D,0x0F,
     0x00,0x00,0x02,0x03,0x0D,0x05,0x00,0x07,0x08,0x0D,0x09,0x0B,0x0C,0x0D,0x09,0x0F,
     0x00,0x09,0x02,0x03,0x09,0x05,0x00,0x07,0x08,0x0D,0x00,0x0B,0x0C,0x0D,0x0D,0x0F,
     0x00,0x00,0x02,0x03,0x0D,0x05,0x00,0x07,0x08,0x0D,0x00,0x09,0x0C,0x0D,0x0D,0x0F,
     0x00,0x00,0x02,0x03,0x0D,0x05,0x09,0x07,0x08,0x09,0x00,0x09,0x0C,0x0D,0x0D,0x0F,
     0x00,0x00,0x02,0x03,0x0D,0x05,0x00,0x07,0x08,0x0D,0x09,0x09,0x0C,0x0D,0x09,0x0F,
     0x00,0x09,0x02,0x03,0x09,0x05,0x00,0x07,0x08,0x0D,0x00,0x09,0x0C,0x0D,0x0D,0x0F,
     0x00,0x0D,0x02,0x03,0x01,0x04,0x05,0x04,0x01,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x03,
     0x00,0x03,0x02,0x0D,0x03,0x01,0x04,0x05,0x04,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x01,
     0x00,0x01,0x02,0x03,0x0D,0x03,0x01,0x04,0x05,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x04,
     0x00,0x04,0x02,0x01,0x03,0x0D,0x03,0x01,0x04,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x05,
     0x00,0x05,0x02,0x04,0x01,0x03,0x0D,0x03,0x01,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x04,
     0x00,0x04,0x02,0x05,0x04,0x01,0x03,0x0D,0x03,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x01,
     0x00,0x01,0x02,0x04,0x05,0x04,0x01,0x03,0x0D,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x03,
     0x00,0x03,0x02,0x01,0x04,0x05,0x04,0x01,0x03,0x09,0x0E,0x0B,0x0C,0x0A,0x09,0x0D,
     0x00,0x0B,0x02,0x03,0x04,0x01,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x09,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x0C,0x02,0x03,0x04,0x01,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x05,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x05,0x02,0x0A,0x05,0x05,0x08,0x08,0x08,0x09,0x0A,0x0B,0x06,0x07,0x0E,0x06,
     0x00,0x09,0x02,0x0B,0x09,0x05,0x02,0x02,0x02,0x09,0x0A,0x0B,0x09,0x0A,0x0E,0x0E,
     0x00,0x04,0x02,0x03,0x01,0x05,0x05,0x05,0x05,0x09,0x0A,0x0B,0x04,0x03,0x0E,0x0F,
     0x00,0x01,0x02,0x0D,0x01,0x05,0x0B,0x0B,0x0B,0x09,0x0A,0x0B,0x05,0x01,0x0E,0x06,
     0x00,0x01,0x02,0x03,0x01,0x05,0x09,0x09,0x09,0x09,0x0A,0x0B,0x0F,0x01,0x0E,0x09,
     0x00,0x01,0x02,0x0D,0x01,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x05,0x04,0x0E,0x0F,
     0x00,0x02,0x02,0x03,0x04,0x05,0x0B,0x02,0x0B,0x09,0x0A,0x0B,0x0C,0x0D,0x02,0x0B,
     0x00,0x02,0x02,0x03,0x04,0x05,0x0B,0x02,0x09,0x09,0x0A,0x0B,0x0C,0x0D,0x09,0x0B,
     0x00,0x02,0x02,0x03,0x04,0x05,0x0B,0x09,0x0B,0x09,0x0A,0x0B,0x0C,0x0D,0x02,0x09,
     0x00,0x09,0x02,0x03,0x04,0x05,0x09,0x02,0x0B,0x09,0x0A,0x0B,0x0C,0x0D,0x02,0x0B,
     0x00,0x0E,0x02,0x0A,0x0B,0x09,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x0B,0x02,0x0A,0x01,0x09,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0C,0x0E,0x0F,
     0x00,0x07,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x04,0x0E,0x0F,
     0x00,0x01,0x02,0x0B,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0C,
     0x00,0x05,0x02,0x07,0x03,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x08,0x0E,0x09,
     0x00,0x0F,0x02,0x01,0x0C,0x0B,0x06,0x07,0x08,0x0D,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x08,0x02,0x06,0x07,0x09,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0A,0x0E,0x05,
     0x00,0x0C,0x02,0x08,0x03,0x04,0x0E,0x0E,0x0E,0x06,0x08,0x0B,0x0C,0x08,0x07,0x0F,
     0x00,0x0B,0x02,0x0A,0x0D,0x0C,0x0E,0x0E,0x0A,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0C,
     0x00,0x06,0x02,0x0D,0x02,0x0A,0x06,0x07,0x08,0x0C,0x01,0x0B,0x0C,0x0D,0x0F,0x0F,
     0x00,0x05,0x02,0x03,0x01,0x04,0x05,0x04,0x01,0x0F,0x03,0x0B,0x0C,0x0D,0x0A,0x0F,
     0x00,0x01,0x02,0x02,0x08,0x06,0x05,0x04,0x01,0x05,0x07,0x0B,0x0C,0x0D,0x0A,0x06,
     0x00,0x01,0x02,0x03,0x04,0x05,0x05,0x01,0x0E,0x09,0x01,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x05,0x06,0x0E,0x09,0x06,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x01,0x0E,0x09,0x01,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x0B,0x0E,0x09,0x0B,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x0E,0x0F,0x0C,0x0D,0x05,0x05,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x09,0x05,0x04,0x03,0x0C,0x0C,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x0F,0x04,0x01,0x03,0x06,0x06,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x09,0x0E,0x0A,0x0D,0x01,0x01,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x0A,0x02,0x0D,0x0C,0x0E,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x07,0x02,0x08,0x06,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x0C,0x02,0x03,0x04,0x06,0x0E,0x07,0x08,0x05,0x0A,0x0B,0x01,0x03,0x06,0x04,
     0x00,0x0C,0x02,0x03,0x04,0x06,0x02,0x07,0x08,0x05,0x0A,0x0B,0x01,0x03,0x06,0x04,
     0x00,0x05,0x02,0x0A,0x05,0x05,0x01,0x01,0x01,0x09,0x0A,0x0B,0x06,0x07,0x0E,0x06,
     0x00,0x05,0x02,0x0A,0x05,0x05,0x05,0x05,0x05,0x09,0x0A,0x0B,0x06,0x07,0x0E,0x06,
     0x00,0x01,0x02,0x03,0x04,0x05,0x02,0x02,0x02,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x09,0x02,0x0B,0x09,0x05,0x01,0x01,0x01,0x09,0x0A,0x0B,0x09,0x0A,0x0E,0x0E,
     0x00,0x04,0x02,0x03,0x01,0x05,0x01,0x01,0x01,0x09,0x0A,0x0B,0x04,0x03,0x0E,0x0F,
     0x00,0x02,0x02,0x03,0x04,0x05,0x01,0x02,0x01,0x02,0x0E,0x01,0x0C,0x01,0x02,0x01,
     0x00,0x02,0x02,0x03,0x04,0x05,0x01,0x02,0x05,0x02,0x0E,0x01,0x0C,0x01,0x05,0x01,
     0x00,0x02,0x02,0x03,0x04,0x05,0x01,0x05,0x01,0x02,0x0E,0x01,0x0C,0x01,0x02,0x05,
     0x00,0x05,0x02,0x03,0x04,0x05,0x05,0x02,0x01,0x02,0x0E,0x01,0x0C,0x01,0x02,0x01,
     0x00,0x02,0x02,0x0A,0x09,0x0E,0x0C,0x02,0x0C,0x02,0x0A,0x0C,0x0C,0x0A,0x02,0x0C,
     0x00,0x02,0x02,0x0A,0x09,0x0E,0x0C,0x02,0x0F,0x02,0x0A,0x0C,0x0C,0x0A,0x0F,0x0C,
     0x00,0x02,0x02,0x0A,0x09,0x0E,0x0C,0x09,0x0C,0x02,0x0A,0x0C,0x0C,0x0A,0x02,0x0F,
     0x00,0x09,0x02,0x0A,0x09,0x0E,0x0F,0x02,0x0C,0x02,0x0A,0x0C,0x0C,0x0A,0x02,0x0C,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x0B,0x0A,0x09,0x0C,0x0D,0x0B,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x03,0x04,0x05,0x0C,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x0B,0x09,0x0E,0x09,0x09,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x0C,0x09,0x0E,0x09,0x09,0x0B,0x0E,0x0D,0x0E,0x0F,
     0x00,0x01,0x02,0x03,0x04,0x05,0x01,0x04,0x03,0x09,0x0A,0x0B,0x04,0x03,0x0E,0x05,
     0x00,0x01,0x02,0x03,0x04,0x0E,0x06,0x07,0x08,0x09,0x0A,0x0B,0x04,0x03,0x0E,0x05,
     0x00,0x01,0x02,0x03,0x04,0x0E,0x05,0x04,0x03,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0A,
     0x00,0x01,0x02,0x03,0x04,0x06,0x05,0x04,0x03,0x0E,0x0A,0x0B,0x01,0x0D,0x0E,0x04,
     0x00,0x01,0x02,0x03,0x04,0x0C,0x01,0x01,0x03,0x09,0x0E,0x0B,0x07,0x08,0x0E,0x06,
     0x00,0x01,0x02,0x03,0x04,0x05,0x09,0x09,0x0A,0x09,0x0A,0x0B,0x01,0x0D,0x0E,0x0C,
     0x00,0x01,0x02,0x03,0x04,0x09,0x05,0x05,0x03,0x09,0x0A,0x0B,0x04,0x04,0x0E,0x03,
     0x00,0x01,0x02,0x03,0x04,0x01,0x0C,0x0C,0x0D,0x01,0x0D,0x0B,0x0A,0x0D,0x0E,0x09,
     0x00,0x01,0x02,0x03,0x04,0x0E,0x06,0x07,0x08,0x0E,0x0A,0x0B,0x04,0x04,0x0E,0x03,
     0x00,0x01,0x02,0x03,0x04,0x0F,0x04,0x01,0x03,0x0F,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};