diff --git a/SSFN/consolas.sfn b/SSFN/consolas.sfn new file mode 100644 index 0000000..9cc6dfc Binary files /dev/null and b/SSFN/consolas.sfn differ diff --git a/SSFN/consolas.ttf b/SSFN/consolas.ttf new file mode 100644 index 0000000..556d2fd Binary files /dev/null and b/SSFN/consolas.ttf differ diff --git a/SSFN/sfnconv.exe b/SSFN/sfnconv.exe new file mode 100644 index 0000000..c4fc9cb Binary files /dev/null and b/SSFN/sfnconv.exe differ diff --git a/SSFN/sfnedit.exe b/SSFN/sfnedit.exe new file mode 100644 index 0000000..e9af970 Binary files /dev/null and b/SSFN/sfnedit.exe differ diff --git a/src/XDON-OG/XDON/XDON.cpp b/src/XDON-OG/XDON/XDON.cpp index b2f84ff..994fd5a 100644 --- a/src/XDON-OG/XDON/XDON.cpp +++ b/src/XDON-OG/XDON/XDON.cpp @@ -3,12 +3,22 @@ #include "stdafx.h" #include "XDON.h" +#include "font.h" + +#define SSFN_IMPLEMENTATION +#define SFFN_MAXLINES 8192 +#define SSFN_memcmp memcmp +#define SSFN_memset memset +#define SSFN_realloc realloc +#define SSFN_free free +#include "ssfn.h" #pragma region +XNADDR localAddr; LPDIRECT3DDEVICE8 pd3dDevice; -LPDIRECT3DVERTEXBUFFER8 pVB; -LPDIRECT3DTEXTURE8 pTexture; +LPDIRECT3DTEXTURE8 pBackgroundTexture; +LPDIRECT3DTEXTURE8 pFontOverlayTexture; //Order must match DEVICE_INDEX_INTERNAL. DEVICE_INFO devices[] = { @@ -70,6 +80,61 @@ BOOLEAN writeTookPlaceOnHDD = FALSE; #pragma region +void CreateFontOverlay(int width, int height) +{ + ssfn_t fontContext; + memset(&fontContext, 0, sizeof(ssfn_t)); + int result = ssfn_load(&fontContext, font_sfn); + assert(result == 0); + + result = ssfn_select(&fontContext, SSFN_FAMILY_SERIF, "FreeSans", SSFN_STYLE_REGULAR, 64); + assert(result == 0); + + HRESULT hr = D3DXCreateTexture(pd3dDevice, width, height, 1, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_DEFAULT, &pFontOverlayTexture); + assert(!FAILED(hr)); + + D3DSURFACE_DESC surfaceDesc; + pFontOverlayTexture->GetLevelDesc(0, &surfaceDesc); + + D3DLOCKED_RECT lockedRect; + hr = pFontOverlayTexture->LockRect(0, &lockedRect, NULL, 0); + assert(!FAILED(hr)); + + memset(lockedRect.pBits, 0x00, surfaceDesc.Size); + + ssfn_buf_t buffer; + memset(&buffer, 0, sizeof(buffer)); + buffer.ptr = (uint8_t*)lockedRect.pBits; + buffer.x = 10; + buffer.y = 100; + buffer.w = surfaceDesc.Width; + buffer.h = surfaceDesc.Height; + buffer.p = surfaceDesc.Width * 4; + buffer.bg = 0xff000000; + buffer.fg = 0xffffffff; + + char ipStr[255]; + sprintf(ipStr, + "IP Address: %u.%u.%u.%u", + (localAddr.ina.S_un.S_un_b.s_b1), + (localAddr.ina.S_un.S_un_b.s_b2), + (localAddr.ina.S_un.S_un_b.s_b3), + (localAddr.ina.S_un.S_un_b.s_b4) + ); + + char* message = ipStr; + int ret = 0; + while((ret = ssfn_render(&fontContext, &buffer, message)) > 0) + { + message += ret; + } + + hr = pFontOverlayTexture->UnlockRect(0); + assert(!FAILED(hr)); + + ssfn_free(&fontContext); +} + VOID Print(PRINT_VERBOSITY_FLAG Verbosity, const PCHAR Format, ...) { if ((Verbosity & verbositySetting) != Verbosity) return; @@ -484,9 +549,11 @@ VOID InitDisplay() HRESULT hr = Direct3DCreate8(D3D_SDK_VERSION)->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice); assert(!FAILED(hr)); - hr = D3DXCreateTextureFromFileInMemory(pd3dDevice, img, imgSize, &pTexture); + hr = D3DXCreateTextureFromFileInMemory(pd3dDevice, img, imgSize, &pBackgroundTexture); assert(!FAILED(hr)); + CreateFontOverlay(width, height); + D3DXMATRIX matProj; D3DXMatrixIdentity(&matProj); hr = pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); @@ -501,29 +568,9 @@ VOID InitDisplay() D3DXMatrixIdentity(&matWorld); hr = pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld); assert(!FAILED(hr)); - - VERTEX vertices[] = - { - { -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, - { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f }, - { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, - { 1.0f, -1.0f, 0.0f, 1.0f, 1.0f }, - { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f } - }; - hr = pd3dDevice->CreateVertexBuffer(sizeof(vertices), 0, 0, 0, &pVB); - assert(!FAILED(hr)); - - PVERTEX pVertices; - hr = pVB->Lock(0, 0, (PBYTE*)&pVertices, 0); - assert(!FAILED(hr)); - memcpy(pVertices, vertices, sizeof(vertices)); - - hr = pVB->Unlock(); - assert(!FAILED(hr)); //On OG Xbox, we can get away with doing all this just once (no render loop). - if (pTexture == NULL) + if (pBackgroundTexture == NULL) { //Display a red screen if the image failed to load (usually a memory issue) to encourage people to report it so it can be investigated. hr = pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0); @@ -561,14 +608,39 @@ VOID InitDisplay() assert(!FAILED(hr)); hr = pd3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); assert(!FAILED(hr)); - hr = pd3dDevice->SetStreamSource(0, pVB, sizeof(VERTEX)); + hr = pd3dDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); + assert(!FAILED(hr)); + hr = pd3dDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); assert(!FAILED(hr)); hr = pd3dDevice->SetVertexShader(D3DFVF_XYZ | D3DFVF_TEX1); assert(!FAILED(hr)); - hr = pd3dDevice->SetTexture(0, pTexture); + + VERTEX textureVertices[] = + { + { -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, + { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f }, + { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, + { 1.0f, -1.0f, 0.0f, 1.0f, 1.0f }, + { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f } + }; + hr = pd3dDevice->SetTexture(0, pBackgroundTexture); assert(!FAILED(hr)); - hr = pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + hr = pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, textureVertices, sizeof(VERTEX)); assert(!FAILED(hr)); + + VERTEX fontOverlayVertices[] = + { + { -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f, (float)width, 0.0f }, + { -1.0f, -1.0f, 0.0f, 0.0f, (float)height }, + { 1.0f, 1.0f, 0.0f, (float)width, 0.0f }, + { 1.0f, -1.0f, 0.0f, (float)width, (float)height }, + { -1.0f, -1.0f, 0.0f, 0.0f, (float)height } + }; + hr = pd3dDevice->SetTexture(0, pFontOverlayTexture); + assert(!FAILED(hr)); + hr = pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, fontOverlayVertices, sizeof(VERTEX)); } hr = pd3dDevice->Present(NULL, NULL, NULL, NULL); assert(!FAILED(hr)); @@ -1299,7 +1371,6 @@ VOID __cdecl main() } else if ((linkStatus & XNET_ETHERNET_LINK_10MBPS) == XNET_ETHERNET_LINK_10MBPS) Print(PRINT_VERBOSITY_FLAG_ESSENTIAL_AND_ERRORS, "Slow ethernet link detected."); - XNADDR localAddr; DWORD status = XNetGetTitleXnAddr(&localAddr); while (status == XNET_GET_XNADDR_PENDING) { diff --git a/src/XDON-OG/XDON/XDON.vcproj b/src/XDON-OG/XDON/XDON.vcproj index 60ee688..9296c4d 100644 --- a/src/XDON-OG/XDON/XDON.vcproj +++ b/src/XDON-OG/XDON/XDON.vcproj @@ -52,7 +52,7 @@ Name="XboxDeploymentTool"/> + + + + diff --git a/src/XDON-OG/XDON/XboxExports.h b/src/XDON-OG/XDON/XboxExports.h index 86d1e0b..5f7fa34 100644 --- a/src/XDON-OG/XDON/XboxExports.h +++ b/src/XDON-OG/XDON/XboxExports.h @@ -3,6 +3,15 @@ #pragma once +typedef signed char int8_t; +typedef short int16_t; +typedef long int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + #pragma region #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) diff --git a/src/XDON-OG/XDON/font.h b/src/XDON-OG/XDON/font.h new file mode 100644 index 0000000..45ec386 --- /dev/null +++ b/src/XDON-OG/XDON/font.h @@ -0,0 +1,582 @@ +#pragma once + +//Font imported to header using https://notisrac.github.io/FileToCArray/ + +const uint8_t font_sfn[] = { + 0x53, 0x46, 0x4e, 0x32, 0xfe, 0x23, 0x00, 0x00, 0x00, 0x00, 0xd7, 0xff, 0xd0, 0xf4, 0x5e, 0x00, + 0xec, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x61, 0x73, 0x00, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x61, + 0x73, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x35, 0x2e, 0x33, 0x33, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x04, 0x54, + 0x01, 0x18, 0x00, 0x15, 0x32, 0x03, 0x32, 0x00, 0x00, 0x18, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x54, 0x01, 0x5b, 0x10, 0x00, 0x10, 0x00, 0x00, 0x5b, 0x00, 0x5b, 0x10, 0x10, 0xa8, + 0xaa, 0xaa, 0xaa, 0x02, 0x10, 0x00, 0x17, 0x01, 0x14, 0x00, 0x1c, 0x05, 0x1a, 0x02, 0x1f, 0x0a, + 0x1e, 0x07, 0x21, 0x10, 0x21, 0x0d, 0x1f, 0x16, 0x21, 0x13, 0x1c, 0x1c, 0x1e, 0x19, 0x17, 0x1f, + 0x1a, 0x1e, 0x10, 0x20, 0x14, 0x20, 0x0a, 0x1f, 0x0d, 0x20, 0x05, 0x1c, 0x07, 0x1e, 0x01, 0x16, + 0x03, 0x19, 0x00, 0x10, 0x00, 0x13, 0x01, 0x0a, 0x00, 0x0d, 0x05, 0x05, 0x03, 0x07, 0x0a, 0x01, + 0x07, 0x02, 0x10, 0x00, 0x0d, 0x00, 0x15, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x38, 0x0b, + 0x37, 0x05, 0x38, 0x13, 0x34, 0x10, 0x36, 0x1a, 0x2e, 0x17, 0x31, 0x1c, 0x26, 0x1c, 0x2b, 0x1a, + 0x1f, 0x1c, 0x22, 0x17, 0x1a, 0x19, 0x1c, 0x14, 0x15, 0x15, 0x18, 0x12, 0x0e, 0x12, 0x12, 0x13, + 0x09, 0x12, 0x0c, 0x15, 0x05, 0x14, 0x07, 0x1a, 0x01, 0x17, 0x03, 0x20, 0x00, 0x1d, 0x00, 0x28, + 0x02, 0x24, 0x00, 0x2e, 0x06, 0x2b, 0x03, 0x32, 0x0e, 0x30, 0x0a, 0x33, 0x1a, 0x33, 0x13, 0x30, + 0x2b, 0x33, 0x22, 0x26, 0x39, 0x2d, 0x33, 0x16, 0x43, 0x20, 0x3f, 0x00, 0x47, 0x0d, 0x47, 0x00, + 0x38, 0x03, 0x54, 0x30, 0x00, 0x00, 0x4a, 0x30, 0x4a, 0x30, 0x00, 0x03, 0x54, 0x2f, 0x4a, 0x17, + 0x00, 0x00, 0x4a, 0x2f, 0x4a, 0x04, 0x54, 0x01, 0x5b, 0xad, 0x49, 0xad, 0x00, 0x00, 0x12, 0x00, + 0x5b, 0xad, 0x04, 0x54, 0x01, 0x78, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x78, 0x00, 0x78, 0x0f, 0x04, + 0x54, 0x01, 0x73, 0x00, 0x11, 0x96, 0x00, 0x96, 0x62, 0x00, 0x73, 0x00, 0x04, 0x54, 0x01, 0x34, + 0x1a, 0x22, 0x1a, 0x00, 0x00, 0x1a, 0x00, 0x34, 0x1a, 0x04, 0x54, 0x01, 0x1b, 0x26, 0x1f, 0x00, + 0x03, 0x00, 0x00, 0x26, 0x1b, 0x26, 0x04, 0x54, 0x01, 0x11, 0xda, 0x00, 0xda, 0x00, 0x00, 0x11, + 0x00, 0x11, 0xda, 0x04, 0x54, 0x01, 0x5b, 0x00, 0x12, 0xad, 0x00, 0xad, 0x49, 0x00, 0x5b, 0x00, + 0x04, 0x54, 0x01, 0x40, 0x11, 0x00, 0x11, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, 0x04, 0x54, 0x01, + 0x16, 0x00, 0x13, 0x6e, 0x03, 0x6e, 0x00, 0x00, 0x16, 0x00, 0x05, 0xa8, 0x06, 0x19, 0x00, 0x06, + 0x06, 0x0c, 0x01, 0x00, 0x13, 0x00, 0x0b, 0x05, 0x1f, 0x00, 0x1a, 0x14, 0x27, 0x0a, 0x23, 0x19, + 0x00, 0x06, 0x54, 0x15, 0x00, 0x0c, 0x0b, 0x00, 0x53, 0x3b, 0x0b, 0x77, 0x00, 0x6b, 0x3a, 0x3c, + 0x00, 0x0c, 0x06, 0x54, 0x15, 0x50, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x13, 0x00, 0x13, 0x7b, 0x50, + 0x7b, 0x50, 0x8b, 0x06, 0x54, 0x15, 0x53, 0x6b, 0x47, 0x77, 0x00, 0x3b, 0x47, 0x00, 0x53, 0x0c, + 0x19, 0x3b, 0x53, 0x6b, 0x07, 0x68, 0xa5, 0x35, 0x1c, 0x2c, 0x07, 0x35, 0x0e, 0x13, 0x00, 0x23, + 0x00, 0x00, 0x00, 0x00, 0x39, 0x12, 0x39, 0x2b, 0x32, 0x22, 0x39, 0x35, 0x1c, 0x35, 0x2b, 0x07, + 0x54, 0x55, 0x5f, 0x44, 0x4c, 0x44, 0x2e, 0x0f, 0x11, 0x44, 0x00, 0x44, 0x27, 0x00, 0x36, 0x00, + 0x5f, 0x44, 0x07, 0xa8, 0x6a, 0x00, 0x2a, 0x14, 0x23, 0x0e, 0x29, 0x1b, 0x15, 0x1b, 0x1e, 0x1a, + 0x0e, 0x1b, 0x11, 0x16, 0x09, 0x18, 0x0b, 0x0f, 0x04, 0x13, 0x06, 0x05, 0x00, 0x0b, 0x02, 0x00, + 0x2a, 0x07, 0x54, 0x55, 0x5e, 0x12, 0x24, 0x8b, 0x0f, 0x8b, 0x4b, 0x12, 0x00, 0x12, 0x00, 0x00, + 0x5e, 0x00, 0x5e, 0x12, 0x08, 0xa8, 0x56, 0x02, 0x3d, 0x36, 0x3b, 0x1d, 0x3d, 0x27, 0x32, 0x0c, + 0x38, 0x13, 0x24, 0x03, 0x2d, 0x06, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x0e, 0x6b, + 0x3d, 0x36, 0x3d, 0x6b, 0x08, 0x54, 0x55, 0x01, 0x65, 0x11, 0x3c, 0x11, 0x3c, 0x8b, 0x29, 0x8b, + 0x29, 0x11, 0x00, 0x11, 0x00, 0x00, 0x65, 0x00, 0x65, 0x11, 0x08, 0x54, 0x55, 0x01, 0x76, 0x8b, + 0x61, 0x8b, 0x57, 0x6d, 0x1d, 0x6d, 0x14, 0x8b, 0x00, 0x8b, 0x2e, 0x00, 0x48, 0x00, 0x76, 0x8b, + 0x08, 0x54, 0x55, 0x01, 0x34, 0xc6, 0x00, 0xc6, 0x00, 0x00, 0x34, 0x00, 0x34, 0x0f, 0x12, 0x0f, + 0x12, 0xb7, 0x34, 0xb7, 0x34, 0xc6, 0x08, 0x54, 0x55, 0x01, 0x34, 0xc6, 0x00, 0xc6, 0x00, 0xb7, + 0x23, 0xb7, 0x23, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x34, 0x00, 0x34, 0xc6, 0x09, 0x54, 0x55, 0x05, + 0x77, 0x00, 0x48, 0x8b, 0x2e, 0x8b, 0x00, 0x00, 0x15, 0x00, 0x33, 0x5e, 0x3c, 0x79, 0x45, 0x5e, + 0x63, 0x00, 0x77, 0x00, 0x09, 0xa8, 0x56, 0x0a, 0x34, 0x16, 0x32, 0x0d, 0x34, 0x11, 0x2b, 0x06, + 0x30, 0x09, 0x21, 0x01, 0x27, 0x03, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x14, 0x2f, + 0x2c, 0x29, 0x24, 0x2f, 0x34, 0x16, 0x34, 0x23, 0x09, 0x68, 0xa5, 0x0a, 0x2c, 0x17, 0x25, 0x06, + 0x2c, 0x0b, 0x12, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x0f, 0x2e, 0x1b, 0x2d, 0x16, 0x2e, + 0x24, 0x28, 0x21, 0x2b, 0x2a, 0x21, 0x28, 0x25, 0x2c, 0x17, 0x2c, 0x1c, 0x09, 0xa8, 0xaa, 0x06, + 0x39, 0x21, 0x37, 0x14, 0x39, 0x1a, 0x32, 0x0a, 0x35, 0x0e, 0x29, 0x03, 0x2e, 0x05, 0x1d, 0x00, + 0x24, 0x00, 0x12, 0x03, 0x17, 0x00, 0x09, 0x09, 0x0d, 0x05, 0x03, 0x14, 0x05, 0x0e, 0x00, 0x21, + 0x01, 0x1a, 0x39, 0x21, 0x09, 0x54, 0x55, 0x05, 0x00, 0x00, 0x15, 0x00, 0x2f, 0x46, 0x35, 0x57, + 0x3b, 0x46, 0x55, 0x00, 0x69, 0x00, 0x3f, 0x6a, 0x2a, 0x6a, 0x00, 0x00, 0x09, 0xa8, 0xa6, 0x0a, + 0x00, 0x28, 0x06, 0x45, 0x00, 0x3b, 0x16, 0x4e, 0x0b, 0x4e, 0x25, 0x48, 0x1d, 0x4e, 0x35, 0x36, + 0x2c, 0x42, 0x35, 0x04, 0x2b, 0x01, 0x30, 0x02, 0x20, 0x00, 0x25, 0x00, 0x08, 0x09, 0x11, 0x00, + 0x00, 0x28, 0x00, 0x13, 0x0a, 0x54, 0x55, 0x15, 0x23, 0x0f, 0x04, 0x0f, 0x04, 0x00, 0x36, 0x00, + 0x36, 0x87, 0x56, 0x87, 0x56, 0x96, 0x00, 0x96, 0x00, 0x87, 0x23, 0x87, 0x23, 0x0f, 0x0a, 0x54, + 0x55, 0x15, 0x5f, 0x0f, 0x18, 0x7a, 0x60, 0x7a, 0x60, 0x8b, 0x00, 0x8b, 0x00, 0x7d, 0x47, 0x12, + 0x02, 0x12, 0x02, 0x00, 0x5f, 0x00, 0x5f, 0x0f, 0x0a, 0xa8, 0xaa, 0x2a, 0x33, 0x13, 0x2c, 0x05, + 0x33, 0x09, 0x19, 0x00, 0x25, 0x00, 0x07, 0x04, 0x0d, 0x00, 0x00, 0x12, 0x00, 0x09, 0x02, 0x1a, + 0x00, 0x16, 0x06, 0x20, 0x03, 0x1d, 0x0f, 0x26, 0x0a, 0x24, 0x1b, 0x2d, 0x14, 0x29, 0x2d, 0x21, + 0x27, 0x27, 0x33, 0x13, 0x33, 0x1b, 0x0a, 0x54, 0x55, 0x15, 0x4e, 0x11, 0x13, 0x11, 0x13, 0x3e, + 0x4b, 0x3e, 0x4b, 0x4d, 0x13, 0x4d, 0x13, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x4e, 0x00, 0x4e, 0x11, + 0x0a, 0x54, 0x55, 0x15, 0x56, 0x6a, 0x00, 0x6a, 0x00, 0x5d, 0x3c, 0x0f, 0x01, 0x0f, 0x01, 0x00, + 0x53, 0x00, 0x53, 0x0e, 0x17, 0x5b, 0x56, 0x5b, 0x56, 0x6a, 0x0a, 0x54, 0x55, 0x15, 0x23, 0x0f, + 0x04, 0x0f, 0x04, 0x00, 0x36, 0x00, 0x36, 0x5b, 0x56, 0x5b, 0x56, 0x6a, 0x00, 0x6a, 0x00, 0x5b, + 0x23, 0x5b, 0x23, 0x0f, 0x0a, 0xa8, 0x9a, 0x2a, 0x00, 0x1c, 0x02, 0x26, 0x00, 0x21, 0x07, 0x2e, + 0x04, 0x2b, 0x0f, 0x33, 0x0b, 0x31, 0x1a, 0x35, 0x14, 0x35, 0x33, 0x2b, 0x28, 0x35, 0x11, 0x00, + 0x0a, 0x06, 0x0d, 0x03, 0x05, 0x0c, 0x07, 0x08, 0x01, 0x13, 0x03, 0x0f, 0x00, 0x1c, 0x00, 0x17, + 0x0a, 0xa8, 0x9a, 0x1a, 0x0b, 0x00, 0x3c, 0x65, 0x3c, 0x2d, 0x3a, 0x7d, 0x3c, 0x71, 0x32, 0x96, + 0x38, 0x89, 0x23, 0xb0, 0x2c, 0xa3, 0x0b, 0xcb, 0x19, 0xbe, 0x00, 0xc0, 0x1f, 0x95, 0x15, 0xac, + 0x29, 0x66, 0x29, 0x7f, 0x00, 0x0b, 0x29, 0x34, 0x0b, 0x00, 0x0a, 0xa8, 0x9a, 0x1a, 0x31, 0xcb, + 0x00, 0x67, 0x00, 0x9e, 0x03, 0x4d, 0x00, 0x5a, 0x0b, 0x33, 0x05, 0x40, 0x1a, 0x1a, 0x11, 0x26, + 0x31, 0x00, 0x24, 0x0d, 0x3c, 0x0b, 0x13, 0x65, 0x13, 0x34, 0x1d, 0x95, 0x13, 0x7e, 0x3c, 0xc0, + 0x28, 0xab, 0x31, 0xcb, 0x0b, 0x54, 0x55, 0x55, 0x5f, 0x8b, 0x47, 0x8b, 0x13, 0x47, 0x13, 0x8b, + 0x00, 0x8b, 0x00, 0x00, 0x13, 0x00, 0x13, 0x41, 0x46, 0x00, 0x5c, 0x00, 0x25, 0x42, 0x5f, 0x8b, + 0x0b, 0xa8, 0x6a, 0xa5, 0x64, 0x44, 0x63, 0x57, 0x64, 0x4e, 0x5e, 0x68, 0x61, 0x61, 0x55, 0x77, + 0x5a, 0x70, 0x48, 0x82, 0x50, 0x7d, 0x35, 0x89, 0x40, 0x86, 0x1e, 0x8b, 0x2b, 0x8b, 0x00, 0x8b, + 0x00, 0x00, 0x24, 0x00, 0x54, 0x11, 0x44, 0x00, 0x64, 0x44, 0x64, 0x22, 0x0b, 0xa8, 0x6a, 0xaa, + 0x00, 0x29, 0x01, 0x39, 0x00, 0x32, 0x05, 0x45, 0x03, 0x40, 0x0c, 0x4d, 0x08, 0x4a, 0x16, 0x4f, + 0x10, 0x4f, 0x25, 0x49, 0x1d, 0x4f, 0x35, 0x37, 0x2c, 0x43, 0x35, 0x05, 0x2b, 0x02, 0x31, 0x03, + 0x20, 0x00, 0x26, 0x00, 0x08, 0x0b, 0x10, 0x00, 0x00, 0x29, 0x00, 0x15, 0x0b, 0x68, 0xaa, 0xaa, + 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x41, 0x3b, 0x19, 0x37, 0x0f, 0x39, 0x13, + 0x31, 0x07, 0x34, 0x0a, 0x29, 0x02, 0x2e, 0x04, 0x20, 0x00, 0x25, 0x00, 0x12, 0x04, 0x18, 0x00, + 0x08, 0x0e, 0x0c, 0x07, 0x02, 0x20, 0x04, 0x15, 0x00, 0x37, 0x00, 0x2a, 0x0b, 0x68, 0xaa, 0xaa, + 0x3b, 0x0f, 0x3b, 0x07, 0x3b, 0x0b, 0x3a, 0x00, 0x3b, 0x04, 0x00, 0x2c, 0x04, 0x36, 0x01, 0x32, + 0x0a, 0x3e, 0x06, 0x3b, 0x11, 0x44, 0x0d, 0x42, 0x1c, 0x45, 0x16, 0x45, 0x29, 0x42, 0x23, 0x45, + 0x33, 0x37, 0x2f, 0x3e, 0x39, 0x26, 0x37, 0x31, 0x3b, 0x0f, 0x3b, 0x1c, 0x0b, 0x54, 0x55, 0x55, + 0x5c, 0x8b, 0x04, 0x8b, 0x04, 0x7a, 0x28, 0x7a, 0x28, 0x15, 0x07, 0x27, 0x00, 0x17, 0x2c, 0x00, + 0x3d, 0x00, 0x3d, 0x7a, 0x5c, 0x7a, 0x5c, 0x8b, 0x0b, 0x54, 0x55, 0x55, 0x6e, 0x6d, 0x56, 0x6d, + 0x56, 0x8b, 0x43, 0x8b, 0x43, 0x6d, 0x00, 0x6d, 0x00, 0x5c, 0x3b, 0x00, 0x56, 0x00, 0x56, 0x5c, + 0x6e, 0x5c, 0x6e, 0x6d, 0x0b, 0x54, 0x55, 0x55, 0x78, 0x00, 0x45, 0x5a, 0x45, 0x8b, 0x32, 0x8b, + 0x32, 0x59, 0x00, 0x00, 0x17, 0x00, 0x33, 0x33, 0x3d, 0x48, 0x46, 0x35, 0x62, 0x00, 0x78, 0x00, + 0x0b, 0xa8, 0x56, 0xaa, 0x30, 0x15, 0x2e, 0x0d, 0x30, 0x10, 0x2a, 0x06, 0x2d, 0x09, 0x21, 0x02, + 0x27, 0x04, 0x13, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x13, 0x2c, 0x1f, 0x2a, 0x19, 0x2c, + 0x28, 0x26, 0x24, 0x29, 0x2d, 0x1f, 0x2b, 0x23, 0x30, 0x15, 0x30, 0x1b, 0x0b, 0x54, 0x55, 0x55, + 0x5e, 0x96, 0x44, 0x96, 0x13, 0x5d, 0x13, 0x96, 0x00, 0x96, 0x00, 0x00, 0x13, 0x00, 0x13, 0x5c, + 0x42, 0x2c, 0x5b, 0x2c, 0x29, 0x5d, 0x5e, 0x96, 0x0c, 0xa8, 0xaa, 0xaa, 0x02, 0x1a, 0x12, 0x17, + 0x04, 0x1a, 0x09, 0x0d, 0x00, 0x13, 0x00, 0x08, 0x01, 0x0a, 0x00, 0x04, 0x05, 0x05, 0x03, 0x01, + 0x0b, 0x02, 0x07, 0x00, 0x12, 0x00, 0x0e, 0x04, 0x20, 0x00, 0x1b, 0x0d, 0x24, 0x07, 0x24, 0x13, + 0x23, 0x10, 0x24, 0x17, 0x1f, 0x15, 0x22, 0x19, 0x19, 0x18, 0x1d, 0x1a, 0x12, 0x1a, 0x16, 0x0c, + 0x54, 0x55, 0x55, 0x01, 0x6a, 0x6a, 0x51, 0x6a, 0x34, 0x42, 0x18, 0x6a, 0x00, 0x6a, 0x29, 0x35, + 0x02, 0x00, 0x1a, 0x00, 0x36, 0x29, 0x51, 0x00, 0x68, 0x00, 0x40, 0x35, 0x6a, 0x6a, 0x0c, 0xa4, + 0xaa, 0xaa, 0x01, 0x31, 0x00, 0x1a, 0x00, 0x0e, 0x01, 0x13, 0x00, 0x06, 0x05, 0x09, 0x03, 0x01, + 0x0b, 0x03, 0x08, 0x00, 0x13, 0x00, 0x0f, 0x01, 0x19, 0x00, 0x16, 0x04, 0x1e, 0x01, 0x1c, 0x09, + 0x22, 0x06, 0x20, 0x11, 0x23, 0x0d, 0x23, 0x20, 0x1f, 0x18, 0x23, 0x31, 0x13, 0x28, 0x1b, 0x31, + 0x00, 0x0c, 0x54, 0x55, 0x55, 0x01, 0x73, 0x8b, 0x5b, 0x8b, 0x3a, 0x53, 0x18, 0x8b, 0x00, 0x8b, + 0x2e, 0x44, 0x04, 0x00, 0x1a, 0x00, 0x3a, 0x35, 0x5a, 0x00, 0x70, 0x00, 0x45, 0x43, 0x73, 0x8b, + 0x0c, 0x54, 0x55, 0x55, 0x01, 0x4f, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x4f, 0x00, 0x4f, 0x10, 0x13, + 0x10, 0x13, 0x3b, 0x4d, 0x3b, 0x4d, 0x4b, 0x13, 0x4b, 0x13, 0x7b, 0x4f, 0x7b, 0x4f, 0x8b, 0x0c, + 0xa8, 0xaa, 0xaa, 0x02, 0x1a, 0x12, 0x17, 0x05, 0x1a, 0x09, 0x0d, 0x00, 0x13, 0x00, 0x08, 0x02, + 0x0a, 0x00, 0x04, 0x05, 0x05, 0x03, 0x01, 0x0b, 0x02, 0x08, 0x00, 0x12, 0x00, 0x0e, 0x04, 0x20, + 0x00, 0x1c, 0x0d, 0x25, 0x07, 0x25, 0x13, 0x23, 0x10, 0x25, 0x17, 0x1f, 0x15, 0x22, 0x19, 0x1a, + 0x18, 0x1d, 0x1a, 0x12, 0x1a, 0x16, 0x0c, 0x54, 0x55, 0x55, 0x01, 0x20, 0x10, 0x00, 0x10, 0x00, + 0x00, 0x53, 0x00, 0x53, 0x10, 0x33, 0x10, 0x33, 0x7b, 0x53, 0x7b, 0x53, 0x8b, 0x00, 0x8b, 0x00, + 0x7b, 0x20, 0x7b, 0x20, 0x10, 0x0c, 0x54, 0x55, 0x55, 0x01, 0x60, 0x8b, 0x4d, 0x8b, 0x4d, 0x4c, + 0x13, 0x4c, 0x13, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x13, 0x00, 0x13, 0x3b, 0x4d, 0x3b, 0x4d, 0x00, + 0x60, 0x00, 0x60, 0x8b, 0x0c, 0x54, 0x55, 0x55, 0x01, 0x66, 0x3b, 0x3c, 0x3b, 0x3c, 0x67, 0x2a, + 0x67, 0x2a, 0x3b, 0x00, 0x3b, 0x00, 0x2b, 0x2a, 0x2b, 0x2a, 0x00, 0x3c, 0x00, 0x3c, 0x2b, 0x66, + 0x2b, 0x66, 0x3b, 0x0d, 0xa8, 0x56, 0xa5, 0x0a, 0x5b, 0x2b, 0x58, 0x3c, 0x5b, 0x33, 0x4e, 0x4b, + 0x55, 0x44, 0x3d, 0x55, 0x47, 0x51, 0x24, 0x59, 0x33, 0x59, 0x13, 0x59, 0x13, 0x8b, 0x00, 0x8b, + 0x00, 0x00, 0x27, 0x00, 0x3b, 0x03, 0x31, 0x00, 0x4c, 0x0a, 0x44, 0x05, 0x57, 0x17, 0x53, 0x0f, + 0x5b, 0x2b, 0x5b, 0x1f, 0x0d, 0xa8, 0xaa, 0xa6, 0x0a, 0x35, 0x26, 0x34, 0x16, 0x35, 0x1e, 0x30, + 0x0a, 0x33, 0x0f, 0x29, 0x03, 0x2e, 0x05, 0x20, 0x00, 0x25, 0x00, 0x18, 0x01, 0x1c, 0x00, 0x11, + 0x05, 0x15, 0x02, 0x09, 0x0c, 0x0d, 0x07, 0x00, 0x16, 0x04, 0x10, 0x00, 0x4a, 0x0a, 0x4d, 0x05, + 0x4c, 0x15, 0x4f, 0x10, 0x4f, 0x2d, 0x45, 0x24, 0x4f, 0x35, 0x26, 0x35, 0x3a, 0x0d, 0xa8, 0xaa, + 0xa6, 0x0a, 0x00, 0x13, 0x08, 0x1e, 0x00, 0x1a, 0x1d, 0x21, 0x0f, 0x21, 0x2c, 0x20, 0x26, 0x21, + 0x36, 0x1b, 0x32, 0x1e, 0x3b, 0x15, 0x3a, 0x19, 0x3d, 0x0f, 0x3d, 0x12, 0x38, 0x05, 0x3d, 0x08, + 0x27, 0x01, 0x32, 0x02, 0x0b, 0x00, 0x06, 0x05, 0x08, 0x03, 0x02, 0x0a, 0x03, 0x07, 0x00, 0x0e, + 0x01, 0x0c, 0x00, 0x13, 0x00, 0x10, 0x0d, 0xa8, 0xaa, 0xa6, 0x0a, 0x22, 0x11, 0x1e, 0x04, 0x22, + 0x09, 0x12, 0x00, 0x19, 0x00, 0x0a, 0x01, 0x0d, 0x00, 0x05, 0x05, 0x07, 0x03, 0x01, 0x0b, 0x02, + 0x07, 0x00, 0x12, 0x00, 0x0e, 0x02, 0x1d, 0x00, 0x18, 0x09, 0x27, 0x04, 0x22, 0x0c, 0x2b, 0x15, + 0x26, 0x11, 0x29, 0x1c, 0x20, 0x19, 0x23, 0x20, 0x19, 0x1f, 0x1d, 0x22, 0x11, 0x22, 0x16, 0x0e, + 0xa8, 0x56, 0xaa, 0x2a, 0x5b, 0x62, 0x57, 0x74, 0x5b, 0x6c, 0x4c, 0x81, 0x53, 0x7b, 0x3b, 0x89, + 0x45, 0x86, 0x24, 0x8b, 0x31, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x28, 0x00, 0x56, 0x22, 0x56, 0x00, + 0x51, 0x36, 0x56, 0x2d, 0x3f, 0x42, 0x4c, 0x3e, 0x4a, 0x45, 0x45, 0x43, 0x53, 0x4c, 0x4f, 0x48, + 0x59, 0x55, 0x57, 0x50, 0x5b, 0x62, 0x5b, 0x5b, 0x0e, 0x54, 0x55, 0x55, 0x15, 0x5f, 0x8b, 0x46, + 0x8b, 0x1d, 0x35, 0x12, 0x19, 0x12, 0x5f, 0x12, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x18, 0x00, 0x3f, + 0x52, 0x4d, 0x72, 0x4d, 0x28, 0x4d, 0x00, 0x5f, 0x00, 0x5f, 0x8b, 0x0f, 0xa8, 0xaa, 0xa6, 0xaa, + 0x35, 0x26, 0x34, 0x16, 0x35, 0x1e, 0x30, 0x0a, 0x33, 0x0f, 0x29, 0x03, 0x2e, 0x05, 0x20, 0x00, + 0x25, 0x00, 0x18, 0x01, 0x1c, 0x00, 0x11, 0x05, 0x15, 0x02, 0x09, 0x0c, 0x0d, 0x07, 0x00, 0x16, + 0x04, 0x10, 0x00, 0x4a, 0x0b, 0x4d, 0x05, 0x4c, 0x15, 0x4f, 0x10, 0x4f, 0x21, 0x4d, 0x1c, 0x4f, + 0x2c, 0x46, 0x27, 0x4b, 0x33, 0x39, 0x30, 0x41, 0x35, 0x26, 0x35, 0x32, 0x0f, 0xa8, 0xaa, 0xaa, + 0x6a, 0x19, 0x03, 0x16, 0x01, 0x18, 0x02, 0x11, 0x00, 0x14, 0x00, 0x0b, 0x02, 0x0e, 0x00, 0x07, + 0x08, 0x09, 0x04, 0x04, 0x11, 0x05, 0x0c, 0x01, 0x1a, 0x02, 0x15, 0x00, 0x24, 0x00, 0x1f, 0x00, + 0x2d, 0x00, 0x29, 0x01, 0x3b, 0x00, 0x37, 0x06, 0x40, 0x02, 0x40, 0x08, 0x3f, 0x07, 0x40, 0x0b, + 0x3d, 0x0a, 0x3f, 0x0e, 0x39, 0x0d, 0x3c, 0x12, 0x32, 0x10, 0x36, 0x19, 0x03, 0x10, 0xa8, 0xaa, + 0xaa, 0xaa, 0x02, 0x39, 0x1c, 0x38, 0x10, 0x39, 0x15, 0x33, 0x07, 0x36, 0x0b, 0x2b, 0x02, 0x30, + 0x04, 0x1f, 0x00, 0x26, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x0e, 0x03, 0x12, 0x01, 0x07, 0x06, 0x0a, + 0x04, 0x00, 0x09, 0x03, 0x07, 0x02, 0x20, 0x00, 0x17, 0x08, 0x2f, 0x04, 0x29, 0x11, 0x37, 0x0c, + 0x34, 0x1e, 0x39, 0x17, 0x39, 0x29, 0x37, 0x24, 0x39, 0x32, 0x31, 0x2e, 0x35, 0x37, 0x28, 0x35, + 0x2d, 0x39, 0x1c, 0x39, 0x23, 0x10, 0x94, 0x6a, 0xaa, 0x5a, 0x01, 0x00, 0x02, 0x11, 0x02, 0x11, + 0x15, 0x24, 0x05, 0x1b, 0x0a, 0x37, 0x00, 0x2d, 0x00, 0x50, 0x0a, 0x47, 0x00, 0x58, 0x2a, 0x58, + 0x15, 0x45, 0x2a, 0x41, 0x16, 0x45, 0x1c, 0x34, 0x10, 0x3d, 0x10, 0x2c, 0x11, 0x30, 0x10, 0x25, + 0x15, 0x29, 0x12, 0x1c, 0x1d, 0x21, 0x18, 0x13, 0x28, 0x18, 0x21, 0x13, 0x6c, 0x00, 0x6c, 0x00, + 0x02, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x44, 0x38, 0x42, 0x21, 0x44, 0x2b, 0x3c, 0x10, 0x40, + 0x17, 0x32, 0x04, 0x38, 0x08, 0x22, 0x00, 0x2b, 0x00, 0x12, 0x05, 0x19, 0x00, 0x08, 0x10, 0x0c, + 0x09, 0x02, 0x21, 0x04, 0x17, 0x00, 0x36, 0x00, 0x2b, 0x02, 0x4d, 0x00, 0x42, 0x08, 0x5e, 0x04, + 0x57, 0x12, 0x6a, 0x0c, 0x66, 0x22, 0x6e, 0x19, 0x6e, 0x31, 0x69, 0x2b, 0x6e, 0x3c, 0x5e, 0x38, + 0x65, 0x42, 0x4d, 0x40, 0x56, 0x44, 0x38, 0x44, 0x43, 0x10, 0xa8, 0x6a, 0x55, 0xaa, 0x02, 0x00, + 0x39, 0x03, 0x23, 0x00, 0x2e, 0x0c, 0x11, 0x06, 0x19, 0x1d, 0x05, 0x13, 0x09, 0x34, 0x00, 0x26, + 0x00, 0x3f, 0x01, 0x3a, 0x00, 0x4a, 0x04, 0x44, 0x02, 0x5b, 0x00, 0x5b, 0x98, 0x48, 0x98, 0x48, + 0x70, 0x49, 0x59, 0x25, 0x6e, 0x3a, 0x6e, 0x15, 0x6a, 0x1c, 0x6e, 0x09, 0x60, 0x0e, 0x67, 0x02, + 0x4f, 0x05, 0x59, 0x00, 0x39, 0x00, 0x45, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x0f, 0x00, 0x14, + 0x01, 0x12, 0x00, 0x19, 0x04, 0x17, 0x02, 0x1c, 0x09, 0x1b, 0x06, 0x1d, 0x0e, 0x1d, 0x0b, 0x1c, + 0x14, 0x1d, 0x11, 0x19, 0x19, 0x1b, 0x17, 0x14, 0x1c, 0x17, 0x1b, 0x0f, 0x1d, 0x12, 0x1d, 0x09, + 0x1c, 0x0b, 0x1d, 0x04, 0x19, 0x06, 0x1b, 0x01, 0x14, 0x02, 0x17, 0x00, 0x0e, 0x00, 0x11, 0x01, + 0x09, 0x00, 0x0b, 0x04, 0x04, 0x02, 0x06, 0x09, 0x01, 0x06, 0x02, 0x0f, 0x00, 0x0b, 0x00, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x44, 0x37, 0x42, 0x21, 0x44, 0x2b, 0x3c, 0x0f, 0x40, 0x17, 0x32, + 0x04, 0x38, 0x08, 0x22, 0x00, 0x2b, 0x00, 0x12, 0x04, 0x19, 0x00, 0x08, 0x10, 0x0c, 0x09, 0x02, + 0x21, 0x04, 0x17, 0x00, 0x36, 0x00, 0x2b, 0x02, 0x4d, 0x00, 0x43, 0x08, 0x5e, 0x04, 0x57, 0x12, + 0x6a, 0x0c, 0x66, 0x22, 0x6e, 0x19, 0x6e, 0x31, 0x6a, 0x2b, 0x6e, 0x3c, 0x5e, 0x38, 0x65, 0x42, + 0x4d, 0x40, 0x56, 0x44, 0x37, 0x44, 0x43, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x3e, 0x28, 0x3c, + 0x17, 0x3e, 0x1e, 0x36, 0x0a, 0x3a, 0x0f, 0x2c, 0x03, 0x32, 0x05, 0x1f, 0x00, 0x26, 0x00, 0x11, + 0x04, 0x17, 0x00, 0x07, 0x0c, 0x0b, 0x07, 0x02, 0x19, 0x03, 0x12, 0x00, 0x28, 0x00, 0x20, 0x02, + 0x39, 0x00, 0x32, 0x08, 0x46, 0x04, 0x41, 0x12, 0x4d, 0x0c, 0x4b, 0x1f, 0x50, 0x18, 0x50, 0x2d, + 0x4c, 0x27, 0x50, 0x37, 0x44, 0x33, 0x49, 0x3c, 0x37, 0x3b, 0x3e, 0x3e, 0x28, 0x3e, 0x30, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x0e, 0x00, 0x14, 0x01, 0x11, 0x00, 0x19, 0x04, 0x17, 0x02, 0x1c, + 0x09, 0x1b, 0x06, 0x1d, 0x0e, 0x1d, 0x0b, 0x1c, 0x14, 0x1d, 0x11, 0x19, 0x19, 0x1b, 0x17, 0x14, + 0x1c, 0x17, 0x1b, 0x0e, 0x1d, 0x11, 0x1d, 0x08, 0x1c, 0x0b, 0x1d, 0x04, 0x19, 0x06, 0x1b, 0x01, + 0x14, 0x02, 0x17, 0x00, 0x0e, 0x00, 0x11, 0x01, 0x09, 0x00, 0x0b, 0x04, 0x04, 0x02, 0x06, 0x08, + 0x01, 0x06, 0x02, 0x0e, 0x00, 0x0b, 0x00, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x1c, 0x00, 0x11, + 0x02, 0x16, 0x00, 0x08, 0x07, 0x0c, 0x04, 0x03, 0x11, 0x05, 0x0b, 0x00, 0x1d, 0x00, 0x16, 0x02, + 0x29, 0x00, 0x24, 0x07, 0x32, 0x04, 0x2e, 0x0f, 0x37, 0x0a, 0x35, 0x1b, 0x39, 0x14, 0x39, 0x23, + 0x38, 0x1f, 0x39, 0x2c, 0x36, 0x28, 0x37, 0x33, 0x33, 0x30, 0x35, 0x3a, 0x30, 0x37, 0x32, 0x38, + 0x19, 0x3a, 0x22, 0x32, 0x0a, 0x36, 0x10, 0x28, 0x02, 0x2e, 0x04, 0x1c, 0x00, 0x23, 0x00, 0x10, + 0xa8, 0x6a, 0x95, 0xaa, 0x02, 0x5b, 0x5f, 0x58, 0x77, 0x5b, 0x6c, 0x4d, 0x89, 0x54, 0x81, 0x3d, + 0x94, 0x46, 0x90, 0x27, 0x98, 0x33, 0x98, 0x14, 0x96, 0x1d, 0x98, 0x00, 0x90, 0x0a, 0x94, 0x00, + 0x00, 0x13, 0x00, 0x13, 0x29, 0x12, 0x3d, 0x23, 0x2e, 0x1a, 0x33, 0x36, 0x2a, 0x2c, 0x2a, 0x46, + 0x2e, 0x3f, 0x2a, 0x52, 0x38, 0x4d, 0x31, 0x59, 0x49, 0x57, 0x3f, 0x5b, 0x5f, 0x5b, 0x53, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x64, 0x36, 0x61, 0x4d, 0x64, 0x43, 0x57, 0x5f, 0x5d, 0x57, 0x47, + 0x6a, 0x50, 0x66, 0x31, 0x6e, 0x3d, 0x6e, 0x1c, 0x6b, 0x26, 0x6e, 0x0d, 0x60, 0x13, 0x67, 0x03, + 0x4f, 0x07, 0x59, 0x00, 0x38, 0x00, 0x45, 0x04, 0x21, 0x00, 0x2b, 0x0e, 0x0f, 0x07, 0x17, 0x1e, + 0x04, 0x14, 0x08, 0x33, 0x00, 0x27, 0x00, 0x48, 0x03, 0x3f, 0x00, 0x57, 0x0e, 0x51, 0x07, 0x61, + 0x1f, 0x5d, 0x15, 0x64, 0x36, 0x64, 0x29, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x39, 0x1f, 0x37, + 0x2c, 0x39, 0x26, 0x31, 0x36, 0x35, 0x32, 0x28, 0x3d, 0x2d, 0x3a, 0x1c, 0x3f, 0x22, 0x3f, 0x10, + 0x3d, 0x15, 0x3f, 0x07, 0x37, 0x0b, 0x3b, 0x02, 0x2d, 0x04, 0x33, 0x00, 0x20, 0x00, 0x27, 0x02, + 0x13, 0x00, 0x19, 0x08, 0x09, 0x04, 0x0d, 0x11, 0x02, 0x0b, 0x05, 0x1d, 0x00, 0x16, 0x00, 0x28, + 0x02, 0x23, 0x00, 0x31, 0x08, 0x2e, 0x04, 0x37, 0x11, 0x35, 0x0c, 0x39, 0x1f, 0x39, 0x17, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x39, 0x20, 0x37, 0x2c, 0x39, 0x27, 0x31, 0x37, 0x35, 0x32, 0x28, + 0x3d, 0x2d, 0x3b, 0x1c, 0x40, 0x22, 0x40, 0x10, 0x3e, 0x15, 0x40, 0x07, 0x38, 0x0b, 0x3c, 0x02, + 0x2e, 0x04, 0x34, 0x00, 0x20, 0x00, 0x28, 0x02, 0x14, 0x00, 0x1a, 0x07, 0x0a, 0x04, 0x0e, 0x11, + 0x03, 0x0b, 0x05, 0x1d, 0x00, 0x16, 0x00, 0x28, 0x02, 0x23, 0x00, 0x31, 0x08, 0x2e, 0x04, 0x37, + 0x12, 0x35, 0x0c, 0x39, 0x20, 0x39, 0x18, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x36, 0x1e, 0x35, + 0x16, 0x36, 0x1a, 0x31, 0x0f, 0x34, 0x12, 0x28, 0x08, 0x2d, 0x0b, 0x1a, 0x00, 0x22, 0x04, 0x0d, + 0x07, 0x12, 0x04, 0x06, 0x0e, 0x09, 0x0b, 0x01, 0x16, 0x03, 0x12, 0x00, 0x1e, 0x00, 0x19, 0x02, + 0x26, 0x00, 0x22, 0x08, 0x2c, 0x04, 0x2a, 0x10, 0x30, 0x0b, 0x2f, 0x1b, 0x31, 0x15, 0x31, 0x26, + 0x30, 0x21, 0x31, 0x2e, 0x2d, 0x2b, 0x2f, 0x34, 0x27, 0x32, 0x2a, 0x36, 0x1e, 0x36, 0x23, 0x10, + 0x68, 0x55, 0x55, 0xa5, 0x01, 0x67, 0x12, 0x4e, 0x0f, 0x58, 0x0f, 0x35, 0x29, 0x35, 0x0f, 0x35, + 0x3c, 0x63, 0x3c, 0x63, 0x4c, 0x35, 0x4c, 0x35, 0x97, 0x22, 0x97, 0x22, 0x4c, 0x00, 0x4c, 0x00, + 0x3c, 0x22, 0x3c, 0x22, 0x2a, 0x4e, 0x00, 0x22, 0x00, 0x67, 0x02, 0x59, 0x00, 0x67, 0x12, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x0e, 0x00, 0x13, 0x01, 0x11, 0x00, 0x17, 0x04, 0x16, 0x02, 0x1a, + 0x09, 0x19, 0x06, 0x1b, 0x0e, 0x1b, 0x0b, 0x1a, 0x14, 0x1b, 0x11, 0x17, 0x18, 0x19, 0x16, 0x13, + 0x1b, 0x16, 0x1a, 0x0e, 0x1c, 0x11, 0x1c, 0x08, 0x1b, 0x0b, 0x1c, 0x04, 0x18, 0x06, 0x1a, 0x01, + 0x14, 0x02, 0x16, 0x00, 0x0e, 0x00, 0x11, 0x01, 0x09, 0x00, 0x0b, 0x04, 0x04, 0x02, 0x06, 0x08, + 0x01, 0x06, 0x02, 0x0e, 0x00, 0x0b, 0x00, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x65, 0x48, 0x62, + 0x65, 0x65, 0x58, 0x58, 0x7c, 0x5f, 0x72, 0x48, 0x8a, 0x52, 0x85, 0x31, 0x8f, 0x3e, 0x8f, 0x1d, + 0x8b, 0x26, 0x8f, 0x0e, 0x7e, 0x14, 0x87, 0x04, 0x68, 0x07, 0x75, 0x00, 0x48, 0x00, 0x5a, 0x03, + 0x2b, 0x00, 0x38, 0x0d, 0x14, 0x06, 0x1e, 0x1d, 0x06, 0x13, 0x0b, 0x34, 0x00, 0x27, 0x00, 0x48, + 0x05, 0x3f, 0x00, 0x58, 0x12, 0x51, 0x09, 0x62, 0x28, 0x5e, 0x1a, 0x65, 0x48, 0x65, 0x35, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x10, 0x00, 0x17, 0x01, 0x14, 0x00, 0x1c, 0x05, 0x1a, 0x02, 0x1f, + 0x0a, 0x1e, 0x07, 0x21, 0x10, 0x21, 0x0d, 0x1f, 0x16, 0x21, 0x13, 0x1c, 0x1b, 0x1e, 0x19, 0x17, + 0x1f, 0x1a, 0x1e, 0x10, 0x20, 0x14, 0x20, 0x0a, 0x1f, 0x0d, 0x20, 0x05, 0x1b, 0x07, 0x1e, 0x01, + 0x16, 0x03, 0x19, 0x00, 0x10, 0x00, 0x13, 0x01, 0x0a, 0x00, 0x0d, 0x05, 0x05, 0x03, 0x07, 0x0a, + 0x01, 0x07, 0x02, 0x10, 0x00, 0x0d, 0x00, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x12, 0x00, 0x18, + 0x01, 0x15, 0x00, 0x1e, 0x05, 0x1c, 0x03, 0x22, 0x0b, 0x21, 0x08, 0x23, 0x12, 0x23, 0x0e, 0x22, + 0x19, 0x23, 0x15, 0x1e, 0x1e, 0x21, 0x1c, 0x18, 0x22, 0x1c, 0x21, 0x12, 0x23, 0x15, 0x23, 0x0b, + 0x22, 0x0e, 0x23, 0x05, 0x1e, 0x08, 0x21, 0x01, 0x19, 0x03, 0x1c, 0x00, 0x12, 0x00, 0x15, 0x01, + 0x0b, 0x00, 0x0e, 0x05, 0x05, 0x03, 0x08, 0x0b, 0x01, 0x08, 0x03, 0x12, 0x00, 0x0e, 0x00, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x0e, 0x00, 0x14, 0x01, 0x11, 0x00, 0x18, 0x04, 0x16, 0x02, 0x1b, + 0x09, 0x1a, 0x06, 0x1c, 0x0e, 0x1c, 0x0b, 0x1b, 0x14, 0x1c, 0x11, 0x18, 0x18, 0x1a, 0x16, 0x14, + 0x1b, 0x16, 0x1a, 0x0e, 0x1c, 0x11, 0x1c, 0x09, 0x1b, 0x0b, 0x1c, 0x04, 0x18, 0x06, 0x1a, 0x01, + 0x14, 0x02, 0x16, 0x00, 0x0e, 0x00, 0x11, 0x01, 0x09, 0x00, 0x0b, 0x04, 0x04, 0x02, 0x06, 0x09, + 0x01, 0x06, 0x02, 0x0e, 0x00, 0x0b, 0x00, 0x10, 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x6c, 0x47, 0x67, + 0x67, 0x6c, 0x5a, 0x5b, 0x7e, 0x63, 0x75, 0x4a, 0x8b, 0x54, 0x87, 0x35, 0x8f, 0x40, 0x8f, 0x1d, + 0x8a, 0x27, 0x8f, 0x0d, 0x7c, 0x13, 0x86, 0x03, 0x66, 0x06, 0x73, 0x00, 0x49, 0x00, 0x59, 0x04, + 0x28, 0x00, 0x36, 0x10, 0x12, 0x09, 0x1b, 0x22, 0x05, 0x18, 0x09, 0x37, 0x00, 0x2c, 0x00, 0x4e, + 0x05, 0x44, 0x00, 0x5f, 0x13, 0x58, 0x0a, 0x69, 0x2a, 0x65, 0x1c, 0x6c, 0x47, 0x6c, 0x37, 0x10, + 0xa8, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x16, 0x02, 0x20, 0x00, 0x1c, 0x07, 0x27, 0x04, 0x24, 0x0e, + 0x2c, 0x0a, 0x2a, 0x17, 0x2d, 0x12, 0x2d, 0x21, 0x2c, 0x1d, 0x2d, 0x28, 0x26, 0x26, 0x2a, 0x2d, + 0x1f, 0x2b, 0x23, 0x2e, 0x16, 0x2e, 0x1b, 0x2d, 0x0d, 0x2e, 0x11, 0x28, 0x06, 0x2b, 0x09, 0x21, + 0x01, 0x25, 0x03, 0x17, 0x00, 0x1c, 0x00, 0x0d, 0x02, 0x12, 0x00, 0x06, 0x07, 0x09, 0x03, 0x02, + 0x0e, 0x03, 0x0a, 0x00, 0x16, 0x00, 0x12, 0x11, 0xa8, 0x6a, 0x55, 0xaa, 0x0a, 0x00, 0x63, 0x04, + 0x4b, 0x00, 0x56, 0x0e, 0x39, 0x07, 0x40, 0x1f, 0x2e, 0x15, 0x32, 0x34, 0x2a, 0x28, 0x2a, 0x3e, + 0x2b, 0x39, 0x2a, 0x48, 0x2d, 0x43, 0x2c, 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x96, 0x4a, 0x96, 0x49, + 0x82, 0x39, 0x93, 0x42, 0x8d, 0x25, 0x98, 0x30, 0x98, 0x15, 0x94, 0x1c, 0x98, 0x09, 0x8a, 0x0e, + 0x91, 0x02, 0x79, 0x05, 0x83, 0x00, 0x63, 0x00, 0x6f, 0x11, 0xa8, 0x6a, 0x55, 0xaa, 0x0a, 0x5b, + 0x35, 0x57, 0x4e, 0x5b, 0x43, 0x4c, 0x60, 0x53, 0x59, 0x3c, 0x6a, 0x45, 0x67, 0x27, 0x6e, 0x32, + 0x6e, 0x1d, 0x6d, 0x22, 0x6e, 0x13, 0x6b, 0x18, 0x6d, 0x13, 0x98, 0x00, 0x98, 0x00, 0x02, 0x10, + 0x02, 0x12, 0x13, 0x23, 0x04, 0x1a, 0x09, 0x36, 0x00, 0x2c, 0x00, 0x46, 0x04, 0x3f, 0x00, 0x52, + 0x0e, 0x4d, 0x07, 0x59, 0x1f, 0x57, 0x15, 0x5b, 0x35, 0x5b, 0x29, 0x12, 0x54, 0x55, 0x55, 0x55, + 0x15, 0x55, 0x3d, 0x4e, 0x4a, 0x30, 0x36, 0x32, 0x5a, 0x23, 0x5a, 0x25, 0x36, 0x07, 0x4a, 0x00, + 0x3d, 0x21, 0x2d, 0x00, 0x1d, 0x07, 0x10, 0x25, 0x24, 0x23, 0x00, 0x32, 0x00, 0x2f, 0x24, 0x4e, + 0x10, 0x55, 0x1d, 0x34, 0x2d, 0x55, 0x3d, 0x12, 0xa4, 0xaa, 0x9a, 0x6a, 0x15, 0x4a, 0x00, 0x4a, + 0x61, 0x47, 0x72, 0x4a, 0x6a, 0x3f, 0x80, 0x45, 0x7a, 0x32, 0x89, 0x3a, 0x86, 0x1e, 0x8d, 0x29, + 0x8d, 0x16, 0x8c, 0x1a, 0x8d, 0x0e, 0x8b, 0x12, 0x8c, 0x06, 0x88, 0x0a, 0x8a, 0x00, 0x85, 0x03, + 0x87, 0x00, 0x72, 0x0f, 0x7a, 0x07, 0x77, 0x1f, 0x7c, 0x17, 0x7c, 0x30, 0x75, 0x2a, 0x7c, 0x37, + 0x61, 0x37, 0x6e, 0x37, 0x11, 0x02, 0x11, 0x02, 0x00, 0x4a, 0x00, 0x12, 0xa4, 0xaa, 0xa9, 0x6a, + 0x15, 0x4b, 0x00, 0x4b, 0x68, 0x48, 0x7c, 0x4b, 0x74, 0x3f, 0x8b, 0x45, 0x85, 0x30, 0x94, 0x39, + 0x91, 0x1d, 0x97, 0x28, 0x97, 0x0e, 0x96, 0x15, 0x97, 0x00, 0x92, 0x06, 0x94, 0x00, 0x80, 0x07, + 0x83, 0x03, 0x82, 0x0f, 0x85, 0x0b, 0x84, 0x17, 0x87, 0x13, 0x86, 0x1f, 0x87, 0x1b, 0x87, 0x32, + 0x80, 0x2b, 0x87, 0x39, 0x69, 0x39, 0x78, 0x39, 0x0f, 0x04, 0x0f, 0x04, 0x00, 0x4b, 0x00, 0x13, + 0x54, 0x55, 0x55, 0x55, 0x55, 0x6d, 0x8b, 0x5b, 0x8b, 0x58, 0x35, 0x57, 0x13, 0x50, 0x27, 0x3c, + 0x5e, 0x2f, 0x5e, 0x1b, 0x29, 0x15, 0x13, 0x14, 0x36, 0x12, 0x8b, 0x00, 0x8b, 0x07, 0x00, 0x1d, + 0x00, 0x30, 0x35, 0x36, 0x46, 0x3c, 0x35, 0x50, 0x00, 0x67, 0x00, 0x6d, 0x8b, 0x13, 0x54, 0x55, + 0x55, 0x55, 0x55, 0x6e, 0x00, 0x65, 0x8b, 0x4c, 0x8b, 0x3b, 0x5a, 0x36, 0x4a, 0x31, 0x5b, 0x21, + 0x8b, 0x0a, 0x8b, 0x00, 0x00, 0x12, 0x00, 0x17, 0x5f, 0x19, 0x79, 0x20, 0x63, 0x30, 0x2f, 0x3d, + 0x2f, 0x51, 0x67, 0x57, 0x79, 0x58, 0x66, 0x5d, 0x00, 0x6e, 0x00, 0x13, 0x94, 0xaa, 0x56, 0xaa, + 0x56, 0x56, 0x6a, 0x45, 0x6a, 0x45, 0x59, 0x3b, 0x62, 0x40, 0x5f, 0x33, 0x68, 0x37, 0x66, 0x2a, + 0x6b, 0x2f, 0x6a, 0x21, 0x6c, 0x26, 0x6c, 0x08, 0x63, 0x11, 0x6c, 0x00, 0x45, 0x00, 0x59, 0x00, + 0x00, 0x13, 0x00, 0x13, 0x44, 0x25, 0x5c, 0x13, 0x5c, 0x2c, 0x5b, 0x28, 0x5c, 0x32, 0x58, 0x2f, + 0x5a, 0x3a, 0x51, 0x36, 0x55, 0x43, 0x46, 0x3e, 0x4d, 0x43, 0x00, 0x56, 0x00, 0x56, 0x6a, 0x13, + 0x54, 0x55, 0x55, 0x55, 0x55, 0x70, 0x00, 0x60, 0x6a, 0x4a, 0x6a, 0x3b, 0x3e, 0x38, 0x33, 0x34, + 0x3e, 0x25, 0x6a, 0x0f, 0x6a, 0x00, 0x00, 0x12, 0x00, 0x1b, 0x48, 0x1d, 0x58, 0x21, 0x4a, 0x31, + 0x1a, 0x3e, 0x1a, 0x4f, 0x4a, 0x54, 0x58, 0x55, 0x49, 0x5e, 0x00, 0x70, 0x00, 0x14, 0x94, 0xaa, + 0x56, 0xaa, 0x5a, 0x01, 0x00, 0x02, 0x10, 0x02, 0x11, 0x13, 0x1a, 0x0a, 0x16, 0x0d, 0x23, 0x04, + 0x1f, 0x06, 0x2b, 0x01, 0x27, 0x01, 0x34, 0x00, 0x30, 0x00, 0x4d, 0x09, 0x45, 0x00, 0x56, 0x27, + 0x56, 0x13, 0x56, 0x6c, 0x43, 0x6c, 0x43, 0x28, 0x3f, 0x16, 0x43, 0x1c, 0x31, 0x10, 0x3a, 0x10, + 0x2a, 0x11, 0x2d, 0x10, 0x23, 0x14, 0x27, 0x12, 0x1c, 0x1b, 0x20, 0x17, 0x13, 0x26, 0x18, 0x1f, + 0x13, 0x6c, 0x00, 0x6c, 0x00, 0x02, 0x14, 0xa8, 0xaa, 0x56, 0xaa, 0x5a, 0x01, 0x61, 0x5b, 0x5d, + 0x70, 0x61, 0x66, 0x54, 0x80, 0x5a, 0x79, 0x44, 0x8a, 0x4e, 0x86, 0x30, 0x8d, 0x3b, 0x8d, 0x1a, + 0x8a, 0x23, 0x8d, 0x0b, 0x80, 0x11, 0x86, 0x03, 0x71, 0x05, 0x7a, 0x00, 0x5e, 0x00, 0x69, 0x00, + 0x00, 0x13, 0x00, 0x13, 0x5c, 0x14, 0x6b, 0x13, 0x65, 0x1a, 0x75, 0x16, 0x71, 0x23, 0x7b, 0x1d, + 0x79, 0x30, 0x7d, 0x28, 0x7d, 0x47, 0x75, 0x3f, 0x7d, 0x4e, 0x5c, 0x4e, 0x6c, 0x4e, 0x00, 0x61, + 0x00, 0x61, 0x5b, 0x14, 0xa8, 0x56, 0x55, 0x55, 0xaa, 0x01, 0x60, 0x8c, 0x53, 0x8e, 0x5a, 0x8d, + 0x46, 0x8f, 0x4d, 0x8f, 0x28, 0x86, 0x32, 0x8f, 0x1e, 0x6a, 0x1e, 0x7d, 0x1e, 0x32, 0x00, 0x32, + 0x00, 0x23, 0x1e, 0x23, 0x1e, 0x05, 0x30, 0x00, 0x30, 0x23, 0x60, 0x23, 0x60, 0x32, 0x30, 0x32, + 0x30, 0x68, 0x36, 0x7a, 0x30, 0x74, 0x49, 0x7f, 0x3d, 0x7f, 0x54, 0x7e, 0x4e, 0x7f, 0x60, 0x7c, + 0x5a, 0x7e, 0x60, 0x8c, 0x15, 0x94, 0xaa, 0x56, 0x95, 0xaa, 0x06, 0x56, 0x96, 0x43, 0x96, 0x43, + 0x52, 0x3f, 0x40, 0x43, 0x46, 0x31, 0x3a, 0x3a, 0x3a, 0x2a, 0x3b, 0x2e, 0x3a, 0x24, 0x3e, 0x27, + 0x3c, 0x1c, 0x45, 0x20, 0x41, 0x13, 0x50, 0x18, 0x49, 0x13, 0x96, 0x00, 0x96, 0x00, 0x00, 0x13, + 0x00, 0x13, 0x2c, 0x12, 0x3c, 0x1a, 0x34, 0x16, 0x37, 0x23, 0x2e, 0x1f, 0x30, 0x2b, 0x2b, 0x27, + 0x2c, 0x34, 0x2a, 0x30, 0x2a, 0x4d, 0x33, 0x44, 0x2a, 0x56, 0x51, 0x56, 0x3d, 0x56, 0x96, 0x15, + 0xa8, 0xaa, 0x9a, 0xaa, 0xaa, 0x06, 0x60, 0x87, 0x3d, 0x8e, 0x4f, 0x8e, 0x10, 0x7d, 0x20, 0x8e, + 0x00, 0x48, 0x00, 0x6b, 0x04, 0x2a, 0x00, 0x38, 0x11, 0x13, 0x09, 0x1d, 0x24, 0x05, 0x19, 0x0a, + 0x3e, 0x00, 0x30, 0x00, 0x50, 0x01, 0x48, 0x00, 0x60, 0x06, 0x58, 0x03, 0x60, 0x19, 0x50, 0x13, + 0x58, 0x15, 0x3f, 0x10, 0x48, 0x10, 0x2d, 0x14, 0x35, 0x10, 0x20, 0x1f, 0x25, 0x18, 0x17, 0x30, + 0x1a, 0x26, 0x14, 0x47, 0x14, 0x3a, 0x1f, 0x6f, 0x14, 0x62, 0x3f, 0x7d, 0x2a, 0x7d, 0x50, 0x7b, + 0x48, 0x7d, 0x60, 0x75, 0x58, 0x79, 0x60, 0x87, 0x15, 0xa4, 0xaa, 0xa9, 0x6a, 0x55, 0x05, 0x6a, + 0x00, 0x45, 0x5f, 0x3a, 0x78, 0x40, 0x6e, 0x2d, 0x89, 0x34, 0x83, 0x1d, 0x93, 0x25, 0x90, 0x0a, + 0x97, 0x14, 0x97, 0x05, 0x96, 0x07, 0x97, 0x00, 0x96, 0x03, 0x96, 0x00, 0x85, 0x05, 0x86, 0x02, + 0x86, 0x0b, 0x86, 0x08, 0x86, 0x14, 0x85, 0x10, 0x86, 0x1d, 0x80, 0x19, 0x83, 0x24, 0x77, 0x21, + 0x7d, 0x2b, 0x6a, 0x28, 0x72, 0x01, 0x00, 0x16, 0x00, 0x31, 0x46, 0x36, 0x57, 0x3c, 0x46, 0x55, + 0x00, 0x6a, 0x00, 0x16, 0x94, 0x6a, 0x55, 0xaa, 0xaa, 0x1a, 0x5e, 0x8b, 0x48, 0x8b, 0x34, 0x5f, + 0x2f, 0x57, 0x31, 0x5a, 0x29, 0x51, 0x2c, 0x53, 0x23, 0x4e, 0x27, 0x4f, 0x1c, 0x4d, 0x20, 0x4d, + 0x13, 0x4d, 0x13, 0x8b, 0x00, 0x8b, 0x00, 0x00, 0x25, 0x00, 0x3a, 0x03, 0x31, 0x00, 0x48, 0x0a, + 0x43, 0x06, 0x50, 0x16, 0x4e, 0x0f, 0x53, 0x25, 0x53, 0x1d, 0x51, 0x31, 0x53, 0x2b, 0x4c, 0x3c, + 0x4f, 0x37, 0x42, 0x44, 0x48, 0x40, 0x35, 0x49, 0x3d, 0x47, 0x3f, 0x50, 0x3b, 0x4b, 0x48, 0x5e, + 0x43, 0x55, 0x5e, 0x8b, 0x16, 0xa8, 0xaa, 0x6a, 0xaa, 0xaa, 0x1a, 0x53, 0x68, 0x44, 0x6c, 0x4c, + 0x6b, 0x35, 0x6e, 0x3d, 0x6e, 0x0e, 0x60, 0x1b, 0x6e, 0x00, 0x38, 0x00, 0x52, 0x04, 0x21, 0x00, + 0x2b, 0x0f, 0x0f, 0x08, 0x17, 0x20, 0x04, 0x16, 0x08, 0x36, 0x00, 0x2a, 0x00, 0x45, 0x01, 0x3e, + 0x00, 0x53, 0x05, 0x4d, 0x02, 0x53, 0x17, 0x45, 0x12, 0x4c, 0x13, 0x36, 0x10, 0x3e, 0x10, 0x29, + 0x13, 0x2f, 0x10, 0x1e, 0x1a, 0x22, 0x15, 0x16, 0x27, 0x19, 0x1f, 0x13, 0x37, 0x13, 0x2e, 0x1d, + 0x54, 0x13, 0x4b, 0x37, 0x5e, 0x26, 0x5e, 0x45, 0x5c, 0x3e, 0x5e, 0x53, 0x57, 0x4d, 0x5b, 0x53, + 0x68, 0x17, 0x68, 0x95, 0xaa, 0x6a, 0xa5, 0xaa, 0x42, 0x2f, 0x38, 0x49, 0x42, 0x41, 0x1c, 0x53, + 0x2f, 0x52, 0x1c, 0x6e, 0x0c, 0x6e, 0x0a, 0x45, 0x17, 0x45, 0x22, 0x44, 0x1d, 0x45, 0x29, 0x40, + 0x26, 0x42, 0x2d, 0x39, 0x2b, 0x3d, 0x2e, 0x31, 0x2e, 0x36, 0x2b, 0x23, 0x2e, 0x29, 0x22, 0x19, + 0x27, 0x1d, 0x14, 0x13, 0x1c, 0x15, 0x03, 0x11, 0x0c, 0x11, 0x00, 0x11, 0x00, 0x00, 0x03, 0x00, + 0x16, 0x02, 0x0e, 0x00, 0x26, 0x08, 0x1f, 0x04, 0x32, 0x10, 0x2d, 0x0b, 0x3b, 0x1a, 0x38, 0x14, + 0x40, 0x24, 0x3f, 0x1f, 0x42, 0x2f, 0x42, 0x2a, 0x18, 0x68, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0x02, + 0x5f, 0x31, 0x5f, 0x38, 0x5f, 0x35, 0x5e, 0x3d, 0x5f, 0x3b, 0x13, 0x3d, 0x1c, 0x56, 0x13, 0x4d, + 0x37, 0x5f, 0x26, 0x5f, 0x40, 0x5f, 0x3c, 0x5f, 0x49, 0x5d, 0x45, 0x5e, 0x52, 0x5c, 0x4e, 0x5d, + 0x59, 0x5a, 0x56, 0x5b, 0x59, 0x69, 0x48, 0x6d, 0x51, 0x6c, 0x34, 0x6e, 0x3e, 0x6e, 0x1d, 0x6b, + 0x26, 0x6e, 0x0c, 0x60, 0x13, 0x67, 0x03, 0x4e, 0x06, 0x59, 0x00, 0x37, 0x00, 0x44, 0x03, 0x22, + 0x00, 0x2c, 0x0d, 0x10, 0x06, 0x18, 0x1c, 0x04, 0x13, 0x09, 0x30, 0x00, 0x25, 0x00, 0x44, 0x03, + 0x3c, 0x00, 0x53, 0x0d, 0x4d, 0x07, 0x5c, 0x1d, 0x59, 0x14, 0x5f, 0x31, 0x5f, 0x26, 0x1a, 0xa8, + 0xaa, 0xaa, 0xa6, 0xaa, 0xaa, 0x1a, 0x6a, 0x06, 0x68, 0x15, 0x6a, 0x0e, 0x62, 0x21, 0x66, 0x1c, + 0x59, 0x29, 0x5f, 0x26, 0x4c, 0x2c, 0x53, 0x2c, 0x41, 0x2a, 0x46, 0x2c, 0x38, 0x25, 0x3d, 0x28, + 0x31, 0x1e, 0x35, 0x22, 0x2b, 0x18, 0x2e, 0x1b, 0x24, 0x13, 0x27, 0x15, 0x1d, 0x11, 0x21, 0x11, + 0x14, 0x16, 0x17, 0x11, 0x11, 0x26, 0x11, 0x1b, 0x00, 0x26, 0x02, 0x17, 0x00, 0x1e, 0x07, 0x0b, + 0x04, 0x10, 0x11, 0x03, 0x0b, 0x06, 0x1e, 0x00, 0x16, 0x00, 0x29, 0x02, 0x24, 0x00, 0x31, 0x07, + 0x2d, 0x04, 0x38, 0x0e, 0x35, 0x0a, 0x3f, 0x14, 0x3c, 0x11, 0x46, 0x19, 0x42, 0x17, 0x4c, 0x1b, + 0x49, 0x1b, 0x56, 0x16, 0x53, 0x1b, 0x59, 0x06, 0x59, 0x11, 0x6a, 0x06, 0x1a, 0xa4, 0xaa, 0x5a, + 0xaa, 0xa9, 0xaa, 0x16, 0x47, 0x6c, 0x47, 0x5e, 0x35, 0x6a, 0x3e, 0x67, 0x22, 0x6e, 0x2c, 0x6e, + 0x13, 0x6c, 0x19, 0x6e, 0x08, 0x66, 0x0c, 0x6a, 0x02, 0x5c, 0x04, 0x61, 0x00, 0x50, 0x00, 0x56, + 0x0c, 0x37, 0x00, 0x40, 0x2f, 0x2e, 0x18, 0x2e, 0x45, 0x2e, 0x45, 0x24, 0x3f, 0x15, 0x45, 0x1b, + 0x2d, 0x0f, 0x39, 0x0f, 0x1b, 0x11, 0x24, 0x0f, 0x09, 0x17, 0x12, 0x13, 0x09, 0x06, 0x11, 0x04, + 0x0c, 0x05, 0x1a, 0x02, 0x15, 0x03, 0x24, 0x00, 0x1f, 0x01, 0x2e, 0x00, 0x29, 0x00, 0x40, 0x02, + 0x38, 0x00, 0x4d, 0x08, 0x48, 0x04, 0x55, 0x13, 0x52, 0x0d, 0x58, 0x23, 0x58, 0x1a, 0x58, 0x6c, + 0x47, 0x6c, 0x1a, 0xa8, 0x56, 0xaa, 0xa9, 0xaa, 0xaa, 0x2a, 0x60, 0x40, 0x5b, 0x63, 0x60, 0x54, + 0x4c, 0x7b, 0x56, 0x72, 0x35, 0x89, 0x43, 0x84, 0x14, 0x8d, 0x27, 0x8d, 0x09, 0x8d, 0x09, 0x7d, + 0x15, 0x7d, 0x2d, 0x7a, 0x23, 0x7d, 0x3e, 0x72, 0x37, 0x78, 0x48, 0x65, 0x44, 0x6d, 0x4c, 0x54, + 0x4b, 0x5e, 0x4d, 0x4f, 0x3d, 0x56, 0x46, 0x53, 0x2a, 0x58, 0x35, 0x58, 0x18, 0x55, 0x20, 0x58, + 0x0b, 0x4c, 0x10, 0x52, 0x03, 0x3f, 0x05, 0x47, 0x00, 0x2f, 0x00, 0x38, 0x04, 0x1d, 0x00, 0x25, + 0x0d, 0x0e, 0x07, 0x14, 0x1c, 0x04, 0x14, 0x08, 0x30, 0x00, 0x25, 0x00, 0x43, 0x04, 0x3a, 0x00, + 0x52, 0x0f, 0x4c, 0x07, 0x5c, 0x23, 0x59, 0x16, 0x60, 0x40, 0x60, 0x2f, 0x1a, 0xa8, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x2a, 0x5f, 0x6a, 0x5b, 0x7a, 0x5f, 0x73, 0x51, 0x86, 0x57, 0x81, 0x42, 0x8d, + 0x4a, 0x8a, 0x2e, 0x8f, 0x39, 0x8f, 0x1a, 0x8d, 0x23, 0x8f, 0x0c, 0x86, 0x12, 0x8a, 0x03, 0x7b, + 0x06, 0x81, 0x00, 0x6d, 0x00, 0x74, 0x07, 0x57, 0x00, 0x60, 0x1d, 0x46, 0x0e, 0x4e, 0x09, 0x37, + 0x10, 0x3f, 0x03, 0x23, 0x03, 0x2e, 0x06, 0x16, 0x03, 0x1d, 0x0e, 0x0b, 0x09, 0x10, 0x1c, 0x03, + 0x14, 0x06, 0x30, 0x00, 0x24, 0x00, 0x43, 0x03, 0x3b, 0x00, 0x50, 0x09, 0x4b, 0x05, 0x59, 0x14, + 0x56, 0x0e, 0x5b, 0x21, 0x5b, 0x1a, 0x55, 0x36, 0x5b, 0x2d, 0x42, 0x45, 0x4e, 0x3e, 0x4d, 0x4b, + 0x48, 0x48, 0x56, 0x54, 0x52, 0x4f, 0x5c, 0x5e, 0x5a, 0x58, 0x5f, 0x6a, 0x5f, 0x64, 0x1b, 0xa8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xa6, 0xaa, 0x2c, 0x8f, 0x18, 0x88, 0x21, 0x8d, 0x0b, 0x79, 0x10, 0x82, + 0x03, 0x64, 0x05, 0x70, 0x00, 0x4a, 0x00, 0x58, 0x04, 0x29, 0x00, 0x37, 0x10, 0x12, 0x09, 0x1b, + 0x22, 0x05, 0x18, 0x09, 0x37, 0x00, 0x2c, 0x00, 0x4e, 0x05, 0x44, 0x00, 0x5f, 0x13, 0x58, 0x0a, + 0x69, 0x29, 0x65, 0x1c, 0x6c, 0x46, 0x6c, 0x36, 0x68, 0x64, 0x6c, 0x57, 0x5e, 0x7a, 0x65, 0x71, + 0x50, 0x88, 0x58, 0x83, 0x3d, 0x8f, 0x47, 0x8d, 0x45, 0x9e, 0x3f, 0x98, 0x55, 0xa3, 0x4b, 0xa3, + 0x5f, 0xa2, 0x5a, 0xa3, 0x69, 0x9c, 0x64, 0xa0, 0x72, 0xa9, 0x63, 0xb1, 0x6b, 0xaf, 0x54, 0xb4, + 0x5c, 0xb4, 0x44, 0xb1, 0x4b, 0xb4, 0x38, 0xaa, 0x3d, 0xaf, 0x2f, 0x9f, 0x33, 0xa6, 0x2c, 0x8f, + 0x2c, 0x98, 0x1b, 0x54, 0xaa, 0xaa, 0x9a, 0xaa, 0xaa, 0x56, 0x5c, 0x8d, 0x00, 0x8d, 0x00, 0x7d, + 0x24, 0x59, 0x32, 0x4a, 0x2d, 0x50, 0x3b, 0x3e, 0x38, 0x44, 0x3f, 0x34, 0x3e, 0x39, 0x40, 0x2a, + 0x40, 0x30, 0x3f, 0x21, 0x40, 0x25, 0x3a, 0x18, 0x3d, 0x1c, 0x33, 0x13, 0x38, 0x15, 0x28, 0x11, + 0x2e, 0x11, 0x18, 0x15, 0x1f, 0x11, 0x0b, 0x1f, 0x11, 0x19, 0x01, 0x13, 0x13, 0x05, 0x08, 0x0a, + 0x2b, 0x00, 0x1d, 0x00, 0x3b, 0x03, 0x34, 0x00, 0x49, 0x0b, 0x43, 0x06, 0x51, 0x18, 0x4e, 0x10, + 0x54, 0x29, 0x54, 0x20, 0x52, 0x38, 0x54, 0x31, 0x4c, 0x45, 0x50, 0x3f, 0x41, 0x53, 0x47, 0x4c, + 0x31, 0x63, 0x3a, 0x5b, 0x18, 0x7c, 0x5c, 0x7c, 0x5c, 0x8d, 0x1c, 0xa8, 0xaa, 0xaa, 0x6a, 0xa5, + 0x9a, 0xaa, 0x02, 0x60, 0x5f, 0x5c, 0x71, 0x60, 0x69, 0x53, 0x80, 0x59, 0x7a, 0x43, 0x8a, 0x4c, + 0x86, 0x2f, 0x8d, 0x3a, 0x8d, 0x1b, 0x8a, 0x24, 0x8d, 0x0c, 0x7e, 0x12, 0x86, 0x03, 0x6b, 0x06, + 0x77, 0x00, 0x50, 0x00, 0x60, 0x01, 0x3b, 0x00, 0x45, 0x06, 0x28, 0x03, 0x31, 0x0e, 0x18, 0x09, + 0x1f, 0x1c, 0x0c, 0x14, 0x11, 0x2e, 0x03, 0x24, 0x06, 0x47, 0x00, 0x39, 0x00, 0x55, 0x00, 0x55, + 0x11, 0x46, 0x11, 0x30, 0x14, 0x3a, 0x11, 0x21, 0x1c, 0x27, 0x16, 0x18, 0x29, 0x1b, 0x21, 0x14, + 0x3a, 0x14, 0x31, 0x13, 0x3e, 0x23, 0x38, 0x1a, 0x3b, 0x36, 0x36, 0x2b, 0x36, 0x48, 0x39, 0x40, + 0x36, 0x55, 0x41, 0x50, 0x3c, 0x5d, 0x4f, 0x5a, 0x47, 0x60, 0x5f, 0x60, 0x56, 0x1c, 0xa8, 0xaa, + 0xa6, 0xaa, 0x5a, 0x55, 0xa9, 0x02, 0x55, 0x5f, 0x50, 0x72, 0x55, 0x69, 0x44, 0x80, 0x4c, 0x7a, + 0x32, 0x8a, 0x3c, 0x86, 0x1b, 0x8d, 0x27, 0x8d, 0x14, 0x8d, 0x18, 0x8d, 0x0d, 0x8d, 0x10, 0x8d, + 0x06, 0x8c, 0x09, 0x8c, 0x00, 0x8b, 0x03, 0x8c, 0x00, 0x7b, 0x0d, 0x7d, 0x06, 0x7c, 0x1c, 0x7d, + 0x15, 0x7d, 0x2b, 0x7b, 0x25, 0x7d, 0x37, 0x75, 0x32, 0x79, 0x3e, 0x6c, 0x3c, 0x72, 0x41, 0x60, + 0x41, 0x67, 0x38, 0x4d, 0x41, 0x53, 0x1d, 0x47, 0x2e, 0x47, 0x02, 0x47, 0x02, 0x00, 0x4d, 0x00, + 0x4d, 0x11, 0x14, 0x11, 0x14, 0x38, 0x20, 0x38, 0x33, 0x39, 0x2a, 0x38, 0x44, 0x40, 0x3d, 0x3b, + 0x50, 0x4c, 0x4c, 0x44, 0x55, 0x5f, 0x55, 0x53, 0x1c, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x01, 0x69, 0x64, 0x51, 0x64, 0x4d, 0x8b, 0x3e, 0x8b, 0x42, 0x64, 0x26, 0x64, 0x22, 0x8b, 0x13, + 0x8b, 0x17, 0x64, 0x00, 0x64, 0x00, 0x57, 0x18, 0x57, 0x1c, 0x31, 0x05, 0x31, 0x05, 0x23, 0x1d, + 0x23, 0x21, 0x00, 0x30, 0x00, 0x2d, 0x23, 0x48, 0x23, 0x4c, 0x00, 0x5b, 0x00, 0x58, 0x23, 0x6f, + 0x23, 0x6f, 0x31, 0x56, 0x31, 0x53, 0x57, 0x69, 0x57, 0x69, 0x64, 0x1f, 0xa4, 0xa9, 0x56, 0xaa, + 0xa9, 0x56, 0xa6, 0x59, 0x00, 0x00, 0x08, 0x00, 0x26, 0x0a, 0x1c, 0x00, 0x30, 0x27, 0x30, 0x14, + 0x30, 0x40, 0x32, 0x49, 0x30, 0x45, 0x36, 0x50, 0x33, 0x4d, 0x3d, 0x54, 0x39, 0x53, 0x4a, 0x56, + 0x42, 0x56, 0x4e, 0x56, 0x4e, 0x65, 0x4a, 0x65, 0x3d, 0x66, 0x42, 0x65, 0x35, 0x6a, 0x38, 0x67, + 0x31, 0x70, 0x33, 0x6c, 0x30, 0x7a, 0x30, 0x74, 0x30, 0x9f, 0x2e, 0xaf, 0x30, 0xa8, 0x27, 0xbb, + 0x2c, 0xb6, 0x1b, 0xc3, 0x23, 0xc1, 0x08, 0xc6, 0x13, 0xc6, 0x00, 0xc6, 0x00, 0xb7, 0x06, 0xb7, + 0x1f, 0x9f, 0x1f, 0xb7, 0x1f, 0x7a, 0x35, 0x5d, 0x1f, 0x60, 0x1f, 0x40, 0x1f, 0x5b, 0x1f, 0x28, + 0x06, 0x0f, 0x1f, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0xa4, 0xa9, 0x56, 0xaa, 0xa9, 0x56, 0xa6, + 0x59, 0x4e, 0xc6, 0x46, 0xc6, 0x28, 0xbc, 0x32, 0xc6, 0x1e, 0x9f, 0x1e, 0xb3, 0x1e, 0x7b, 0x1d, + 0x71, 0x1e, 0x75, 0x18, 0x6a, 0x1b, 0x6d, 0x11, 0x66, 0x16, 0x68, 0x05, 0x65, 0x0c, 0x65, 0x00, + 0x65, 0x00, 0x56, 0x05, 0x56, 0x11, 0x54, 0x0c, 0x56, 0x19, 0x51, 0x16, 0x53, 0x1d, 0x4a, 0x1c, + 0x4e, 0x1e, 0x40, 0x1e, 0x46, 0x1e, 0x27, 0x20, 0x17, 0x1e, 0x1e, 0x27, 0x0b, 0x22, 0x10, 0x33, + 0x03, 0x2c, 0x06, 0x46, 0x00, 0x3b, 0x00, 0x4e, 0x00, 0x4e, 0x0f, 0x48, 0x0f, 0x2f, 0x27, 0x2f, + 0x0f, 0x2f, 0x40, 0x19, 0x5d, 0x2f, 0x5a, 0x2f, 0x7a, 0x2f, 0x5f, 0x2f, 0x9f, 0x48, 0xb7, 0x2f, + 0xb7, 0x4e, 0xb7, 0x4e, 0xc6, 0x21, 0x68, 0xa5, 0xaa, 0xaa, 0xa9, 0xaa, 0xaa, 0x6a, 0x06, 0x67, + 0x4b, 0x64, 0x64, 0x67, 0x59, 0x5c, 0x79, 0x61, 0x70, 0x72, 0x93, 0x59, 0x93, 0x50, 0x88, 0x3f, + 0x92, 0x48, 0x8e, 0x2b, 0x95, 0x36, 0x95, 0x18, 0x92, 0x20, 0x95, 0x0b, 0x8a, 0x10, 0x8f, 0x03, + 0x7e, 0x06, 0x85, 0x00, 0x6e, 0x00, 0x77, 0x02, 0x60, 0x00, 0x66, 0x08, 0x54, 0x04, 0x59, 0x10, + 0x4c, 0x0b, 0x4f, 0x1a, 0x45, 0x15, 0x48, 0x18, 0x41, 0x0f, 0x32, 0x12, 0x3a, 0x0c, 0x24, 0x0c, + 0x2b, 0x0e, 0x15, 0x0c, 0x1c, 0x16, 0x0a, 0x11, 0x0f, 0x21, 0x03, 0x1a, 0x06, 0x31, 0x00, 0x28, + 0x00, 0x40, 0x03, 0x3a, 0x00, 0x4b, 0x09, 0x47, 0x05, 0x52, 0x13, 0x50, 0x0e, 0x54, 0x1f, 0x54, + 0x19, 0x51, 0x2d, 0x54, 0x27, 0x4a, 0x38, 0x4e, 0x33, 0x40, 0x40, 0x46, 0x3c, 0x34, 0x47, 0x3a, + 0x44, 0x50, 0x69, 0x54, 0x4b, 0x54, 0x5d, 0x67, 0x4b, 0x22, 0xa8, 0xaa, 0xaa, 0x6a, 0x55, 0xaa, + 0xaa, 0xaa, 0x1a, 0x64, 0x1a, 0x54, 0x14, 0x5c, 0x16, 0x42, 0x11, 0x4c, 0x11, 0x2e, 0x15, 0x37, + 0x11, 0x20, 0x21, 0x26, 0x19, 0x17, 0x32, 0x1a, 0x28, 0x14, 0x48, 0x14, 0x3c, 0x16, 0x5f, 0x14, + 0x55, 0x1e, 0x70, 0x19, 0x69, 0x2c, 0x7b, 0x24, 0x77, 0x40, 0x7f, 0x35, 0x7f, 0x45, 0x7e, 0x42, + 0x7f, 0x49, 0x7e, 0x47, 0x7e, 0x4e, 0x7d, 0x4c, 0x7d, 0x52, 0x7c, 0x50, 0x7c, 0x52, 0x4f, 0x35, + 0x4f, 0x35, 0x40, 0x65, 0x40, 0x65, 0x87, 0x5b, 0x8a, 0x60, 0x89, 0x51, 0x8d, 0x57, 0x8c, 0x47, + 0x8f, 0x4c, 0x8e, 0x3e, 0x8f, 0x42, 0x8f, 0x24, 0x8b, 0x30, 0x8f, 0x11, 0x7e, 0x19, 0x86, 0x04, + 0x68, 0x09, 0x75, 0x00, 0x49, 0x00, 0x5b, 0x05, 0x2b, 0x00, 0x38, 0x12, 0x14, 0x0a, 0x1d, 0x27, + 0x05, 0x1b, 0x0a, 0x42, 0x00, 0x33, 0x00, 0x54, 0x02, 0x4b, 0x00, 0x64, 0x07, 0x5c, 0x04, 0x64, + 0x1a, 0x22, 0x94, 0xa6, 0xa9, 0xaa, 0x56, 0x9a, 0xa6, 0xaa, 0x1a, 0x33, 0x00, 0x43, 0x00, 0x40, + 0x15, 0x4b, 0x17, 0x45, 0x16, 0x55, 0x19, 0x50, 0x17, 0x55, 0x29, 0x49, 0x26, 0x4f, 0x27, 0x3e, + 0x25, 0x44, 0x25, 0x38, 0x52, 0x46, 0x58, 0x3f, 0x55, 0x52, 0x60, 0x4d, 0x5c, 0x5b, 0x6a, 0x58, + 0x64, 0x5f, 0x79, 0x5f, 0x70, 0x5b, 0x89, 0x5f, 0x82, 0x51, 0x94, 0x58, 0x90, 0x42, 0x9c, 0x4b, + 0x99, 0x2e, 0x9f, 0x38, 0x9f, 0x2a, 0xb8, 0x1a, 0xb8, 0x1e, 0x9f, 0x0e, 0x9d, 0x15, 0x9f, 0x00, + 0x9b, 0x06, 0x9c, 0x00, 0x89, 0x0f, 0x8d, 0x07, 0x8b, 0x20, 0x8f, 0x17, 0x8e, 0x26, 0x5f, 0x19, + 0x59, 0x20, 0x5c, 0x0d, 0x52, 0x12, 0x56, 0x04, 0x48, 0x08, 0x4d, 0x01, 0x3a, 0x01, 0x42, 0x04, + 0x2d, 0x01, 0x33, 0x0c, 0x21, 0x07, 0x26, 0x1b, 0x19, 0x12, 0x1c, 0x30, 0x15, 0x24, 0x15, 0x33, + 0x00, 0x26, 0xa4, 0xaa, 0x5a, 0xa9, 0xaa, 0x56, 0xa5, 0xaa, 0xaa, 0x16, 0x54, 0x6c, 0x54, 0x20, + 0x53, 0x18, 0x54, 0x1b, 0x52, 0x13, 0x53, 0x14, 0x50, 0x10, 0x51, 0x11, 0x4d, 0x0f, 0x4f, 0x0f, + 0x49, 0x10, 0x4b, 0x0f, 0x45, 0x15, 0x47, 0x12, 0x41, 0x1c, 0x43, 0x17, 0x3b, 0x28, 0x3e, 0x21, + 0x3b, 0x6c, 0x2a, 0x6c, 0x2a, 0x22, 0x29, 0x18, 0x2a, 0x1c, 0x28, 0x13, 0x29, 0x15, 0x26, 0x10, + 0x27, 0x11, 0x23, 0x0f, 0x25, 0x0f, 0x1f, 0x10, 0x21, 0x0f, 0x1c, 0x14, 0x1e, 0x11, 0x17, 0x1c, + 0x1a, 0x17, 0x11, 0x28, 0x15, 0x20, 0x11, 0x6c, 0x00, 0x6c, 0x00, 0x02, 0x0e, 0x02, 0x0f, 0x16, + 0x14, 0x0c, 0x12, 0x10, 0x1a, 0x05, 0x17, 0x07, 0x20, 0x01, 0x1c, 0x02, 0x27, 0x00, 0x23, 0x00, + 0x34, 0x05, 0x2f, 0x00, 0x38, 0x17, 0x38, 0x0b, 0x3d, 0x0d, 0x3b, 0x11, 0x42, 0x06, 0x40, 0x09, + 0x49, 0x01, 0x45, 0x03, 0x50, 0x00, 0x4c, 0x00, 0x65, 0x1f, 0x65, 0x00, 0x65, 0x6c, 0x54, 0x6c, + 0x2a, 0xa8, 0xaa, 0xa6, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xaa, 0xaa, 0x2a, 0x52, 0x4f, 0x50, 0x59, + 0x52, 0x55, 0x4b, 0x61, 0x4e, 0x5e, 0x43, 0x67, 0x48, 0x65, 0x3a, 0x6b, 0x3f, 0x6a, 0x30, 0x6e, + 0x35, 0x6d, 0x26, 0x6e, 0x2b, 0x6e, 0x12, 0x6d, 0x1b, 0x6e, 0x00, 0x6a, 0x09, 0x6c, 0x00, 0x59, + 0x13, 0x5d, 0x09, 0x5c, 0x25, 0x5f, 0x1c, 0x5f, 0x39, 0x5b, 0x32, 0x5f, 0x3f, 0x51, 0x3f, 0x57, + 0x3e, 0x4c, 0x3f, 0x4e, 0x3a, 0x47, 0x3d, 0x49, 0x32, 0x43, 0x38, 0x45, 0x23, 0x3e, 0x2d, 0x41, + 0x15, 0x39, 0x1c, 0x3c, 0x0b, 0x33, 0x0f, 0x36, 0x04, 0x2a, 0x06, 0x2f, 0x01, 0x1e, 0x01, 0x25, + 0x03, 0x14, 0x01, 0x1a, 0x0b, 0x0a, 0x06, 0x0f, 0x18, 0x03, 0x10, 0x06, 0x2d, 0x00, 0x21, 0x00, + 0x3b, 0x00, 0x34, 0x00, 0x4b, 0x03, 0x43, 0x01, 0x4b, 0x13, 0x3b, 0x10, 0x42, 0x11, 0x2d, 0x0f, + 0x33, 0x0f, 0x21, 0x10, 0x26, 0x0f, 0x1a, 0x13, 0x1d, 0x11, 0x16, 0x18, 0x17, 0x15, 0x14, 0x1d, + 0x14, 0x1a, 0x15, 0x22, 0x14, 0x20, 0x1a, 0x27, 0x17, 0x24, 0x22, 0x2b, 0x1d, 0x29, 0x30, 0x30, + 0x27, 0x2d, 0x40, 0x35, 0x3a, 0x32, 0x4b, 0x3c, 0x47, 0x38, 0x50, 0x45, 0x4f, 0x40, 0x52, 0x4f, + 0x52, 0x49, 0x2b, 0xa8, 0x6a, 0xaa, 0xaa, 0x5a, 0xa9, 0xaa, 0xa6, 0xaa, 0xaa, 0xaa, 0x57, 0x63, + 0x53, 0x74, 0x57, 0x6c, 0x48, 0x82, 0x50, 0x7c, 0x35, 0x8c, 0x41, 0x88, 0x1b, 0x8f, 0x2a, 0x8f, + 0x0c, 0x8f, 0x13, 0x8f, 0x00, 0x8d, 0x06, 0x8e, 0x00, 0x7d, 0x0e, 0x7f, 0x07, 0x7e, 0x1d, 0x7f, + 0x15, 0x7f, 0x2f, 0x7d, 0x27, 0x7f, 0x3b, 0x78, 0x36, 0x7b, 0x42, 0x6f, 0x3f, 0x74, 0x44, 0x64, + 0x44, 0x6a, 0x41, 0x5a, 0x44, 0x5e, 0x3a, 0x53, 0x3f, 0x56, 0x2f, 0x4f, 0x35, 0x50, 0x21, 0x4d, + 0x29, 0x4d, 0x11, 0x4d, 0x11, 0x3e, 0x21, 0x3e, 0x2c, 0x3d, 0x27, 0x3e, 0x35, 0x38, 0x32, 0x3b, + 0x3b, 0x30, 0x39, 0x35, 0x3d, 0x26, 0x3d, 0x2c, 0x36, 0x16, 0x3d, 0x1b, 0x22, 0x11, 0x2f, 0x11, + 0x14, 0x12, 0x1b, 0x11, 0x04, 0x16, 0x0c, 0x13, 0x04, 0x06, 0x0b, 0x04, 0x07, 0x05, 0x14, 0x02, + 0x10, 0x03, 0x1c, 0x01, 0x18, 0x01, 0x24, 0x00, 0x20, 0x00, 0x37, 0x03, 0x2f, 0x00, 0x45, 0x0a, + 0x3f, 0x05, 0x4e, 0x15, 0x4b, 0x0e, 0x50, 0x23, 0x50, 0x1b, 0x4a, 0x37, 0x50, 0x2f, 0x3a, 0x44, + 0x44, 0x3f, 0x44, 0x47, 0x3f, 0x45, 0x4e, 0x4e, 0x49, 0x4a, 0x54, 0x57, 0x52, 0x52, 0x57, 0x63, + 0x57, 0x5d, 0x2c, 0xa8, 0xaa, 0xa6, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xaa, 0xaa, 0x02, 0x5e, + 0x68, 0x5a, 0x79, 0x5e, 0x72, 0x4f, 0x85, 0x56, 0x80, 0x3d, 0x8d, 0x48, 0x8a, 0x27, 0x8f, 0x33, + 0x8f, 0x1c, 0x8f, 0x22, 0x8f, 0x12, 0x8e, 0x17, 0x8e, 0x08, 0x8c, 0x0d, 0x8d, 0x00, 0x8a, 0x04, + 0x8b, 0x00, 0x78, 0x12, 0x7d, 0x08, 0x7b, 0x29, 0x7f, 0x1c, 0x7f, 0x38, 0x7d, 0x32, 0x7f, 0x43, + 0x79, 0x3f, 0x7c, 0x49, 0x72, 0x47, 0x76, 0x4a, 0x69, 0x4a, 0x6e, 0x47, 0x5f, 0x4a, 0x63, 0x3f, + 0x58, 0x44, 0x5b, 0x33, 0x52, 0x3a, 0x55, 0x26, 0x4d, 0x2d, 0x50, 0x19, 0x47, 0x1f, 0x4a, 0x0d, + 0x3f, 0x12, 0x44, 0x05, 0x35, 0x08, 0x3b, 0x02, 0x27, 0x02, 0x2f, 0x05, 0x19, 0x02, 0x20, 0x0e, + 0x0c, 0x08, 0x12, 0x1e, 0x04, 0x14, 0x07, 0x35, 0x00, 0x28, 0x00, 0x3d, 0x01, 0x39, 0x00, 0x45, + 0x02, 0x41, 0x01, 0x4e, 0x03, 0x4a, 0x02, 0x55, 0x05, 0x52, 0x04, 0x55, 0x16, 0x45, 0x12, 0x4d, + 0x13, 0x35, 0x11, 0x3d, 0x11, 0x1d, 0x16, 0x25, 0x11, 0x15, 0x25, 0x15, 0x1c, 0x19, 0x2f, 0x15, + 0x2a, 0x21, 0x36, 0x1c, 0x33, 0x2c, 0x3c, 0x26, 0x39, 0x3a, 0x41, 0x33, 0x3e, 0x47, 0x47, 0x41, + 0x44, 0x53, 0x4f, 0x4e, 0x4a, 0x5b, 0x59, 0x58, 0x53, 0x5e, 0x68, 0x5e, 0x5f, 0x2e, 0xa8, 0xaa, + 0xaa, 0xa6, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x15, 0x54, 0x11, 0x58, 0x19, 0x57, 0x14, + 0x5a, 0x24, 0x5a, 0x1e, 0x57, 0x33, 0x5a, 0x2c, 0x4f, 0x3f, 0x54, 0x3a, 0x41, 0x47, 0x49, 0x44, + 0x30, 0x49, 0x3a, 0x49, 0x24, 0x48, 0x2a, 0x49, 0x1b, 0x44, 0x1e, 0x46, 0x17, 0x4a, 0x19, 0x47, + 0x16, 0x50, 0x16, 0x4d, 0x1a, 0x57, 0x16, 0x54, 0x24, 0x59, 0x1e, 0x59, 0x40, 0x5a, 0x4f, 0x5d, + 0x48, 0x5b, 0x5a, 0x62, 0x55, 0x5e, 0x62, 0x6a, 0x5f, 0x65, 0x65, 0x76, 0x65, 0x6f, 0x62, 0x83, + 0x65, 0x7d, 0x58, 0x8e, 0x5e, 0x8a, 0x48, 0x96, 0x52, 0x93, 0x30, 0x99, 0x3e, 0x99, 0x1a, 0x97, + 0x23, 0x99, 0x0b, 0x91, 0x11, 0x95, 0x03, 0x88, 0x05, 0x8e, 0x00, 0x7d, 0x00, 0x83, 0x04, 0x70, + 0x00, 0x76, 0x0f, 0x64, 0x07, 0x6a, 0x0a, 0x61, 0x0c, 0x63, 0x07, 0x5d, 0x08, 0x5f, 0x05, 0x58, + 0x05, 0x5b, 0x04, 0x53, 0x04, 0x56, 0x07, 0x47, 0x04, 0x4c, 0x0f, 0x3c, 0x0b, 0x41, 0x0b, 0x37, + 0x0d, 0x39, 0x09, 0x32, 0x0a, 0x35, 0x07, 0x2c, 0x08, 0x2f, 0x07, 0x25, 0x07, 0x29, 0x0a, 0x16, + 0x07, 0x1d, 0x12, 0x0a, 0x0d, 0x0f, 0x1f, 0x02, 0x18, 0x05, 0x30, 0x00, 0x27, 0x00, 0x38, 0x00, + 0x34, 0x00, 0x3e, 0x02, 0x3c, 0x01, 0x65, 0x02, 0x65, 0x11, 0x54, 0x11, 0x39, 0xa8, 0xaa, 0xaa, + 0xaa, 0xaa, 0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x05, 0x52, 0x6c, 0x51, 0x77, + 0x51, 0x73, 0x51, 0x7e, 0x51, 0x7c, 0x54, 0x82, 0x52, 0x81, 0x57, 0x83, 0x55, 0x83, 0x5d, 0x80, + 0x5a, 0x83, 0x62, 0x76, 0x60, 0x7d, 0x65, 0x65, 0x64, 0x6f, 0x66, 0x4e, 0x66, 0x5b, 0x64, 0x32, + 0x66, 0x3e, 0x5e, 0x1e, 0x62, 0x26, 0x53, 0x11, 0x5a, 0x16, 0x43, 0x0d, 0x4d, 0x0d, 0x35, 0x11, + 0x3c, 0x0d, 0x29, 0x1b, 0x2f, 0x14, 0x1e, 0x2b, 0x23, 0x21, 0x16, 0x3f, 0x1a, 0x34, 0x11, 0x58, + 0x13, 0x4b, 0x0f, 0x73, 0x0f, 0x65, 0x19, 0xa6, 0x0f, 0x95, 0x36, 0xb7, 0x24, 0xb7, 0x48, 0xb4, + 0x40, 0xb7, 0x59, 0xae, 0x50, 0xb2, 0x59, 0xbc, 0x48, 0xc2, 0x50, 0xc0, 0x35, 0xc4, 0x3f, 0xc4, + 0x0d, 0xaf, 0x1a, 0xc4, 0x00, 0x73, 0x00, 0x9b, 0x02, 0x54, 0x00, 0x63, 0x09, 0x39, 0x04, 0x45, + 0x13, 0x21, 0x0d, 0x2c, 0x20, 0x0f, 0x19, 0x17, 0x31, 0x04, 0x28, 0x08, 0x44, 0x00, 0x3a, 0x00, + 0x5a, 0x05, 0x51, 0x00, 0x69, 0x14, 0x63, 0x0a, 0x72, 0x2c, 0x6f, 0x1e, 0x75, 0x4c, 0x75, 0x3a, + 0x73, 0x6b, 0x75, 0x5e, 0x6c, 0x81, 0x71, 0x78, 0x62, 0x8d, 0x68, 0x89, 0x55, 0x91, 0x5c, 0x91, + 0x49, 0x8c, 0x4d, 0x91, 0x45, 0x81, 0x45, 0x88, 0x3c, 0x8d, 0x41, 0x89, 0x31, 0x91, 0x37, 0x91, + 0x22, 0x89, 0x27, 0x91, 0x1d, 0x72, 0x1d, 0x82, 0x1d, 0x65, 0x1d, 0x6c, 0x20, 0x58, 0x1e, 0x5e, + 0x24, 0x4b, 0x21, 0x51, 0x2b, 0x40, 0x27, 0x44, 0x34, 0x38, 0x2f, 0x3b, 0x40, 0x35, 0x39, 0x35, + 0x48, 0x36, 0x44, 0x35, 0x4d, 0x38, 0x4b, 0x37, 0x5a, 0x35, 0x52, 0x6c, 0x9f, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x02, 0x1d, 0xd2, 0x4b, 0x00, 0x03, 0x39, 0x9d, 0x01, 0x00, 0x00, 0xb5, + 0x6f, 0x0e, 0x00, 0x00, 0x02, 0x42, 0x6c, 0x5d, 0x00, 0x00, 0x39, 0x5e, 0x00, 0x00, 0x29, 0x39, + 0x5e, 0x00, 0x00, 0x00, 0x02, 0x70, 0xd0, 0x74, 0x00, 0x00, 0x44, 0xe8, 0x17, 0x00, 0x28, 0x75, + 0x69, 0x01, 0x00, 0x00, 0x03, 0x60, 0xe9, 0x6d, 0x00, 0x00, 0x30, 0x11, 0x1a, 0x00, 0x15, 0x55, + 0xaa, 0x01, 0x00, 0x30, 0x95, 0x22, 0x02, 0x00, 0x00, 0x05, 0x74, 0xd2, 0x76, 0x00, 0x02, 0x38, + 0x47, 0x0c, 0x00, 0x00, 0x39, 0x4f, 0x01, 0x00, 0x11, 0x45, 0xff, 0x06, 0x00, 0x39, 0x91, 0x8f, + 0x0c, 0x00, 0x48, 0x9f, 0x38, 0x06, 0x00, 0x00, 0x03, 0x73, 0xd2, 0x72, 0x00, 0x00, 0x3c, 0x05, + 0x19, 0x00, 0x1f, 0x4c, 0x36, 0x08, 0x00, 0x13, 0x8c, 0x44, 0x04, 0x00, 0x00, 0x01, 0x19, 0x6c, + 0x49, 0x00, 0x00, 0x39, 0x5e, 0x00, 0x00, 0x00, 0x01, 0x3d, 0xfd, 0x58, 0x00, 0x00, 0x31, 0x9a, + 0x04, 0x00, 0x00, 0x01, 0x3d, 0xfd, 0x5d, 0x00, 0x00, 0x31, 0x70, 0x04, 0x00, 0x00, 0x01, 0x56, + 0x94, 0x67, 0x00, 0x00, 0x39, 0xcb, 0x0f, 0x00, 0x00, 0x01, 0x67, 0xca, 0x6f, 0x00, 0x00, 0x62, + 0x74, 0x07, 0x00, 0x00, 0x01, 0x34, 0xf5, 0x5f, 0x00, 0x00, 0xad, 0xc6, 0x00, 0x00, 0x00, 0x01, + 0x41, 0x9f, 0x5c, 0x00, 0x00, 0x8d, 0x90, 0x01, 0x00, 0x00, 0x01, 0x24, 0xd2, 0x4f, 0x00, 0x00, + 0xae, 0x27, 0x0e, 0x00, 0x00, 0x01, 0x5c, 0xe7, 0x6c, 0x00, 0x00, 0x39, 0x83, 0x01, 0x00, 0x00, + 0x03, 0x66, 0xd2, 0x6f, 0x00, 0x00, 0x42, 0x97, 0x0d, 0x00, 0x13, 0x52, 0x3c, 0x05, 0x00, 0x17, + 0x7c, 0x6c, 0x05, 0x00, 0x00, 0x01, 0x5d, 0xd0, 0x6a, 0x00, 0x00, 0x44, 0x9c, 0x05, 0x00, 0x00, + 0x01, 0x5d, 0xd0, 0x69, 0x00, 0x00, 0x42, 0xa2, 0x16, 0x00, 0x00, 0x01, 0x58, 0xd2, 0x67, 0x00, + 0x00, 0x42, 0xd2, 0x1b, 0x00, 0x00, 0x02, 0x6f, 0xd0, 0x74, 0x00, 0x00, 0x44, 0xb8, 0x05, 0x00, + 0x13, 0x56, 0x21, 0x01, 0x00, 0x00, 0x01, 0x56, 0xd2, 0x65, 0x00, 0x00, 0x44, 0x7d, 0x17, 0x00, + 0x00, 0x02, 0x61, 0xd2, 0x6b, 0x00, 0x00, 0x44, 0x0a, 0x17, 0x00, 0x13, 0x89, 0x4d, 0x09, 0x00, + 0x00, 0x01, 0x5f, 0xd0, 0x6c, 0x00, 0x00, 0x44, 0x41, 0x02, 0x00, 0x00, 0x03, 0x60, 0xd2, 0x6c, + 0x00, 0x00, 0x42, 0xbc, 0x15, 0x00, 0x16, 0x52, 0xc8, 0x03, 0x00, 0x14, 0x90, 0xd7, 0x0c, 0x00, + 0x00, 0x02, 0x61, 0xd0, 0x6e, 0x00, 0x00, 0x42, 0x52, 0x15, 0x00, 0x13, 0x52, 0x77, 0x0b, 0x00, + 0x00, 0x02, 0x22, 0xd2, 0x4d, 0x00, 0x00, 0x63, 0x7e, 0x00, 0x00, 0x00, 0xb1, 0xdf, 0x0d, 0x00, + 0x00, 0x02, 0x34, 0xf5, 0x5e, 0x00, 0x11, 0x63, 0x7e, 0x00, 0x00, 0x00, 0xad, 0xc6, 0x00, 0x00, + 0x00, 0x01, 0x54, 0xd2, 0x6a, 0x00, 0x00, 0x5a, 0xe3, 0x01, 0x00, 0x00, 0x02, 0x5c, 0xb1, 0x6a, + 0x00, 0x00, 0x7b, 0x71, 0x00, 0x00, 0x00, 0xa0, 0x71, 0x00, 0x00, 0x00, 0x01, 0x54, 0xd2, 0x62, + 0x00, 0x00, 0x5a, 0xc1, 0x01, 0x00, 0x00, 0x02, 0x43, 0xd2, 0x58, 0x00, 0x00, 0x39, 0xc1, 0x13, + 0x00, 0x06, 0xb5, 0x4f, 0x0d, 0x00, 0x00, 0x02, 0x76, 0xfd, 0x77, 0x00, 0x00, 0x38, 0xfc, 0x1d, + 0x00, 0x2e, 0x7b, 0x0c, 0x09, 0x00, 0x00, 0x02, 0x77, 0xd0, 0x77, 0x00, 0x00, 0x44, 0x8a, 0x02, + 0x00, 0x23, 0x56, 0x2b, 0x01, 0x00, 0x00, 0x03, 0x5c, 0xd0, 0x68, 0x00, 0x00, 0x44, 0x6f, 0x08, + 0x00, 0x13, 0x54, 0xf0, 0x05, 0x00, 0x13, 0x90, 0xe4, 0x02, 0x00, 0x00, 0x01, 0x61, 0xd2, 0x6f, + 0x00, 0x00, 0x43, 0x6f, 0x12, 0x00, 0x00, 0x02, 0x65, 0xd0, 0x6d, 0x00, 0x00, 0x44, 0xe0, 0x04, + 0x00, 0x13, 0x54, 0x54, 0x02, 0x00, 0x00, 0x01, 0x50, 0xd0, 0x63, 0x00, 0x00, 0x44, 0xe0, 0x06, + 0x00, 0x00, 0x01, 0x4f, 0xd0, 0x63, 0x00, 0x00, 0x44, 0xf6, 0x03, 0x00, 0x00, 0x01, 0x66, 0xd2, + 0x71, 0x00, 0x00, 0x42, 0x89, 0x19, 0x00, 0x00, 0x01, 0x61, 0xd0, 0x6d, 0x00, 0x00, 0x44, 0x55, + 0x07, 0x00, 0x00, 0x01, 0x54, 0xd0, 0x66, 0x00, 0x00, 0x44, 0x36, 0x07, 0x00, 0x00, 0x01, 0x4b, + 0xd2, 0x65, 0x00, 0x00, 0x44, 0xf7, 0x0f, 0x00, 0x00, 0x01, 0x60, 0xd0, 0x68, 0x00, 0x00, 0x44, + 0xc4, 0x04, 0x00, 0x00, 0x01, 0x51, 0xd0, 0x60, 0x00, 0x00, 0x44, 0xd2, 0x01, 0x00, 0x00, 0x01, + 0x6e, 0xd0, 0x73, 0x00, 0x00, 0x44, 0x7f, 0x10, 0x00, 0x00, 0x01, 0x60, 0xd0, 0x6c, 0x00, 0x00, + 0x44, 0xa8, 0x08, 0x00, 0x00, 0x02, 0x6d, 0xd2, 0x72, 0x00, 0x00, 0x42, 0xb7, 0x0e, 0x00, 0x14, + 0x53, 0x9f, 0x0a, 0x00, 0x00, 0x02, 0x5c, 0xd0, 0x68, 0x00, 0x00, 0x44, 0x93, 0x07, 0x00, 0x13, + 0x54, 0xf4, 0x01, 0x00, 0x00, 0x02, 0x73, 0xf7, 0x72, 0x00, 0x00, 0x42, 0x2e, 0x16, 0x00, 0x14, + 0x53, 0xd1, 0x09, 0x00, 0x00, 0x02, 0x5f, 0xd0, 0x66, 0x00, 0x00, 0x44, 0x13, 0x13, 0x00, 0x13, + 0x54, 0x08, 0x03, 0x00, 0x00, 0x01, 0x5f, 0xd2, 0x6d, 0x00, 0x00, 0x42, 0x82, 0x1c, 0x00, 0x00, + 0x01, 0x66, 0xd0, 0x6f, 0x00, 0x00, 0x44, 0x74, 0x02, 0x00, 0x00, 0x01, 0x62, 0xd2, 0x6d, 0x00, + 0x00, 0x44, 0x96, 0x11, 0x00, 0x00, 0x01, 0x78, 0xd0, 0x78, 0x00, 0x00, 0x44, 0xcc, 0x02, 0x00, + 0x00, 0x01, 0x6f, 0xd0, 0x74, 0x00, 0x00, 0x44, 0xad, 0x10, 0x00, 0x00, 0x01, 0x74, 0xd0, 0x76, + 0x00, 0x00, 0x44, 0xc1, 0x06, 0x00, 0x00, 0x01, 0x79, 0xd0, 0x78, 0x00, 0x00, 0x44, 0xd4, 0x05, + 0x00, 0x00, 0x01, 0x61, 0xd0, 0x6d, 0x00, 0x00, 0x44, 0xae, 0x03, 0x00, 0x00, 0x01, 0x35, 0xfc, + 0x54, 0x00, 0x00, 0x35, 0xa0, 0x02, 0x00, 0x00, 0x01, 0x5c, 0xe7, 0x67, 0x00, 0x00, 0x39, 0x35, + 0x01, 0x00, 0x00, 0x01, 0x35, 0xfc, 0x5a, 0x00, 0x00, 0x35, 0xb6, 0x02, 0x00, 0x00, 0x01, 0x60, + 0x89, 0x6b, 0x00, 0x00, 0x44, 0x0f, 0x02, 0x00, 0x00, 0x01, 0x79, 0xfc, 0x78, 0x00, 0x00, 0xec, + 0x42, 0x01, 0x00, 0x00, 0x02, 0x48, 0x66, 0x78, 0x00, 0x13, 0x39, 0x5c, 0x01, 0x00, 0x00, 0x65, + 0x6b, 0x00, 0x00, 0x00, 0x02, 0x59, 0xd2, 0x6a, 0x00, 0x00, 0x63, 0xec, 0x14, 0x00, 0x14, 0x9f, + 0x8e, 0x06, 0x00, 0x00, 0x02, 0x5c, 0xd2, 0x67, 0x00, 0x00, 0x39, 0xbf, 0x0b, 0x00, 0x13, 0x73, + 0xcb, 0x08, 0x00, 0x00, 0x01, 0x54, 0xd2, 0x68, 0x00, 0x00, 0x63, 0x64, 0x13, 0x00, 0x00, 0x02, + 0x5c, 0xd2, 0x6d, 0x00, 0x00, 0x39, 0x47, 0x0f, 0x00, 0x13, 0x73, 0x6c, 0x03, 0x00, 0x00, 0x02, + 0x60, 0xd2, 0x6c, 0x00, 0x00, 0x63, 0x18, 0x14, 0x00, 0x13, 0x71, 0x2c, 0x03, 0x00, 0x00, 0x02, + 0x71, 0xd0, 0x78, 0x00, 0x09, 0x38, 0x1f, 0x0d, 0x00, 0x00, 0x65, 0x6b, 0x00, 0x00, 0x00, 0x03, + 0x66, 0xfd, 0x6e, 0x00, 0x00, 0x63, 0x3d, 0x1d, 0x00, 0x19, 0x71, 0xff, 0x0e, 0x00, 0x14, 0xcc, + 0xfd, 0x07, 0x00, 0x00, 0x01, 0x57, 0xd0, 0x67, 0x00, 0x00, 0x39, 0x24, 0x12, 0x00, 0x00, 0x02, + 0x57, 0xd0, 0x66, 0x00, 0x1b, 0x38, 0x57, 0x0a, 0x00, 0x00, 0x65, 0x2a, 0x04, 0x00, 0x00, 0x02, + 0x50, 0xfd, 0x6a, 0x00, 0x32, 0x38, 0x2f, 0x0b, 0x00, 0x00, 0x65, 0x3b, 0x10, 0x00, 0x00, 0x01, + 0x5f, 0xd0, 0x65, 0x00, 0x00, 0x39, 0x1c, 0x06, 0x00, 0x00, 0x01, 0x57, 0xd0, 0x66, 0x00, 0x00, + 0x39, 0x94, 0x03, 0x00, 0x00, 0x01, 0x66, 0xd0, 0x6f, 0x00, 0x00, 0x63, 0x91, 0x1a, 0x00, 0x00, + 0x01, 0x57, 0xd0, 0x67, 0x00, 0x00, 0x63, 0x4d, 0x11, 0x00, 0x00, 0x02, 0x65, 0xd2, 0x6f, 0x00, + 0x00, 0x63, 0xff, 0x0b, 0x00, 0x13, 0x72, 0xe7, 0x0a, 0x00, 0x00, 0x02, 0x5c, 0xfc, 0x67, 0x00, + 0x00, 0x63, 0x89, 0x0f, 0x00, 0x13, 0x73, 0xc4, 0x07, 0x00, 0x00, 0x02, 0x5c, 0xfc, 0x6d, 0x00, + 0x00, 0x63, 0x19, 0x0a, 0x00, 0x13, 0x72, 0x0c, 0x05, 0x00, 0x00, 0x01, 0x59, 0xd0, 0x63, 0x00, + 0x00, 0x63, 0x95, 0x09, 0x00, 0x00, 0x01, 0x53, 0xd2, 0x65, 0x00, 0x00, 0x63, 0x20, 0x1b, 0x00, + 0x00, 0x01, 0x61, 0xd2, 0x72, 0x00, 0x00, 0x42, 0xe3, 0x11, 0x00, 0x00, 0x01, 0x57, 0xd2, 0x67, + 0x00, 0x00, 0x65, 0xdb, 0x10, 0x00, 0x00, 0x01, 0x6a, 0xd0, 0x71, 0x00, 0x00, 0x65, 0x54, 0x03, + 0x00, 0x00, 0x01, 0x71, 0xd0, 0x74, 0x00, 0x00, 0x65, 0x1f, 0x11, 0x00, 0x00, 0x01, 0x6b, 0xd0, + 0x71, 0x00, 0x00, 0x65, 0x6f, 0x06, 0x00, 0x00, 0x01, 0x6b, 0xfd, 0x72, 0x00, 0x00, 0x65, 0xc8, + 0x12, 0x00, 0x00, 0x01, 0x57, 0xd0, 0x67, 0x00, 0x00, 0x65, 0x10, 0x04, 0x00, 0x00, 0x01, 0x4f, + 0xfc, 0x67, 0x00, 0x00, 0x35, 0x98, 0x18, 0x00, 0x00, 0x01, 0x12, 0xfc, 0x45, 0x00, 0x00, 0x21, + 0x76, 0x01, 0x00, 0x00, 0x01, 0x4f, 0xfc, 0x60, 0x00, 0x00, 0x35, 0x2b, 0x18, 0x00, 0x00, 0x01, + 0x6b, 0xac, 0x71, 0x00, 0x00, 0x7f, 0x7e, 0x14, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xc3, 0x5f, 0x32, 0x4e, 0x46, 0x53 +}; \ No newline at end of file diff --git a/src/XDON-OG/XDON/ssfn.h b/src/XDON-OG/XDON/ssfn.h new file mode 100644 index 0000000..f41e94b --- /dev/null +++ b/src/XDON-OG/XDON/ssfn.h @@ -0,0 +1,1521 @@ +/* + * ssfn.h + * https://gitlab.com/bztsrc/scalable-font2 + * + * Copyright (C) 2020 - 2022 bzt + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @brief Scalable Screen Font renderers + * + */ + +#ifndef _SSFN_H_ +#define _SSFN_H_ + +#define SSFN_VERSION 0x0200 + +/***** file format *****/ + +/* magic bytes */ +#define SSFN_MAGIC "SFN2" +#define SSFN_COLLECTION "SFNC" +#define SSFN_ENDMAGIC "2NFS" + +/* ligatures area */ +#define SSFN_LIG_FIRST 0xF000 +#define SSFN_LIG_LAST 0xF8FF + +/* font family group in font type byte */ +#define SSFN_TYPE_FAMILY(x) ((x)&15) +#define SSFN_FAMILY_SERIF 0 +#define SSFN_FAMILY_SANS 1 +#define SSFN_FAMILY_DECOR 2 +#define SSFN_FAMILY_MONOSPACE 3 +#define SSFN_FAMILY_HAND 4 + +/* font style flags in font type byte */ +#define SSFN_TYPE_STYLE(x) (((x)>>4)&15) +#define SSFN_STYLE_REGULAR 0 +#define SSFN_STYLE_BOLD 1 +#define SSFN_STYLE_ITALIC 2 +#define SSFN_STYLE_USRDEF1 4 /* user defined variant 1 */ +#define SSFN_STYLE_USRDEF2 8 /* user defined variant 2 */ + +/* contour commands */ +#define SSFN_CONTOUR_MOVE 0 +#define SSFN_CONTOUR_LINE 1 +#define SSFN_CONTOUR_QUAD 2 +#define SSFN_CONTOUR_CUBIC 3 + +/* glyph fragments, kerning groups and hinting grid info */ +#define SSFN_FRAG_CONTOUR 0 +#define SSFN_FRAG_BITMAP 1 +#define SSFN_FRAG_PIXMAP 2 +#define SSFN_FRAG_KERNING 3 +#define SSFN_FRAG_HINTING 4 + +/* main SSFN header, 32 bytes */ +#ifndef _MSC_VER +#define _pack __attribute__((packed)) +#else +#define _pack +#pragma pack(push) +#pragma pack(1) +#endif +typedef struct { + uint8_t magic[4]; /* SSFN magic bytes */ + uint32_t size; /* total size in bytes */ + uint8_t type; /* font family and style */ + uint8_t features; /* format features and revision */ + uint8_t width; /* overall width of the font */ + uint8_t height; /* overall height of the font */ + uint8_t baseline; /* horizontal baseline in grid pixels */ + uint8_t underline; /* position of under line in grid pixels */ + uint16_t fragments_offs; /* offset of fragments table */ + uint32_t characters_offs; /* characters table offset */ + uint32_t ligature_offs; /* ligatures table offset */ + uint32_t kerning_offs; /* kerning table offset */ + uint32_t cmap_offs; /* color map offset */ +} _pack ssfn_font_t; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +/***** renderer API *****/ +#define SSFN_FAMILY_ANY 0xff /* select the first loaded font */ +#define SSFN_FAMILY_BYNAME 0xfe /* select font by its unique name */ + +/* additional styles not stored in fonts */ +#define SSFN_STYLE_UNDERLINE 16 /* under line glyph */ +#define SSFN_STYLE_STHROUGH 32 /* strike through glyph */ +#define SSFN_STYLE_NOAA 64 /* no anti-aliasing */ +#define SSFN_STYLE_NOKERN 128 /* no kerning */ +#define SSFN_STYLE_NODEFGLYPH 256 /* don't draw default glyph */ +#define SSFN_STYLE_NOCACHE 512 /* don't cache rasterized glyph */ +#define SSFN_STYLE_NOHINTING 1024 /* no auto hinting grid (not used as of now) */ +#define SSFN_STYLE_RTL 2048 /* render right-to-left */ +#define SSFN_STYLE_ABS_SIZE 4096 /* scale absoulte height */ +#define SSFN_STYLE_NOSMOOTH 8192 /* no edge-smoothing for bitmaps */ +#define SSFN_STYLE_A 16384 /* keep original alpha channel */ + +/* error codes */ +#define SSFN_OK 0 /* success */ +#define SSFN_ERR_ALLOC -1 /* allocation error */ +#define SSFN_ERR_BADFILE -2 /* bad SSFN file format */ +#define SSFN_ERR_NOFACE -3 /* no font face selected */ +#define SSFN_ERR_INVINP -4 /* invalid input */ +#define SSFN_ERR_BADSTYLE -5 /* bad style */ +#define SSFN_ERR_BADSIZE -6 /* bad size */ +#define SSFN_ERR_NOGLYPH -7 /* glyph (or kerning info) not found */ + +#define SSFN_SIZE_MAX 192 /* biggest size we can render */ +#define SSFN_ITALIC_DIV 4 /* italic angle divisor, glyph top side pushed width / this pixels */ +#define SSFN_PREC 4 /* precision in bits */ + +/* destination frame buffer context */ +typedef struct { + uint8_t *ptr; /* pointer to the buffer */ + int w; /* width (positive: ARGB, negative: ABGR pixels) */ + int h; /* height */ + uint16_t p; /* pitch, bytes per line */ + int x; /* cursor x */ + int y; /* cursor y */ + uint32_t fg; /* foreground color */ + uint32_t bg; /* background color */ +} ssfn_buf_t; + +/* cached bitmap struct */ +#define SSFN_DATA_MAX 65536 +typedef struct { + uint16_t p; /* data buffer pitch, bytes per line */ + uint8_t h; /* data buffer height */ + uint8_t o; /* overlap of glyph, scaled to size */ + uint8_t x; /* advance x, scaled to size */ + uint8_t y; /* advance y, scaled to size */ + uint8_t a; /* ascender, scaled to size */ + uint8_t d; /* descender, scaled to size */ + uint8_t data[SSFN_DATA_MAX]; /* data buffer */ +} ssfn_glyph_t; + +/* character metrics */ +typedef struct { + uint8_t t; /* type and overlap */ + uint8_t n; /* number of fragments */ + uint8_t w; /* width */ + uint8_t h; /* height */ + uint8_t x; /* advance x */ + uint8_t y; /* advance y */ +} ssfn_chr_t; + +#ifdef SSFN_PROFILING +#include +#include +#endif + +/* renderer context */ +typedef struct { +#ifdef SSFN_MAXLINES + const ssfn_font_t *fnt[5][16]; /* static font registry */ +#else + const ssfn_font_t **fnt[5]; /* dynamic font registry */ +#endif + const ssfn_font_t *s; /* explicitly selected font */ + const ssfn_font_t *f; /* font selected by best match */ + ssfn_glyph_t ga; /* glyph sketch area */ + ssfn_glyph_t *g; /* current glyph pointer */ +#ifdef SSFN_MAXLINES + uint16_t p[SSFN_MAXLINES*2]; +#else + ssfn_glyph_t ***c[17]; /* glyph cache */ + uint16_t *p; + char **bufs; /* allocated extra buffers */ +#endif + ssfn_chr_t *rc; /* pointer to current character */ + int numbuf, lenbuf, np, ap, ox, oy, ax; + int mx, my, lx, ly; /* move to coordinates, last coordinates */ + int len[5]; /* number of fonts in registry */ + int family; /* required family */ + int style; /* required style */ + int size; /* required size */ + int line; /* calculate line height */ +#ifdef SSFN_PROFILING + uint64_t lookup, raster, blit, kern;/* profiling accumulators */ +#endif +} ssfn_t; + +/***** API function protoypes *****/ + +uint32_t ssfn_utf8(char **str); /* decode UTF-8 sequence */ + +/* normal renderer */ +int ssfn_load(ssfn_t *ctx, const void *data); /* add an SSFN to context */ +int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size); /* select font to use */ +int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str); /* render a glyph to a pixel buffer */ +int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top); /* get bounding box */ +ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg); /* renders text to a newly allocated buffer */ +int ssfn_mem(ssfn_t *ctx); /* return how much memory is used */ +void ssfn_free(ssfn_t *ctx); /* free context */ +#define ssfn_error(err) (err<0&&err>=-7?ssfn_errstr[-err]:"Unknown error") /* return string for error code */ +extern const char *ssfn_errstr[]; + +/* simple renderer */ +extern ssfn_font_t *ssfn_src; /* font buffer */ +extern ssfn_buf_t ssfn_dst; /* destination frame buffer */ +int ssfn_putc(uint32_t unicode); /* render console bitmap font */ + +/***** renderer implementations *****/ + +/*** these go for both renderers ***/ +#if (defined(SSFN_IMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \ + defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)) && !defined(SSFN_COMMON) +#define SSFN_COMMON + +/** + * Error code strings + */ +const char *ssfn_errstr[] = { "", + "Memory allocation error", + "Bad file format", + "No font face found", + "Invalid input value", + "Invalid style", + "Invalid size", + "Glyph not found" +}; + +/** + * Decode an UTF-8 multibyte, advance string pointer and return UNICODE. Watch out, no input checks + * + * @param **s pointer to an UTF-8 string pointer + * @return unicode, and *s moved to next multibyte sequence + */ +uint32_t ssfn_utf8(char **s) +{ + uint32_t c = **s; + + if((**s & 128) != 0) { + if(!(**s & 32)) { c = ((**s & 0x1F)<<6)|(*(*s+1) & 0x3F); *s += 1; } else + if(!(**s & 16)) { c = ((**s & 0xF)<<12)|((*(*s+1) & 0x3F)<<6)|(*(*s+2) & 0x3F); *s += 2; } else + if(!(**s & 8)) { c = ((**s & 0x7)<<18)|((*(*s+1) & 0x3F)<<12)|((*(*s+2) & 0x3F)<<6)|(*(*s+3) & 0x3F); *s += 3; } + else c = 0; + } + (*s)++; + return c; +} +#endif + +#ifdef SSFN_IMPLEMENTATION +/*** normal renderer (ca. 28k, fully featured with error checking) ***/ + +// # ifndef NULL +// # define NULL (void*)0 +// # endif +// # ifndef size_t +// typedef __SIZE_TYPE__ size_t; +// # endif +// # ifndef inline +// # define inline __inline__ +// # endif + +//#ifndef _STRING_H_ +//extern int memcmp (const void *__s1, const void *__s2, size_t __n) __THROW; +//extern void *memset (void *__s, int __c, size_t __n) __THROW; +//#endif + +/* Clang does not have built-ins */ +# ifndef SSFN_memcmp +# ifdef __builtin_memcmp +# define SSFN_memcmp __builtin_memcmp +# else +# ifndef SSFN_MAXLINES +# define SSFN_memcmp memcmp +# else +static int SSFN_memcmp(const void *__s1, const void *__s2, size_t __n) +{ unsigned char *a = (unsigned char *)__s1, *b = (unsigned char *)__s2; + if(__n > 0) { while(__n-- > 0) { if(*a != *b) { return *a - *b; } a++; b++; } } return 0; } +# endif +# endif +# endif + +# ifndef SSFN_memset +# ifdef __builtin_memset +# define SSFN_memset __builtin_memset +# else +# ifndef SSFN_MAXLINES +# define SSFN_memset memset +# else +static void *SSFN_memset(void *__s, int __c, size_t __n) +{ unsigned char *a = (unsigned char*)__s; if(__n > 0) { while(__n-- > 0) *a++ = __c; } return (unsigned char*)__s; } +# endif +# endif +# endif + +# ifndef SSFN_MAXLINES + +# ifndef SSFN_realloc +# ifdef __builtin_realloc +# define SSFN_realloc __builtin_realloc +# else +# define SSFN_realloc realloc + extern void *realloc (void *__ptr, size_t __size) __THROW; +# endif +# endif + +# ifndef SSFN_free +# ifdef __builtin_free +# define SSFN_free __builtin_free +# else +# define SSFN_free free + extern void free (void *p) __THROW; +# endif +# endif + +# endif /* if !SSFN_MAXLINES */ + +/*** Private functions ***/ + +/* parse character table */ +static uint8_t *_ssfn_c(const ssfn_font_t *font, const char *str, int *len, uint32_t *unicode) +{ + uint32_t i, j, u = 0xffffffff; + uint16_t *l; + uint8_t *ptr, *s; + + *len = 0; *unicode = 0; + if(!font || !font->characters_offs || !str || !*str) return NULL; + + if(font->ligature_offs) { + for(l = (uint16_t*)((uint8_t*)font + font->ligature_offs), i = 0; l[i] && u == 0xffffffff; i++) { + for(ptr = (uint8_t*)font + l[i], s = (uint8_t*)str; *ptr && *ptr == *s; ptr++, s++); + if(!*ptr) { u = SSFN_LIG_FIRST + i; break; } + } + } + if(u == 0xffffffff) { + /* inline ssfn_utf8 to workaround -O2 bug in gcc 11.1 */ + s = (uint8_t*)str; u = *s; + if((*s & 128) != 0) { + if(!(*s & 32)) { u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s++; } else + if(!(*s & 16)) { u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 2; } else + if(!(*s & 8)) { u = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); s += 3; } + else u = 0; + } + s++; + } + *len = (int)(s - (uint8_t*)str); + *unicode = u; + for(ptr = (uint8_t*)font + font->characters_offs, i = 0; i < 0x110000; i++) { + if(ptr[0] == 0xFF) { i += 65535; ptr++; } + else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; } + else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; } + else { + if(i == u) return ptr; + ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); + } + } + return NULL; +} + +/* add a line to contour */ +static void _ssfn_l(ssfn_t *ctx, int p, int h, int x, int y) +{ + if(x < 0 || y < 0 || x >= p || y >= h || ( + ((ctx->lx + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((x + (1 << (SSFN_PREC-1))) >> SSFN_PREC) && + ((ctx->ly + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((y + (1 << (SSFN_PREC-1))) >> SSFN_PREC))) return; +#ifdef SSFN_MAXLINES + if(ctx->np >= SSFN_MAXLINES*2-2) return; +#else + if(ctx->ap <= ctx->np) { + ctx->ap = ctx->np + 512; + ctx->p = (uint16_t*)SSFN_realloc(ctx->p, ctx->ap * sizeof(uint16_t)); + if(!ctx->p) { ctx->ap = ctx->np = 0; return; } + } +#endif + if(!ctx->np) { + ctx->p[0] = ctx->mx; + ctx->p[1] = ctx->my; + ctx->np += 2; + } + ctx->p[ctx->np+0] = x; + ctx->p[ctx->np+1] = y; + ctx->np += 2; + ctx->lx = x; ctx->ly = y; +} + +/* add a Bezier curve to contour */ +static void _ssfn_b(ssfn_t *ctx, int p,int h, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l) +{ + int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y; + if(l<4 && (x0!=x3 || y0!=y3)) { + m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0; + m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1; + m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2; + m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y; + m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y; + m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y; + _ssfn_b(ctx, p,h, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1); + _ssfn_b(ctx, p,h, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1); + } + if(l) _ssfn_l(ctx, p,h, x3, y3); +} + +#ifndef SSFN_MAXLINES +static void _ssfn_fc(ssfn_t *ctx) +{ + int i, j, k; + if(!ctx) return; + for(k = 0; k <= 16; k++) + if(ctx->c[k]) { + for(j = 0; j < 256; j++) + if(ctx->c[k][j]) { + for(i = 0; i < 256; i++) + if(ctx->c[k][j][i]) SSFN_free(ctx->c[k][j][i]); + SSFN_free(ctx->c[k][j]); + } + SSFN_free(ctx->c[k]); + ctx->c[k] = NULL; + } +} + +/* + * gzip deflate uncompressor from stb_image.h with minor modifications to reduce dependency + * stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h + */ +#define SSFN__ZFAST_BITS 9 +#define SSFN__ZFAST_MASK ((1 << SSFN__ZFAST_BITS) - 1) + +typedef struct +{ + uint16_t fast[1 << SSFN__ZFAST_BITS]; + uint16_t firstcode[16]; + int maxcode[17]; + uint16_t firstsymbol[16]; + unsigned char size[288]; + uint16_t value[288]; +} _ssfn__zhuffman; + +inline static int _ssfn__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +inline static int _ssfn__bit_reverse(int v, int bits) +{ + return _ssfn__bitreverse16(v) >> (16-bits); +} + +static int _ssfn__zbuild_huffman(_ssfn__zhuffman *z, unsigned char *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + SSFN_memset(sizes, 0, sizeof(sizes)); + SSFN_memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return 0; + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (uint16_t) code; + z->firstsymbol[i] = (uint16_t) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return 0; + z->maxcode[i] = code << (16-i); + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + uint16_t fastv = (uint16_t) ((s << 9) | i); + z->size [c] = (unsigned char) s; + z->value[c] = (uint16_t) i; + if (s <= SSFN__ZFAST_BITS) { + int j = _ssfn__bit_reverse(next_code[s],s); + while (j < (1 << SSFN__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +typedef struct +{ + unsigned char *zbuffer; + int num_bits; + uint32_t code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + + _ssfn__zhuffman z_length, z_distance; +} _ssfn__zbuf; + +inline static unsigned char _ssfn__zget8(_ssfn__zbuf *z) +{ + return *z->zbuffer++; +} + +static void _ssfn__fill_bits(_ssfn__zbuf *z) +{ + do { + z->code_buffer |= (unsigned int) _ssfn__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +inline static unsigned int _ssfn__zreceive(_ssfn__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) _ssfn__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int _ssfn__zhuffman_decode_slowpath(_ssfn__zbuf *a, _ssfn__zhuffman *z) +{ + int b,s,k; + k = _ssfn__bit_reverse(a->code_buffer, 16); + for (s=SSFN__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +inline static int _ssfn__zhuffman_decode(_ssfn__zbuf *a, _ssfn__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) _ssfn__fill_bits(a); + b = z->fast[a->code_buffer & SSFN__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return _ssfn__zhuffman_decode_slowpath(a, z); +} + +static int _ssfn__zexpand(_ssfn__zbuf *z, char *zout) +{ + char *q; + unsigned int cur, limit; +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" +#endif + z->zout = zout; cur = (unsigned int) (z->zout - z->zout_start); limit = (unsigned int) (z->zout_end - z->zout_start); + if(limit == 8) { if(z->zout_start[0] != 'S' || z->zout_start[1] != 'F' || z->zout_start[2] != 'N') return 0; limit = *((uint32_t*)&z->zout_start[4]); } else return 0; + q = (char *) SSFN_realloc(z->zout_start, limit); + if (q == NULL) return 0; + z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + return 1; +} + +static int _ssfn__zlength_base[31]={3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0}; +static int _ssfn__zlength_extra[31]={0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0}; +static int _ssfn__zdist_base[32]={1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; +static int _ssfn__zdist_extra[32]={0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int _ssfn__parse_huffman_block(_ssfn__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = _ssfn__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return 0; + if (zout >= a->zout_end) { if (!_ssfn__zexpand(a, zout)) return 0; zout = a->zout; } + *zout++ = (char) z; + } else { + unsigned char *p; + int len,dist; + if (z == 256) { a->zout = zout; return 1; } + z -= 257; + len = _ssfn__zlength_base[z]; + if (_ssfn__zlength_extra[z]) len += _ssfn__zreceive(a, _ssfn__zlength_extra[z]); + z = _ssfn__zhuffman_decode(a, &a->z_distance); + if (z < 0) return 0; + dist = _ssfn__zdist_base[z]; + if (_ssfn__zdist_extra[z]) dist += _ssfn__zreceive(a, _ssfn__zdist_extra[z]); + if (zout - a->zout_start < dist) return 0; + if (zout + len > a->zout_end) { + if (!_ssfn__zexpand(a, zout)) return 0; + zout = a->zout; + } + p = (unsigned char *) (zout - dist); + if (dist == 1) {unsigned char v = *p;if (len) { do *zout++ = v; while (--len); } + } else { if (len) { do *zout++ = *p++; while (--len); } } + } + } +} + +static int _ssfn__compute_huffman_codes(_ssfn__zbuf *a) +{ + static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + _ssfn__zhuffman z_codelength; + unsigned char lencodes[286+32+137]; + unsigned char codelength_sizes[19]; + int i,n; + + int hlit = _ssfn__zreceive(a,5) + 257; + int hdist = _ssfn__zreceive(a,5) + 1; + int hclen = _ssfn__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + SSFN_memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = _ssfn__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (unsigned char) s; + } + if (!_ssfn__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = _ssfn__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return 0; + if (c < 16) + lencodes[n++] = (unsigned char) c; + else { + unsigned char fill = 0; + if (c == 16) { + c = _ssfn__zreceive(a,2)+3; + if (n == 0) return 0; + fill = lencodes[n-1]; + } else + if (c == 17) c = _ssfn__zreceive(a,3)+3; + else { c = _ssfn__zreceive(a,7)+11; } + if (ntot - n < c) return 0; + SSFN_memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return 0; + if (!_ssfn__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!_ssfn__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +inline static int _ssfn__parse_uncompressed_block(_ssfn__zbuf *a) +{ + unsigned char header[4]; + int len,nlen,k; + if (a->num_bits & 7) + _ssfn__zreceive(a, a->num_bits & 7); + k = 0; + while (a->num_bits > 0) { + header[k++] = (unsigned char) (a->code_buffer & 255); + a->code_buffer >>= 8; + a->num_bits -= 8; + } + while (k < 4) + header[k++] = _ssfn__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return 0; + if (a->zout + len > a->zout_end) + if (!_ssfn__zexpand(a, a->zout)) return 0; + for(k = 0; k < len; k++) + a->zout[k] = a->zbuffer[k]; + a->zbuffer += len; + a->zout += len; + return 1; +} + +static unsigned char _ssfn__zdefault_length[288], _ssfn__zdefault_distance[32]; +static void _ssfn__init_zdefaults(void) +{ + int i; + for (i=0; i <= 143; ++i) _ssfn__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) _ssfn__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) _ssfn__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) _ssfn__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) _ssfn__zdefault_distance[i] = 5; +} + +static int _ssfn__parse_zlib(_ssfn__zbuf *a) +{ + int fin, type; + a->num_bits = 0; + a->code_buffer = 0; + do { + fin = _ssfn__zreceive(a,1); + type = _ssfn__zreceive(a,2); + if (type == 0) { if (!_ssfn__parse_uncompressed_block(a)) return 0; } + else if (type == 3) { return 0; } + else { + if (type == 1) { + if (!_ssfn__zbuild_huffman(&a->z_length , _ssfn__zdefault_length , 288)) return 0; + if (!_ssfn__zbuild_huffman(&a->z_distance, _ssfn__zdefault_distance, 32)) return 0; + } else { + if (!_ssfn__compute_huffman_codes(a)) return 0; + } + if (!_ssfn__parse_huffman_block(a)) return 0; + } + } while (!fin); + return 1; +} + +char *_ssfn_zlib_decode(const char *buffer) +{ + _ssfn__zbuf a; + char *p = (char *) SSFN_realloc(NULL, 8); + if (p == NULL) return NULL; + a.zbuffer = (unsigned char *) buffer; + a.zout_start = p; a.zout = p; a.zout_end = p + 8; + _ssfn__init_zdefaults(); + if (_ssfn__parse_zlib(&a)) { return a.zout_start; } else { SSFN_free(a.zout_start); return NULL; } +} +#endif /* if !SSFN_MAXLINES */ + +/*** Public API implementation ***/ + +/** + * Load a font or font collection into renderer context + * + * @param ctx rendering context + * @param font SSFN font or font collection in memory + * @return error code + */ +int ssfn_load(ssfn_t *ctx, const void *data) +{ + const ssfn_font_t *font = (const ssfn_font_t *)data; + ssfn_font_t *fnt, *end; + int family; +#ifndef SSFN_MAXLINES + uint8_t c, r, *ptr = (uint8_t *)font; +#endif + if(!ctx || !font) + return SSFN_ERR_INVINP; + if(((uint8_t *)font)[0] == 0x1f && ((uint8_t *)font)[1] == 0x8b) { +#ifdef SSFN_MAXLINES + return SSFN_ERR_BADFILE; +#else + ptr += 2; + if(*ptr++ != 8) return SSFN_ERR_BADFILE; + c = *ptr++; ptr += 6; + if(c & 4) { r = *ptr++; r += (*ptr++ << 8); ptr += r; } + if(c & 8) { while(*ptr++ != 0); } + if(c & 16) { while(*ptr++ != 0); } + font = (ssfn_font_t*)_ssfn_zlib_decode((const char*)ptr); + if(!font) return SSFN_ERR_BADFILE; + ctx->bufs = (char**)SSFN_realloc(ctx->bufs, (ctx->numbuf + 1) * sizeof(char*)); + if(!ctx->bufs) { ctx->numbuf = 0; return SSFN_ERR_ALLOC; } + ctx->bufs[ctx->numbuf++] = (char*)font; + ctx->lenbuf += font->size; +#endif + } + if(!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) { + end = (ssfn_font_t*)((uint8_t*)font + font->size); + for(fnt = (ssfn_font_t*)((uint8_t*)font + 8); fnt < end && !ssfn_load(ctx, (const void *)fnt); + fnt = (ssfn_font_t*)((uint8_t*)fnt + fnt->size)); + } else { + family = SSFN_TYPE_FAMILY(font->type); + if(SSFN_memcmp(font->magic, SSFN_MAGIC, 4) || SSFN_memcmp((uint8_t*)font + font->size - 4, SSFN_ENDMAGIC, 4) || + family > SSFN_FAMILY_HAND || font->fragments_offs >= font->size || font->characters_offs >= font->size || + font->ligature_offs >= font->size || font->kerning_offs >= font->size || font->cmap_offs >= font->size || + font->fragments_offs >= font->characters_offs) { + return SSFN_ERR_BADFILE; + } else { + ctx->len[family]++; +#ifdef SSFN_MAXLINES + if(ctx->len[family] > 15) return SSFN_ERR_ALLOC; +#else + ctx->fnt[family] = (const ssfn_font_t**)SSFN_realloc(ctx->fnt[family], ctx->len[family]*sizeof(void*)); + if(!ctx->fnt[family]) { + ctx->len[family] = 0; + return SSFN_ERR_ALLOC; + } else +#endif + ctx->fnt[family][ctx->len[family]-1] = font; + } +#ifndef SSFN_MAXLINES + _ssfn_fc(ctx); +#endif + } + return SSFN_OK; +} + +/** + * Free renderer context + * + * @param ctx rendering context + */ +void ssfn_free(ssfn_t *ctx) +{ +#ifndef SSFN_MAXLINES + int i; +#endif + if(!ctx) return; +#ifndef SSFN_MAXLINES + _ssfn_fc(ctx); + if(ctx->bufs) { + for(i = 0; i < ctx->numbuf; i++) + if(ctx->bufs[i]) SSFN_free(ctx->bufs[i]); + SSFN_free(ctx->bufs); + } + for(i = 0; i < 5; i++) + if(ctx->fnt[i]) SSFN_free(ctx->fnt[i]); + if(ctx->p) SSFN_free(ctx->p); +#endif + SSFN_memset(ctx, 0, sizeof(ssfn_t)); +} + +/** + * Returns how much memory a context consumes + * + * @param ctx rendering context + * @return total memory used by that context in bytes + */ +int ssfn_mem(ssfn_t *ctx) +{ +#ifdef SSFN_MAXLINES + return ctx ? sizeof(ssfn_t) : 0; +#else + int i, j, k, ret = sizeof(ssfn_t); + + if(!ctx) return 0; + for(i = 0; i < 5; i++) ret += ctx->len[i] * sizeof(ssfn_font_t*); + ret += ctx->lenbuf; + for(k = 0; k <= 16; k++) { + if(ctx->c[k]) { + for(j = 0; j < 256; j++) + if(ctx->c[k][j]) { + for(i = 0; i < 256; i++) + if(ctx->c[k][j][i]) ret += 8 + ctx->c[k][j][i]->p * ctx->c[k][j][i]->h; + ret += 256 * sizeof(void*); + } + ret += 256 * sizeof(void*); + } + } + if(ctx->p) ret += ctx->ap * sizeof(uint16_t); + return ret; +#endif +} + +/** + * Set up rendering parameters + * + * @param ctx rendering context + * @param family one of SSFN_FAMILY_* + * @param name NULL or UTF-8 string if family is SSFN_FAMILY_BYNAME + * @param style OR'd values of SSFN_STYLE_* + * @param size how big glyph it should render, 8 - 192 + * @return error code + */ +int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size) +{ + int i, j, l; + + if(!ctx) return SSFN_ERR_INVINP; +#ifndef SSFN_MAXLINES + _ssfn_fc(ctx); +#endif + if((style & ~0x5FFF)) return SSFN_ERR_BADSTYLE; + if(size < 8 || size > SSFN_SIZE_MAX) return SSFN_ERR_BADSIZE; + + if(family == SSFN_FAMILY_BYNAME) { + if(!name || !name[0]) return SSFN_ERR_INVINP; + for(l=0; name[l]; l++); + for(i=0; i < 5; i++) { + for(j=0; j < ctx->len[i]; j++) { + if(!SSFN_memcmp(name, (uint8_t*)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t), l)) { + ctx->s = ctx->fnt[i][j]; + goto familyfound; + } + } + } + return SSFN_ERR_NOFACE; + } else { + if(family != SSFN_FAMILY_ANY && (family > SSFN_FAMILY_HAND || !ctx->len[family])) return SSFN_ERR_NOFACE; + ctx->s = NULL; + } +familyfound: + ctx->f = NULL; + ctx->family = family; + ctx->style = style; + ctx->size = size; + ctx->line = 0; + return SSFN_OK; +} + +/** + * Render a glyph to a pixel buffer + * + * @param ctx rendering context + * @param dst destination buffer + * @param str pointer to an UTF-8 string + * @return number of bytes parsed in str (zero means end of string) or error code + */ + +int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str) +{ + ssfn_font_t **fl; + uint8_t *ptr = NULL, *frg, *end, *tmp, color, ci = 0, cb = 0, cs, dec[65536]; + uint16_t r[640]; + uint32_t unicode, P, O, *Op, *Ol; + unsigned long int sR, sG, sB, sA; + int ret = 0, i, j, k, l, p, m, n, o, s, x, y, w, h, H, a, A, b, B, nr, uix, uax; + int ox, oy, y0, y1, Y0, Y1, x0, x1, X0, X1, X2, xs, ys, yp, pc, fB, fG, fR, fA, bB, bG, bR, dB, dG, dR, dA; +#ifdef SSFN_PROFILING + struct timeval tv0, tv1, tvd; + gettimeofday(&tv0, NULL); +#endif +#define PUTPIXEL O = *Ol;bR = (O >> (16 - cs)) & 0xFF; bG = (O >> 8) & 0xFF; bB = (O >> cs) & 0xFF;\ + bB += ((fB - bB) * fA) >> 8; bG += ((fG - bG) * fA) >> 8; bR += ((fR - bR) * fA) >> 8;\ + *Ol = (ctx->style & SSFN_STYLE_A ? O & 0xFF000000 : ((uint32_t)fA << 24)) | (bR << (16 - cs)) | (bG << 8) | (bB << cs); + + if(!ctx || !str) return SSFN_ERR_INVINP; + if(!*str) return 0; + if(*str == '\r') { dst->x = 0; return 1; } + if(*str == '\n') { dst->x = 0; dst->y += ctx->line ? ctx->line : ctx->size; return 1; } + + if(ctx->s) { + ctx->f = ctx->s; + ptr = _ssfn_c(ctx->f, str, &ret, &unicode); + } else { + /* find best match */ + p = ctx->family; + ctx->f = NULL; +again: if(p >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = p; + for(; n <= m; n++) { + fl = (ssfn_font_t **)ctx->fnt[n]; + if(ctx->style & 3) { + /* check if we have a specific ctx->f for the requested style and size */ + for(i=0;ilen[n];i++) + if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && fl[i]->height == ctx->size && + (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } + /* if not, check if we have the requested size (for bitmap fonts) */ + if(!ptr) + for(i=0;ilen[n];i++) + if(fl[i]->height == ctx->size && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } + /* if neither size+style nor size matched, look for style match */ + if(!ptr) + for(i=0;ilen[n];i++) + if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) + { ctx->f = fl[i]; break; } + /* if bold italic was requested, check if we have at least bold or italic */ + if(!ptr && (ctx->style & 3) == 3) + for(i=0;ilen[n];i++) + if(((fl[i]->type>>4) & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } + } + /* last resort, get the first ctx->f which has a glyph for this multibyte, no matter style */ + if(!ptr) { + for(i=0;ilen[n];i++) + if((ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } + } + } + /* if glyph still not found, try any family group */ + if(!ptr && p != SSFN_FAMILY_ANY) { p = SSFN_FAMILY_ANY; goto again; } + } + if(!ptr) { + if(ctx->style & SSFN_STYLE_NODEFGLYPH) return SSFN_ERR_NOGLYPH; + else { + unicode = 0; + if(ctx->family >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = ctx->family; + for(; n <= m && !ptr; n++) + if(ctx->len[n] && ctx->fnt[n][0] && !(*((uint8_t*)ctx->fnt[n][0] + ctx->fnt[n][0]->characters_offs) & 0x80)) + { ctx->f = ctx->fnt[n][0]; ptr = (uint8_t*)ctx->f + ctx->f->characters_offs; } + } + if(!ptr) return SSFN_ERR_NOGLYPH; + } + if(!ctx->f || !ctx->f->height || !ctx->size) return SSFN_ERR_NOFACE; + if((unicode >> 16) > 0x10) return SSFN_ERR_INVINP; + ctx->rc = (ssfn_chr_t*)ptr; ptr += sizeof(ssfn_chr_t); + H = (ctx->style & SSFN_STYLE_ABS_SIZE) || SSFN_TYPE_FAMILY(ctx->f->type) == SSFN_FAMILY_MONOSPACE || !ctx->f->baseline ? + ctx->size : ctx->size * ctx->f->height / ctx->f->baseline; + +#ifdef SSFN_PROFILING + gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + ctx->lookup += tvd.tv_sec * 1000000L + tvd.tv_usec; + memcpy(&tv0, &tv1, sizeof(struct timeval)); +#endif + /* render glyph into cache */ +#ifndef SSFN_MAXLINES + if(!(ctx->style & SSFN_STYLE_NOCACHE) && ctx->c[unicode >> 16] && ctx->c[unicode >> 16][(unicode >> 8) & 0xFF] && + ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]) { + ctx->g = ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]; + } else +#endif + { + h = ctx->style & SSFN_STYLE_NOAA ? H : (ctx->size > ctx->f->height ? (ctx->size + 4) & ~3 : ctx->f->height); + ci = (ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC); + cb = (ctx->style & SSFN_STYLE_BOLD) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_BOLD) ? (ctx->f->height+64)>>6 : 0; + w = (ctx->rc->w * h + ctx->f->height - 1) / ctx->f->height; + if(w > SSFN_SIZE_MAX) { h = h * SSFN_SIZE_MAX / w; w = SSFN_SIZE_MAX; } + p = w + (ci ? h / SSFN_ITALIC_DIV : 0) + cb; + /* failsafe, should never happen */ + if(p * h >= SSFN_DATA_MAX) return SSFN_ERR_BADSIZE; +#ifndef SSFN_MAXLINES + if(!(ctx->style & SSFN_STYLE_NOCACHE)) { + if(!ctx->c[unicode >> 16]) { + ctx->c[unicode >> 16] = (ssfn_glyph_t***)SSFN_realloc(NULL, 256 * sizeof(void*)); + if(!ctx->c[unicode >> 16]) return SSFN_ERR_ALLOC; + SSFN_memset(ctx->c[unicode >> 16], 0, 256 * sizeof(void*)); + } + if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF]) { + ctx->c[unicode >> 16][(unicode >> 8) & 0xFF] = (ssfn_glyph_t**)SSFN_realloc(NULL, 256 * sizeof(void*)); + if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF]) return SSFN_ERR_ALLOC; + SSFN_memset(ctx->c[unicode >> 16][(unicode >> 8) & 0xFF], 0, 256 * sizeof(void*)); + } + ctx->g = ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF] = (ssfn_glyph_t*)SSFN_realloc(NULL, p * h + 8); + if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]) return SSFN_ERR_ALLOC; + } else +#endif + ctx->g = &ctx->ga; + x = (ctx->rc->x > 0 && ci ? (ctx->f->height - ctx->f->baseline) * h / SSFN_ITALIC_DIV / ctx->f->height : 0); + ctx->g->p = p; + ctx->g->h = h; + ctx->g->x = (ctx->rc->x + x > 255 ? 255 : ctx->rc->x + x); + ctx->g->y = ctx->rc->y; + ctx->g->o = (ctx->rc->t & 0x3F) + x; + SSFN_memset(&ctx->g->data, 0xFF, p * h); + color = 0xFE; ctx->g->a = ctx->g->d = 0; + for(n = 0; n < ctx->rc->n; n++) { + if(ptr[0] == 255 && ptr[1] == 255) { color = ptr[2]; ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; } + x = ((ptr[0] + cb) << SSFN_PREC) * h / ctx->f->height; y = (ptr[1] << SSFN_PREC) * h / ctx->f->height; + if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; } + else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; } + frg = (uint8_t*)ctx->f + m; + if(!(frg[0] & 0x80)) { + /* contour */ + j = (frg[0] & 0x3F); + if(frg[0] & 0x40) { j <<= 8; j |= frg[1]; frg++; } + j++; frg++; tmp = frg; frg += (j+3)/4; ctx->np = 0; + for(i = 0; i < j; i++) { + k = (frg[0] << SSFN_PREC) * h / ctx->f->height + x; m = (frg[1] << SSFN_PREC) * h / ctx->f->height + y; + switch((tmp[i >> 2] >> ((i & 3) << 1)) & 3) { + case SSFN_CONTOUR_MOVE: ctx->mx = ctx->lx = k; ctx->my = ctx->ly = m; frg += 2; break; + case SSFN_CONTOUR_LINE: _ssfn_l(ctx, p << SSFN_PREC, h << SSFN_PREC, k, m); frg += 2; break; + case SSFN_CONTOUR_QUAD: + a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y; + _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, ((a-ctx->lx)/2)+ctx->lx, + ((A-ctx->ly)/2)+ctx->ly, ((k-a)/2)+a,((A-m)/2)+m, k,m, 0); + frg += 4; + break; + case SSFN_CONTOUR_CUBIC: + a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y; + b = (frg[4] << SSFN_PREC) * h / ctx->f->height + x; B = (frg[5] << SSFN_PREC) * h / ctx->f->height + y; + _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, a,A, b,B, k,m, 0); + frg += 6; + break; + } + } + /* close path */ + if(ctx->mx != ctx->lx || ctx->my != ctx->ly) { ctx->p[ctx->np+0] = ctx->mx; ctx->p[ctx->np+1] = ctx->my; ctx->np += 2; } + /* add rasterized vector layers to cached glyph */ + if(ctx->np > 4) { + for(b = A = B = o = 0; b < h; b++, B += p) { + a = b << SSFN_PREC; + for(nr = 0, i = 0; i < ctx->np - 3; i += 2) { + if( (ctx->p[i+1] < a && ctx->p[i+3] >= a) || + (ctx->p[i+3] < a && ctx->p[i+1] >= a)) { + if((ctx->p[i+1] >> SSFN_PREC) == (ctx->p[i+3] >> SSFN_PREC)) + x = (((int)ctx->p[i]+(int)ctx->p[i+2])>>1); + else + x = ((int)ctx->p[i]) + ((a - (int)ctx->p[i+1])* + ((int)ctx->p[i+2] - (int)ctx->p[i])/ + ((int)ctx->p[i+3] - (int)ctx->p[i+1])); + x >>= SSFN_PREC; + if(ci) x += (h - b) / SSFN_ITALIC_DIV; + if(cb && !o) { + if(ctx->g->data[B + x] != color) { o = -cb; A = cb; } + else { o = cb; A = -cb; } + } + for(k = 0; k < nr && x > r[k]; k++); + for(l = nr; l > k; l--) r[l] = r[l-1]; + r[k] = x; + nr++; + } + } + if(nr > 1 && nr & 1) { r[nr - 2] = r[nr - 1]; nr--; } + if(nr) { + if(ctx->g->d < y + b) ctx->g->d = y + b; + for(i = 0; i < nr - 1; i += 2) { + l = r[i] + o; m = r[i + 1] + A; + if(l < 0) l = 0; + if(m > p) m = p; + if(i > 0 && l < r[i - 1] + A) l = r[i - 1] + A; + for(; l < m; l++) + ctx->g->data[B + l] = ctx->g->data[B + l] == color ? 0xFF : color; + } + } + } + } + } else if((frg[0] & 0x60) == 0x00) { + /* bitmap */ + B = ((frg[0] & 0x1F) + 1) << 3; A = frg[1] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC; + b = B * h / ctx->f->height; a = A * h / ctx->f->height; + if(ctx->g->d < y + a) ctx->g->d = y + a; + frg += 2; + for(j = 0; j < a; j++) { + k = j * A / a; + l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0); + for(i = 0; i < b; i++) { + m = i * B / b; + if(frg[(k * B + m) >> 3] & (1 << (m & 7))) { + for(o = 0; o <= cb; o++) + ctx->g->data[l + i + o] = color; + } + } + } + if(!(ctx->style & (SSFN_STYLE_NOAA|SSFN_STYLE_NOSMOOTH))) { + m = color == 0xFD ? 0xFC : 0xFD; o = y * p + p + x; + for(k = h; k > ctx->f->height + 4; k -= 2*ctx->f->height) { + for(j = 1, l = o; j < a - 1; j++, l += p) + for(i = 1; i < b - 1; i++) { + if(ctx->g->data[l + i] == 0xFF && (ctx->g->data[l + i - p] == color || + ctx->g->data[l + i + p] == color) && (ctx->g->data[l + i - 1] == color || + ctx->g->data[l + i + 1] == color)) ctx->g->data[l + i] = m; + } + for(j = 1, l = o; j < a - 1; j++, l += p) + for(i = 1; i < b - 1; i++) { + if(ctx->g->data[l + i] == m) ctx->g->data[l + i] = color; + } + } + } + } else if((frg[0] & 0x60) == 0x20) { + /* pixmap */ + k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; B = frg[2] + 1; A = frg[3] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC; + b = B * h / ctx->f->height; a = A * h / ctx->f->height; + if(ctx->g->d < y + a) ctx->g->d = y + a; + frg += 4; end = frg + k; i = 0; + while(frg < end) { + l = ((*frg++) & 0x7F) + 1; + if(frg[-1] & 0x80) { + while(l--) dec[i++] = *frg; + frg++; + } else while(l--) dec[i++] = *frg++; + } + for(j = 0; j < a; j++) { + k = j * A / a * B; + l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0); + for(i = 0; i < b; i++) { + m = dec[k + i * B / b]; + if(m != 0xFF) ctx->g->data[l + i] = m; + } + } + } + color = 0xFE; + } + ctx->g->a = ctx->f->baseline; + if(ctx->g->d > ctx->g->a + 1) ctx->g->d -= ctx->g->a + 1; else ctx->g->d = 0; +#ifdef SSFN_DEBUGGLYPH + printf("\nU+%06X size %d p %d h %d base %d under %d overlap %d ascender %d descender %d advance x %d advance y %d cb %d\n", + unicode, ctx->size,p,h,ctx->f->baseline,ctx->f->underline,ctx->g->o,ctx->g->a,ctx->g->d,ctx->g->x,ctx->g->y,cb); + for(j = 0; j < h; j++) { printf("%3d: ", j); for(i = 0; i < p; i++) { if(ctx->g->data[j*p+i] == 0xFF) printf(j == ctx->g->a ? "_" : "."); else printf("%x", ctx->g->data[j*p+i] & 0xF); } printf("\n"); } +#endif +#ifdef SSFN_PROFILING + gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + ctx->raster += tvd.tv_sec * 1000000L + tvd.tv_usec; + memcpy(&tv0, &tv1, sizeof(struct timeval)); +#endif + } + if(dst) { + /* blit glyph from cache into buffer */ + h = H; + if(h > ctx->line) ctx->line = h; + w = ctx->g->p * h / ctx->g->h; + s = ((ctx->g->x - ctx->g->o) * h + ctx->f->height - 1) / ctx->f->height; + n = ctx->size > 16 ? 2 : 1; + if(w < n) w = n; + if(s < n) s = n; + if(ctx->g->x) { + ctx->ox = ox = ((ctx->g->o * h + ctx->f->height - 1) / ctx->f->height) + (ctx->style & SSFN_STYLE_RTL ? w : 0); + ctx->oy = oy = (ctx->g->a * h + ctx->f->height - 1) / ctx->f->height; + } else { ctx->ox = ox = w / 2; ctx->oy = oy = 0; } + if(dst->ptr) { + j = dst->w < 0 ? -dst->w : dst->w; + cs = dst->w < 0 ? 16 : 0; + cb = (h + 64) >> 6; uix = w > s ? w : s; uax = 0; + n = (ctx->f->underline * h + ctx->f->height - 1) / ctx->f->height; +#ifdef SSFN_DEBUGGLYPH + printf("Scaling to w %d h %d (glyph %d %d, cache %d %d, font %d)\n", + w,h,ctx->rc->w,ctx->rc->h,ctx->g->p,ctx->g->h,ctx->f->height); +#endif + fR = (dst->fg >> 16) & 0xFF; fG = (dst->fg >> 8) & 0xFF; fB = (dst->fg >> 0) & 0xFF; fA = (dst->fg >> 24) & 0xFF; + bR = (dst->bg >> 16) & 0xFF; bG = (dst->bg >> 8) & 0xFF; bB = (dst->bg >> 0) & 0xFF; O = 0xFF000000; + Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy) + ((dst->x - ox) << 2)); + for (y = 0; y < h && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) { + if(dst->y + y - oy < 0) continue; + y0 = (y << 8) * ctx->g->h / h; Y0 = y0 >> 8; y1 = ((y + 1) << 8) * ctx->g->h / h; Y1 = y1 >> 8; Ol = Op; + for (x = 0; x < w && dst->x + x - ox < j; x++, Ol++) { + if(dst->x + x - ox < 0) continue; + m = 0; sR = sG = sB = sA = 0; + if(!dst->bg) { + /* real linear frame buffers should be accessed only as uint32_t on 32 bit boundary */ + O = *Ol; + bR = (O >> (16 - cs)) & 0xFF; + bG = (O >> 8) & 0xFF; + bB = (O >> cs) & 0xFF; + } + x0 = (x << 8) * ctx->g->p / w; X0 = x0 >> 8; x1 = ((x + 1) << 8) * ctx->g->p / w; X1 = x1 >> 8; + for(ys = y0; ys < y1; ys += 256) { + if(ys >> 8 == Y0) { yp = 256 - (ys & 0xFF); ys &= ~0xFF; if(yp > y1 - y0) yp = y1 - y0; } + else if(ys >> 8 == Y1) yp = y1 & 0xFF; else yp = 256; + X2 = (ys >> 8) * ctx->g->p; + for(xs = x0; xs < x1; xs += 256) { + if (xs >> 8 == X0) { + k = 256 - (xs & 0xFF); xs &= ~0xFF; if(k > x1 - x0) k = x1 - x0; pc = k == 256 ? yp : (k * yp)>>8; + } else + if (xs >> 8 == X1) { k = x1 & 0xFF; pc = k == 256 ? yp : (k * yp) >> 8; } + else pc = yp; + m += pc; + k = ctx->g->data[X2 + (xs >> 8)]; + if(k == 0xFF) { + sB += bB * pc; sG += bG * pc; sR += bR * pc; sA += 255; + } else { + if(k == 0xFE || !ctx->f->cmap_offs) { + dB = fB; dG = fG; dR = fR; dA = fA; + } else { + P = *((uint32_t*)((uint8_t*)ctx->f + ctx->f->cmap_offs + (k << 2))); + dR = (P >> 16) & 0xFF; dG = (P >> 8) & 0xFF; dB = (P >> 0) & 0xFF; dA = (P >> 24) & 0xFF; + } + if(dA == 255) { + sB += dB * pc; sG += dG * pc; sR += dR * pc; sA += dA * pc; + } else { + sB += (dB * dA + bB * (255 - dA)) * pc / 255; sG += (dG * dA + bG * (255 - dA)) * pc / 255; + sR += (dR * dA + bR * (255 - dA)) * pc / 255; sA += dA * pc; + } + } + } + } + if(m) { sR /= m; sG /= m; sB /= m; sA /= m; } else { sR >>= 8; sG >>= 8; sB >>= 8; sA >>= 8; } + if(ctx->style & SSFN_STYLE_NOAA) sA = sA > 127 ? 255 : 0; + if(sA > 15) { + *Ol = (ctx->style & SSFN_STYLE_A ? O & 0xFF000000 : ((sA > 255 ? 255 : sA) << 24)) | + ((sR > 255 ? 255 : sR) << (16 - cs)) | ((sG > 255 ? 255 : sG) << 8) | ((sB > 255 ? 255 : sB) << cs); + if(y == n) { if(uix > x) { uix = x; } if(uax < x) { uax = x; } } + } + } + } + if(ctx->style & SSFN_STYLE_UNDERLINE) { + uix -= cb + 1; uax += cb + 2; + if(uax < uix) uax = uix + 1; + k = (w > s ? w : s); + Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2)); + for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) { + if(dst->y + y - oy < 0) continue; + for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) { + if(dst->x + x - ox < 0 || (x > uix && x < uax)) continue; + PUTPIXEL; + } + } + } + if(ctx->style & SSFN_STYLE_STHROUGH) { + n = (h >> 1); k = (w > s ? w : s) + 1; + Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2)); + for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) { + if(dst->y + y - oy < 0) continue; + for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) { + if(dst->x + x - ox < 0) continue; + PUTPIXEL; + } + } + } +#ifdef SSFN_PROFILING + gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + ctx->blit += tvd.tv_sec * 1000000L + tvd.tv_usec; + memcpy(&tv0, &tv1, sizeof(struct timeval)); +#endif + } + /* add advance and kerning */ + ctx->ax = (ctx->style & SSFN_STYLE_RTL ? -s : s); + dst->x += ctx->ax; + dst->y += (ctx->g->y * h + ctx->f->height - 1) / ctx->f->height; + ptr = (uint8_t*)str + ret; + if(!(ctx->style & SSFN_STYLE_NOKERN) && ctx->f->kerning_offs && _ssfn_c(ctx->f, (const char*)ptr, &i, &P) && P > 32) { + ptr = (uint8_t*)ctx->rc + sizeof(ssfn_chr_t); + /* check all kerning fragments, because we might have both vertical and horizontal kerning offsets */ + for(n = 0; n < ctx->rc->n; n++) { + if(ptr[0] == 255 && ptr[1] == 255) { ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; } + x = ptr[0]; + if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; } + else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; } + frg = (uint8_t*)ctx->f + m; + if((frg[0] & 0xE0) == 0xC0) { + k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; frg += 2; + while(k--) { + m = ((frg[2] & 0xF) << 16) | (frg[1] << 8) | frg[0]; + if(P >= (uint32_t)m && P <= (uint32_t)(((frg[5] & 0xF) << 16) | (frg[4] << 8) | frg[3])) { + P -= m; + m = ctx->f->kerning_offs + ((((frg[2] >> 4) & 0xF) << 24) | (((frg[5] >> 4) & 0xF) << 16) | + (frg[7] << 8) | frg[6]); + tmp = (uint8_t*)ctx->f + m; + while(tmp < (uint8_t*)ctx->f + ctx->f->size - 4) { + if((uint32_t)(tmp[0] & 0x7F) < P) { + P -= (tmp[0] & 0x7F) + 1; + tmp += 2 + (tmp[0] & 0x80 ? 0 : tmp[0] & 0x7F); + } else { + y = (int)((signed char)tmp[1 + ((tmp[0] & 0x80) ? 0 : P)]) * h / ctx->f->height; + if(x) dst->x += y; else dst->y += y; + break; + } + } + break; + } + frg += 8; + } + } + } +#ifdef SSFN_PROFILING + gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + ctx->kern += tvd.tv_sec * 1000000L + tvd.tv_usec; +#endif + } + } + return ret; +} + +/** + * Get the bounding box for a string + + * @param ctx rendering context + * @param str string to measure + * @param w returned width + * @param h returned height + * @param left returned left margin + * @param top returned ascender + * @return error code + */ +int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top) +{ + ssfn_buf_t buf; + int ret, f = 1, l = 0, t = 0; + + if(!ctx || !str) return SSFN_ERR_INVINP; + if(w) {*w = 0;} if(h) {*h = 0;} if(top) {*top = 0;} if(left) {*left = 0;} + if(!*str) return SSFN_OK; + SSFN_memset(&buf, 0, sizeof(ssfn_buf_t)); ctx->line = 0; + while((ret = ssfn_render(ctx, &buf, str))) { + if(ret < 0 || !ctx->g) return ret; + if(f) { f = 0; l = ctx->ox; buf.x += l; } + if(ctx->g->x) { + if(ctx->oy > t) t = ctx->oy; + } else { + if(buf.w < ctx->g->p) buf.w = ctx->g->p; + buf.h += ctx->g->y ? ctx->g->y : ctx->g->h; + } + str += ret; + } + if((ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC)) + buf.x += ctx->size / SSFN_ITALIC_DIV - l; + if(ctx->g->x) { if(w) {*w = buf.x;} if(h) {*h = ctx->line;} if(left) {*left = l;} if(top) {*top = t;} } + else { if(w) {*w = buf.w;} if(h) {*h = buf.y;} if(top) {*top = 0;} if(left) {*left = 0;} } + return SSFN_OK; +} + +/** + * Render text to a newly allocated pixel buffer + * + * @param ctx rendering context + * @param str string to measure + * @return a newly allocated pixel buffer or NULL + */ +ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg) +{ +#ifndef SSFN_MAXLINES + ssfn_buf_t *buf; + int ret; + + if(!ctx || !str) return NULL; + buf = (ssfn_buf_t*)SSFN_realloc(NULL, sizeof(ssfn_buf_t)); + if(!buf) return NULL; + SSFN_memset(buf, 0, sizeof(ssfn_buf_t)); + buf->fg = fg; + if(!*str || ssfn_bbox(ctx, str, (int*)&buf->w, (int*)&buf->h, (int*)&buf->x, (int*)&buf->y) != SSFN_OK) + return buf; + buf->p = buf->w * (uint8_t)sizeof(uint32_t); + buf->ptr = (uint8_t*)SSFN_realloc(NULL, buf->p * buf->h); + SSFN_memset(buf->ptr, 0, buf->p * buf->h); + ctx->style &= ~SSFN_STYLE_A; + while((ret = ssfn_render(ctx, buf, str)) > 0) + str += ret; + if(ret != SSFN_OK) { SSFN_free(buf->ptr); SSFN_free(buf); return NULL; } + return buf; +#else + (void)ctx; + (void)str; + (void)fg; + return NULL; +#endif +} + +#endif /* SSFN_IMPLEMENTATION */ + +#if defined(SSFN_CONSOLEBITMAP_PALETTE) || defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR) +/*** special console bitmap font renderer (ca. 1.5k, no dependencies, no memory allocation and no error checking) ***/ + +/** + * public variables to configure + */ +ssfn_font_t *ssfn_src; /* font buffer with an inflated bitmap font */ +ssfn_buf_t ssfn_dst; /* destination frame buffer */ + +/** + * Minimal OS kernel console renderer + * + * @param unicode character + * @return error code + */ +int ssfn_putc(uint32_t unicode) +{ +# ifdef SSFN_CONSOLEBITMAP_PALETTE +# define SSFN_PIXEL uint8_t +# else +# ifdef SSFN_CONSOLEBITMAP_HICOLOR +# define SSFN_PIXEL uint16_t +# else +# define SSFN_PIXEL uint32_t +# endif +# endif + register SSFN_PIXEL *o, *p; + register uint8_t *ptr, *chr = NULL, *frg; + register int i, j, k, l, m, y = 0, w, s = ssfn_dst.p / sizeof(SSFN_PIXEL); + + if(!ssfn_src || ssfn_src->magic[0] != 'S' || ssfn_src->magic[1] != 'F' || ssfn_src->magic[2] != 'N' || + ssfn_src->magic[3] != '2' || !ssfn_dst.ptr || !ssfn_dst.p) return SSFN_ERR_INVINP; + w = ssfn_dst.w < 0 ? -ssfn_dst.w : ssfn_dst.w; + for(ptr = (uint8_t*)ssfn_src + ssfn_src->characters_offs, i = 0; i < 0x110000; i++) { + if(ptr[0] == 0xFF) { i += 65535; ptr++; } + else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; } + else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; } + else { if((uint32_t)i == unicode) { chr = ptr; break; } ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); } + } +#ifdef SSFN_CONSOLEBITMAP_CONTROL + i = ssfn_src->height; j = ssfn_dst.h - i - (ssfn_dst.h % i); + if(chr && w) { + if(unicode == '\t') ssfn_dst.x -= ssfn_dst.x % chr[4]; + if(ssfn_dst.x + chr[4] > w) { ssfn_dst.x = 0; ssfn_dst.y += i; } + } + if(unicode == '\n') ssfn_dst.y += i; + if(j > 0 && ssfn_dst.y > j) { + ssfn_dst.y = j; + for(k = 0; k < j; k++) + for(l = 0; l < ssfn_dst.p; l++) ssfn_dst.ptr[k * ssfn_dst.p + l] = ssfn_dst.ptr[(k + i) * ssfn_dst.p + l]; + } + if(unicode == '\r' || unicode == '\n') { ssfn_dst.x = 0; return SSFN_OK; } +#endif + if(!chr) return SSFN_ERR_NOGLYPH; + ptr = chr + 6; o = (SSFN_PIXEL*)(ssfn_dst.ptr + ssfn_dst.y * ssfn_dst.p + ssfn_dst.x * sizeof(SSFN_PIXEL)); + for(i = 0; i < chr[1]; i++, ptr += chr[0] & 0x40 ? 6 : 5) { + if(ptr[0] == 255 && ptr[1] == 255) continue; + frg = (uint8_t*)ssfn_src + (chr[0] & 0x40 ? ((ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]) : + ((ptr[4] << 16) | (ptr[3] << 8) | ptr[2])); + if((frg[0] & 0xE0) != 0x80) continue; + if(ssfn_dst.bg) { + for(; y < ptr[1] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) { + for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++) + *p = ssfn_dst.bg; + } + } else { o += (int)(ptr[1] - y) * s; y = ptr[1]; } + k = ((frg[0] & 0x1F) + 1) << 3; j = frg[1] + 1; frg += 2; + for(m = 1; j && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); j--, y++, o += s) + for(p = o, l = 0; l < k; l++, p++, m <<= 1) { + if(m > 0x80) { frg++; m = 1; } + if(ssfn_dst.x + l >= 0 && (!w || ssfn_dst.x + l < w)) { + if(*frg & m) *p = ssfn_dst.fg; else + if(ssfn_dst.bg) *p = ssfn_dst.bg; + } + } + } + if(ssfn_dst.bg) + for(; y < chr[3] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) { + for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++) + *p = ssfn_dst.bg; + } + ssfn_dst.x += chr[4]; ssfn_dst.y += chr[5]; + return SSFN_OK; +} + +#endif /* SSFN_CONSOLEBITMAP */ + +/* */ +#endif /* _SSFN_H_ */ diff --git a/src/XDON-OG/XDON/stdafx.h b/src/XDON-OG/XDON/stdafx.h index aa8a01c..556fd5a 100644 --- a/src/XDON-OG/XDON/stdafx.h +++ b/src/XDON-OG/XDON/stdafx.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include