diff --git a/demos/modules/gdisp/gdisp_images_animated/gfxconf.h b/demos/modules/gdisp/gdisp_images_animated/gfxconf.h new file mode 100644 index 00000000..cd368e95 --- /dev/null +++ b/demos/modules/gdisp/gdisp_images_animated/gfxconf.h @@ -0,0 +1,57 @@ +/** + * This file has a different license to the rest of the GFX system. + * You can copy, modify and distribute this file as you see fit. + * You do not need to publish your source modifications to this file. + * The only thing you are not permitted to do is to relicense it + * under a different license. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE +#define GFX_USE_GWIN FALSE +#define GFX_USE_GEVENT FALSE +#define GFX_USE_GTIMER FALSE +#define GFX_USE_GINPUT FALSE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT FALSE +#define GDISP_NEED_CIRCLE FALSE +#define GDISP_NEED_ELLIPSE FALSE +#define GDISP_NEED_ARC FALSE +#define GDISP_NEED_CONVEX_POLYGON FALSE +#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD FALSE +#define GDISP_NEED_CONTROL FALSE +#define GDISP_NEED_IMAGE TRUE +#define GDISP_NEED_MULTITHREAD FALSE +#define GDISP_NEED_ASYNC FALSE +#define GDISP_NEED_MSGAPI FALSE + +/* Builtin Fonts */ +#define GDISP_INCLUDE_FONT_SMALL FALSE +#define GDISP_INCLUDE_FONT_LARGER FALSE +#define GDISP_INCLUDE_FONT_UI1 FALSE +#define GDISP_INCLUDE_FONT_UI2 FALSE +#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE + +/* GDISP image decoders */ +#define GDISP_NEED_IMAGE_NATIVE FALSE +#define GDISP_NEED_IMAGE_GIF TRUE +#define GDISP_NEED_IMAGE_BMP FALSE +#define GDISP_NEED_IMAGE_JPG FALSE +#define GDISP_NEED_IMAGE_PNG FALSE +#define GDISP_NEED_IMAGE_ACCOUNTING FALSE + +/* Features for the GWIN sub-system. */ +#define GWIN_NEED_BUTTON FALSE +#define GWIN_NEED_CONSOLE FALSE + +/* Features for the GINPUT sub-system. */ +#define GINPUT_NEED_MOUSE FALSE + +#endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/gdisp_images_animated/main.c b/demos/modules/gdisp/gdisp_images_animated/main.c new file mode 100644 index 00000000..d5c3d712 --- /dev/null +++ b/demos/modules/gdisp/gdisp_images_animated/main.c @@ -0,0 +1,101 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#define USE_IMAGE_CACHE FALSE // Only if you want to get performance at the expense of RAM +#define MY_BG_COLOR RGB2COLOR(220, 220, 255) // Pale blue so we can see the transparent parts + +#ifdef WIN32 + #define USE_MEMORY_FILE FALSE // Can be true or false for Win32 +#else + #define USE_MEMORY_FILE TRUE // Non-Win32 - use the compiled in image +#endif + +#define SHOW_ERROR(color) gdispFillArea(swidth-10, 0, 10, sheight, color) + +#if USE_MEMORY_FILE + #include "testanim.h" +#endif + +static gdispImage myImage; + +/** + * This demo display the animated gif (either directly from a file or from a + * file encoded in flash. + * To show the various stages of encoding it displays a colored bar down the + * right hand side of the display to indicate what is happenning. + * Green - Image has completed and is displayed correctly + * Red - A really bad image fault. We couldn't open the image + * Yellow - Waiting to decode the next animation frame + * Orange - Decoding a frame has produced an error. + */ +int main(void) { + coord_t swidth, sheight; + systime_t delay; + + halInit(); // Initialize the Hardware + chSysInit(); // Initialize the OS + gdispInit(); // Initialize the display + + gdispClear(MY_BG_COLOR); + + // Get the display dimensions + swidth = gdispGetWidth(); + sheight = gdispGetHeight(); + + // Set up IO for our image +#if USE_MEMORY_FILE + gdispImageSetMemoryReader(&myImage, testanim); +#else + gdispImageSetSimulFileReader(&myImage, "testanim.gif"); +#endif + + if (gdispImageOpen(&myImage) == GDISP_IMAGE_ERR_OK) { + gdispImageSetBgColor(&myImage, MY_BG_COLOR); + while(1) { + #if USE_IMAGE_CACHE + gdispImageCache(&myImage); + #endif + if (gdispImageDraw(&myImage, 5, 5, myImage.width, myImage.height, 0, 0) != GDISP_IMAGE_ERR_OK) { + SHOW_ERROR(Orange); + break; + } + delay = gdispImageNext(&myImage); + if (delay == TIME_INFINITE) { + SHOW_ERROR(Green); + break; + } + SHOW_ERROR(Yellow); + if (delay != TIME_IMMEDIATE) + chThdSleepMilliseconds(delay); + } + gdispImageClose(&myImage); + } else + SHOW_ERROR(Red); + + while(1) { + chThdSleepMilliseconds(1000); + } + + return 0; +} diff --git a/demos/modules/gdisp/gdisp_images_animated/testanim.gif b/demos/modules/gdisp/gdisp_images_animated/testanim.gif new file mode 100644 index 00000000..6639acb2 Binary files /dev/null and b/demos/modules/gdisp/gdisp_images_animated/testanim.gif differ diff --git a/demos/modules/gdisp/gdisp_images_animated/testanim.h b/demos/modules/gdisp/gdisp_images_animated/testanim.h new file mode 100644 index 00000000..ce2ba8c7 --- /dev/null +++ b/demos/modules/gdisp/gdisp_images_animated/testanim.h @@ -0,0 +1,567 @@ +/** + * This file was generated from "testanim.gif" using... + * + * file2c -cs testanim.gif testanim.h + * + */ +static const unsigned char testanim[] = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x99, 0x00, 0x73, 0x00, 0xE6, 0x46, 0x00, 0x04, 0x07, 0x00, + 0x10, 0x0F, 0x04, 0x1D, 0x1E, 0x29, 0x20, 0x23, 0x08, 0x2E, 0x2C, 0x18, 0x31, 0x32, 0x01, 0x2E, + 0x32, 0x2A, 0x35, 0x37, 0x3B, 0x20, 0x28, 0x42, 0x2B, 0x37, 0x53, 0x3E, 0x41, 0x03, 0x3C, 0x44, + 0x53, 0x3C, 0x4E, 0x67, 0x44, 0x3B, 0x34, 0x44, 0x3D, 0x43, 0x63, 0x36, 0x42, 0x7A, 0x35, 0x46, + 0x51, 0x4E, 0x04, 0x4C, 0x49, 0x32, 0x62, 0x5C, 0x06, 0x6C, 0x6D, 0x0A, 0x68, 0x65, 0x2C, 0x4F, + 0x55, 0x68, 0x5F, 0x5F, 0x60, 0x5D, 0x66, 0x79, 0x63, 0x5B, 0x4E, 0x4A, 0x5C, 0x81, 0x58, 0x68, + 0x89, 0x56, 0x79, 0xAF, 0x63, 0x6E, 0x81, 0x6E, 0x75, 0x8C, 0x78, 0x61, 0x8C, 0x6E, 0x7C, 0xA6, + 0x7F, 0x7E, 0xBF, 0x7D, 0x84, 0x7B, 0x5C, 0x82, 0xBA, 0x7D, 0x83, 0x96, 0x5B, 0x8A, 0xD2, 0x5F, + 0x9D, 0xEF, 0x77, 0xA4, 0xD0, 0x6F, 0xB2, 0xEF, 0x7E, 0xC1, 0xF3, 0x8C, 0x7F, 0x33, 0xB5, 0x6C, + 0x83, 0x9C, 0x86, 0x4B, 0x80, 0x83, 0xA1, 0x88, 0x95, 0xAA, 0x8C, 0x9B, 0xB5, 0x99, 0xA6, 0x9A, + 0xAE, 0xAD, 0x9A, 0x92, 0x9F, 0xC0, 0xA7, 0xA4, 0xC0, 0xA1, 0xAA, 0xC0, 0xAE, 0xB7, 0xD0, 0xB8, + 0xC3, 0xBC, 0x99, 0xC8, 0xDB, 0x91, 0xCD, 0xF0, 0x9C, 0xD7, 0xF1, 0xB8, 0xC7, 0xD5, 0xAE, 0xE7, + 0xF9, 0xC8, 0xC9, 0xBB, 0xD3, 0xC2, 0xBB, 0xC2, 0xD2, 0xDE, 0xD1, 0xE4, 0xDE, 0xC8, 0xF2, 0xEA, + 0xE1, 0xDE, 0xDB, 0xEE, 0xEB, 0xDA, 0xFA, 0xF7, 0xE6, 0xFD, 0xFC, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, + 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, + 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, 0xFF, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x05, 0x16, 0x00, 0x46, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x73, + 0x00, 0x00, 0x07, 0xFE, 0x80, 0x00, 0x01, 0x01, 0x16, 0x16, 0x82, 0x04, 0x08, 0x46, 0x8A, 0x8B, + 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x94, 0x38, 0x26, 0x29, 0x29, + 0x25, 0x1E, 0x16, 0x1B, 0x02, 0x02, 0x04, 0x83, 0x00, 0x82, 0x02, 0x01, 0x00, 0x07, 0x27, 0x2D, + 0xA5, 0xAD, 0x82, 0x00, 0x08, 0xA7, 0x03, 0x0B, 0x97, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0x95, 0x38, + 0x08, 0x0C, 0x0C, 0x16, 0x18, 0x18, 0x1B, 0x16, 0x01, 0x08, 0x09, 0xA4, 0xA5, 0xB1, 0x2D, 0x08, + 0x0B, 0xAE, 0x00, 0xA1, 0x00, 0xA3, 0x82, 0x1B, 0x23, 0x20, 0xBA, 0xD7, 0xD8, 0xD9, 0xD8, 0x25, + 0x25, 0x32, 0x09, 0x08, 0x85, 0x16, 0xDF, 0x01, 0xA1, 0x06, 0x83, 0xE7, 0x82, 0x08, 0x01, 0xAC, + 0xC5, 0x0C, 0xA5, 0x0B, 0xA8, 0xA4, 0x01, 0x03, 0xA7, 0xDA, 0xF6, 0xF7, 0xF8, 0x8E, 0xDF, 0xCB, + 0xBF, 0x85, 0x08, 0xFF, 0xE6, 0x4E, 0x91, 0x43, 0x95, 0x2A, 0x40, 0x82, 0x66, 0x86, 0x50, 0xE0, + 0x00, 0xC0, 0xEE, 0x95, 0xC0, 0x75, 0xF9, 0x22, 0x4A, 0xCC, 0xF5, 0x6D, 0xC1, 0xAF, 0x0D, 0x1B, + 0x18, 0xFC, 0x8B, 0xB5, 0x80, 0x99, 0x81, 0x53, 0xCF, 0xCE, 0x2D, 0x80, 0x57, 0x0C, 0x43, 0x0B, + 0x14, 0x08, 0x5C, 0x91, 0x22, 0x46, 0x6B, 0xA2, 0xCB, 0x97, 0x90, 0x34, 0x0A, 0xF8, 0x27, 0xC0, + 0x62, 0xAC, 0x99, 0x33, 0x8D, 0x85, 0xEA, 0x38, 0xE0, 0x5C, 0x80, 0x03, 0xCD, 0x4A, 0x11, 0x00, + 0xB0, 0x21, 0x05, 0x41, 0x9F, 0xA6, 0x2C, 0x30, 0x80, 0xC9, 0x74, 0xE2, 0x0C, 0x23, 0x00, 0x47, + 0xCE, 0x2C, 0x94, 0x20, 0x94, 0x80, 0x6F, 0xA1, 0x36, 0xCE, 0xF4, 0x80, 0xAA, 0x81, 0xA0, 0xA0, + 0x00, 0x06, 0x3C, 0xF3, 0xA0, 0x52, 0x90, 0xCF, 0x44, 0x4D, 0xD3, 0x66, 0x5B, 0x11, 0xC2, 0xC2, + 0x32, 0x8E, 0xFE, 0x16, 0x16, 0x08, 0x50, 0x4A, 0x33, 0x67, 0x47, 0x04, 0x06, 0xC0, 0x81, 0x90, + 0x4B, 0xB0, 0x94, 0xD8, 0x78, 0x09, 0xC8, 0x96, 0x92, 0xE7, 0x33, 0x00, 0x06, 0xB5, 0x88, 0x71, + 0xE5, 0xE0, 0x70, 0x80, 0xE6, 0xC7, 0x6F, 0xC6, 0x22, 0x83, 0x8B, 0x65, 0xE0, 0xEE, 0x81, 0x04, + 0x16, 0x7A, 0xAA, 0x1B, 0x2C, 0xE0, 0x59, 0xA9, 0xCE, 0x9D, 0xE5, 0x0E, 0x7E, 0x35, 0x98, 0x5C, + 0xE2, 0xD3, 0x96, 0x72, 0x78, 0x5A, 0xF0, 0x31, 0x32, 0x56, 0x66, 0x1B, 0x63, 0x13, 0xA8, 0xBC, + 0x00, 0x58, 0xAB, 0x79, 0x03, 0x8D, 0x25, 0x2B, 0x65, 0xA0, 0xF1, 0x68, 0xB3, 0xF1, 0x36, 0x50, + 0x5A, 0x8A, 0x3A, 0xED, 0x07, 0x10, 0x0C, 0x3A, 0x62, 0x86, 0xAD, 0x35, 0x56, 0xEC, 0x7E, 0xB5, + 0x99, 0x1D, 0x3C, 0x70, 0x3B, 0x1A, 0x80, 0x04, 0x97, 0x35, 0x5A, 0xC4, 0x40, 0xE8, 0xF7, 0xD1, + 0x9E, 0xC4, 0x8D, 0x68, 0x70, 0xB4, 0x21, 0x81, 0x22, 0x6E, 0x46, 0x0A, 0x09, 0x10, 0xDF, 0xA8, + 0x84, 0xB0, 0x12, 0xC5, 0x71, 0xC9, 0xB4, 0x20, 0xE0, 0x40, 0xF2, 0x8A, 0xB1, 0x9D, 0x5B, 0xD0, + 0xB0, 0x1A, 0x18, 0xDE, 0x94, 0x5E, 0xB9, 0x32, 0x0A, 0x46, 0x07, 0x8D, 0xE4, 0x0B, 0x7D, 0x66, + 0xDD, 0x16, 0x4F, 0x00, 0xF0, 0x29, 0xD2, 0x8B, 0x11, 0x0C, 0x08, 0x67, 0x11, 0x01, 0x23, 0x55, + 0x58, 0xDB, 0x02, 0x18, 0x60, 0xE8, 0xC1, 0x02, 0xC3, 0x00, 0x15, 0x97, 0x00, 0x0F, 0x40, 0x10, + 0x1F, 0x25, 0x1F, 0xDC, 0xB7, 0xC1, 0x5D, 0x35, 0xC9, 0x05, 0x94, 0x31, 0x09, 0x54, 0x85, 0xC0, + 0x30, 0xC1, 0x84, 0x63, 0x81, 0x07, 0x02, 0x18, 0xA0, 0x92, 0x61, 0x07, 0x14, 0xB2, 0xC0, 0x2C, + 0xBE, 0x94, 0x87, 0xCC, 0x2B, 0xE8, 0x0C, 0xD2, 0x20, 0x07, 0x73, 0x19, 0x51, 0xC2, 0x41, 0xB4, + 0x59, 0xFE, 0xB8, 0x00, 0x85, 0x23, 0x11, 0x70, 0xC1, 0x02, 0x0D, 0x60, 0xE0, 0x01, 0x02, 0x19, + 0x8E, 0x34, 0x0B, 0x06, 0x27, 0xA4, 0x30, 0x22, 0x24, 0x98, 0x85, 0xC3, 0x80, 0x01, 0xFE, 0x6C, + 0x84, 0x61, 0x8E, 0x71, 0x05, 0x63, 0xE6, 0x5C, 0x85, 0x80, 0x80, 0xD7, 0x60, 0xB3, 0x10, 0x70, + 0x40, 0x00, 0xB5, 0x61, 0xA0, 0x40, 0x04, 0x18, 0x30, 0x70, 0x80, 0x01, 0x09, 0x88, 0x35, 0xDA, + 0x82, 0xD1, 0x58, 0xA0, 0xC8, 0x31, 0x79, 0xED, 0x48, 0x61, 0x95, 0x71, 0x5D, 0x68, 0xC0, 0x47, + 0x14, 0x52, 0x18, 0xD7, 0x8C, 0x0B, 0x78, 0x80, 0xC1, 0x00, 0x95, 0x65, 0xB8, 0xA5, 0x3E, 0xDF, + 0x08, 0xF3, 0x4F, 0x02, 0xC9, 0x4D, 0x76, 0x90, 0x9D, 0x91, 0xCD, 0xE5, 0x81, 0x07, 0x2D, 0xE4, + 0xE4, 0xD6, 0x9B, 0x23, 0x79, 0x08, 0x82, 0x7A, 0x4A, 0xC5, 0x45, 0x80, 0x04, 0x03, 0x10, 0x40, + 0x41, 0x04, 0x05, 0x0C, 0x25, 0x0F, 0x70, 0x03, 0x20, 0x47, 0xCC, 0x6C, 0x23, 0x45, 0xBA, 0x00, + 0x50, 0x16, 0x2A, 0xCA, 0x5A, 0x86, 0x51, 0x9A, 0xB9, 0x6A, 0x03, 0xAD, 0x36, 0xD0, 0xC0, 0x0B, + 0x93, 0x2E, 0x02, 0x0E, 0x9A, 0x1B, 0x00, 0x74, 0xA7, 0x81, 0x9E, 0x78, 0x54, 0x4E, 0x9C, 0x0C, + 0xEC, 0x64, 0xC1, 0x46, 0x19, 0xE6, 0x15, 0x98, 0x94, 0x71, 0x69, 0x34, 0xE8, 0x02, 0x19, 0x10, + 0xA0, 0x67, 0x75, 0x0B, 0x22, 0xA2, 0xCE, 0x3C, 0x4D, 0xC2, 0x59, 0xA8, 0x01, 0x04, 0x6C, 0x58, + 0xA5, 0x01, 0xC1, 0x30, 0xE3, 0x81, 0x01, 0x03, 0x5C, 0x90, 0xE1, 0x00, 0xF8, 0x12, 0x3B, 0x80, + 0x94, 0xC9, 0x16, 0xB8, 0x00, 0x66, 0x1D, 0x01, 0xC5, 0xC0, 0x37, 0x07, 0xC5, 0x82, 0xDD, 0x4D, + 0x56, 0x5D, 0x65, 0x15, 0x33, 0x72, 0xD5, 0xE6, 0x89, 0x2F, 0x1A, 0x50, 0x09, 0x5D, 0x7D, 0x11, + 0xFE, 0x44, 0xD0, 0x93, 0x50, 0x85, 0xF9, 0x05, 0xA9, 0x4F, 0x0D, 0xCC, 0xD6, 0x2A, 0x94, 0x23, + 0x65, 0x28, 0xE5, 0xBB, 0x0D, 0x8F, 0x84, 0xD7, 0x02, 0x17, 0x88, 0x5B, 0xEC, 0x48, 0x0D, 0x4C, + 0xCA, 0xCC, 0xC0, 0x2D, 0xD2, 0xD7, 0x91, 0x76, 0x1B, 0x7D, 0x93, 0xD7, 0x4D, 0x37, 0xE5, 0x48, + 0x93, 0x74, 0xA1, 0x60, 0x76, 0x22, 0x33, 0x1A, 0x14, 0x52, 0x67, 0x8B, 0x3B, 0x52, 0xD0, 0x53, + 0x04, 0x0B, 0x06, 0x39, 0xC8, 0x28, 0xE7, 0x88, 0xDB, 0x51, 0xC9, 0xD7, 0xB2, 0x1B, 0x4C, 0x92, + 0x18, 0x06, 0x20, 0x6E, 0x03, 0xF4, 0xF6, 0x64, 0xF5, 0x20, 0x0D, 0x78, 0x40, 0xC2, 0x88, 0xBF, + 0xEC, 0xBC, 0xD1, 0xB5, 0xB1, 0x2C, 0x7A, 0xED, 0x55, 0xEA, 0xE1, 0x7C, 0x10, 0x64, 0x3B, 0x65, + 0x65, 0x5F, 0xC1, 0x98, 0xFD, 0x52, 0x67, 0x47, 0x4F, 0x36, 0x10, 0x00, 0xD2, 0xA5, 0x11, 0xB6, + 0x75, 0x3C, 0x1F, 0x97, 0x2C, 0x65, 0x85, 0xF4, 0x36, 0xE0, 0x40, 0x95, 0x56, 0xF6, 0x84, 0x2F, + 0xBE, 0x56, 0x1F, 0xBE, 0x80, 0x04, 0xF1, 0x5D, 0xBB, 0x9C, 0x46, 0x3A, 0x89, 0x23, 0xC0, 0x7D, + 0x05, 0xD7, 0xF4, 0x29, 0xC2, 0xE0, 0x84, 0xD9, 0xDC, 0x41, 0x3A, 0x9A, 0x6C, 0xD1, 0x2F, 0x07, + 0x21, 0x82, 0x6F, 0x01, 0x37, 0x16, 0x16, 0x24, 0xBE, 0xBB, 0x16, 0xD2, 0x93, 0x00, 0xD9, 0x12, + 0xC0, 0x24, 0x6D, 0x8E, 0xEE, 0x78, 0x8E, 0xDD, 0x14, 0x1A, 0x4E, 0x21, 0xB2, 0xA8, 0xC1, 0xAC, + 0x55, 0x4D, 0xB1, 0x59, 0x54, 0x55, 0x63, 0x68, 0xD6, 0x66, 0x95, 0x05, 0x40, 0x61, 0x5A, 0x17, + 0x33, 0x97, 0x61, 0x10, 0xD7, 0x3F, 0x18, 0x7C, 0x95, 0x01, 0x9C, 0x7E, 0xCD, 0x53, 0xBA, 0x59, + 0x5A, 0xFF, 0x35, 0x80, 0x04, 0xF6, 0x66, 0x78, 0x0E, 0x95, 0xC1, 0x00, 0x5E, 0xD2, 0xA1, 0xFE, + 0x61, 0xCD, 0xA3, 0xF5, 0x3C, 0x04, 0x34, 0xF0, 0xEB, 0x69, 0x2D, 0x40, 0xB6, 0xBB, 0x31, 0xF4, + 0x25, 0x90, 0x57, 0xB5, 0x75, 0x35, 0x4A, 0x02, 0x7D, 0x38, 0xCD, 0xA8, 0x23, 0x06, 0x75, 0x59, + 0x10, 0x81, 0x04, 0x2F, 0xEA, 0x3F, 0x00, 0x75, 0xB8, 0x21, 0x88, 0x58, 0x22, 0xE0, 0x8C, 0x04, + 0x89, 0x2F, 0x1E, 0xE1, 0x73, 0x14, 0x77, 0xC4, 0x87, 0x80, 0x4F, 0x01, 0xA3, 0x4A, 0x18, 0xA8, + 0xD1, 0xA1, 0x06, 0xD1, 0x91, 0xF0, 0xED, 0x2D, 0x00, 0x12, 0x38, 0x0C, 0x62, 0x7A, 0xA0, 0xBB, + 0xFC, 0x60, 0x06, 0x7F, 0x77, 0xE1, 0xC8, 0x54, 0xEC, 0x27, 0xB9, 0x9B, 0x1C, 0xE4, 0x02, 0xCB, + 0x50, 0xDE, 0x3F, 0x74, 0x34, 0xBF, 0x42, 0x34, 0x20, 0x02, 0xE2, 0x0A, 0x00, 0x05, 0x06, 0x41, + 0x40, 0xD2, 0xDC, 0x88, 0x4D, 0x7F, 0x69, 0x9A, 0x07, 0x8C, 0x35, 0x88, 0x59, 0x34, 0x6C, 0x16, + 0x87, 0x3A, 0xC0, 0x01, 0xE8, 0xE1, 0x93, 0x66, 0x9C, 0x03, 0x5F, 0xAB, 0xCA, 0x60, 0x23, 0x44, + 0x41, 0x02, 0x0F, 0x4C, 0x64, 0x4A, 0xFF, 0xD2, 0x49, 0x2F, 0xCA, 0xA6, 0xB6, 0x4B, 0xD5, 0xA6, + 0x10, 0x39, 0xBA, 0xDC, 0xC2, 0xE6, 0xE2, 0x80, 0x84, 0xCD, 0x65, 0x24, 0xC0, 0xC8, 0x00, 0x05, + 0x2E, 0x20, 0x08, 0xA4, 0x89, 0xA5, 0x00, 0xB8, 0x21, 0x5D, 0x5F, 0xF2, 0x46, 0x18, 0xEA, 0xE1, + 0x0A, 0x37, 0x24, 0x38, 0xC0, 0xA3, 0xC8, 0x17, 0xB2, 0x76, 0xCD, 0xEA, 0x10, 0x3D, 0x64, 0xD5, + 0x48, 0x18, 0x21, 0x0C, 0x03, 0xE8, 0x80, 0x42, 0x93, 0xA8, 0x8D, 0x70, 0x2C, 0xD1, 0x83, 0x6E, + 0xE1, 0xCF, 0x39, 0xCF, 0x11, 0xC7, 0xD3, 0xEC, 0x82, 0x01, 0x07, 0x60, 0x47, 0x88, 0xE0, 0x98, + 0xD2, 0xC2, 0x9C, 0x93, 0xB0, 0x7F, 0x01, 0xA3, 0x00, 0xB0, 0xEA, 0x8B, 0xC5, 0x5C, 0xFE, 0x31, + 0x81, 0x02, 0x26, 0xED, 0x93, 0xE8, 0x32, 0x0B, 0xD3, 0x6A, 0x23, 0x88, 0x56, 0x11, 0x20, 0x33, + 0x01, 0xA4, 0x60, 0x29, 0x0D, 0x37, 0x8F, 0x0C, 0x68, 0xF0, 0x3C, 0xDC, 0x39, 0x54, 0xCB, 0x1C, + 0x21, 0x83, 0x45, 0x58, 0x00, 0x90, 0x96, 0x00, 0x82, 0x3F, 0x64, 0x62, 0xB0, 0x99, 0x14, 0x8C, + 0x19, 0x02, 0x00, 0xC5, 0x4C, 0x02, 0x96, 0x1C, 0x21, 0x7A, 0xE8, 0x6C, 0x94, 0x9C, 0x64, 0x64, + 0x1C, 0x70, 0xB7, 0x01, 0x58, 0x6C, 0x02, 0x46, 0x03, 0x00, 0x1A, 0x61, 0x55, 0x40, 0x20, 0x1D, + 0xB1, 0x30, 0xA6, 0xB4, 0x51, 0x00, 0x48, 0x40, 0x02, 0x0C, 0x30, 0x2D, 0x71, 0xE7, 0x6A, 0x23, + 0x28, 0xE1, 0xD4, 0x12, 0x45, 0xB4, 0x40, 0x06, 0xF4, 0xC0, 0x65, 0x23, 0x5A, 0x30, 0x00, 0x08, + 0x6D, 0x88, 0x00, 0xB8, 0xA3, 0x04, 0xC1, 0x76, 0xA6, 0xBE, 0xE6, 0x74, 0xE4, 0x5A, 0x8D, 0xC9, + 0x4B, 0x38, 0xB0, 0xE3, 0x40, 0xAC, 0x24, 0x2C, 0x36, 0x55, 0x99, 0xD1, 0x39, 0x24, 0x80, 0xC6, + 0xC3, 0xA1, 0xF1, 0x55, 0xCE, 0xF4, 0x64, 0x69, 0x80, 0x73, 0x44, 0x78, 0xD8, 0x48, 0x76, 0x50, + 0xEA, 0xE1, 0xE1, 0x0E, 0xB8, 0xC6, 0xBC, 0xF5, 0x64, 0x24, 0x2D, 0x58, 0xC4, 0x08, 0x76, 0x62, + 0x1A, 0x45, 0x68, 0x49, 0x11, 0x24, 0x18, 0xC0, 0x0B, 0x5A, 0xD0, 0x02, 0x78, 0x10, 0xA0, 0x12, + 0x64, 0xE3, 0x65, 0x4E, 0x68, 0x22, 0x93, 0x16, 0xF1, 0x0E, 0x92, 0x72, 0x99, 0x9C, 0x3F, 0x6A, + 0xF3, 0xCB, 0x7F, 0x5E, 0xAA, 0x40, 0x85, 0x5A, 0x00, 0x26, 0x5F, 0x15, 0x81, 0x09, 0x44, 0xC0, + 0x68, 0x33, 0xAC, 0x26, 0x69, 0x4C, 0x17, 0x3E, 0xE0, 0x08, 0x60, 0x75, 0xAB, 0x44, 0x5C, 0xAB, + 0x18, 0xEA, 0x1D, 0x5C, 0xCD, 0xC8, 0x96, 0x24, 0x41, 0x9D, 0x11, 0x4E, 0xA0, 0xFE, 0xC1, 0x13, + 0x30, 0x60, 0x00, 0xEB, 0x6A, 0x15, 0x0C, 0x22, 0xB1, 0x83, 0x1D, 0x40, 0x05, 0x1C, 0xD5, 0x5A, + 0x69, 0x6C, 0x14, 0xA6, 0xB0, 0x86, 0xB5, 0x08, 0x28, 0x72, 0xC4, 0x40, 0x63, 0x26, 0x43, 0x8E, + 0x8D, 0x34, 0xE6, 0x9E, 0x0E, 0x08, 0x87, 0xEB, 0x62, 0xC5, 0x1D, 0x67, 0x16, 0x00, 0x9A, 0xF3, + 0xA8, 0x00, 0xE9, 0x6E, 0x68, 0xC0, 0xF1, 0x21, 0x85, 0xA1, 0xCF, 0xA3, 0x9E, 0xE9, 0x70, 0xC3, + 0xD0, 0x56, 0xF9, 0xB0, 0x9C, 0xD5, 0x1A, 0x08, 0x86, 0x16, 0xC0, 0x81, 0x0D, 0x38, 0xD1, 0x08, + 0x21, 0xC5, 0x2A, 0x86, 0x5C, 0xF7, 0x35, 0x48, 0x74, 0x55, 0x07, 0xBE, 0xD4, 0x4A, 0x14, 0x27, + 0x47, 0x49, 0x84, 0x0D, 0xB3, 0x61, 0xC0, 0x88, 0xD6, 0x5C, 0x4E, 0x51, 0x9F, 0x48, 0xCE, 0x48, + 0x79, 0x85, 0xC0, 0x88, 0x01, 0x62, 0x95, 0xC3, 0x34, 0x0E, 0xC0, 0xA7, 0x35, 0x2C, 0xDD, 0x51, + 0x94, 0x86, 0x0E, 0x41, 0xB0, 0x2A, 0x00, 0x01, 0x12, 0x2C, 0x02, 0x6F, 0x53, 0x3D, 0x5C, 0x49, + 0x40, 0x9D, 0x0B, 0x24, 0x07, 0x87, 0x76, 0xD0, 0x28, 0x23, 0x78, 0x80, 0x54, 0x02, 0xA0, 0x81, + 0x28, 0x8E, 0x25, 0x89, 0xB7, 0x84, 0xF0, 0x2A, 0xAE, 0xF1, 0x85, 0x73, 0x6E, 0xF6, 0x11, 0x34, + 0xAD, 0xF0, 0x8A, 0x1B, 0xAA, 0x89, 0x30, 0x3E, 0x05, 0x2A, 0x0F, 0x5C, 0x00, 0x04, 0x0E, 0x04, + 0x46, 0x00, 0x2A, 0x83, 0x08, 0x69, 0xF4, 0xB0, 0x87, 0x7B, 0x1D, 0x6A, 0x6D, 0x99, 0xCA, 0xA7, + 0x78, 0x98, 0x6F, 0x34, 0xE3, 0xB3, 0xA1, 0x35, 0xD9, 0x64, 0x81, 0x8E, 0x31, 0xCE, 0x08, 0x32, + 0x10, 0x05, 0x6E, 0x28, 0x54, 0xD2, 0x44, 0x24, 0x47, 0x5C, 0x16, 0x00, 0x41, 0xD6, 0x74, 0x50, + 0x4B, 0x48, 0x2C, 0x6F, 0x9E, 0x62, 0x1D, 0x49, 0x55, 0x70, 0xE2, 0x59, 0xFE, 0xB7, 0x78, 0x6D, + 0x4A, 0x71, 0x39, 0xC0, 0x30, 0x95, 0xE7, 0x28, 0xEF, 0x5A, 0x98, 0xBB, 0x85, 0xC8, 0xCB, 0x2C, + 0x36, 0x33, 0x13, 0x4C, 0x4A, 0x6F, 0x5C, 0x0A, 0xCD, 0x18, 0x70, 0xE6, 0x3B, 0x4E, 0x10, 0xCB, + 0x96, 0x82, 0xA3, 0x80, 0xD4, 0x09, 0x94, 0x42, 0x02, 0x73, 0x9C, 0xA3, 0xA4, 0x2D, 0xD8, 0xD0, + 0x39, 0xE6, 0xB2, 0x34, 0x0C, 0xC4, 0xB3, 0x11, 0x77, 0x81, 0xDC, 0xF0, 0x56, 0xD8, 0x22, 0xF5, + 0x79, 0x51, 0x00, 0x2D, 0x68, 0xE1, 0x15, 0x63, 0xA1, 0xA8, 0x0D, 0xC5, 0xEE, 0xB8, 0xA7, 0x0D, + 0x2F, 0x06, 0x5C, 0xC4, 0x61, 0xC4, 0x11, 0x90, 0x9A, 0x42, 0x6D, 0xEF, 0x51, 0x46, 0xFC, 0x23, + 0x03, 0x56, 0xB4, 0x2F, 0xDF, 0xF1, 0x2B, 0x21, 0x42, 0x25, 0x90, 0x56, 0x09, 0x63, 0x18, 0x31, + 0x9E, 0xF1, 0x1C, 0xCD, 0xF7, 0xCA, 0x45, 0x78, 0x60, 0x07, 0x85, 0x72, 0xD1, 0x4E, 0xF2, 0xD3, + 0x59, 0x04, 0x48, 0x38, 0x2B, 0x15, 0x52, 0x1E, 0xFE, 0xF2, 0x52, 0x13, 0x0B, 0x1C, 0xAA, 0x51, + 0x85, 0xF0, 0xC4, 0xA2, 0x62, 0x84, 0x9D, 0xAB, 0x24, 0x20, 0x2C, 0x61, 0x71, 0xA6, 0x5D, 0x29, + 0x20, 0x54, 0x05, 0x29, 0xAD, 0x3A, 0x65, 0x61, 0x63, 0x1B, 0xCB, 0x22, 0x51, 0xDC, 0x20, 0x60, + 0x04, 0x2D, 0xE0, 0xC0, 0x2A, 0x2D, 0xD0, 0xC2, 0x70, 0x0E, 0x62, 0x81, 0xF0, 0x2C, 0xA7, 0x22, + 0x7E, 0x71, 0x97, 0x7A, 0xD6, 0x53, 0x26, 0x56, 0x51, 0x73, 0xFD, 0xB0, 0x78, 0x80, 0xD9, 0xB8, + 0x39, 0x47, 0x42, 0xA4, 0x50, 0x02, 0x2E, 0x40, 0x1F, 0x37, 0x07, 0x98, 0xCF, 0xDF, 0x78, 0x53, + 0x00, 0x41, 0x32, 0x0F, 0x02, 0x56, 0xD4, 0x19, 0xC8, 0xF8, 0xD1, 0xAD, 0x6F, 0x78, 0x5E, 0xF9, + 0x5A, 0xF3, 0xBC, 0xE8, 0x6A, 0xC1, 0x82, 0x50, 0x97, 0xDC, 0x03, 0xFE, 0xC2, 0x2B, 0x33, 0x8A, + 0x6B, 0x84, 0x07, 0x11, 0x49, 0x93, 0x2E, 0x4D, 0x25, 0x3F, 0x59, 0x01, 0x47, 0x86, 0xEA, 0x63, + 0x15, 0x42, 0x78, 0x20, 0x39, 0x3F, 0xC9, 0x62, 0x0B, 0x4C, 0xD2, 0xDD, 0x65, 0x60, 0x07, 0x3B, + 0x86, 0xBD, 0x9B, 0x57, 0xF8, 0xA4, 0xD0, 0xE8, 0x05, 0x29, 0x6F, 0xBE, 0xFE, 0x75, 0x95, 0x69, + 0x7B, 0x4D, 0x9F, 0x0C, 0xF1, 0xBC, 0x3D, 0x99, 0xA0, 0x44, 0xEB, 0x8A, 0x2E, 0x23, 0x6C, 0xC2, + 0x48, 0xE0, 0x08, 0x21, 0x22, 0xF9, 0x72, 0x4A, 0xCC, 0x40, 0xB7, 0x26, 0x38, 0xC9, 0x4A, 0xA0, + 0x6A, 0xD3, 0xC3, 0x2C, 0x6A, 0x6F, 0x5F, 0x81, 0x69, 0xC1, 0x0B, 0xE2, 0xE2, 0xC0, 0xE2, 0xB9, + 0x6F, 0x7F, 0x77, 0xDB, 0x64, 0x01, 0x5E, 0x55, 0x68, 0x45, 0x5F, 0x59, 0x41, 0x15, 0xF7, 0x0E, + 0x02, 0x53, 0xC9, 0xF1, 0x61, 0x6F, 0x18, 0x23, 0xED, 0xC6, 0x4D, 0x4D, 0x5A, 0x90, 0x83, 0x1B, + 0x78, 0x43, 0x32, 0x63, 0xA5, 0x97, 0x28, 0x28, 0xB9, 0xD6, 0x95, 0xD6, 0xCF, 0x43, 0xCD, 0x12, + 0xC9, 0x86, 0x30, 0x74, 0x38, 0x39, 0x82, 0x6A, 0x49, 0x52, 0x72, 0xF5, 0x5A, 0x2D, 0x28, 0xCD, + 0x02, 0xD8, 0x35, 0xE3, 0x9F, 0x2C, 0xB7, 0xAE, 0x85, 0xCE, 0x46, 0x86, 0x9A, 0xEE, 0x62, 0xE7, + 0x25, 0x86, 0x96, 0x0F, 0xD8, 0x2A, 0x19, 0xE4, 0x20, 0x01, 0xE5, 0x69, 0x76, 0x47, 0xA2, 0xFD, + 0xEE, 0x62, 0x8C, 0x36, 0x67, 0x04, 0x58, 0x98, 0x10, 0x05, 0x79, 0x8C, 0xA5, 0x1D, 0xA0, 0x63, + 0x59, 0x9F, 0x07, 0x09, 0x2E, 0xF0, 0xA9, 0x6A, 0x19, 0x60, 0x02, 0x87, 0x6A, 0x55, 0x65, 0x24, + 0x00, 0x00, 0x02, 0xA2, 0xF1, 0x6E, 0x01, 0xC0, 0x64, 0xC6, 0x47, 0xAC, 0xDE, 0xA4, 0x55, 0xFC, + 0x8E, 0x56, 0xC6, 0xA6, 0x88, 0x7B, 0x08, 0x80, 0xF9, 0xF1, 0xFE, 0x6D, 0x7C, 0xA8, 0xCB, 0x41, + 0x0A, 0x34, 0x42, 0x2F, 0x68, 0xCF, 0xA5, 0xEB, 0x90, 0x3A, 0xC5, 0x4D, 0xE6, 0x81, 0x80, 0x01, + 0x20, 0x6C, 0x46, 0x09, 0x58, 0x72, 0xE3, 0x07, 0xE1, 0x00, 0x96, 0xB9, 0xEE, 0xA8, 0x03, 0xE0, + 0xA6, 0x9E, 0xC5, 0xE5, 0x66, 0x04, 0x14, 0x60, 0x01, 0x15, 0xC0, 0x00, 0xAB, 0x7C, 0x4E, 0x01, + 0xD2, 0xA9, 0xF1, 0xEE, 0x06, 0x64, 0x6F, 0x95, 0xA3, 0xBC, 0xFA, 0x90, 0x8B, 0xAF, 0x94, 0x84, + 0xC1, 0x97, 0xD4, 0x88, 0xD1, 0x34, 0x89, 0x0E, 0xC0, 0x03, 0x27, 0x80, 0x4C, 0xA0, 0x8E, 0x67, + 0x8C, 0x37, 0xB5, 0xEA, 0xA8, 0xD5, 0x6E, 0xD5, 0x3C, 0x86, 0x19, 0x0E, 0x8B, 0xB8, 0xB8, 0x6F, + 0x3D, 0x19, 0x85, 0xEB, 0x8E, 0x7D, 0xAD, 0x7E, 0x2F, 0xA9, 0x55, 0x72, 0x24, 0xE8, 0xE1, 0x14, + 0x30, 0x81, 0x02, 0x58, 0x9F, 0xF5, 0x18, 0xC7, 0x3B, 0xA0, 0x81, 0x9E, 0xA0, 0xEA, 0xC4, 0x17, + 0x71, 0x1D, 0x07, 0xF6, 0xC6, 0x8F, 0x68, 0xD8, 0x05, 0xB0, 0xB3, 0x18, 0xF3, 0x14, 0x53, 0xEF, + 0x03, 0x32, 0x88, 0x99, 0xCC, 0xD6, 0xF1, 0xAB, 0xD6, 0x9C, 0x9B, 0xF3, 0x08, 0x8F, 0x59, 0xD4, + 0x2B, 0x43, 0x4A, 0x69, 0xD1, 0x2C, 0xBE, 0x2E, 0x2E, 0x03, 0x48, 0x00, 0x86, 0x3F, 0x25, 0x16, + 0x03, 0x80, 0x49, 0xD7, 0x77, 0x77, 0x22, 0x56, 0x4D, 0xAB, 0x97, 0x68, 0xE4, 0xE2, 0x13, 0x80, + 0x47, 0x6E, 0x49, 0x35, 0x62, 0x48, 0xB7, 0x24, 0x18, 0xA2, 0x0E, 0x98, 0x87, 0x08, 0x93, 0x94, + 0x00, 0x0E, 0x70, 0x00, 0x53, 0x72, 0x16, 0x8D, 0x67, 0x38, 0xA8, 0x73, 0x00, 0x19, 0xF0, 0x09, + 0xBB, 0x22, 0x61, 0x0C, 0x28, 0x17, 0x48, 0xA4, 0x76, 0xBE, 0x10, 0x3A, 0xE6, 0x00, 0x43, 0x2A, + 0x63, 0x0E, 0x43, 0x61, 0x31, 0xCE, 0x34, 0x01, 0xD2, 0xFE, 0x50, 0x68, 0xA4, 0x10, 0x5F, 0x53, + 0x86, 0x6E, 0x44, 0xB7, 0x5B, 0x52, 0x66, 0x77, 0x46, 0x67, 0x18, 0x8E, 0x16, 0x7B, 0xB8, 0x62, + 0x3E, 0xE3, 0xC5, 0x2E, 0xF9, 0xD1, 0x0F, 0xD8, 0x36, 0x0F, 0x1D, 0x13, 0x0A, 0x47, 0x24, 0x2E, + 0x83, 0xB2, 0x64, 0xAA, 0xF2, 0x4D, 0x4C, 0x67, 0x38, 0x33, 0x61, 0x1F, 0x1D, 0x71, 0x67, 0xAE, + 0x63, 0x4A, 0x86, 0x13, 0x68, 0x7F, 0x01, 0x65, 0xAC, 0x17, 0x5F, 0x40, 0x62, 0x68, 0xBB, 0x66, + 0x77, 0x53, 0xA6, 0x77, 0xA8, 0x20, 0x2B, 0xA5, 0xC3, 0x34, 0xF2, 0x86, 0x0A, 0xEC, 0xD2, 0x24, + 0xE0, 0x67, 0x2E, 0x2B, 0x24, 0x0E, 0x6B, 0x93, 0x27, 0x4B, 0x43, 0x0F, 0x5D, 0x26, 0x7C, 0x59, + 0xB7, 0x21, 0x71, 0x41, 0x2F, 0x01, 0x24, 0x7B, 0xBD, 0x55, 0x3E, 0x7E, 0x38, 0x1B, 0x40, 0xE1, + 0x3A, 0x08, 0x70, 0x85, 0x82, 0xE0, 0x73, 0x7A, 0x32, 0x3A, 0x06, 0xC8, 0x6E, 0xD3, 0x73, 0x6B, + 0x58, 0x56, 0x77, 0xEA, 0xB6, 0x7D, 0x36, 0x44, 0x18, 0x2F, 0x02, 0x24, 0x3D, 0xB1, 0x28, 0xD0, + 0x27, 0x7C, 0x2C, 0xA2, 0x3C, 0x60, 0xF4, 0x11, 0x4B, 0xD8, 0x1A, 0xE2, 0xA3, 0x7C, 0x02, 0xE0, + 0x28, 0xD3, 0x11, 0x43, 0x4D, 0xA3, 0x32, 0x9F, 0xE8, 0x3A, 0x1D, 0x93, 0x2B, 0x0E, 0x70, 0x28, + 0x83, 0x38, 0x88, 0xD2, 0xE4, 0x4C, 0x71, 0x97, 0x49, 0xE9, 0x05, 0x74, 0x7F, 0xB5, 0x46, 0x7F, + 0xC5, 0x68, 0x77, 0xA4, 0x37, 0xB7, 0x88, 0x8B, 0xBA, 0x36, 0x08, 0x81, 0x08, 0x29, 0xE0, 0x17, + 0x00, 0x95, 0xB7, 0x00, 0x1D, 0x80, 0x1D, 0x16, 0x21, 0x3B, 0xA6, 0x24, 0x01, 0xAC, 0x11, 0x8C, + 0x90, 0x42, 0x21, 0x2F, 0xC3, 0x00, 0x7B, 0x88, 0x44, 0x4C, 0xE8, 0x3A, 0x2A, 0x33, 0x1B, 0x84, + 0xC3, 0x1A, 0x41, 0x34, 0x5E, 0x07, 0x34, 0x71, 0xFE, 0xD3, 0x44, 0x68, 0x73, 0xB7, 0x5E, 0x88, + 0x86, 0x71, 0xAC, 0x67, 0x8B, 0x44, 0x95, 0x80, 0x91, 0xD8, 0x19, 0xBC, 0xF5, 0x89, 0xAC, 0xF4, + 0x31, 0x1D, 0xA0, 0x3C, 0xC5, 0x53, 0x38, 0x2A, 0xB3, 0x8A, 0x7A, 0x18, 0x43, 0xD9, 0x24, 0x17, + 0x78, 0x31, 0x08, 0x2E, 0x26, 0x01, 0xBF, 0x75, 0x25, 0x15, 0x60, 0x67, 0x4C, 0x68, 0x3E, 0xF6, + 0xC3, 0x2B, 0xF4, 0x12, 0x16, 0x15, 0xD3, 0x76, 0x16, 0x63, 0x31, 0xB3, 0xB8, 0x6B, 0x3D, 0xF8, + 0x1B, 0x8C, 0xD6, 0x7D, 0x8A, 0xE6, 0x49, 0xE7, 0x06, 0x91, 0x03, 0x91, 0x31, 0x83, 0x20, 0x02, + 0x3C, 0x10, 0x03, 0x42, 0x30, 0x04, 0x3C, 0x20, 0x73, 0x9F, 0x30, 0x38, 0x34, 0x77, 0x38, 0xA3, + 0x43, 0x3E, 0x12, 0x10, 0x2E, 0xF4, 0x38, 0x1B, 0x12, 0x80, 0x35, 0x50, 0xD2, 0x31, 0xEC, 0xA2, + 0x76, 0xD4, 0x28, 0x2E, 0xA2, 0x20, 0x41, 0x50, 0x62, 0x01, 0x71, 0x45, 0x3C, 0x29, 0x56, 0x0A, + 0xB0, 0x72, 0x34, 0x15, 0x33, 0x8B, 0x51, 0x96, 0x43, 0x5A, 0xE3, 0x90, 0x0A, 0x98, 0x68, 0x48, + 0x67, 0x71, 0xE0, 0x78, 0x1B, 0xEC, 0xC2, 0x90, 0x5B, 0x43, 0x00, 0x24, 0xF0, 0x03, 0x42, 0xB0, + 0x94, 0x43, 0x20, 0x04, 0x31, 0x90, 0x3D, 0xD8, 0xD5, 0x01, 0x2A, 0x63, 0x88, 0x48, 0x24, 0x00, + 0x23, 0x29, 0x01, 0x0E, 0x60, 0x2C, 0xBF, 0xB5, 0x23, 0xE0, 0x82, 0x2B, 0x26, 0x58, 0x0E, 0xA1, + 0xA0, 0x32, 0x76, 0xB8, 0x7C, 0x8B, 0x82, 0x8D, 0x08, 0x74, 0x34, 0x98, 0x04, 0x8B, 0xDF, 0xE8, + 0x17, 0xDD, 0x67, 0x8E, 0xE6, 0x18, 0x8E, 0x7A, 0xE3, 0x85, 0xB8, 0xC6, 0x96, 0x63, 0x18, 0x77, + 0xAB, 0x42, 0x03, 0x3F, 0xF0, 0x03, 0x34, 0xD0, 0x94, 0x3C, 0x30, 0x04, 0x7E, 0xE9, 0x97, 0x42, + 0xF0, 0x03, 0x7F, 0x09, 0x98, 0x3E, 0xA0, 0xFE, 0x02, 0xCA, 0x97, 0x01, 0x88, 0x89, 0x98, 0xC6, + 0x22, 0x38, 0x7D, 0x23, 0x15, 0x02, 0xE0, 0x00, 0x19, 0xC0, 0x3F, 0x4C, 0x68, 0x4A, 0x2D, 0x69, + 0x3E, 0xFF, 0x12, 0x1D, 0x18, 0x54, 0x6B, 0x3E, 0x55, 0x00, 0x2A, 0xC0, 0x8D, 0x73, 0x67, 0x71, + 0x0B, 0x15, 0x89, 0x0A, 0x49, 0x77, 0x48, 0x41, 0x54, 0x12, 0x29, 0x9A, 0x89, 0x23, 0x01, 0x24, + 0x20, 0x04, 0x36, 0x10, 0x03, 0x31, 0x10, 0x04, 0x3C, 0x10, 0x04, 0x83, 0x39, 0x98, 0x19, 0x39, + 0x04, 0x3F, 0x60, 0x03, 0xCF, 0x13, 0x2B, 0x4E, 0x72, 0x01, 0x19, 0xF0, 0x24, 0x06, 0x60, 0x2C, + 0x47, 0xD5, 0x31, 0x95, 0x97, 0x8A, 0x19, 0x60, 0x7F, 0x47, 0x75, 0x8A, 0xD4, 0x18, 0x44, 0xA9, + 0x36, 0x88, 0xB0, 0xE8, 0x73, 0x48, 0x83, 0x90, 0x9F, 0x59, 0x54, 0x3D, 0x29, 0x8E, 0xF3, 0x85, + 0x7D, 0x7B, 0x32, 0x58, 0x10, 0x89, 0x68, 0x4B, 0x83, 0x98, 0x4F, 0x42, 0x03, 0x3A, 0x60, 0x03, + 0x3F, 0x40, 0x02, 0x7E, 0xE9, 0x01, 0xB3, 0xE9, 0x97, 0x82, 0xF9, 0x97, 0x34, 0xC0, 0x4E, 0x6D, + 0xE8, 0x00, 0x75, 0x53, 0x01, 0x19, 0x40, 0x2F, 0x59, 0x99, 0x95, 0x0B, 0xE0, 0x00, 0x0E, 0x90, + 0x75, 0xAB, 0xD3, 0x7E, 0x93, 0x99, 0x9C, 0xBD, 0xE1, 0x8A, 0x29, 0x51, 0x6B, 0x98, 0x44, 0x8F, + 0xD1, 0x39, 0x4E, 0xA1, 0x49, 0x9D, 0x43, 0x85, 0x8B, 0x16, 0x45, 0x18, 0xDF, 0xC4, 0x5E, 0xAF, + 0x40, 0x00, 0x19, 0x20, 0x02, 0x19, 0xE0, 0x02, 0x24, 0xE0, 0x03, 0x32, 0xE0, 0x01, 0x30, 0xF0, + 0x03, 0xE4, 0x09, 0x98, 0x7F, 0x69, 0x03, 0x83, 0xE9, 0x9D, 0xAF, 0x87, 0x44, 0xF3, 0x59, 0x9C, + 0x60, 0x72, 0x58, 0x83, 0x78, 0x28, 0x2E, 0x89, 0x2F, 0x47, 0x45, 0x8D, 0x61, 0xA9, 0x9F, 0xB1, + 0x10, 0x7B, 0x05, 0x75, 0x90, 0xD1, 0xFE, 0x59, 0x74, 0x3E, 0x69, 0x8B, 0xD9, 0xA9, 0x37, 0x5F, + 0x38, 0x6B, 0xB3, 0x10, 0x2A, 0x48, 0x31, 0x2E, 0xB3, 0xB2, 0x4D, 0x3A, 0xE0, 0x03, 0x63, 0x67, + 0x91, 0x31, 0x80, 0x9E, 0x7F, 0x29, 0x9B, 0x7F, 0xF9, 0x03, 0x3E, 0xC0, 0x03, 0x54, 0x29, 0x0B, + 0xB3, 0x41, 0x5E, 0xEC, 0x22, 0x0A, 0xBD, 0xD1, 0x11, 0x59, 0xA7, 0x0E, 0x26, 0xBA, 0x7C, 0x6A, + 0xE7, 0xA4, 0xEC, 0x72, 0x28, 0x01, 0xB1, 0x4A, 0xE7, 0x10, 0x5B, 0xD1, 0x79, 0x31, 0x33, 0xCA, + 0x83, 0xB8, 0x66, 0x9A, 0x42, 0x19, 0x00, 0x91, 0x69, 0x03, 0x24, 0x80, 0x98, 0xA3, 0x29, 0x08, + 0x1E, 0xF0, 0x02, 0x35, 0xE0, 0x02, 0x2F, 0xE0, 0x02, 0x42, 0x20, 0x02, 0x3E, 0xE0, 0x97, 0x3A, + 0xA0, 0x03, 0x7E, 0x69, 0x03, 0xB5, 0x39, 0x04, 0x34, 0x20, 0x03, 0x3E, 0xE0, 0x73, 0xE4, 0x47, + 0x8D, 0xC6, 0xC2, 0x2E, 0x97, 0x97, 0x75, 0x84, 0xAA, 0x84, 0xE4, 0x83, 0x17, 0xF4, 0x30, 0x88, + 0xCB, 0x77, 0xA5, 0x02, 0x51, 0x0A, 0x69, 0xF9, 0x7A, 0x2F, 0x9A, 0x4A, 0x3F, 0xB9, 0x50, 0x61, + 0x38, 0x4E, 0xD8, 0xA9, 0x35, 0xC4, 0xF2, 0xA1, 0x6F, 0x39, 0x08, 0x17, 0x20, 0x03, 0x2E, 0xD0, + 0x02, 0x17, 0x10, 0x9E, 0x49, 0xF9, 0x03, 0x32, 0x00, 0x04, 0x76, 0xDA, 0xA3, 0xB6, 0xA9, 0x97, + 0x2E, 0x40, 0x03, 0x54, 0xE9, 0x81, 0x8F, 0xD9, 0x92, 0xB3, 0x21, 0x88, 0x44, 0x56, 0xA8, 0x97, + 0x67, 0x15, 0x2E, 0x49, 0x8D, 0xBF, 0x77, 0x74, 0x72, 0xF9, 0x8D, 0xA8, 0x60, 0x62, 0xBB, 0x05, + 0xA3, 0x40, 0x39, 0x5B, 0xB1, 0xC7, 0x80, 0x12, 0xD5, 0x00, 0x12, 0xF0, 0x10, 0xD8, 0x29, 0x03, + 0x2F, 0xA0, 0x03, 0xA0, 0xEA, 0x03, 0x34, 0xE0, 0x02, 0x3E, 0xE0, 0x03, 0x15, 0xDA, 0xA3, 0x2F, + 0x20, 0x98, 0x3F, 0x00, 0x04, 0xFE, 0x2D, 0xE0, 0x02, 0x1D, 0xE0, 0x73, 0xF4, 0xE8, 0xAA, 0x4E, + 0x8A, 0x17, 0x19, 0x28, 0x44, 0x44, 0xB8, 0x7C, 0xFF, 0x01, 0xAB, 0xA5, 0x56, 0x8D, 0x5D, 0xD6, + 0x6B, 0x2F, 0xEA, 0x7D, 0x21, 0x76, 0x9D, 0xE3, 0x48, 0x9A, 0x96, 0x8A, 0x9D, 0xBF, 0xBA, 0x27, + 0x32, 0xA0, 0x03, 0x1D, 0x40, 0x03, 0x0B, 0x00, 0x03, 0x71, 0xFA, 0x02, 0x7A, 0x9A, 0x97, 0x40, + 0x40, 0x02, 0x78, 0x69, 0x9B, 0x31, 0x26, 0x03, 0xE2, 0x33, 0x51, 0xF4, 0x30, 0xA5, 0xB3, 0x81, + 0x35, 0x77, 0x42, 0x5D, 0x58, 0x5A, 0x19, 0xE5, 0xEA, 0x66, 0x27, 0x2A, 0x0B, 0x33, 0xE6, 0x6B, + 0x0A, 0x89, 0x65, 0xB3, 0x35, 0xA0, 0xA5, 0xE9, 0x93, 0xBC, 0x78, 0x9D, 0xEA, 0xFA, 0x1D, 0xAE, + 0xD3, 0x88, 0x05, 0x1A, 0x00, 0x9E, 0xDA, 0x02, 0x33, 0xE2, 0x01, 0x16, 0xFA, 0x02, 0x42, 0xF0, + 0x02, 0x3E, 0x90, 0x97, 0x3A, 0x80, 0x97, 0xA4, 0xEA, 0x03, 0x24, 0x45, 0x3E, 0xAC, 0x64, 0xAB, + 0x47, 0x95, 0x81, 0xE1, 0x9A, 0x17, 0x37, 0x73, 0x27, 0x6E, 0x86, 0xA5, 0x00, 0xD1, 0xA4, 0x2E, + 0xA9, 0x8B, 0x91, 0xAA, 0x83, 0x07, 0x98, 0x7D, 0x43, 0x69, 0x68, 0x46, 0xAB, 0x7A, 0x7C, 0x15, + 0x8E, 0x43, 0x95, 0x9E, 0x32, 0x40, 0x02, 0x2E, 0x30, 0x04, 0xDC, 0x14, 0x03, 0x3E, 0xA0, 0x03, + 0x3F, 0xD0, 0xB2, 0x2B, 0xAB, 0x03, 0x4F, 0xBB, 0x6D, 0xB8, 0x31, 0x51, 0xFB, 0x25, 0x00, 0x8B, + 0x49, 0x1B, 0xD4, 0xD5, 0x79, 0xCE, 0x82, 0xA5, 0x2D, 0x77, 0xA5, 0x33, 0xF6, 0x96, 0x34, 0x28, + 0xA3, 0x74, 0x07, 0x97, 0x0A, 0xE9, 0xA5, 0xB9, 0x36, 0x7E, 0x03, 0xAA, 0xB1, 0xAD, 0x30, 0x14, + 0xAE, 0x50, 0x03, 0x3E, 0xF0, 0xA9, 0xA1, 0x7A, 0x01, 0x2F, 0x00, 0x04, 0xCE, 0x0A, 0x04, 0x43, + 0x20, 0x03, 0x35, 0x40, 0xFE, 0xB5, 0xB6, 0x59, 0x03, 0x34, 0x90, 0x62, 0x5B, 0x7B, 0x5E, 0x0D, + 0x50, 0x01, 0xC6, 0x82, 0x17, 0x38, 0xCB, 0xB0, 0x8D, 0x0B, 0x14, 0xBD, 0xC1, 0x8A, 0xFF, 0x31, + 0x91, 0x68, 0x1B, 0xA0, 0xBB, 0x5A, 0xA0, 0x14, 0x2B, 0xAC, 0x57, 0x26, 0x86, 0x20, 0x06, 0xB7, + 0x4B, 0x53, 0x40, 0x18, 0xF0, 0xAC, 0x34, 0x90, 0x94, 0x1D, 0xA0, 0xAF, 0x7F, 0x9B, 0x97, 0x43, + 0xE0, 0xAC, 0x7E, 0x19, 0xAD, 0x34, 0xF0, 0x3C, 0xE2, 0x03, 0x7C, 0xA1, 0x60, 0x2C, 0x0E, 0xC0, + 0xB8, 0xB2, 0x8A, 0x17, 0x6B, 0xB5, 0xB0, 0x0A, 0x0B, 0x49, 0xEE, 0x03, 0x10, 0xD5, 0x96, 0xA6, + 0x96, 0xEB, 0x96, 0x89, 0x16, 0x86, 0x38, 0xD8, 0x88, 0xE0, 0x58, 0x5B, 0xEE, 0x35, 0x83, 0x83, + 0x61, 0x00, 0x80, 0xEB, 0x02, 0x16, 0xE0, 0x02, 0x9F, 0xEA, 0x03, 0x42, 0x00, 0xAD, 0xE0, 0xE9, + 0x9D, 0x7F, 0xE9, 0x03, 0x2F, 0x70, 0x0C, 0x20, 0x49, 0x87, 0xE1, 0xB2, 0x30, 0xB1, 0x8A, 0x08, + 0x41, 0xF4, 0xBD, 0x0B, 0x2B, 0x44, 0x18, 0x28, 0x8F, 0x77, 0x32, 0x91, 0xEB, 0x1A, 0x65, 0xBA, + 0x65, 0x80, 0x46, 0x87, 0x6E, 0xE2, 0x24, 0x9A, 0x3C, 0xD9, 0x31, 0x7E, 0x25, 0x54, 0x06, 0x10, + 0x64, 0x9E, 0x80, 0x01, 0x31, 0x70, 0xAF, 0x43, 0x00, 0xAD, 0x79, 0xE9, 0x02, 0x35, 0x30, 0x04, + 0x40, 0x90, 0x97, 0xF3, 0xB2, 0xB5, 0xC5, 0xD2, 0x00, 0xC0, 0x27, 0xA8, 0xD2, 0xB8, 0xA4, 0x38, + 0x8B, 0x8D, 0xFF, 0x50, 0x3C, 0x8E, 0xB4, 0x56, 0xFD, 0xE9, 0xBB, 0x01, 0x4A, 0x65, 0x0D, 0x69, + 0x94, 0xB9, 0xB8, 0x27, 0x24, 0x86, 0x43, 0x56, 0xF3, 0x8F, 0x6B, 0x5B, 0x40, 0x48, 0xD9, 0x02, + 0x1D, 0x80, 0x32, 0x43, 0x40, 0xA1, 0x7A, 0xE9, 0xB2, 0x6E, 0x2A, 0x98, 0xD1, 0xEA, 0x01, 0x1D, + 0x90, 0x7C, 0x0C, 0xFE, 0x9A, 0x01, 0x04, 0x0C, 0xAB, 0x28, 0xCA, 0x84, 0xFF, 0x61, 0x00, 0xAB, + 0x28, 0x44, 0x96, 0x79, 0x99, 0x90, 0x64, 0x0E, 0xF4, 0x70, 0xBE, 0xDC, 0xC7, 0x88, 0x13, 0xBC, + 0x71, 0x73, 0x49, 0xA9, 0x85, 0x75, 0x3D, 0x93, 0x59, 0x5B, 0x36, 0x52, 0x40, 0xF0, 0xE2, 0x01, + 0x34, 0x80, 0x01, 0xA1, 0xEA, 0x01, 0x2E, 0x50, 0xB5, 0x2E, 0xBB, 0xAC, 0x2B, 0x0B, 0x04, 0x40, + 0x50, 0x03, 0x5C, 0x41, 0x9F, 0xE4, 0x30, 0xA8, 0xCB, 0x47, 0x3B, 0x57, 0xE8, 0xA4, 0xCB, 0xC7, + 0x1A, 0x07, 0x20, 0x01, 0x97, 0x71, 0x4C, 0x77, 0x52, 0x6A, 0xD2, 0xA3, 0xC3, 0x66, 0xAC, 0xB6, + 0xBF, 0xF6, 0xC3, 0xF3, 0x5A, 0x1A, 0x2A, 0xDC, 0x2A, 0x7E, 0xBA, 0xC6, 0x0E, 0x41, 0x8C, 0xF8, + 0xE7, 0x03, 0x22, 0x20, 0x02, 0x78, 0x19, 0xB0, 0x34, 0xE0, 0x9D, 0x12, 0x9A, 0x9E, 0xDC, 0xD1, + 0x48, 0x57, 0x0C, 0x76, 0x28, 0xFA, 0x7B, 0xE9, 0x14, 0xAB, 0x0D, 0x2B, 0xBE, 0x18, 0x88, 0x67, + 0x63, 0x9C, 0xA5, 0x66, 0x8C, 0xBE, 0x9F, 0x59, 0x97, 0x79, 0x67, 0xB1, 0x1C, 0x27, 0x4D, 0x32, + 0x3B, 0x00, 0x1D, 0x03, 0x86, 0x1C, 0x9C, 0x64, 0x0B, 0xE0, 0x02, 0x30, 0x40, 0x02, 0x41, 0x0A, + 0xAD, 0xD8, 0xDA, 0x02, 0x2B, 0x0B, 0xB3, 0x8D, 0x64, 0x87, 0x2D, 0x6C, 0x2C, 0xD4, 0xD8, 0x81, + 0x27, 0x88, 0xAB, 0xE0, 0x5B, 0x19, 0xAB, 0x58, 0x08, 0x5F, 0x52, 0x6A, 0x26, 0xB6, 0xC8, 0x6D, + 0x29, 0xB7, 0xB4, 0xB8, 0x6E, 0xE9, 0xD8, 0x57, 0x27, 0x58, 0xB9, 0x02, 0x62, 0x01, 0x1D, 0x10, + 0x64, 0x0B, 0x00, 0xB0, 0x22, 0x00, 0x9E, 0xAB, 0x9A, 0x9E, 0x2D, 0x60, 0xA7, 0xD8, 0x7A, 0x5C, + 0xA3, 0x20, 0xA8, 0xA8, 0xE8, 0xC2, 0x51, 0x48, 0xA8, 0x08, 0x5C, 0x19, 0x07, 0xE0, 0x48, 0xE1, + 0x30, 0xBB, 0xFE, 0xBA, 0xBC, 0xAE, 0x40, 0xCB, 0x7D, 0xA1, 0xE9, 0x80, 0xD4, 0xA3, 0x71, 0x87, + 0x43, 0xCB, 0x08, 0x68, 0x00, 0x37, 0xE7, 0x00, 0x1E, 0x40, 0xC7, 0x77, 0x9C, 0xC7, 0x9F, 0x02, + 0xCA, 0x32, 0x90, 0xAD, 0x2F, 0x10, 0x57, 0x02, 0x91, 0xA2, 0x95, 0x39, 0x3E, 0x93, 0x29, 0x7B, + 0x58, 0xDA, 0x00, 0x97, 0x41, 0x9F, 0xF3, 0xC9, 0x4C, 0x10, 0x7C, 0xBE, 0xEF, 0x97, 0xCF, 0x1C, + 0x2B, 0x86, 0xE1, 0x93, 0x43, 0x6C, 0x62, 0x7D, 0xFA, 0x92, 0x7C, 0xF0, 0x50, 0x71, 0xA7, 0x24, + 0x0C, 0x18, 0xD2, 0x44, 0x49, 0xE9, 0x9D, 0x2F, 0x80, 0xC2, 0x2D, 0x50, 0x03, 0x13, 0x0A, 0x2A, + 0xA3, 0x70, 0xA2, 0x57, 0xAC, 0xA8, 0xF4, 0x32, 0x44, 0x4A, 0x45, 0x0E, 0xD2, 0xB8, 0xB0, 0xBD, + 0x61, 0xCF, 0xCB, 0x93, 0x6E, 0xB2, 0x7C, 0x65, 0x5E, 0x8A, 0xB9, 0xA3, 0x59, 0xBC, 0x45, 0xA5, + 0xB9, 0xA3, 0x23, 0x01, 0x8A, 0x5B, 0xD0, 0x25, 0x3D, 0x00, 0x0E, 0xF0, 0xC1, 0x95, 0xE7, 0x02, + 0x18, 0x10, 0xA1, 0xC5, 0xCC, 0xA7, 0x5E, 0x13, 0xAD, 0xE9, 0x8C, 0x01, 0x4D, 0x6A, 0xAB, 0x94, + 0xC9, 0x84, 0x75, 0x78, 0xB0, 0x80, 0x88, 0x8D, 0xF6, 0x6C, 0x21, 0xD3, 0x29, 0xCB, 0x73, 0x29, + 0x0F, 0x9D, 0x0B, 0xC1, 0xA5, 0x39, 0x74, 0xDA, 0xC9, 0xB5, 0x27, 0x5D, 0xB1, 0x83, 0x00, 0x0C, + 0xEC, 0xE2, 0x16, 0x1D, 0xE0, 0x01, 0x32, 0x90, 0xC7, 0x3A, 0x40, 0xB8, 0x2D, 0x80, 0x97, 0x35, + 0x40, 0x02, 0x2D, 0x30, 0x41, 0xA2, 0xE0, 0xC2, 0xF5, 0x49, 0x87, 0x47, 0xD4, 0x00, 0x0C, 0x53, + 0x19, 0x87, 0x32, 0xD4, 0x2D, 0xC2, 0x89, 0xD5, 0xBC, 0xC8, 0xF8, 0x92, 0xB6, 0x12, 0x49, 0x91, + 0x80, 0x06, 0xA9, 0xAD, 0xC0, 0x4A, 0x41, 0xCB, 0x3A, 0xF3, 0x02, 0x14, 0x31, 0x66, 0xD5, 0x21, + 0x4C, 0xFE, 0x52, 0x54, 0x5C, 0xAD, 0x54, 0xDC, 0x01, 0x9C, 0x28, 0x0A, 0xC6, 0x84, 0xA5, 0x51, + 0x2A, 0x8D, 0x35, 0x32, 0xC6, 0x98, 0x52, 0x79, 0x33, 0x49, 0xD4, 0x8E, 0x67, 0x15, 0x46, 0xAD, + 0xB4, 0x45, 0x85, 0xBE, 0x9B, 0x5B, 0x8E, 0x34, 0xFA, 0x7E, 0x6F, 0x7D, 0x83, 0x08, 0x78, 0x0E, + 0xBD, 0xFC, 0x56, 0x2E, 0xE0, 0x28, 0x7B, 0xE9, 0xB4, 0xF5, 0x1A, 0x63, 0xD1, 0x1A, 0x63, 0x5D, + 0x3C, 0xC3, 0x1C, 0xBD, 0xA4, 0x61, 0x79, 0x67, 0xBB, 0xA2, 0x24, 0x71, 0xE5, 0x3B, 0x3B, 0x02, + 0x29, 0x2B, 0x0A, 0xD2, 0xFA, 0x8C, 0x65, 0x6F, 0x8D, 0xCD, 0xEA, 0x06, 0x6F, 0x71, 0x69, 0x4D, + 0xDD, 0x5C, 0xB4, 0x61, 0x8A, 0x55, 0x78, 0xF8, 0xD2, 0xDB, 0xD6, 0xC4, 0x2F, 0x90, 0x9E, 0xCC, + 0x5A, 0xAF, 0x35, 0xD0, 0xA6, 0x82, 0xBD, 0x8A, 0xB9, 0x82, 0xA5, 0xF3, 0x59, 0x21, 0xE9, 0x04, + 0x26, 0xA8, 0xA5, 0x23, 0x4A, 0xD1, 0xDA, 0x56, 0x13, 0x01, 0x74, 0x86, 0x0A, 0xD0, 0x10, 0xD9, + 0xB2, 0xF5, 0x85, 0xC1, 0x6B, 0xCB, 0xD4, 0x83, 0x38, 0xAF, 0x50, 0x3D, 0x9F, 0xD4, 0x93, 0xBE, + 0x2B, 0x73, 0x15, 0x72, 0x01, 0x63, 0xD7, 0x02, 0x7A, 0x79, 0xB7, 0x57, 0x2D, 0x03, 0xF0, 0x0D, + 0xD1, 0x32, 0x89, 0x32, 0x76, 0xD2, 0xB0, 0xBF, 0xA9, 0x23, 0xDE, 0x2B, 0x23, 0x08, 0x9D, 0x1C, + 0xB5, 0x71, 0x55, 0x7E, 0xD8, 0x75, 0xE4, 0x80, 0x8E, 0xC0, 0x4A, 0xDB, 0xEB, 0x86, 0x5E, 0xE2, + 0xFD, 0xC3, 0x16, 0x8C, 0xB1, 0xE6, 0x4D, 0x9D, 0x3D, 0xF1, 0xC6, 0x95, 0xBB, 0x20, 0xE0, 0x4C, + 0x28, 0x28, 0xCC, 0xBF, 0x46, 0x9A, 0xCE, 0xE7, 0x74, 0x4E, 0xCC, 0x5A, 0x08, 0xF4, 0x09, 0xB9, + 0xF4, 0x4C, 0x35, 0xA5, 0xA6, 0x5D, 0x8E, 0x25, 0x25, 0x18, 0x01, 0x23, 0xF4, 0xF2, 0x9B, 0xAC, + 0xFE, 0xB2, 0xA2, 0x0F, 0xFC, 0x0C, 0x0F, 0x41, 0x83, 0x49, 0x6B, 0x41, 0xC1, 0x88, 0xE0, 0xBC, + 0xB6, 0xA3, 0x54, 0x59, 0xC6, 0x99, 0xAD, 0x31, 0xAD, 0x72, 0x5B, 0x15, 0x5B, 0x1A, 0xF3, 0x9B, + 0x11, 0x71, 0x15, 0x64, 0x00, 0xAB, 0xA7, 0x24, 0xA5, 0x70, 0x24, 0x25, 0xA1, 0x1B, 0x62, 0xCF, + 0xF2, 0x28, 0x38, 0x15, 0x92, 0x87, 0x6E, 0xF2, 0x40, 0x18, 0x00, 0x5E, 0x18, 0x72, 0x01, 0x87, + 0xFB, 0x7C, 0xAE, 0x13, 0x12, 0xED, 0x47, 0x5A, 0xC0, 0x4B, 0x83, 0xAC, 0xD4, 0xAB, 0xB1, 0x9C, + 0xB6, 0x9A, 0x9D, 0xE5, 0xBD, 0x7A, 0x3A, 0x62, 0xB9, 0xE5, 0x08, 0x78, 0x4A, 0x66, 0x33, 0xA1, + 0x24, 0x00, 0x03, 0x40, 0x90, 0x9E, 0x8E, 0x02, 0xDF, 0x59, 0x4D, 0xB8, 0x18, 0x78, 0x19, 0x8D, + 0x0B, 0x26, 0x8B, 0xE2, 0x28, 0x88, 0x80, 0x6C, 0x56, 0xC3, 0x32, 0x27, 0xF9, 0x87, 0x56, 0x83, + 0x8E, 0xED, 0xAC, 0x84, 0x86, 0x9A, 0xCF, 0x87, 0x16, 0xBF, 0xB5, 0xBC, 0xA3, 0x02, 0xA4, 0x85, + 0xD2, 0x24, 0xC9, 0x1B, 0x67, 0x38, 0x95, 0x9C, 0x88, 0x77, 0xDE, 0x3D, 0x25, 0xEB, 0xB4, 0x78, + 0x39, 0xA1, 0xF7, 0xCA, 0xA7, 0x81, 0x0B, 0xDF, 0x39, 0xB2, 0xE1, 0xC6, 0x94, 0xE4, 0xFE, 0xF0, + 0xB1, 0x20, 0x59, 0x3E, 0xE5, 0x40, 0x2C, 0xE6, 0xDB, 0xA8, 0x86, 0xBA, 0xE2, 0x8B, 0x8C, 0x5E, + 0x15, 0xC0, 0xCF, 0x17, 0xAC, 0xA5, 0xC1, 0x88, 0xD2, 0x03, 0x78, 0x7A, 0xDA, 0xC9, 0xC6, 0xFB, + 0x92, 0xAD, 0x23, 0x51, 0x61, 0x24, 0x00, 0xD8, 0x10, 0x9A, 0xDC, 0x04, 0xF6, 0xAC, 0x32, 0x70, + 0xCF, 0xD8, 0x41, 0xCF, 0x96, 0x39, 0x23, 0x1A, 0xA0, 0xD3, 0xA6, 0x28, 0xB3, 0x2E, 0xE9, 0x00, + 0x6E, 0x5B, 0xE5, 0x94, 0xDB, 0x7E, 0xE6, 0xAB, 0xC3, 0xB5, 0x56, 0x01, 0x0A, 0x60, 0xCD, 0xFE, + 0x35, 0xCA, 0x26, 0xE2, 0xD7, 0x17, 0x61, 0xEE, 0x73, 0xA8, 0xD7, 0x43, 0x7A, 0xD1, 0x02, 0x95, + 0xD7, 0x01, 0x1D, 0xD0, 0x44, 0xCB, 0xDA, 0xA3, 0x56, 0xCD, 0xBA, 0x92, 0x4E, 0x3C, 0x43, 0xAD, + 0x60, 0x57, 0xB4, 0x01, 0xC2, 0x4E, 0x8A, 0xB9, 0x8C, 0x5B, 0x50, 0x38, 0x10, 0xC8, 0xDA, 0x7E, + 0x03, 0x4E, 0xDB, 0xB8, 0x36, 0x01, 0x13, 0x30, 0x27, 0xFF, 0x67, 0x1D, 0xC8, 0x60, 0x62, 0xAD, + 0x25, 0xDE, 0x06, 0x8B, 0x0E, 0x06, 0xDB, 0xE0, 0x53, 0x3E, 0xA9, 0x3E, 0x51, 0x67, 0xF3, 0xC9, + 0xCB, 0xE0, 0xE5, 0xD5, 0x36, 0xE0, 0x03, 0x35, 0x90, 0xAD, 0x2B, 0x0B, 0xDF, 0x1D, 0xE0, 0x02, + 0x23, 0x31, 0x8C, 0x60, 0x54, 0x08, 0xD9, 0xB3, 0x01, 0xB3, 0x31, 0x7C, 0x27, 0x48, 0x87, 0x64, + 0xFD, 0xE7, 0xEF, 0xCE, 0x54, 0xE5, 0x96, 0x71, 0x82, 0x76, 0x37, 0xDE, 0x58, 0x01, 0x12, 0x80, + 0x0A, 0x46, 0x03, 0x9D, 0x46, 0xCB, 0x80, 0x88, 0xE3, 0x73, 0x86, 0x88, 0x0A, 0x7B, 0xF5, 0x89, + 0x76, 0x93, 0x80, 0xBA, 0xE8, 0x34, 0x49, 0x5E, 0xD5, 0x0A, 0x77, 0xC7, 0x43, 0x5E, 0xB5, 0x13, + 0xFA, 0x02, 0xD7, 0x68, 0x36, 0x41, 0xF3, 0x40, 0xEC, 0x02, 0x4E, 0xF8, 0xF2, 0x5B, 0xB5, 0xDA, + 0xBB, 0x12, 0xEC, 0xDD, 0x1F, 0x9F, 0x71, 0xD6, 0x37, 0x08, 0xD5, 0xC7, 0x02, 0x27, 0x4F, 0x01, + 0x50, 0x4F, 0x01, 0x2A, 0x40, 0x40, 0xE3, 0x12, 0x94, 0xB7, 0xED, 0xB6, 0x59, 0x68, 0xBC, 0xBD, + 0xAD, 0xC6, 0x0C, 0xE5, 0x3A, 0xB9, 0x22, 0x34, 0xA0, 0x52, 0xDC, 0x7A, 0x0A, 0x2A, 0x34, 0x10, + 0xAD, 0x23, 0x25, 0x64, 0x85, 0x12, 0x0E, 0x17, 0xC0, 0x6A, 0x19, 0x36, 0x2C, 0x4C, 0xE8, 0x01, + 0x2E, 0xED, 0x50, 0x56, 0x91, 0x4E, 0x96, 0xBD, 0x90, 0xA9, 0x27, 0xD9, 0xD2, 0x8E, 0xFE, 0x2F, + 0x14, 0x20, 0x01, 0xF4, 0x1E, 0xF5, 0x53, 0x4F, 0x01, 0x13, 0x70, 0x96, 0xD3, 0x29, 0xE8, 0x7F, + 0x67, 0x94, 0x06, 0x2B, 0x5F, 0xBA, 0xEA, 0x3A, 0x32, 0x49, 0x1B, 0x33, 0x72, 0x4E, 0x79, 0x4C, + 0xC5, 0x48, 0xCC, 0xBA, 0x41, 0x06, 0x0C, 0x9A, 0x1E, 0x0E, 0x7F, 0x73, 0x27, 0x44, 0x3F, 0x00, + 0xC5, 0x69, 0x3B, 0x19, 0xB0, 0x8A, 0xFD, 0x89, 0x08, 0x4B, 0x7D, 0xD4, 0x41, 0xEB, 0x71, 0x38, + 0xA9, 0x02, 0x52, 0x3F, 0x71, 0x50, 0xBF, 0x49, 0x75, 0xAD, 0x27, 0xB5, 0x38, 0x1A, 0xD6, 0x57, + 0xD4, 0x5A, 0xBA, 0x35, 0xA8, 0x49, 0x7E, 0xF0, 0xC2, 0x1A, 0x71, 0x85, 0x42, 0x4C, 0x0C, 0xAD, + 0xA3, 0xEB, 0xF8, 0xFB, 0xCB, 0xBC, 0x66, 0x22, 0x25, 0x1A, 0xF0, 0xF3, 0x9E, 0xE0, 0x3A, 0xCA, + 0xE8, 0xF6, 0xBF, 0x65, 0x2C, 0xB1, 0x7D, 0xEA, 0x19, 0xFC, 0xB1, 0x79, 0x37, 0xD7, 0xBD, 0x1A, + 0xC1, 0xCF, 0x1F, 0x8B, 0x15, 0x03, 0x4D, 0x3F, 0x95, 0xFA, 0x11, 0x50, 0x01, 0x41, 0x15, 0x3E, + 0x2D, 0x9F, 0x85, 0xE8, 0xD6, 0xCD, 0x05, 0x64, 0x58, 0x48, 0xA7, 0xB9, 0x12, 0x35, 0x1B, 0x9E, + 0x60, 0xCF, 0x64, 0xC7, 0xC4, 0x65, 0xCF, 0xAC, 0xE7, 0x24, 0x03, 0x46, 0xFA, 0xA9, 0xDC, 0x6E, + 0x26, 0x1E, 0x10, 0x34, 0x9F, 0xA2, 0xD3, 0x23, 0x41, 0xF4, 0xE5, 0x13, 0x38, 0x1E, 0x58, 0x00, + 0x50, 0x6E, 0xD9, 0x32, 0xAA, 0xCD, 0xEA, 0x0B, 0x08, 0x01, 0x03, 0x00, 0x83, 0x05, 0x2A, 0x14, + 0x88, 0x87, 0x88, 0x13, 0x14, 0x11, 0x13, 0x11, 0x03, 0x05, 0x82, 0x11, 0x05, 0x05, 0x83, 0x03, + 0x03, 0x01, 0x00, 0x84, 0x01, 0x9D, 0x82, 0x92, 0x9D, 0x9B, 0x99, 0x9E, 0x9E, 0x00, 0xA4, 0xA7, + 0x98, 0x06, 0x04, 0x18, 0x18, 0x0E, 0x0E, 0x16, 0x17, 0x1D, 0x1E, 0x1E, 0x34, 0xFE, 0x3F, 0x3E, + 0x2E, 0x24, 0x2D, 0x2D, 0x35, 0x35, 0x32, 0xBE, 0x1A, 0xAC, 0x18, 0x16, 0x1E, 0x18, 0xB3, 0x0B, + 0x16, 0x0B, 0x04, 0x04, 0x0D, 0x06, 0x99, 0xA3, 0x9E, 0x98, 0x03, 0x12, 0xCF, 0xA7, 0x9A, 0xA4, + 0xD1, 0x9B, 0xD9, 0xDA, 0xDB, 0x9A, 0xD9, 0x01, 0x95, 0x01, 0x0A, 0x14, 0x2C, 0x14, 0x0A, 0x11, + 0x11, 0x88, 0x8B, 0x2A, 0x2A, 0xE0, 0xE7, 0x8D, 0x05, 0xE7, 0x90, 0xA3, 0x98, 0xDF, 0x96, 0x90, + 0xDD, 0xA6, 0x82, 0x9D, 0xD4, 0xD0, 0xD1, 0x98, 0x02, 0x06, 0x0C, 0xB0, 0x72, 0xB5, 0x20, 0x96, + 0x87, 0x16, 0x32, 0x6C, 0xE9, 0xD2, 0x25, 0xE3, 0x85, 0x8E, 0x5E, 0x1D, 0x30, 0x6C, 0x08, 0xC6, + 0xEA, 0x40, 0x83, 0x03, 0x19, 0x1A, 0x28, 0x1B, 0xD0, 0x60, 0x9A, 0xB2, 0x4D, 0x04, 0x04, 0x39, + 0xF3, 0x64, 0xA9, 0x94, 0xB7, 0x7D, 0xFB, 0xB6, 0xA9, 0x9C, 0x00, 0xCF, 0x54, 0x3E, 0x70, 0x88, + 0x06, 0x88, 0x73, 0x34, 0x80, 0x82, 0x0A, 0x46, 0x88, 0x2A, 0x35, 0x6A, 0xC4, 0xA8, 0x52, 0x24, + 0x4C, 0x3E, 0x45, 0x4A, 0x1A, 0xE4, 0x32, 0x1F, 0xBF, 0x7D, 0xCF, 0x32, 0x09, 0x38, 0x20, 0xB0, + 0x81, 0x2B, 0x07, 0xB1, 0x48, 0x78, 0x70, 0xA1, 0xC3, 0x87, 0x0C, 0x86, 0x3A, 0x64, 0xD0, 0xA8, + 0x41, 0x83, 0xD5, 0x86, 0xAF, 0x20, 0x30, 0x1C, 0x20, 0x80, 0x80, 0x63, 0x47, 0x09, 0x11, 0x34, + 0x12, 0x58, 0xE0, 0xB4, 0xC1, 0xCF, 0x48, 0x02, 0x9C, 0x8D, 0xDA, 0xE4, 0x49, 0xC0, 0x29, 0x97, + 0xF8, 0x54, 0x9A, 0xCA, 0x54, 0xC0, 0xA8, 0x4C, 0x05, 0x91, 0x0A, 0xEC, 0xBC, 0x99, 0x28, 0x1D, + 0x85, 0x09, 0x8F, 0x1C, 0x4D, 0x40, 0x5B, 0xA9, 0x40, 0x83, 0xC6, 0xF3, 0x42, 0xD1, 0x35, 0x5A, + 0x4D, 0x2E, 0xCA, 0x00, 0xAA, 0x90, 0x11, 0xB4, 0x50, 0x8C, 0xC4, 0x8B, 0xFE, 0x1A, 0x3F, 0x5C, + 0x30, 0xA4, 0xE1, 0x42, 0xC6, 0x09, 0x19, 0x13, 0x41, 0xC8, 0x02, 0x61, 0x41, 0xD5, 0x00, 0x03, + 0x67, 0x23, 0x28, 0x63, 0x36, 0x20, 0xA3, 0xDB, 0x01, 0xCA, 0x02, 0x3A, 0x0B, 0x69, 0xAD, 0x77, + 0x27, 0xBB, 0xDF, 0x32, 0xE9, 0x9D, 0x8C, 0x2F, 0xA9, 0x4C, 0x49, 0x94, 0xD0, 0x19, 0x76, 0x14, + 0x2F, 0x02, 0x5A, 0x74, 0x05, 0x94, 0x41, 0x96, 0x44, 0x1D, 0xD3, 0xDE, 0x93, 0x01, 0x08, 0xD0, + 0x7B, 0x66, 0x37, 0x9A, 0x20, 0x80, 0x06, 0x2C, 0x58, 0x20, 0x78, 0x81, 0x95, 0x07, 0x18, 0x34, + 0xAC, 0xEA, 0xE2, 0xEA, 0xAB, 0x85, 0xD4, 0x0E, 0x20, 0x3C, 0x90, 0x60, 0x4A, 0x20, 0xA0, 0x04, + 0xE9, 0xD3, 0xB2, 0x63, 0xCA, 0x80, 0x5B, 0x82, 0x00, 0x02, 0x71, 0x49, 0x66, 0x52, 0x37, 0x01, + 0x04, 0x28, 0x88, 0x36, 0x79, 0x65, 0x13, 0x18, 0x3E, 0x9D, 0x58, 0xB2, 0x5D, 0x24, 0x11, 0x54, + 0xD0, 0x88, 0x62, 0x12, 0x52, 0x00, 0xCF, 0x85, 0x94, 0x44, 0xD7, 0x18, 0x28, 0xDB, 0x89, 0xC4, + 0x60, 0x27, 0xDA, 0x51, 0xF3, 0x20, 0x26, 0xB3, 0x19, 0xF0, 0x8A, 0x03, 0x07, 0x14, 0x54, 0x8C, + 0x2E, 0x34, 0xE8, 0x40, 0x83, 0x0C, 0x2E, 0xB0, 0xE7, 0x0B, 0x0D, 0x0B, 0x11, 0x93, 0x9B, 0x2A, + 0xD1, 0x29, 0x43, 0x80, 0x63, 0xDA, 0x75, 0xB4, 0x00, 0x5B, 0x06, 0xFC, 0x27, 0x09, 0x82, 0xF9, + 0x60, 0x47, 0xCA, 0x70, 0x0A, 0x9A, 0xC4, 0xC9, 0x27, 0xC1, 0x35, 0xF6, 0xCE, 0x00, 0xE7, 0x54, + 0x00, 0x0F, 0x4D, 0x3A, 0xB1, 0xE4, 0xD3, 0x90, 0xF9, 0xA0, 0x24, 0x9C, 0x37, 0x24, 0xFA, 0xE3, + 0x8F, 0x00, 0x60, 0x92, 0x65, 0xE2, 0x02, 0xAF, 0xFC, 0xB8, 0x00, 0x03, 0x11, 0x4D, 0x95, 0x1E, + 0x0D, 0x34, 0x90, 0xD0, 0x22, 0x9B, 0x3E, 0x90, 0x56, 0xA3, 0x04, 0xFE, 0x12, 0x04, 0xA4, 0x23, + 0x60, 0xFD, 0x11, 0x50, 0x01, 0x6E, 0x19, 0x2C, 0x70, 0x80, 0x03, 0x41, 0x6E, 0x49, 0x57, 0x28, + 0x09, 0x4E, 0x86, 0xE4, 0x70, 0x5A, 0xF6, 0x05, 0x89, 0x3C, 0x11, 0x1C, 0x02, 0xA5, 0x72, 0xF0, + 0x4C, 0x58, 0x80, 0x95, 0x3C, 0x55, 0x52, 0x41, 0x04, 0x9D, 0xC8, 0xA3, 0xC2, 0x37, 0x08, 0x82, + 0xA8, 0x9D, 0x8E, 0x00, 0xE6, 0x06, 0xA8, 0x32, 0xAF, 0xB0, 0x72, 0x01, 0x32, 0x06, 0xB1, 0xC8, + 0x0B, 0x69, 0x2D, 0xF6, 0xE2, 0xCB, 0x55, 0xC8, 0x64, 0x50, 0x9F, 0x2A, 0xDA, 0x49, 0x20, 0x08, + 0x01, 0xB6, 0x55, 0xF0, 0x29, 0x01, 0x0E, 0x84, 0xDA, 0x0C, 0x76, 0x27, 0x15, 0x79, 0x1D, 0x92, + 0xD6, 0x01, 0x40, 0xC9, 0x5E, 0x72, 0x11, 0xE2, 0x0C, 0x4B, 0xF5, 0xB0, 0x04, 0xE5, 0x85, 0x8D, + 0x01, 0x30, 0x69, 0x4F, 0x0D, 0x34, 0x8A, 0x08, 0x0B, 0xE4, 0x38, 0xA2, 0x02, 0x25, 0x84, 0x66, + 0xA2, 0x51, 0x03, 0x66, 0x3A, 0xB5, 0x59, 0x41, 0xE5, 0xCD, 0xE2, 0x41, 0x44, 0x18, 0x90, 0x90, + 0x0B, 0x42, 0x5B, 0xB9, 0xF8, 0xE2, 0xAB, 0x2E, 0xC4, 0xBB, 0x00, 0xAD, 0xB0, 0x3D, 0xE6, 0x4C, + 0x01, 0xB6, 0x72, 0x04, 0x54, 0x6D, 0xD1, 0xFC, 0x47, 0xA0, 0x3E, 0xDC, 0x14, 0x69, 0xD7, 0xA1, + 0xDE, 0x20, 0x6B, 0x21, 0x28, 0xDF, 0x3C, 0xF9, 0x28, 0x25, 0x10, 0xFE, 0xD4, 0xD8, 0x9E, 0x96, + 0xC4, 0x34, 0x49, 0x3A, 0x82, 0x29, 0x47, 0x81, 0x70, 0xFE, 0x78, 0x00, 0x2E, 0x32, 0x3F, 0x3A, + 0x70, 0x4C, 0x2C, 0x1D, 0xAC, 0xEB, 0x01, 0x08, 0xB9, 0x90, 0x20, 0x4B, 0x2E, 0x2F, 0xB8, 0xC0, + 0xE6, 0x8B, 0x5D, 0xE9, 0x12, 0x6F, 0x7C, 0xB3, 0x06, 0xD4, 0x40, 0x47, 0xD2, 0x74, 0xA4, 0x56, + 0x74, 0x8F, 0xC1, 0xF6, 0x4F, 0x76, 0xFE, 0x0E, 0x58, 0x0A, 0xFE, 0x81, 0x00, 0x10, 0x20, 0xAC, + 0x5E, 0x79, 0xF5, 0x33, 0xC0, 0x04, 0x91, 0x28, 0xA0, 0x09, 0xC3, 0x0D, 0x4A, 0xF3, 0xEC, 0x95, + 0x94, 0x24, 0x16, 0xA9, 0x84, 0xF2, 0xD0, 0x63, 0x8E, 0x26, 0x6F, 0x05, 0xB0, 0x00, 0x45, 0x5C, + 0x87, 0xAC, 0xB2, 0x56, 0x6C, 0xBA, 0x90, 0xF2, 0x41, 0x9E, 0xCD, 0xD8, 0xE6, 0x8A, 0x07, 0x91, + 0x2C, 0x55, 0x40, 0xF6, 0x11, 0x70, 0x1F, 0x47, 0xCA, 0x30, 0xA6, 0x21, 0x6E, 0x33, 0x47, 0xB3, + 0x11, 0x6F, 0x0C, 0x1A, 0xFA, 0xB3, 0x26, 0x42, 0x13, 0xBD, 0xCD, 0x3C, 0x43, 0x61, 0xEA, 0x60, + 0x5F, 0x3F, 0x07, 0x26, 0xDD, 0x86, 0xF1, 0xEC, 0x74, 0x58, 0xA3, 0x13, 0x04, 0x90, 0x0E, 0x21, + 0xE0, 0x7C, 0xA3, 0xAE, 0x7C, 0xEA, 0x2E, 0xA4, 0xAE, 0xD8, 0x2B, 0xAF, 0xDC, 0x5E, 0x0B, 0xF1, + 0xD2, 0xF0, 0xC2, 0x8B, 0x1B, 0x5C, 0x70, 0xD0, 0x41, 0x21, 0x77, 0xD0, 0x1A, 0xAD, 0xDF, 0xE6, + 0xE6, 0xB6, 0x02, 0x3E, 0x79, 0xE9, 0xE5, 0x7F, 0xC4, 0xA9, 0x54, 0x0D, 0x5D, 0x96, 0x6C, 0x63, + 0xD3, 0x04, 0x2A, 0x0D, 0x82, 0x92, 0xD2, 0xA2, 0x48, 0x8B, 0x71, 0x60, 0x19, 0x62, 0x18, 0xE5, + 0x84, 0xF1, 0x28, 0x92, 0xD3, 0xBE, 0xD6, 0x0D, 0xB0, 0x2E, 0xCA, 0x2F, 0x5C, 0x75, 0x4C, 0x2E, + 0x0D, 0x65, 0xCE, 0x26, 0x8C, 0xAF, 0xB2, 0xDC, 0x02, 0x06, 0xB2, 0x8C, 0xEE, 0x76, 0x6E, 0x36, + 0x97, 0xF8, 0x58, 0x86, 0xC6, 0xF9, 0x23, 0xF4, 0xC0, 0x40, 0xE3, 0x03, 0xE6, 0xDE, 0x07, 0x12, + 0xA5, 0xCD, 0x04, 0x2A, 0xA8, 0x8F, 0xA0, 0x33, 0xB1, 0xD7, 0x43, 0xC9, 0x8E, 0x1B, 0x5A, 0x22, + 0xD8, 0x61, 0x39, 0xB9, 0xF3, 0x68, 0x25, 0x90, 0x20, 0xAD, 0x49, 0x5F, 0xA6, 0xC8, 0x80, 0x7C, + 0xDC, 0xE3, 0x81, 0xF0, 0x44, 0xA4, 0x3C, 0x9C, 0xC1, 0xFE, 0x00, 0xE7, 0xA4, 0xE7, 0xB9, 0xE9, + 0x71, 0xEE, 0x7A, 0x16, 0xD8, 0xC0, 0x41, 0x04, 0xA0, 0x16, 0x5A, 0x49, 0x20, 0x3A, 0xBD, 0x42, + 0x80, 0x76, 0x34, 0x04, 0x8D, 0x7E, 0xC4, 0x85, 0x28, 0x1F, 0x1A, 0x94, 0x64, 0x8A, 0x02, 0x80, + 0xC3, 0x48, 0x29, 0x00, 0x55, 0x1B, 0x0A, 0xEE, 0xB8, 0x81, 0x14, 0x80, 0xD9, 0x0F, 0x12, 0x3E, + 0x01, 0x1F, 0x50, 0x50, 0x18, 0x09, 0x67, 0x9D, 0x03, 0x6B, 0xCF, 0x18, 0x8A, 0x4F, 0x4C, 0x51, + 0x8C, 0x59, 0x80, 0xC0, 0x00, 0x64, 0xAA, 0x8F, 0x04, 0x2C, 0x00, 0x9F, 0x5C, 0x60, 0x60, 0x65, + 0x35, 0x78, 0x48, 0x69, 0x3A, 0xD0, 0x82, 0x91, 0x6D, 0x20, 0x22, 0x4F, 0xEC, 0x00, 0xA8, 0xD4, + 0xA2, 0x23, 0x5A, 0xE1, 0x26, 0x47, 0xC9, 0x23, 0x89, 0x63, 0x46, 0x32, 0x80, 0xB2, 0x64, 0x69, + 0x50, 0xF9, 0xE8, 0x4E, 0x27, 0xCA, 0xE1, 0x38, 0x14, 0xDE, 0x30, 0x02, 0xD2, 0xB2, 0x10, 0x00, + 0x70, 0xF7, 0xB3, 0xEA, 0xF0, 0xA5, 0x12, 0x56, 0xB2, 0xC4, 0x8E, 0xB2, 0x36, 0x94, 0x4C, 0xD1, + 0x10, 0x4F, 0x36, 0x11, 0xCA, 0x4F, 0xF2, 0x41, 0x80, 0xD1, 0x65, 0x24, 0x03, 0x17, 0xC8, 0x80, + 0x04, 0x00, 0xB9, 0x00, 0x12, 0x14, 0x92, 0x89, 0xBC, 0xE0, 0xC5, 0x0B, 0xAC, 0x72, 0xAE, 0x60, + 0x10, 0x03, 0x7B, 0x16, 0x58, 0x06, 0x6E, 0x40, 0xB5, 0x11, 0xB9, 0xBC, 0x46, 0x19, 0xA8, 0xB0, + 0x0C, 0x18, 0xE3, 0x27, 0x42, 0x7C, 0xA0, 0x71, 0x27, 0x7D, 0x79, 0x1A, 0x74, 0x2C, 0x84, 0x0E, + 0xC9, 0xD0, 0x43, 0x1F, 0xDC, 0x0A, 0x8E, 0x48, 0x22, 0xD1, 0xB4, 0x68, 0x44, 0x4E, 0x7F, 0x8F, + 0xFB, 0x04, 0x60, 0xD0, 0x28, 0x0A, 0x56, 0x64, 0xC0, 0x02, 0x82, 0x84, 0xCA, 0x20, 0x1B, 0x20, + 0xBA, 0x61, 0xB0, 0x42, 0x08, 0x3F, 0x00, 0xE6, 0xFE, 0x10, 0x7E, 0x00, 0x84, 0x1F, 0x74, 0xE0, + 0x98, 0x8F, 0x6C, 0xC5, 0x7F, 0x28, 0xA9, 0xA3, 0x49, 0xD6, 0x27, 0x37, 0x6F, 0xBB, 0x86, 0x3E, + 0x46, 0x88, 0x17, 0x43, 0x65, 0x89, 0x50, 0x8E, 0x3B, 0x07, 0x75, 0xCC, 0x78, 0x8E, 0xC6, 0x59, + 0xE8, 0x11, 0x2D, 0x11, 0x05, 0x0A, 0x83, 0x23, 0xAD, 0xC6, 0x7C, 0x22, 0x78, 0x6F, 0x7C, 0x47, + 0x73, 0xA6, 0x84, 0x88, 0x71, 0x42, 0x86, 0x28, 0x03, 0x80, 0xD8, 0x05, 0xD8, 0x32, 0xB3, 0xB8, + 0x95, 0xE7, 0x02, 0xF3, 0xB4, 0x80, 0x08, 0x7C, 0xA0, 0x03, 0x18, 0xBC, 0x00, 0x08, 0x36, 0xB0, + 0x05, 0xBA, 0x26, 0x12, 0x11, 0x5A, 0x31, 0x93, 0x44, 0xD2, 0xD1, 0x4E, 0x33, 0xA2, 0x43, 0xA8, + 0xBD, 0x14, 0x8D, 0x84, 0x24, 0xA4, 0x66, 0x36, 0x6E, 0x48, 0x81, 0x6C, 0x4C, 0x6A, 0x7F, 0xE8, + 0x60, 0x44, 0x26, 0x58, 0x27, 0x4E, 0x57, 0x5A, 0xE2, 0x11, 0x98, 0x70, 0x56, 0x49, 0x1A, 0x93, + 0x21, 0x6D, 0x5E, 0x70, 0x61, 0x6F, 0x4C, 0x16, 0x07, 0x07, 0xF0, 0xA3, 0x9A, 0x9D, 0xA5, 0x01, + 0xB3, 0x28, 0x8F, 0x02, 0x5B, 0x24, 0x84, 0x21, 0x0C, 0x93, 0x04, 0xE9, 0xC2, 0xE9, 0x23, 0x93, + 0x91, 0x50, 0x1D, 0xD9, 0xCB, 0xA7, 0x76, 0xD1, 0x08, 0x3F, 0xDE, 0x12, 0x99, 0x04, 0x95, 0x4F, + 0x49, 0x9B, 0xA0, 0xA5, 0xEF, 0x0C, 0xA1, 0x1C, 0xF0, 0x7D, 0x02, 0x80, 0xD7, 0x44, 0xE1, 0x48, + 0x19, 0xC6, 0xB4, 0x26, 0x55, 0x62, 0x47, 0xCB, 0x70, 0xC4, 0xA5, 0xE6, 0xF8, 0x93, 0x69, 0x3E, + 0x4B, 0x2E, 0x94, 0x9C, 0x99, 0x04, 0x1C, 0xD0, 0x00, 0x56, 0x78, 0xC6, 0x07, 0x3F, 0x48, 0x2B, + 0x4E, 0x27, 0xE2, 0x48, 0x0C, 0x2C, 0xC0, 0x99, 0xA1, 0x62, 0xA6, 0xEA, 0xE6, 0x37, 0x97, 0x06, + 0x05, 0xCF, 0x7E, 0x25, 0xB1, 0x06, 0x91, 0xFE, 0x7A, 0x13, 0x30, 0xA0, 0x5C, 0x88, 0x05, 0x82, + 0xDB, 0x0E, 0xA6, 0xC8, 0xA9, 0xBB, 0x4C, 0x10, 0x0F, 0x30, 0xFC, 0x7B, 0xD6, 0x53, 0xEB, 0xA7, + 0x13, 0x0A, 0x9C, 0xF0, 0x1B, 0xA4, 0x98, 0x12, 0x5E, 0x71, 0xE3, 0xCC, 0x8E, 0xB8, 0x4D, 0x02, + 0x5B, 0xFB, 0x81, 0x0D, 0x7C, 0x20, 0x04, 0x1D, 0xD8, 0xE0, 0x05, 0x2F, 0xA0, 0xC8, 0x2C, 0x5A, + 0x03, 0x10, 0xAC, 0x1E, 0xB4, 0x19, 0xFE, 0x80, 0xC7, 0x5C, 0x36, 0xF1, 0xCE, 0xC5, 0x96, 0xE4, + 0x19, 0x5F, 0xB4, 0x66, 0x1A, 0x33, 0x85, 0x8E, 0x73, 0xA4, 0x36, 0x30, 0x0E, 0x52, 0x9F, 0x19, + 0xDF, 0x91, 0x30, 0x0B, 0xB1, 0x92, 0xB1, 0x95, 0x78, 0x4C, 0x0C, 0xF7, 0x74, 0x8F, 0x7D, 0x90, + 0xD4, 0xB6, 0x0E, 0xF2, 0xE9, 0x33, 0x2F, 0x2B, 0x84, 0x16, 0x04, 0x53, 0x08, 0xD0, 0xFD, 0x81, + 0x0E, 0x70, 0xDA, 0x99, 0x26, 0x8E, 0xAA, 0xB2, 0x9F, 0x12, 0x09, 0x26, 0x43, 0x94, 0xCA, 0xC2, + 0x5D, 0x28, 0x6B, 0xA7, 0xBC, 0x66, 0xC1, 0xB6, 0x31, 0xD8, 0x45, 0x81, 0x02, 0x96, 0x30, 0x81, + 0x52, 0xEF, 0xC4, 0x89, 0x42, 0xE2, 0x35, 0x87, 0x49, 0x1C, 0xD1, 0x90, 0x70, 0x27, 0xD5, 0x9C, + 0x0B, 0xAA, 0x80, 0x1C, 0xD8, 0xCA, 0x56, 0x8E, 0xAA, 0xA8, 0x8A, 0x80, 0xF4, 0x6A, 0x56, 0xCB, + 0xA0, 0x13, 0x9B, 0xA4, 0xA2, 0x2E, 0x1A, 0x08, 0xA1, 0x4D, 0xA8, 0x9D, 0xE4, 0x05, 0xEB, 0x81, + 0xD0, 0x1C, 0x25, 0x07, 0xB1, 0x92, 0xD0, 0xCE, 0x02, 0x1C, 0x04, 0xD9, 0x86, 0xCE, 0x6E, 0xBC, + 0xDA, 0xA8, 0x21, 0xF2, 0x5A, 0x07, 0xA5, 0x6F, 0x40, 0xA7, 0x12, 0x59, 0x0A, 0xE5, 0xC2, 0x72, + 0x1B, 0xB9, 0xC1, 0x7D, 0x37, 0x52, 0x8A, 0x43, 0xC7, 0x21, 0x56, 0xAC, 0x9C, 0xE4, 0x91, 0x85, + 0x7B, 0xAA, 0x2B, 0x11, 0x9D, 0xCA, 0x66, 0xE3, 0xA2, 0xCF, 0xBD, 0x49, 0x06, 0x3C, 0xDD, 0x15, + 0x65, 0xA7, 0x81, 0xDB, 0x0D, 0x29, 0xE0, 0xC7, 0xAC, 0xBB, 0x95, 0x74, 0x56, 0x79, 0xA4, 0x22, + 0xFF, 0x2B, 0x6F, 0x60, 0xBC, 0x61, 0xEF, 0xBA, 0xC1, 0x17, 0xE8, 0x40, 0x82, 0x10, 0x80, 0x69, + 0x12, 0x0D, 0x4F, 0xD9, 0xC2, 0xBD, 0xD8, 0x23, 0x39, 0xF6, 0x40, 0x44, 0x73, 0xF2, 0x67, 0x09, + 0x5B, 0x65, 0xC7, 0xA0, 0xB0, 0x59, 0x46, 0x47, 0xFA, 0x64, 0x80, 0x41, 0x5E, 0x20, 0xA0, 0xD0, + 0x6D, 0xD1, 0x0B, 0x84, 0xE0, 0x01, 0x8B, 0x98, 0x76, 0x47, 0x3C, 0x65, 0xEC, 0x15, 0x7B, 0xCC, + 0x11, 0x0F, 0x61, 0xED, 0xA1, 0xB1, 0x15, 0x4E, 0xD1, 0x34, 0x11, 0x08, 0x00, 0x00, 0x21, 0xF9, + 0x04, 0x05, 0x1E, 0x00, 0x46, 0x00, 0x2C, 0x48, 0x00, 0x2C, 0x00, 0x23, 0x00, 0x3F, 0x00, 0x00, + 0x07, 0xFE, 0x80, 0x46, 0x82, 0x46, 0x16, 0x83, 0x86, 0x87, 0x0B, 0x87, 0x8A, 0x8B, 0x8C, 0x8D, + 0x84, 0x8E, 0x90, 0x91, 0x8D, 0x06, 0x92, 0x8A, 0x85, 0x18, 0x8C, 0x01, 0x95, 0x46, 0x31, 0x34, + 0x43, 0x46, 0x01, 0x3E, 0x9B, 0x87, 0x19, 0x8A, 0x0D, 0x87, 0x9F, 0x3C, 0x8A, 0x2F, 0x82, 0x03, + 0x9C, 0x87, 0x02, 0x83, 0x19, 0xA7, 0x83, 0xB4, 0x82, 0x36, 0x82, 0x43, 0x9F, 0xA3, 0xA5, 0x8C, + 0x34, 0x3F, 0xAF, 0x82, 0x41, 0x8A, 0xC3, 0x46, 0x9F, 0x42, 0x46, 0xBD, 0x90, 0x34, 0x42, 0x3F, + 0x42, 0xB8, 0x46, 0x3C, 0xC5, 0xA8, 0x83, 0x3C, 0x35, 0x8A, 0x0E, 0x86, 0x24, 0x46, 0x0E, 0x3E, + 0x40, 0x32, 0x3A, 0x36, 0x43, 0xE2, 0x87, 0x41, 0x41, 0x9F, 0x3F, 0xC0, 0x3A, 0x30, 0x8A, 0xCA, + 0x83, 0xBF, 0xC8, 0x3C, 0x36, 0x24, 0xBB, 0xC8, 0xC2, 0x86, 0x41, 0x34, 0x34, 0x9A, 0x8D, 0xFC, + 0x35, 0xBF, 0x1E, 0x38, 0xD1, 0x33, 0xF2, 0x43, 0x97, 0x11, 0x7B, 0x82, 0x0A, 0xD6, 0xE0, 0xE7, + 0xC8, 0x83, 0x0F, 0x1D, 0x46, 0x3C, 0xC4, 0x60, 0x65, 0xCC, 0x88, 0xA7, 0x83, 0x3C, 0xEA, 0x01, + 0xD9, 0x05, 0xC9, 0x02, 0x0D, 0x1D, 0x1E, 0x2E, 0x90, 0xB0, 0xE1, 0x42, 0x9C, 0x8E, 0x17, 0x3A, + 0x88, 0x0C, 0xD1, 0xF1, 0x69, 0xC8, 0x8F, 0x1A, 0x10, 0x23, 0x11, 0xB0, 0x20, 0x43, 0x06, 0x09, + 0x12, 0x42, 0x3C, 0x6C, 0xF3, 0x51, 0x92, 0x20, 0x33, 0x82, 0x42, 0x68, 0xB4, 0xB0, 0xD5, 0x68, + 0x40, 0xA2, 0x1A, 0x21, 0x87, 0x78, 0x80, 0x11, 0xD4, 0x18, 0xCC, 0x5C, 0x46, 0x80, 0xB4, 0xD0, + 0x90, 0x40, 0xD2, 0x82, 0x1A, 0xDB, 0x2E, 0xCC, 0x33, 0xC2, 0x52, 0xC6, 0x0F, 0x5C, 0x32, 0x6A, + 0x0C, 0x01, 0xE2, 0xA3, 0x05, 0x86, 0x0E, 0x92, 0x0E, 0x90, 0x78, 0x61, 0x61, 0xC1, 0x0B, 0x1B, + 0xFE, 0x2F, 0x3C, 0xD1, 0x20, 0x08, 0xE4, 0xE3, 0x8F, 0x17, 0x35, 0x6A, 0xB4, 0x70, 0x61, 0xD5, + 0xC8, 0x82, 0xBF, 0x5C, 0x49, 0xB8, 0xF0, 0xF1, 0x71, 0x88, 0x8C, 0x8F, 0x3E, 0x78, 0x1A, 0x21, + 0xD1, 0x22, 0xAD, 0x87, 0x0E, 0x6D, 0x2F, 0xFC, 0xE8, 0x50, 0x92, 0x46, 0x8D, 0x1F, 0x27, 0x8D, + 0xF8, 0xF8, 0x41, 0xC3, 0xC7, 0x63, 0x49, 0x06, 0x30, 0x78, 0x60, 0x40, 0xE2, 0xAA, 0x11, 0x17, + 0x31, 0x7C, 0xE0, 0xA5, 0x41, 0xE2, 0x17, 0x11, 0x9E, 0x01, 0x37, 0xB9, 0x00, 0x8C, 0x94, 0xC4, + 0x35, 0x17, 0x35, 0x5E, 0xDC, 0x14, 0xA4, 0xFA, 0x05, 0x02, 0x43, 0xEE, 0x14, 0x75, 0xC0, 0xF0, + 0x77, 0x29, 0x09, 0x60, 0x9D, 0x69, 0x74, 0x20, 0xE1, 0x15, 0xAF, 0x0C, 0x03, 0xAE, 0x22, 0x1D, + 0x88, 0x28, 0x48, 0xAB, 0x07, 0x17, 0xC0, 0x08, 0xB7, 0xF0, 0xE0, 0xD5, 0x62, 0x8B, 0x03, 0xD1, + 0x3B, 0x62, 0xC0, 0x60, 0x60, 0xC1, 0x52, 0x41, 0x44, 0x34, 0xA3, 0xAC, 0x29, 0x08, 0x29, 0xC3, + 0x48, 0x24, 0x2C, 0x4C, 0xF7, 0xD0, 0xB8, 0x85, 0x8E, 0x6D, 0x2E, 0x64, 0xBC, 0x90, 0xA1, 0x59, + 0x07, 0xA6, 0x41, 0xD3, 0x35, 0x62, 0x81, 0x07, 0x16, 0x50, 0x62, 0x81, 0x0B, 0x94, 0xF9, 0x80, + 0x41, 0x0B, 0x2F, 0xBC, 0xD0, 0xD8, 0x47, 0x20, 0x79, 0xE0, 0x40, 0x22, 0x90, 0x1C, 0x80, 0x89, + 0x85, 0x16, 0x5C, 0x63, 0x9B, 0x11, 0x2D, 0xB4, 0x40, 0x83, 0x0C, 0x1E, 0x6A, 0xD6, 0xC2, 0x35, + 0x95, 0x9C, 0x95, 0xC8, 0x02, 0x7C, 0xB5, 0x96, 0x9E, 0x11, 0x0E, 0xEA, 0x63, 0x19, 0x83, 0x01, + 0x46, 0xC2, 0x00, 0x26, 0x89, 0xE8, 0xC4, 0xDC, 0x4B, 0xDE, 0xB1, 0xE8, 0xE1, 0x61, 0xD9, 0xA4, + 0x05, 0x02, 0x71, 0xE6, 0xC5, 0x36, 0x84, 0x0F, 0x35, 0xC8, 0x40, 0x9F, 0x83, 0x32, 0x10, 0xFE, + 0xD9, 0xA3, 0x24, 0x1E, 0x10, 0x27, 0x88, 0x6E, 0x7C, 0xD9, 0xB3, 0x1D, 0x8B, 0x04, 0xC5, 0x24, + 0x49, 0x00, 0x1B, 0xA0, 0x65, 0x44, 0x07, 0x36, 0x72, 0x25, 0x88, 0x07, 0xDC, 0xE1, 0xF5, 0xD0, + 0x5C, 0x83, 0x14, 0xC2, 0x88, 0x01, 0x2E, 0x90, 0x70, 0x81, 0x11, 0x67, 0x2D, 0x66, 0x44, 0x91, + 0x20, 0x8D, 0xA8, 0x99, 0x5E, 0x27, 0x54, 0x72, 0x40, 0x87, 0x14, 0x6E, 0xC9, 0x58, 0x92, 0x1C, + 0xF6, 0x27, 0xCA, 0x7F, 0x79, 0x36, 0xB2, 0xC0, 0x72, 0x13, 0x1E, 0x88, 0xD6, 0x5E, 0xA2, 0xB4, + 0xF7, 0x83, 0x6A, 0x37, 0x99, 0x29, 0xDD, 0x05, 0x0B, 0x4C, 0x88, 0x09, 0x63, 0x2F, 0x2C, 0x4A, + 0x03, 0x08, 0x97, 0x71, 0xD6, 0xC2, 0x70, 0x46, 0xC4, 0x28, 0x28, 0x06, 0x0D, 0xE4, 0xB9, 0x8D, + 0x66, 0x3C, 0x79, 0xA8, 0x03, 0x67, 0xF4, 0xC5, 0x06, 0x89, 0x01, 0xD3, 0x1D, 0x90, 0x8D, 0x05, + 0x37, 0xE5, 0xA7, 0x0F, 0x87, 0xFC, 0x2D, 0xFA, 0x42, 0x9A, 0x5A, 0x42, 0xB2, 0x80, 0x93, 0x8F, + 0xEC, 0x19, 0x16, 0x92, 0xBF, 0x18, 0x71, 0x58, 0xAE, 0xE2, 0x09, 0x92, 0x88, 0x68, 0x6B, 0xE9, + 0xA0, 0x5D, 0x7E, 0x9A, 0x19, 0x01, 0x82, 0x0B, 0x6B, 0x46, 0x62, 0xC1, 0x7F, 0x46, 0x44, 0xCB, + 0xA0, 0xA5, 0xDB, 0x84, 0x55, 0x43, 0x59, 0x48, 0x39, 0xFA, 0xE9, 0x05, 0x3D, 0x8A, 0x96, 0x10, + 0x91, 0x7D, 0xC2, 0x69, 0x99, 0xAA, 0x8E, 0x58, 0x90, 0xCD, 0x01, 0xC7, 0x6A, 0xB9, 0xED, 0x35, + 0x8D, 0xFD, 0x93, 0x9C, 0x07, 0x1A, 0x3C, 0x72, 0x66, 0xA4, 0x9E, 0x2E, 0xD7, 0x1A, 0x61, 0x83, + 0x88, 0x52, 0xD3, 0x5A, 0xD4, 0x0A, 0x2A, 0x9F, 0xB1, 0xE3, 0xED, 0xA6, 0x43, 0x4C, 0x61, 0xD1, + 0xF0, 0xC2, 0x09, 0x8D, 0x45, 0x82, 0x00, 0x02, 0x7F, 0x51, 0x38, 0x69, 0x6B, 0xDB, 0xD9, 0x2A, + 0x9C, 0xE4, 0x87, 0x73, 0xB1, 0x66, 0x15, 0x60, 0xD3, 0x2E, 0xD6, 0x42, 0x58, 0x84, 0x35, 0x28, + 0x8A, 0x65, 0x45, 0x8E, 0xEA, 0xC8, 0x89, 0x27, 0x46, 0xB4, 0xCD, 0x5C, 0x89, 0x26, 0x49, 0xE2, + 0x6D, 0x91, 0xEC, 0x7A, 0x81, 0x05, 0x6D, 0xA9, 0xBC, 0x56, 0x7B, 0x1F, 0x8A, 0xF2, 0x4F, 0x5C, + 0x14, 0xA5, 0x8B, 0x49, 0xB4, 0x6C, 0xEA, 0x14, 0x97, 0x20, 0x1F, 0x0E, 0xF2, 0xC2, 0x75, 0x15, + 0x12, 0x82, 0x41, 0x21, 0x40, 0xDF, 0x34, 0xB4, 0xB0, 0x64, 0xF2, 0x47, 0xDF, 0x21, 0x44, 0x0D, + 0xB2, 0x40, 0x64, 0xEA, 0x0A, 0xB2, 0x9B, 0x21, 0x87, 0xB1, 0x08, 0xA2, 0x60, 0x0D, 0x1B, 0x51, + 0xB5, 0x20, 0x85, 0xD0, 0x0C, 0x98, 0x9B, 0x71, 0x25, 0xC6, 0xA2, 0xC5, 0x36, 0xB9, 0x00, 0x03, + 0x3B, 0xF0, 0x51, 0xD7, 0x41, 0x07, 0x64, 0xBE, 0x69, 0x91, 0x21, 0x6E, 0xBF, 0x3D, 0x0A, 0x09, + 0x1D, 0x34, 0xC8, 0x1F, 0x7F, 0x82, 0x74, 0xCD, 0x9F, 0xDB, 0x1C, 0x98, 0x7C, 0x08, 0xE0, 0x0D, + 0xF3, 0xD5, 0xA7, 0x22, 0xC3, 0x1A, 0x02, 0x03, 0x07, 0xA3, 0x70, 0x18, 0xF6, 0xDA, 0x16, 0x7D, + 0x66, 0x48, 0xBD, 0x44, 0x1B, 0xEB, 0x6D, 0xE4, 0x82, 0x34, 0x16, 0x23, 0x25, 0x5F, 0x32, 0x1E, + 0x09, 0xE0, 0x92, 0x53, 0xCD, 0xF9, 0x20, 0x20, 0x50, 0x17, 0x49, 0x06, 0x67, 0xDB, 0x6B, 0x37, + 0xD7, 0x82, 0xFC, 0x87, 0xAE, 0x20, 0x04, 0x10, 0xA0, 0x48, 0xA0, 0x86, 0xCC, 0x05, 0x0C, 0x30, + 0x87, 0x2C, 0x38, 0x88, 0xED, 0x86, 0x04, 0x02, 0x00, 0x3B, +}; diff --git a/gfxconf.example.h b/gfxconf.example.h index 5d29600f..ce4d4ca6 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -56,6 +56,7 @@ #define GDISP_NEED_IMAGE_BMP FALSE #define GDISP_NEED_IMAGE_JPG FALSE #define GDISP_NEED_IMAGE_PNG FALSE +#define GDISP_NEED_IMAGE_ACCOUNTING FALSE /* Optional image support that can be turned off */ /* diff --git a/include/gdisp/image.h b/include/gdisp/image.h index 49b10d42..99e51118 100644 --- a/include/gdisp/image.h +++ b/include/gdisp/image.h @@ -113,9 +113,13 @@ typedef struct gdispImageIO { typedef struct gdispImage { gdispImageType type; /* @< The image type */ gdispImageFlags flags; /* @< The image flags */ + color_t bgcolor; /* @< The default background color */ coord_t width, height; /* @< The image dimensions */ gdispImageIO io; /* @< The image IO functions */ - uint32_t membytes; /* @< How much RAM has been allocated */ + #if GDISP_NEED_IMAGE_ACCOUNTING + uint32_t memused; /* @< How much RAM is currently allocated */ + uint32_t maxmemused; /* @< How much RAM has been allocated (maximum) */ + #endif const struct gdispImageHandlers * fns; /* @< Don't mess with this! */ struct gdispImagePrivate * priv; /* @< Don't mess with this! */ } gdispImage; @@ -176,6 +180,7 @@ extern "C" { * * @note This determines which decoder to use and then initialises all other fields * in the gdispImage structure. + * @note The image background color is set to White. * @note There are three types of return - everything OK, partial success and unrecoverable * failures. For everything OK it returns GDISP_IMAGE_ERR_OK. A partial success can * be distinguished from a unrecoverable failure by testing the GDISP_IMAGE_ERR_UNRECOVERABLE @@ -197,6 +202,19 @@ extern "C" { * @note Also calls the IO close function (if it hasn't already been called). */ void gdispImageClose(gdispImage *img); + + /** + * @brief Set the background color of the image. + * + * @param[in] img The image structure + * @param[in] bgcolor The background color to use + * + * @pre gdispImageOpen() must have returned successfully. + * + * @note This color is only used when an image has to restore part of the background before + * continuing with drawing that includes transparency eg some GIF animations. + */ + void gdispImageSetBgColor(gdispImage *img, color_t bgcolor); /** * @brief Cache the image diff --git a/include/gdisp/options.h b/include/gdisp/options.h index deacc036..5cdfbf59 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -186,6 +186,13 @@ #ifndef GDISP_NEED_IMAGE_PNG #define GDISP_NEED_IMAGE_PNG FALSE #endif + /** + * @brief Is memory accounting required during image decoding. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE_ACCOUNTING + #define GDISP_NEED_IMAGE_ACCOUNTING FALSE + #endif /** * @} * diff --git a/src/gdisp/image.c b/src/gdisp/image.c index 3da0844d..061db5fe 100644 --- a/src/gdisp/image.c +++ b/src/gdisp/image.c @@ -167,6 +167,7 @@ bool_t gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPt gdispImageError gdispImageOpen(gdispImage *img) { gdispImageError err; + img->bgcolor = White; for(img->fns = ImageHandlers; img->fns < ImageHandlers+sizeof(ImageHandlers)/sizeof(ImageHandlers[0]); img->fns++) { err = img->fns->open(img); if (err != GDISP_IMAGE_ERR_BADFORMAT) { @@ -190,6 +191,10 @@ void gdispImageClose(gdispImage *img) { img->io.fns->close(&img->io); } +void gdispImageSetBgColor(gdispImage *img, color_t bgcolor) { + img->bgcolor = bgcolor; +} + gdispImageError gdispImageCache(gdispImage *img) { if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT; return img->fns->cache(img); @@ -205,6 +210,34 @@ systime_t gdispImageNext(gdispImage *img) { return img->fns->next(img); } +// Helper Routines +void *gdispImageAlloc(gdispImage *img, size_t sz) { + #if GDISP_NEED_IMAGE_ACCOUNTING + void *ptr; + + ptr = chHeapAlloc(NULL, sz); + if (ptr) { + img->memused += sz; + if (img->memused > img->maxmemused) + img->maxmemused = img->memused; + } + return ptr; + #else + (void) img; + return chHeapAlloc(NULL, sz); + #endif +} + +void gdispImageFree(gdispImage *img, void *ptr, size_t sz) { + #if GDISP_NEED_IMAGE_ACCOUNTING + chHeapFree(ptr); + img->memused -= sz; + #else + (void) img; + (void) sz; + chHeapFree(ptr); + #endif +} #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */ /** @} */ diff --git a/src/gdisp/image_bmp.c b/src/gdisp/image_bmp.c index 4ddfc7f8..bab9b4e9 100644 --- a/src/gdisp/image_bmp.c +++ b/src/gdisp/image_bmp.c @@ -53,6 +53,12 @@ #define GDISP_NEED_IMAGE_BMP_32 TRUE #endif +/** + * Helper Routines Needed + */ +void *gdispImageAlloc(gdispImage *img, size_t sz); +void gdispImageFree(gdispImage *img, void *ptr, size_t sz); + /** * How big a pixel array to allocate for blitting (in pixels) * Bigger is faster but uses more RAM. @@ -148,9 +154,8 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) { img->flags = 0; /* Allocate our private area */ - if (!(img->priv = (gdispImagePrivate *)chHeapAlloc(NULL, sizeof(gdispImagePrivate)))) + if (!(img->priv = (gdispImagePrivate *)gdispImageAlloc(img, sizeof(gdispImagePrivate)))) return GDISP_IMAGE_ERR_NOMEMORY; - img->membytes = sizeof(gdispImagePrivate); /* Initialise the essential bits in the private area */ priv = img->priv; @@ -336,9 +341,8 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) { if (priv->bmpflags & BMP_PALETTE) { img->io.fns->seek(&img->io, offsetColorTable); - if (!(priv->palette = (color_t *)chHeapAlloc(NULL, priv->palsize*sizeof(color_t)))) + if (!(priv->palette = (color_t *)gdispImageAlloc(img, priv->palsize*sizeof(color_t)))) return GDISP_IMAGE_ERR_NOMEMORY; - img->membytes += priv->palsize * sizeof(color_t); if (priv->bmpflags & BMP_V2) { for(aword = 0; aword < priv->palsize; aword++) { if (img->io.fns->read(&img->io, &priv->buf, 3) != 3) goto baddatacleanup; @@ -430,14 +434,13 @@ void gdispImageClose_BMP(gdispImage *img) { if (img->priv) { #if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE if (img->priv->palette) - chHeapFree((void *)img->priv->palette); + gdispImageFree(img, (void *)img->priv->palette, img->priv->palsize*sizeof(color_t)); #endif if (img->priv->frame0cache) - chHeapFree((void *)img->priv->frame0cache); - chHeapFree((void *)img->priv); + gdispImageFree(img, (void *)img->priv->frame0cache, img->width*img->height*sizeof(pixel_t)); + gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate)); img->priv = 0; } - img->membytes = 0; img->io.fns->close(&img->io); } @@ -794,7 +797,7 @@ gdispImageError gdispImageCache_BMP(gdispImage *img) { /* We need to allocate the cache */ len = img->width * img->height * sizeof(pixel_t); - priv->frame0cache = (pixel_t *)chHeapAlloc(NULL, len); + priv->frame0cache = (pixel_t *)gdispImageAlloc(img, len); if (!priv->frame0cache) return GDISP_IMAGE_ERR_NOMEMORY; img->membytes += len; diff --git a/src/gdisp/image_gif.c b/src/gdisp/image_gif.c index b7a940ad..2672333f 100644 --- a/src/gdisp/image_gif.c +++ b/src/gdisp/image_gif.c @@ -28,20 +28,1162 @@ #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_GIF -#error "GIF support not implemented yet" +/** + * Helper Routines Needed + */ +void *gdispImageAlloc(gdispImage *img, size_t sz); +void gdispImageFree(gdispImage *img, void *ptr, size_t sz); -/* A pallete structure */ -typedef struct gdispImagePallete { - uint8_t flags; - #define GDISP_IMAGE_FLG_INT_TRANSPARENT 0x01 - uint8_t idxtrans; /* The transparent idx */ - uint8_t maxidx; /* The maximum index (0..255) */ - uint8_t repidx; /* The index to use if the image data > maxidx */ - color_t pal[256]; /* The pallete entries - not all may actually be allocated */ -} gdispImagePallete; +/** + * How big an array to allocate for blitting (in pixels) + * Bigger is faster but uses more RAM. + */ +#define BLIT_BUFFER_SIZE 32 -/* Draw a single palletized line (or partial line) */ -static void gdispDrawPalleteLine(const gdispImagePallete *pal, const uint8_t *line, coord_t x, coord_t y, coord_t cx); +/* + * Determining endianness as at compile time is not guaranteed or compiler portable. + * We use the best test we can. If we can't guarantee little endianness we do things the + * hard way. + */ +#define GUARANTEED_LITTLE_ENDIAN (!defined(SAFE_ENDIAN) && !defined(SAFE_ALIGNMENT) && (\ + (defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__LITTLE_ENDIAN) \ + || defined(_LITTLE_ENDIAN) \ +/* || (1 == *(unsigned char *)&(const int){1})*/ \ + )) + + +/* This is a runtime test */ +static const uint8_t dwordOrder[4] = { 1, 2, 3, 4 }; + +#define isWordLittleEndian() (*(uint16_t *)&dwordOrder == 0x0201) +#define isDWordLittleEndian() (*(uint32_t *)&dwordOrder == 0x04030201) + +#if GUARANTEED_LITTLE_ENDIAN + /* These are fast routines for guaranteed little endian machines */ + #define CONVERT_FROM_WORD_LE(w) + #define CONVERT_FROM_DWORD_LE(dw) +#else + /* These are slower routines for when little endianness cannot be guaranteed at compile time */ + #define CONVERT_FROM_WORD_LE(w) { if (!isWordLittleEndian()) w = ((((uint16_t)(w))>>8)|(((uint16_t)(w))<<8)); } + #define CONVERT_FROM_DWORD_LE(dw) { if (!isDWordLittleEndian()) dw = (((uint32_t)(((const uint8_t *)(&dw))[0]))|(((uint32_t)(((const uint8_t *)(&dw))[1]))<<8)|(((uint32_t)(((const uint8_t *)(&dw))[2]))<<16)|(((uint32_t)(((const uint8_t *)(&dw))[3]))<<24)); } +#endif + +// We need a special error to indicate the end of file (which may not actually be an error) +#define GDISP_IMAGE_EOF ((gdispImageError)-1) +#define GDISP_IMAGE_LOOP ((gdispImageError)-2) + +#define MAX_CODE_BITS 12 +#define CODE_MAX ((1<priv; + + // We need the decode ram, and possibly a palette + if (!(decode = (imgdecode *)gdispImageAlloc(img, sizeof(imgdecode)+priv->frame.palsize*sizeof(color_t)))) + return GDISP_IMAGE_ERR_NOMEMORY; + + // We currently have not read any image data block + decode->blocksz = 0; + + // Set the palette + if (priv->frame.palsize) { + // Local palette + decode->maxpixel = priv->frame.palsize-1; + decode->palette = (color_t *)(decode+1); + img->io.fns->seek(&img->io, priv->frame.pospal); + for(cnt = 0; cnt < priv->frame.palsize; cnt++) { + if (img->io.fns->read(&img->io, &decode->buf, 3) != 3) + goto baddatacleanup; + decode->palette[cnt] = RGB2COLOR(decode->buf[0], decode->buf[1], decode->buf[2]); + } + } else if (priv->palette) { + // Global palette + decode->maxpixel = priv->palsize-1; + decode->palette = priv->palette; + } else { + // Oops - we must have a palette + goto baddatacleanup; + } + + // Get the initial lzw code size and values + img->io.fns->seek(&img->io, priv->frame.posimg); + if (img->io.fns->read(&img->io, &decode->bitsperpixel, 1) != 1 || decode->bitsperpixel >= MAX_CODE_BITS) + goto baddatacleanup; + decode->code_clear = 1 << decode->bitsperpixel; + decode->code_eof = decode->code_clear + 1; + decode->code_max = decode->code_clear + 2; + decode->code_last = CODE_NONE; + decode->bitspercode = decode->bitsperpixel+1; + decode->maxcodesz = 1 << decode->bitspercode; + decode->shiftbits = 0; + decode->shiftdata = 0; + decode->stackcnt = 0; + for(cnt = 0; cnt <= CODE_MAX; cnt++) + decode->prefix[cnt] = CODE_NONE; + + // All ready to go + priv->decode = decode; + return GDISP_IMAGE_ERR_OK; + +baddatacleanup: + gdispImageFree(img, decode, sizeof(imgdecode)+priv->frame.palsize*sizeof(color_t)); + return GDISP_IMAGE_ERR_BADDATA; +} + +/** + * Stop decoding a frame. + * + * Pre: Frame info has been read. + */ +static void stopDecode(gdispImage *img) { + gdispImagePrivate * priv; + + priv = img->priv; + + // Free the decode data + if (priv->decode) { + gdispImageFree(img, (void *)priv->decode, sizeof(imgdecode)+priv->frame.palsize*sizeof(color_t)); + priv->decode = 0; + } +} + +static uint16_t getPrefix(imgdecode *decode, uint16_t code) { + uint16_t i; + + for(i=0; code > decode->code_clear && i <= CODE_MAX; i++, code = decode->prefix[code]) { + if (code > CODE_MAX) + return CODE_NONE; + } + return code; +} + +/** + * Decode some pixels from a frame. + * + * Pre: We are ready for decoding. + * + * Return: The number of pixels decoded 0 .. BLIT_BUFFER_SIZE-1. 0 means EOF + * + * Note: The resulting pixels are stored in decode->buf + */ +static uint16_t getbytes(gdispImage *img) { + gdispImagePrivate * priv; + imgdecode * decode; + uint16_t cnt; + uint16_t code, prefix; + uint8_t bdata; + + priv = img->priv; + decode = priv->decode; + cnt = 0; + + // At EOF + if (decode->code_last == decode->code_eof) + return 0; + + while(cnt < sizeof(decode->buf)) { + // Use the stack up first + if (decode->stackcnt > 0) { + decode->buf[cnt++] = decode->stack[--decode->stackcnt]; + continue; + } + + // Get another code - a code is made up of decode->bitspercode bits. + while (decode->shiftbits < decode->bitspercode) { + // Get a byte - we may have to start a new data block + if ((!decode->blocksz && (img->io.fns->read(&img->io, &decode->blocksz, 1) != 1 || !decode->blocksz)) + || img->io.fns->read(&img->io, &bdata, 1) != 1) { + // Pretend we got the EOF code - some encoders seem to just end the file + decode->code_last = decode->code_eof; + return cnt; + } + decode->blocksz--; + + decode->shiftdata |= ((unsigned long)bdata) << decode->shiftbits; + decode->shiftbits += 8; + } + code = decode->shiftdata & BitMask[decode->bitspercode]; + decode->shiftdata >>= decode->bitspercode; + decode->shiftbits -= decode->bitspercode; + /** + * If code cannot fit into bitspercode bits we must raise its size. + * Note that codes above CODE_MAX are used for special signaling. + * If we're using MAX_CODE_BITS bits already and we're at the max code, just + * keep using the table as it is, don't increment decode->bitspercode. + */ + if (decode->code_max < CODE_MAX + 2 && ++decode->code_max > decode->maxcodesz && decode->bitspercode < MAX_CODE_BITS) { + decode->maxcodesz <<= 1; + decode->bitspercode++; + } + + // EOF - the appropriate way to stop decoding + if (code == decode->code_eof) { + // Skip to the end of the data blocks + do { + img->io.fns->seek(&img->io, img->io.pos+decode->blocksz); + } while (img->io.fns->read(&img->io, &decode->blocksz, 1) == 1 && decode->blocksz); + + // Mark the end + decode->code_last = decode->code_eof; + break; + } + + if (code == decode->code_clear) { + // Start again + for(prefix = 0; prefix <= CODE_MAX; prefix++) + decode->prefix[prefix] = CODE_NONE; + decode->code_max = decode->code_eof + 1; + decode->bitspercode = decode->bitsperpixel + 1; + decode->maxcodesz = 1 << decode->bitspercode; + decode->code_last = CODE_NONE; + continue; + } + + if (code < decode->code_clear) { + // Simple unencoded pixel - add it + decode->buf[cnt++] = code; + + } else { + /** + * Its a LZW code - trace the linked list until the prefix is a + * valid pixel while pushing the suffix pixels on the stack. + * If done, pop the stack in reverse order adding the pixels + */ + if (decode->prefix[code] != CODE_NONE) + prefix = code; + + /** + * Only allowed if the code equals the partial code. + * In that case code = XXXCode, CrntCode or the + * prefix code is last code and the suffix char is + * exactly the prefix of last code! + */ + else if (code == decode->code_max - 2 && decode->stackcnt < sizeof(decode->stack)) { + prefix = decode->code_last; + decode->suffix[decode->code_max - 2] = decode->stack[decode->stackcnt++] = getPrefix(decode, decode->code_last); + } else + return 0; + + /** + * If the image is OK we should not get a CODE_NONE while tracing. + * To prevent looping with a bad image we use StackPtr as loop counter + * and stop before overflowing Stack[]. + */ + while (decode->stackcnt < sizeof(decode->stack) && prefix > decode->code_clear && prefix <= CODE_MAX) { + decode->stack[decode->stackcnt++] = decode->suffix[prefix]; + prefix = decode->prefix[prefix]; + } + if (decode->stackcnt >= sizeof(decode->stack) || prefix > CODE_MAX) + return 0; + + /* Push the last character on stack: */ + decode->stack[decode->stackcnt++] = prefix; + } + + if (decode->code_last != CODE_NONE && decode->prefix[decode->code_max - 2] == CODE_NONE) { + decode->prefix[decode->code_max - 2] = decode->code_last; + + /* Only allowed if code is exactly the running code: + * In that case code = XXXCode, CrntCode or the + * prefix code is last code and the suffix char is + * exactly the prefix of last code! */ + decode->suffix[decode->code_max - 2] = getPrefix(decode, code == decode->code_max - 2 ? decode->code_last : code); + } + decode->code_last = code; + } + return cnt; +} + +/** + * Read the info on a frame. + * + * Pre: The file position is at the start of the frame. + */ +static gdispImageError initFrame(gdispImage *img) { + gdispImagePrivate * priv; + imgcache * cache; + uint8_t blocktype; + uint8_t blocksz; + + priv = img->priv; + + // Save the dispose info from the existing frame + priv->dispose.flags = priv->frame.flags; + priv->dispose.paltrans = priv->frame.paltrans; + priv->dispose.x = priv->frame.x; + priv->dispose.y = priv->frame.y; + priv->dispose.width = priv->frame.width; + priv->dispose.height = priv->frame.height; + + // Check for a cached version of this image + for(cache=priv->cache; cache && cache->frame.posstart <= img->io.pos; cache=cache->next) { + if (cache->frame.posstart == img->io.pos) { + priv->frame = cache->frame; + priv->curcache = cache; + return GDISP_IMAGE_ERR_OK; + } + } + + // Get ready for a new image + priv->curcache = 0; + priv->frame.posstart = img->io.pos; + priv->frame.flags = 0; + priv->frame.delay = 0; + priv->frame.palsize = 0; + + // Process blocks until we reach the image descriptor + while(1) { + if (img->io.fns->read(&img->io, &blocktype, 1) != 1) + return GDISP_IMAGE_ERR_BADDATA; + + switch(blocktype) { + case 0x2C: //',' - IMAGE_DESC_RECORD_TYPE; + // Read the Image Descriptor + if (img->io.fns->read(&img->io, priv->buf, 9) != 9) + return GDISP_IMAGE_ERR_BADDATA; + priv->frame.x = *(uint16_t *)(((uint8_t *)priv->buf)+0); + CONVERT_FROM_WORD_LE(priv->frame.x); + priv->frame.y = *(uint16_t *)(((uint8_t *)priv->buf)+2); + CONVERT_FROM_WORD_LE(priv->frame.y); + priv->frame.width = *(uint16_t *)(((uint8_t *)priv->buf)+4); + CONVERT_FROM_WORD_LE(priv->frame.width); + priv->frame.height = *(uint16_t *)(((uint8_t *)priv->buf)+6); + CONVERT_FROM_WORD_LE(priv->frame.height); + if (((uint8_t *)priv->buf)[8] & 0x80) // Local color table? + priv->frame.palsize = 2 << (((uint8_t *)priv->buf)[8] & 0x07); + if (((uint8_t *)priv->buf)[8] & 0x40) // Interlaced? + priv->frame.flags |= GIFL_INTERLACE; + + // We are ready to go for the actual palette read and image decode + priv->frame.pospal = img->io.pos; + priv->frame.posimg = priv->frame.pospal+priv->frame.palsize*3; + priv->frame.posend = 0; + + // Mark this as an animated image if more than 1 frame. + if (priv->frame.posstart != priv->frame0pos) + img->flags |= GDISP_IMAGE_FLG_ANIMATED; + return GDISP_IMAGE_ERR_OK; + + case 0x21: //'!' - EXTENSION_RECORD_TYPE; + // Read the extension type + if (img->io.fns->read(&img->io, &blocktype, 1) != 1) + return GDISP_IMAGE_ERR_BADDATA; + + switch(blocktype) { + case 0xF9: // EXTENSION - Graphics Control Block + // Read the GCB + if (img->io.fns->read(&img->io, priv->buf, 6) != 6) + return GDISP_IMAGE_ERR_BADDATA; + // Check we have read a 4 byte data block and a data block terminator (0) + if (((uint8_t *)priv->buf)[0] != 4 || ((uint8_t *)priv->buf)[5] != 0) + return GDISP_IMAGE_ERR_BADDATA; + // Process the flags + switch(((uint8_t *)priv->buf)[1] & 0x1C) { + case 0x00: case 0x04: break; // Dispose = do nothing + case 0x08: priv->frame.flags |= GIFL_DISPOSECLEAR; break; // Dispose = clear + case 0x0C: case 0x10: priv->frame.flags |= GIFL_DISPOSEREST; break; // Dispose = restore. Value 0x10 is a hack for bad encoders + default: return GDISP_IMAGE_ERR_UNSUPPORTED; + } + if (((uint8_t *)priv->buf)[1] & 0x01) { + priv->frame.flags |= GIFL_TRANSPARENT; + img->flags |= GDISP_IMAGE_FLG_TRANSPARENT; // We set this but never clear it + } + if (((uint8_t *)priv->buf)[1] & 0x02) // Wait for user input? + img->flags |= GDISP_IMAGE_FLG_MULTIPAGE; + else + img->flags &= ~GDISP_IMAGE_FLG_MULTIPAGE; + // Process frame delay and the transparent color (if any) + priv->frame.delay = *(uint16_t *)(((uint8_t *)priv->buf)+2); + CONVERT_FROM_WORD_LE(priv->frame.delay); + priv->frame.paltrans = ((uint8_t *)priv->buf)[4]; + break; + + case 0xFF: // EXTENSION - Application + // We only handle this for the special Netscape loop counter for animation + if (priv->flags & GIF_LOOP) + goto skipdatablocks; + // Read the Application header + if (img->io.fns->read(&img->io, priv->buf, 16) != 16) + return GDISP_IMAGE_ERR_BADDATA; + // Check we have read a 11 byte data block + if (((uint8_t *)priv->buf)[0] != 11 && ((uint8_t *)priv->buf)[12] != 3) + return GDISP_IMAGE_ERR_BADDATA; + // Check the vendor + if (((uint8_t *)priv->buf)[1] == 'N' && ((uint8_t *)priv->buf)[2] == 'E' && ((uint8_t *)priv->buf)[3] == 'T' + && ((uint8_t *)priv->buf)[4] == 'S' && ((uint8_t *)priv->buf)[5] == 'C' && ((uint8_t *)priv->buf)[6] == 'A' + && ((uint8_t *)priv->buf)[7] == 'P' && ((uint8_t *)priv->buf)[8] == 'E' && ((uint8_t *)priv->buf)[9] == '2' + && ((uint8_t *)priv->buf)[10] == '.' && ((uint8_t *)priv->buf)[11] == '0') { + if (((uint8_t *)priv->buf)[13] == 1) { + priv->loops = *(uint16_t *)(((uint8_t *)priv->buf)+14); + CONVERT_FROM_WORD_LE(priv->loops); + priv->flags |= GIF_LOOP; + if (!priv->loops) + priv->flags |= GIF_LOOPFOREVER; + } + } + goto skipdatablocks; + + case 0x01: // EXTENSION - Plain Text (Graphics Rendering) + case 0xFE: // EXTENSION - Comment + default: + // 0x00-0x7F (0-127) are the Graphic Rendering blocks + if (blocktype <= 0x7F) + return GDISP_IMAGE_ERR_UNSUPPORTED; + // 0x80-0xF9 (128-249) are the Control blocks + // 0xFA-0xFF (250-255) are the Special Purpose blocks + // We don't understand this extension - just skip it by skipping data blocks + skipdatablocks: + while(1) { + if (img->io.fns->read(&img->io, &blocksz, 1) != 1) + return GDISP_IMAGE_ERR_BADDATA; + if (!blocksz) + break; + img->io.fns->seek(&img->io, img->io.pos + blocksz); + } + break; + } + break; + + case 0x3B: //';' - TERMINATE_RECORD_TYPE; + // Are we an looping animation + if (!(priv->flags & GIF_LOOP)) + return GDISP_IMAGE_EOF; + if (!(priv->flags & GIF_LOOPFOREVER)) { + if (!priv->loops) + return GDISP_IMAGE_EOF; + priv->loops--; + } + + // Seek back to frame0 + img->io.fns->seek(&img->io, priv->frame0pos); + return GDISP_IMAGE_LOOP; + + default: // UNDEFINED_RECORD_TYPE; + return GDISP_IMAGE_ERR_UNSUPPORTED; + } + } +} + +gdispImageError gdispImageOpen_GIF(gdispImage *img) { + gdispImagePrivate *priv; + uint8_t hdr[6]; + uint16_t aword; + + /* Read the file identifier */ + if (img->io.fns->read(&img->io, hdr, 6) != 6) + return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us + + /* Process the GIFFILEHEADER structure */ + + if (hdr[0] != 'G' || hdr[1] != 'I' || hdr[2] != 'F' + || hdr[3] != '8' || (hdr[4] != '7' && hdr[4] != '9') || hdr[5] != 'a') + return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us + + /* We know we are a GIF format image */ + img->flags = 0; + + /* Allocate our private area */ + if (!(img->priv = (gdispImagePrivate *)gdispImageAlloc(img, sizeof(gdispImagePrivate)))) + return GDISP_IMAGE_ERR_NOMEMORY; + + /* Initialise the essential bits in the private area */ + priv = img->priv; + priv->flags = 0; + priv->palsize = 0; + priv->palette = 0; + priv->frame.flags = 0; + + /* Process the Screen Descriptor structure */ + + // Read the screen descriptor + if (img->io.fns->read(&img->io, priv->buf, 7) != 7) + goto baddatacleanup; + // Get the width + img->width = *(uint16_t *)(((uint8_t *)priv->buf)+0); + CONVERT_FROM_WORD_LE(img->width); + // Get the height + img->height = *(uint16_t *)(((uint8_t *)priv->buf)+2); + CONVERT_FROM_WORD_LE(img->height); + if (((uint8_t *)priv->buf)[4] & 0x80) { + // Global color table + priv->palsize = 2 << (((uint8_t *)priv->buf)[4] & 0x07); + // Allocate the global palette + if (!(priv->palette = (color_t *)gdispImageAlloc(img, priv->palsize*sizeof(color_t)))) + goto nomemcleanup; + // Read the global palette + for(aword = 0; aword < priv->palsize; aword++) { + if (img->io.fns->read(&img->io, &priv->buf, 3) != 3) + goto baddatacleanup; + priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[0], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[2]); + } + } + priv->bgcolor = ((uint8_t *)priv->buf)[5]; + + // Save the fram0pos + priv->frame0pos = img->io.pos; + + // Read the first frame descriptor + switch(initFrame(img)) { + case GDISP_IMAGE_ERR_OK: // Everything OK + return GDISP_IMAGE_ERR_OK; + case GDISP_IMAGE_ERR_UNSUPPORTED: // Unsupported + gdispImageClose_GIF(img); // Clean up the private data area + return GDISP_IMAGE_ERR_UNSUPPORTED; + case GDISP_IMAGE_ERR_NOMEMORY: // Out of Memory + nomemcleanup: + gdispImageClose_GIF(img); // Clean up the private data area + return GDISP_IMAGE_ERR_NOMEMORY; + case GDISP_IMAGE_EOF: // We should have a frame but we don't seem to + case GDISP_IMAGE_LOOP: // We should have a frame but we don't seem to + case GDISP_IMAGE_ERR_BADDATA: // Oops - something wrong with the data + default: + baddatacleanup: + gdispImageClose_GIF(img); // Clean up the private data area + return GDISP_IMAGE_ERR_BADDATA; + } +} + +void gdispImageClose_GIF(gdispImage *img) { + gdispImagePrivate * priv; + imgcache * cache; + imgcache * ncache; + + priv = img->priv; + if (priv) { + // Free any stored frames + cache = priv->cache; + while(cache) { + ncache = cache->next; + gdispImageFree(img, (void *)cache, sizeof(imgcache)+cache->frame.width*cache->frame.height+cache->frame.palsize*sizeof(color_t)); + cache = ncache; + } + if (priv->palette) + gdispImageFree(img, (void *)priv->palette, priv->palsize*sizeof(color_t)); + gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate)); + img->priv = 0; + } + img->io.fns->close(&img->io); +} + +gdispImageError gdispImageCache_GIF(gdispImage *img) { + gdispImagePrivate * priv; + imgcache * cache; + imgdecode * decode; + uint8_t * p; + uint8_t * q; + coord_t mx, my; + uint16_t cnt; + + /* If we are already cached - just return OK */ + priv = img->priv; + if (priv->curcache) + return GDISP_IMAGE_ERR_OK; + + /* We need to allocate the frame, the palette and bits for the image */ + if (!(cache = (imgcache *)gdispImageAlloc(img, sizeof(imgcache) + priv->frame.palsize*sizeof(color_t) + priv->frame.width*priv->frame.height))) + return GDISP_IMAGE_ERR_NOMEMORY; + + /* Initialise the cache */ + decode = 0; + cache->frame = priv->frame; + cache->imagebits = (uint8_t *)(cache+1) + cache->frame.palsize*sizeof(color_t); + cache->next = 0; + + /* Start the decode */ + switch(startDecode(img)) { + case GDISP_IMAGE_ERR_OK: break; + case GDISP_IMAGE_ERR_NOMEMORY: goto nomemcleanup; + case GDISP_IMAGE_ERR_BADDATA: + default: goto baddatacleanup; + } + decode = priv->decode; + + // Save the palette + if (cache->frame.palsize) { + cache->palette = (color_t *)(cache+1); + + /* Copy the local palette into the cache */ + for(cnt = 0; cnt < cache->frame.palsize; cnt++) + cache->palette[cnt] = decode->palette[cnt]; + } else + cache->palette = priv->palette; + + // Check for interlacing + cnt = 0; + if (cache->frame.flags & GIFL_INTERLACE) { + // Every 8th row starting at row 0 + for(p=cache->imagebits, my=0; my < cache->frame.height; my+=8, p += cache->frame.width*7) { + for(mx=0; mx < cache->frame.width; mx++) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + while(cnt < sizeof(decode->buf)) + decode->buf[cnt++] = (cache->frame.flags & GIFL_TRANSPARENT) ? cache->frame.paltrans : 0; + } + q = decode->buf; + } + *p++ = *q++; + cnt--; + } + } + // Every 8th row starting at row 4 + for(p=cache->imagebits+cache->frame.width*4, my=4; my < cache->frame.height; my+=8, p += cache->frame.width*7) { + for(mx=0; mx < cache->frame.width; mx++) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + while(cnt < sizeof(decode->buf)) + decode->buf[cnt++] = (cache->frame.flags & GIFL_TRANSPARENT) ? cache->frame.paltrans : 0; + } + q = decode->buf; + } + *p++ = *q++; + cnt--; + } + } + // Every 4th row starting at row 2 + for(p=cache->imagebits+cache->frame.width*2, my=2; my < cache->frame.height; my+=4, p += cache->frame.width*3) { + for(mx=0; mx < cache->frame.width; mx++) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + while(cnt < sizeof(decode->buf)) + decode->buf[cnt++] = (cache->frame.flags & GIFL_TRANSPARENT) ? cache->frame.paltrans : 0; + } + q = decode->buf; + } + *p++ = *q++; + cnt--; + } + } + // Every 2nd row starting at row 1 + for(p=cache->imagebits+cache->frame.width, my=1; my < cache->frame.height; my+=2, p += cache->frame.width) { + for(mx=0; mx < cache->frame.width; mx++) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + while(cnt < sizeof(decode->buf)) + decode->buf[cnt++] = (cache->frame.flags & GIFL_TRANSPARENT) ? cache->frame.paltrans : 0; + } + q = decode->buf; + } + *p++ = *q++; + cnt--; + } + } + } else { + // Every row in sequence + p=cache->imagebits; + for(my=0; my < cache->frame.height; my++) { + for(mx=0; mx < cache->frame.width; mx++) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + while(cnt < sizeof(decode->buf)) + decode->buf[cnt++] = (cache->frame.flags & GIFL_TRANSPARENT) ? cache->frame.paltrans : 0; + } + q = decode->buf; + } + *p++ = *q++; + cnt--; + } + } + } + // We could be pedantic here but extra bytes won't hurt us + while(getbytes(img)); + priv->frame.posend = cache->frame.posend = img->io.pos; + + // Save everything + priv->curcache = cache; + if (!priv->cache) + priv->cache = cache; + else if (priv->cache->frame.posstart > cache->frame.posstart) { + cache->next = priv->cache; + priv->cache = cache; + } else { + imgcache *pc; + + for(pc = priv->cache; pc; pc = pc->next) { + if (!pc->next || pc->next->frame.posstart > cache->frame.posstart) { + cache->next = pc->next; + pc->next = cache; + break; + } + } + } + stopDecode(img); + return GDISP_IMAGE_ERR_OK; + +nomemcleanup: + stopDecode(img); + gdispImageFree(img, cache, sizeof(imgcache) + priv->frame.palsize*sizeof(color_t) + priv->frame.width*priv->frame.height); + return GDISP_IMAGE_ERR_NOMEMORY; + +baddatacleanup: + stopDecode(img); + gdispImageFree(img, cache, sizeof(imgcache) + priv->frame.palsize*sizeof(color_t) + priv->frame.width*priv->frame.height); + return GDISP_IMAGE_ERR_BADDATA; +} + +gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { + gdispImagePrivate * priv; + imgdecode * decode; + uint8_t * q; + coord_t mx, my, fx, fy; + uint16_t cnt, gcnt; + uint8_t col; + + priv = img->priv; + + /* Handle previous frame disposing */ + if (priv->dispose.flags & (GIFL_DISPOSECLEAR|GIFL_DISPOSEREST)) { + // Clip to the disposal area - clip area = mx,my -> fx, fy (sx,sy,cx,cy are unchanged) + mx = priv->dispose.x; + my = priv->dispose.y; + fx = priv->dispose.x+priv->dispose.width; + fy = priv->dispose.y+priv->dispose.height; + if (sx > mx) mx = sx; + if (sy > my) my = sy; + if (sx+cx <= fx) fx = sx+cx; + if (sy+cy <= fy) fy = sy+cy; + if (fx > mx && fy > my) { + // We only support clearing (not restoring). The specification says that we are allowed to do this. + // Calculate the bgcolor + // The spec says to restore the backgound color (priv->bgcolor) but in practice if there is transparency + // image decoders tend to assume that a restore to the transparent color is required instead + if (((priv->dispose.flags & GIFL_TRANSPARENT) /*&& priv->dispose.paltrans == priv->bgcolor*/) || priv->bgcolor >= priv->palsize) + gdispFillArea(x+mx, y+my, fx-mx, fy-my, img->bgcolor); + else + gdispFillArea(x+mx, y+my, fx-mx, fy-my, priv->palette[priv->bgcolor]); + } + } + + /* Clip to just this frame - clip area = sx,sy -> fx, fy */ + fx = priv->frame.x+priv->frame.width; + fy = priv->frame.y+priv->frame.height; + if (sx >= fx || sy >= fy || sx+cx < priv->frame.x || sy+cy < priv->frame.y) return GDISP_IMAGE_ERR_OK; + if (sx < priv->frame.x) { mx = priv->frame.x - sx; x += mx; cx -= mx; sx = priv->frame.x; } + if (sy < priv->frame.y) { my = priv->frame.y - sy; y += my; cy -= my; sy = priv->frame.y; } + if (sx+cx > fx) cx = fx-sx; + if (sy+cy > fy) cy = fy-sy; + + // Make sx, sy relative to this frame so we are not adding priv->frame.x & priv->frame.y each time + sx -= priv->frame.x; sy -= priv->frame.y; + fx = sx + cx; + fy = sy + cy; + + /* Draw from the image cache - if it exists */ + if (priv->curcache) { + imgcache * cache; + + cache = priv->curcache; + q = cache->imagebits+priv->frame.width*sy+sx; + + for(my=sy; my < fy; my++, q += priv->frame.width - cx) { + for(gcnt=0, mx=sx, cnt=0; mx < fx; mx++) { + col = *q++; + if ((priv->frame.flags & GIFL_TRANSPARENT) && col == priv->frame.paltrans) { + // We have a transparent pixel - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + gcnt = 0; + continue; + } + priv->buf[gcnt++] = cache->palette[col]; + if (gcnt >= BLIT_BUFFER_SIZE) { + // We have run out of buffer - dump it to the display + gdispBlitAreaEx(x+mx-gcnt+1, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); + gcnt = 0; + } + } + // We have finished the line - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + } + + return GDISP_IMAGE_ERR_OK; + } + + /* Start the decode */ + switch(startDecode(img)) { + case GDISP_IMAGE_ERR_OK: break; + case GDISP_IMAGE_ERR_NOMEMORY: return GDISP_IMAGE_ERR_NOMEMORY; + case GDISP_IMAGE_ERR_BADDATA: + default: return GDISP_IMAGE_ERR_BADDATA; + } + decode = priv->decode; + + // Check for interlacing + cnt = 0; + if (priv->frame.flags & GIFL_INTERLACE) { + // Every 8th row starting at row 0 + for(my=0; my < priv->frame.height; my+=8) { + for(gcnt=0, mx=0; mx < priv->frame.width; mx++, q++, cnt--) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + mx++; + break; + } + q = decode->buf; + } + if (my >= sy && my < fy && mx >= sx && mx < fx) { + col = *q; + if ((priv->frame.flags & GIFL_TRANSPARENT) && col == priv->frame.paltrans) { + // We have a transparent pixel - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + gcnt = 0; + continue; + } + priv->buf[gcnt++] = decode->palette[col]; + if (gcnt >= BLIT_BUFFER_SIZE) { + // We have run out of buffer - dump it to the display + gdispBlitAreaEx(x+mx-gcnt+1, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); + gcnt = 0; + } + } + } + // We have finished the line - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + } + // Every 8th row starting at row 4 + for(my=4; my < priv->frame.height; my+=8) { + for(gcnt=0, mx=0; mx < priv->frame.width; mx++, q++, cnt--) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + mx++; + break; + } + q = decode->buf; + } + if (my >= sy && my < fy && mx >= sx && mx < fx) { + col = *q; + if ((priv->frame.flags & GIFL_TRANSPARENT) && col == priv->frame.paltrans) { + // We have a transparent pixel - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + gcnt = 0; + continue; + } + priv->buf[gcnt++] = decode->palette[col]; + if (gcnt >= BLIT_BUFFER_SIZE) { + // We have run out of buffer - dump it to the display + gdispBlitAreaEx(x+mx-gcnt+1, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); + gcnt = 0; + } + } + } + // We have finished the line - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + } + // Every 4th row starting at row 2 + for(my=2; my < priv->frame.height; my+=4) { + for(gcnt=0, mx=0; mx < priv->frame.width; mx++, q++, cnt--) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + mx++; + break; + } + q = decode->buf; + } + if (my >= sy && my < fy && mx >= sx && mx < fx) { + col = *q; + if ((priv->frame.flags & GIFL_TRANSPARENT) && col == priv->frame.paltrans) { + // We have a transparent pixel - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + gcnt = 0; + continue; + } + priv->buf[gcnt++] = decode->palette[col]; + if (gcnt >= BLIT_BUFFER_SIZE) { + // We have run out of buffer - dump it to the display + gdispBlitAreaEx(x+mx-gcnt+1, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); + gcnt = 0; + } + } + } + // We have finished the line - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + } + // Every 2nd row starting at row 1 + for(my=1; my < priv->frame.height; my+=2) { + for(gcnt=0, mx=0; mx < priv->frame.width; mx++, q++, cnt--) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + mx++; + break; + } + q = decode->buf; + } + if (my >= sy && my < fy && mx >= sx && mx < fx) { + col = *q; + if ((priv->frame.flags & GIFL_TRANSPARENT) && col == priv->frame.paltrans) { + // We have a transparent pixel - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + gcnt = 0; + continue; + } + priv->buf[gcnt++] = decode->palette[col]; + if (gcnt >= BLIT_BUFFER_SIZE) { + // We have run out of buffer - dump it to the display + gdispBlitAreaEx(x+mx-gcnt+1, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); + gcnt = 0; + } + } + } + // We have finished the line - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + } + } else { + // Every row in sequence + for(my=0; my < priv->frame.height; my++) { + for(gcnt=0, mx=0; mx < priv->frame.width; mx++, q++, cnt--) { + if (!cnt) { + if (!(cnt = getbytes(img))) { + // Sometimes the image EOF is a bit early - treat the rest as transparent + if (decode->code_last != decode->code_eof) + goto baddatacleanup; + mx++; + break; + } + q = decode->buf; + } + if (my >= sy && my < fy && mx >= sx && mx < fx) { + col = *q; + if ((priv->frame.flags & GIFL_TRANSPARENT) && col == priv->frame.paltrans) { + // We have a transparent pixel - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + gcnt = 0; + continue; + } + priv->buf[gcnt++] = decode->palette[col]; + if (gcnt >= BLIT_BUFFER_SIZE) { + // We have run out of buffer - dump it to the display + gdispBlitAreaEx(x+mx-gcnt+1, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); + gcnt = 0; + } + } + } + // We have finished the line - dump the buffer to the display + switch(gcnt) { + case 0: break; + case 1: gdispDrawPixel(x+mx-gcnt, y+my, priv->buf[0]); break; + default: gdispBlitAreaEx(x+mx-gcnt, y+my, gcnt, 1, 0, 0, gcnt, priv->buf); break; + } + } + } + // We could be pedantic here but extra bytes won't hurt us + while (getbytes(img)); + priv->frame.posend = img->io.pos; + + stopDecode(img); + return GDISP_IMAGE_ERR_OK; + +baddatacleanup: + stopDecode(img); + return GDISP_IMAGE_ERR_BADDATA; +} + +systime_t gdispImageNext_GIF(gdispImage *img) { + gdispImagePrivate * priv; + systime_t delay; + uint8_t blocksz; + + priv = img->priv; + + // Save the delay and convert to millisecs + delay = (systime_t)priv->frame.delay * 10; + + // We need to get to the end of this frame + if (!priv->frame.posend) { + // We don't know where the end of the frame is yet - find it! + img->io.fns->seek(&img->io, priv->frame.posimg+1); // Skip the code size byte too + while(1) { + if (img->io.fns->read(&img->io, &blocksz, 1) != 1) + return TIME_INFINITE; + if (!blocksz) + break; + img->io.fns->seek(&img->io, img->io.pos + blocksz); + } + priv->frame.posend = img->io.pos; + } + + // Seek to the end of this frame + img->io.fns->seek(&img->io, priv->frame.posend); + + // Read the next frame descriptor + for(blocksz=0; blocksz < 2; blocksz++) { // 2 loops max to prevent cycling forever with a bad file + switch(initFrame(img)) { + case GDISP_IMAGE_ERR_OK: // Everything OK + return delay; + case GDISP_IMAGE_LOOP: // Back to the beginning + break; + case GDISP_IMAGE_EOF: // The real End-Of-File + case GDISP_IMAGE_ERR_BADDATA: // Oops - something wrong with the data + case GDISP_IMAGE_ERR_NOMEMORY: // Out of Memory + case GDISP_IMAGE_ERR_UNSUPPORTED: // Unsupported + default: + return TIME_INFINITE; + } + } + return TIME_INFINITE; +} #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_GIF */ /** @} */