From 428532865387840fdb11874d1c7dd27c42aa7400 Mon Sep 17 00:00:00 2001 From: Subs Date: Thu, 27 Jul 2023 23:09:20 +0200 Subject: [PATCH] Squashed 'deps/switchres/' content from commit 4df022c68a git-subtree-dir: deps/switchres git-subtree-split: 4df022c68a43b6481e18d5aa8e0ea27481291d1a --- .github/workflows/build.yml | 64 + .gitignore | 10 + .gitlab-ci.yml | 59 + README.md | 60 + custom_video.cpp | 178 ++ custom_video.h | 107 + custom_video_adl.cpp | 532 +++++ custom_video_adl.h | 201 ++ custom_video_ati.cpp | 343 ++++ custom_video_ati.h | 53 + custom_video_ati_family.cpp | 848 ++++++++ custom_video_drmkms.cpp | 1276 ++++++++++++ custom_video_drmkms.h | 97 + custom_video_pstrip.cpp | 628 ++++++ custom_video_pstrip.h | 83 + custom_video_xrandr.cpp | 1204 +++++++++++ custom_video_xrandr.h | 123 ++ display.cpp | 547 +++++ display.h | 225 +++ display_linux.cpp | 171 ++ display_linux.h | 30 + display_sdl2.cpp | 304 +++ display_sdl2.h | 32 + display_windows.cpp | 311 +++ display_windows.h | 45 + drm_hook.cpp | 211 ++ edid.cpp | 244 +++ edid.h | 37 + examples/README.md | 56 + examples/multi_monitor.cpp | 31 + examples/test_dlopen.cpp | 84 + examples/test_liblink.cpp | 36 + font.h | 3776 +++++++++++++++++++++++++++++++++++ geometry.py | 324 +++ grid.cpp | 410 ++++ log.cpp | 78 + log.h | 38 + makefile | 159 ++ modeline.cpp | 917 +++++++++ modeline.h | 144 ++ monitor.cpp | 437 ++++ monitor.h | 64 + resync_windows.cpp | 171 ++ resync_windows.h | 43 + switchres.cpp | 411 ++++ switchres.h | 70 + switchres.ini | 165 ++ switchres_defines.h | 41 + switchres_main.cpp | 354 ++++ switchres_wrapper.cpp | 435 ++++ switchres_wrapper.h | 190 ++ tests/test_dlopen.cpp | 47 + tests/test_liblink.cpp | 7 + tv.ico | Bin 0 -> 67646 bytes 54 files changed, 16511 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 README.md create mode 100644 custom_video.cpp create mode 100644 custom_video.h create mode 100644 custom_video_adl.cpp create mode 100644 custom_video_adl.h create mode 100644 custom_video_ati.cpp create mode 100644 custom_video_ati.h create mode 100644 custom_video_ati_family.cpp create mode 100755 custom_video_drmkms.cpp create mode 100755 custom_video_drmkms.h create mode 100644 custom_video_pstrip.cpp create mode 100644 custom_video_pstrip.h create mode 100644 custom_video_xrandr.cpp create mode 100644 custom_video_xrandr.h create mode 100644 display.cpp create mode 100644 display.h create mode 100644 display_linux.cpp create mode 100644 display_linux.h create mode 100644 display_sdl2.cpp create mode 100644 display_sdl2.h create mode 100644 display_windows.cpp create mode 100644 display_windows.h create mode 100644 drm_hook.cpp create mode 100644 edid.cpp create mode 100644 edid.h create mode 100644 examples/README.md create mode 100644 examples/multi_monitor.cpp create mode 100644 examples/test_dlopen.cpp create mode 100644 examples/test_liblink.cpp create mode 100644 font.h create mode 100644 geometry.py create mode 100644 grid.cpp create mode 100644 log.cpp create mode 100644 log.h create mode 100644 makefile create mode 100644 modeline.cpp create mode 100644 modeline.h create mode 100644 monitor.cpp create mode 100644 monitor.h create mode 100644 resync_windows.cpp create mode 100644 resync_windows.h create mode 100644 switchres.cpp create mode 100644 switchres.h create mode 100644 switchres.ini create mode 100644 switchres_defines.h create mode 100644 switchres_main.cpp create mode 100644 switchres_wrapper.cpp create mode 100644 switchres_wrapper.h create mode 100644 tests/test_dlopen.cpp create mode 100644 tests/test_liblink.cpp create mode 100644 tv.ico diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000000..f363537afa2 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,64 @@ +name: Switchres CIv2 + +on: [push, pull_request] + +jobs: + buildx86_64: + runs-on: ubuntu-latest + name: ${{ matrix.platform.name }} ${{ matrix.config.name }} + strategy: + matrix: + platform: + - { name: Linux GCC } + - { name: Windows MINGW, make_opts: PLATFORM=NT CROSS_COMPILE=x86_64-w64-mingw32- } + + steps: + - uses: actions/checkout@v3 + - name: Install Linux dependencies + if: matrix.platform.name == 'Linux GCC' + run: sudo apt-get install libxrandr-dev libdrm-dev libsdl2-dev + - name: Install Windows dependencies + if: matrix.platform.name == 'Windows MINGW' + run: | + sudo apt-get install mingw-w64 wget tar + sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix + wget https://github.com/libsdl-org/SDL/releases/download/release-2.26.2/SDL2-devel-2.26.2-mingw.tar.gz + tar xvzf SDL2-devel-2.26.2-mingw.tar.gz + sudo make -C SDL2-2.26.2 CROSS_PATH=/usr ARCHITECTURES=x86_64-w64-mingw32 cross + wget https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.20.1/SDL2_ttf-devel-2.20.1-mingw.tar.gz + tar xvzf SDL2_ttf-devel-2.20.1-mingw.tar.gz + sudo make -C SDL2_ttf-2.20.1 CROSS_PATH=/usr ARCHITECTURES=x86_64-w64-mingw32 cross + - name: Build libs and binary + run: | + make libswitchres ${{matrix.platform.make_opts}} + make ${{matrix.platform.make_opts}} + - name: Build grid.exe (Windows only) + if: matrix.platform.name == 'Windows MINGW' + run: | + make ${{matrix.platform.make_opts}} clean + make ${{matrix.platform.make_opts}} grid + - name: Prepare artifacts + run: mkdir artifacts && cp -v libswitchres.{so,a,dll,lib} switchres{,.exe,.ini} grid{,.exe} /usr/x86_64-w64-mingw32/bin/SDL2{,_ttf}.dll /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll artifacts/ || true + - name: Upload artifact + uses: actions/upload-artifact@v3.1.0 + with: + name: switchres-${{matrix.platform.name}}-x86_64 + path: artifacts/ + + win32-build-x86_64-geometry: + + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Build geometry.exe + run: | + pip install pyinstaller + pyinstaller --onefile geometry.py --icon=tv.ico + - name: Upload artifact + uses: actions/upload-artifact@v3.1.0 + with: + name: geometry-win32-x86_64 + path: dist/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..467e3df2724 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.o +*.exe +*.a +*.so.* +*.lib +*.dll +switchres_main +grid +switchres +switchres.pc diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000000..f1c9fb9f795 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,59 @@ +# This file is a template, and might need editing before it works on your project. +# use the official gcc image, based on debian +# can use verions as well, like gcc:5.2 +# see https://hub.docker.com/_/gcc/ +image: gcc:latest + +before_script: + - apt update + - apt -y install make + +.pre_requisites_linux: &prerequisiteslinux + before_script: + - apt update + - apt -y install make + +.pre_requisites_win32: &prerequisiteswin32 + image: "ubuntu:rolling" + before_script: + - apt update + - apt -y install make mingw-w64 + + +linux:x86_64:standalone: + stage: build + <<: *prerequisiteslinux + script: + - make + +linux:x86_64:lib: + stage: build + <<: *prerequisiteslinux + script: + - make libswitchres + +win32:x86_64:standalone: + stage: build + <<: *prerequisiteswin32 + script: + - make PLATFORM=NT CROSS_COMPILE=x86_64-w64-mingw32- + +win32:x86_64:lib: + stage: build + <<: *prerequisiteswin32 + script: + - make PLATFORM=NT CROSS_COMPILE=x86_64-w64-mingw32- libswitchres + + +win32:i686:standalone: + stage: build + <<: *prerequisiteswin32 + script: + - make PLATFORM=NT CROSS_COMPILE=i686-w64-mingw32- + + +win32:i686:lib: + stage: build + <<: *prerequisiteswin32 + script: + - make PLATFORM=NT CROSS_COMPILE=i686-w64-mingw32- libswitchres \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000000..9ee0fc8e117 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# What is Switchres 2.0 +Switchres is a modeline generation engine for emulation. + +Its purpose is on-the-fly creation of fully customized video modes that accurately reproduce those of the emulated systems. Based on a monitor profile, it will provide the best video mode for a given width, height, and refresh rate. + +Switchres features the most versatile modeline generation ever, ranging from 15-kHz low resolutions up to modern 8K, with full geometry control, smart scaling, refresh scaling, mode rotation, aspect ratio correction and much more. + +Switchres can be integrated into open-source emulators either as a library, or used as a standalone emulator launcher. It's written in C++ and a C wrapper is also available. + +Switchres 2.0 is a rewrite of the original Switchres code used in GroovyMAME. It currently supports mode switching on the following platforms, with their respective backends: + - **Windows**: + - AMD ADL (AMD Radeon HD 5000+) + - ATI legacy (ATI Radeon pre-HD 5000) + - PowerStrip (ATI, Nvidia, Matrox, etc., models up to 2012) + - **Linux**: + - X11/Xorg + - KMS/DRM (WIP) + +Each platform supports a different feature set, being X11/Xorg the most performant currently. In general, AMD video cards offer the best compatibility, and are a real requirement for the Windows platform. + +# Using Switchres as a library +If you are an emulator writer, you can integrate Switchres into your emulator in two ways: + +- **Switchres shared library** (.dll or .so). This method offers a simplified way to add advanced mode switching features to your emulator, with minimal knowledge of Switchres internals. + +- **Full Switchres integration**. If your emulator is written in C++, you can gain full access to Switchres' gears by including a Switchres manager class into your project, à la GroovyMAME. + +Ask our devs for help and advice. + +# Using Switchres standalone +The standalone binary supports the following options: +``` +Usage: switchres [options] +Options: + -c, --calc Calculate video mode and exit + -s, --switch Switch to video mode + -l, --launch Launch + -m, --monitor Monitor preset (generic_15, arcade_15, pal, ntsc, etc.) + -a --aspect Monitor aspect ratio + -r --rotated Original mode's native orientation is rotated + -d, --display Use target display (Windows: \\\\.\\DISPLAY1, ... Linux: VGA-0, ...) + -f, --force x@ Force a specific video mode from display mode list + -i, --ini Specify an ini file + -b, --backend Specify the api name + -k, --keep Keep changes on exit (warning: this disables cleanup) +``` + +A default `switchres.ini` file will be searched in the current working directory, then in `.\ini` on Windows, `./ini` then `/etc` on Linux. The repo has a switchres.ini example. + +## Examples +`switchres 320 240 60 --calc` will calculate and show a modeline for 320x240@60, computed using the current monitor preset in `switchres.ini`. + +`switchres 320 240 60 -m ntsc -s` will switch your primary screen to 320x240 at 60Hz using the ntsc monitor model. Then it will wait until you press enter, and restore your initial screen resolution on exit. + +`switchres 384 256 55.017605 -m arcade_15 -s -d \\.\DISPLAY1 -l "mame rtype"` will switch your display #1 to 384x256@55.017605 using the arcade_15 preset, then launch ``mame rtype``. Once mame has exited, it will restore the original resolution. + +`switchres 640 480 57 -d 0 -m arcade_15 -d 1 -m arcade_31 -s` will set 640x480@57i (15-kHz preset) on your first display (index #0), 640x480@57p (31-kHz preset) on your second display (index #1) + +# License +GNU General Public License, version 2 or later (GPL-2.0+). diff --git a/custom_video.cpp b/custom_video.cpp new file mode 100644 index 00000000000..32989f5173d --- /dev/null +++ b/custom_video.cpp @@ -0,0 +1,178 @@ +/************************************************************** + + custom_video.cpp - Custom video library + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + + + +#include +#include "custom_video.h" +#include "log.h" + +#if defined(_WIN32) +#include "custom_video_ati.h" +#include "custom_video_adl.h" +#include "custom_video_pstrip.h" +#elif defined(__linux__) +#ifdef SR_WITH_XRANDR +#include "custom_video_xrandr.h" +#endif +#ifdef SR_WITH_KMSDRM +#include "custom_video_drmkms.h" +#endif +#endif + + +extern bool ati_is_legacy(int vendor, int device); + +//============================================================ +// custom_video::make +//============================================================ + +custom_video *custom_video::make(char *device_name, char *device_id, int method, custom_video_settings *vs) +{ +#if defined(_WIN32) + if (method == CUSTOM_VIDEO_TIMING_POWERSTRIP) + { + m_custom_video = new pstrip_timing(device_name, vs); + if (m_custom_video) + { + m_custom_method = CUSTOM_VIDEO_TIMING_POWERSTRIP; + return m_custom_video; + } + } + else + { + int vendor, device; + sscanf(device_id, "PCI\\VEN_%x&DEV_%x", &vendor, &device); + + if (vendor == 0x1002) // ATI/AMD + { + if (ati_is_legacy(vendor, device)) + { + m_custom_video = new ati_timing(device_name, vs); + if (m_custom_video) + { + m_custom_method = CUSTOM_VIDEO_TIMING_ATI_LEGACY; + return m_custom_video; + } + } + else + { + m_custom_video = new adl_timing(device_name, vs); + if (m_custom_video) + { + m_custom_method = CUSTOM_VIDEO_TIMING_ATI_ADL; + return m_custom_video; + } + } + } + else + log_info("Video chipset is not compatible.\n"); + } +#elif defined(__linux__) + if (device_id != NULL) + log_info("Device value is %s.\n", device_id); + +#ifdef SR_WITH_XRANDR + if (method == CUSTOM_VIDEO_TIMING_XRANDR || method == 0) + { + try + { + m_custom_video = new xrandr_timing(device_name, vs); + } + catch (...) {}; + if (m_custom_video) + { + m_custom_method = CUSTOM_VIDEO_TIMING_XRANDR; + return m_custom_video; + } + } +#endif /* SR_WITH_XRANDR */ + +#ifdef SR_WITH_KMSDRM + if (method == CUSTOM_VIDEO_TIMING_DRMKMS || method == 0) + { + m_custom_video = new drmkms_timing(device_name, vs); + if (m_custom_video) + { + m_custom_method = CUSTOM_VIDEO_TIMING_DRMKMS; + return m_custom_video; + } + } +#endif /* SR_WITH_KMSDRM */ +#endif + + return this; +} + +//============================================================ +// custom_video::init +//============================================================ + +bool custom_video::init() { return false; } + +//============================================================ +// custom_video::get_timing +//============================================================ + +bool custom_video::get_timing(modeline *mode) +{ + log_verbose("system mode\n"); + mode->type |= CUSTOM_VIDEO_TIMING_SYSTEM; + return false; +} + +//============================================================ +// custom_video::set_timing +//============================================================ + +bool custom_video::set_timing(modeline *) +{ + return false; +} + +//============================================================ +// custom_video::add_mode +//============================================================ + +bool custom_video::add_mode(modeline *) +{ + return false; +} + +//============================================================ +// custom_video::delete_mode +//============================================================ + +bool custom_video::delete_mode(modeline *) +{ + return false; +} + +//============================================================ +// custom_video::update_mode +//============================================================ + +bool custom_video::update_mode(modeline *) +{ + return false; +} + +//============================================================ +// custom_video::process_modelist +//============================================================ + +bool custom_video::process_modelist(std::vector) +{ + return false; +} diff --git a/custom_video.h b/custom_video.h new file mode 100644 index 00000000000..4d393da8f08 --- /dev/null +++ b/custom_video.h @@ -0,0 +1,107 @@ +/************************************************************** + + custom_video.h - Custom video library header + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __CUSTOM_VIDEO__ +#define __CUSTOM_VIDEO__ + +#include +#include +#include "modeline.h" + + +#define CUSTOM_VIDEO_TIMING_MASK 0x00000ff0 +#define CUSTOM_VIDEO_TIMING_AUTO 0x00000000 +#define CUSTOM_VIDEO_TIMING_SYSTEM 0x00000010 +#define CUSTOM_VIDEO_TIMING_XRANDR 0x00000020 +#define CUSTOM_VIDEO_TIMING_POWERSTRIP 0x00000040 +#define CUSTOM_VIDEO_TIMING_ATI_LEGACY 0x00000080 +#define CUSTOM_VIDEO_TIMING_ATI_ADL 0x00000100 +#define CUSTOM_VIDEO_TIMING_DRMKMS 0x00000200 + +// Custom video caps +#define CUSTOM_VIDEO_CAPS_UPDATE 0x001 +#define CUSTOM_VIDEO_CAPS_ADD 0x002 +#define CUSTOM_VIDEO_CAPS_DESKTOP_EDITABLE 0x004 +#define CUSTOM_VIDEO_CAPS_SCAN_EDITABLE 0x008 + +// Timing creation commands +#define TIMING_DELETE 0x001 +#define TIMING_CREATE 0x002 +#define TIMING_UPDATE 0x004 +#define TIMING_UPDATE_LIST 0x008 + +typedef struct custom_video_settings +{ + bool screen_compositing; + bool screen_reordering; + bool allow_hardware_refresh; + char device_reg_key[128]; + char custom_timing[256]; +} custom_video_settings; + +class custom_video +{ +public: + + custom_video() {}; + virtual ~custom_video() + { + if (m_custom_video) + { + delete m_custom_video; + m_custom_video = nullptr; + } + }; + + custom_video *make(char *device_name, char *device_id, int method, custom_video_settings *vs); + virtual const char *api_name() { return "empty"; } + virtual bool init(); + virtual int caps() { return 0; } + + virtual bool add_mode(modeline *mode); + virtual bool delete_mode(modeline *mode); + virtual bool update_mode(modeline *mode); + + virtual bool get_timing(modeline *mode); + virtual bool set_timing(modeline *mode); + + virtual bool process_modelist(std::vector); + + // getters + bool screen_compositing() { return m_vs.screen_compositing; } + bool screen_reordering() { return m_vs.screen_reordering; } + bool allow_hardware_refresh() { return m_vs.allow_hardware_refresh; } + const char *custom_timing() { return (const char*) &m_vs.custom_timing; } + + // setters + void set_screen_compositing(bool value) { m_vs.screen_compositing = value; } + void set_screen_reordering(bool value) { m_vs.screen_reordering = value; } + void set_allow_hardware_refresh(bool value) { m_vs.allow_hardware_refresh = value; } + void set_custom_timing(const char *custom_timing) { strncpy(m_vs.custom_timing, custom_timing, sizeof(m_vs.custom_timing)-1); } + + // options + custom_video_settings m_vs = {}; + + modeline m_user_mode = {}; + modeline m_backup_mode = {}; + +private: + char m_device_name[32]; + char m_device_key[128]; + + custom_video *m_custom_video = 0; + int m_custom_method; +}; + +#endif diff --git a/custom_video_adl.cpp b/custom_video_adl.cpp new file mode 100644 index 00000000000..699bf250d6b --- /dev/null +++ b/custom_video_adl.cpp @@ -0,0 +1,532 @@ +/************************************************************** + + custom_video_adl.cpp - ATI/AMD ADL library + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +// Constants and structures ported from AMD ADL SDK files + +#include +#include +#include "custom_video_adl.h" +#include "log.h" + + +//============================================================ +// memory allocation callbacks +//============================================================ + +void* __stdcall ADL_Main_Memory_Alloc(int iSize) +{ + void* lpBuffer = malloc(iSize); + return lpBuffer; +} + +void __stdcall ADL_Main_Memory_Free(void** lpBuffer) +{ + if (NULL != *lpBuffer) + { + free(*lpBuffer); + *lpBuffer = NULL; + } +} + +//============================================================ +// adl_timing::adl_timing +//============================================================ + +adl_timing::adl_timing(char *display_name, custom_video_settings *vs) +{ + m_vs = *vs; + strcpy (m_display_name, display_name); + strcpy (m_device_key, m_vs.device_reg_key); +} + +//============================================================ +// adl_timing::~adl_timing +//============================================================ + +adl_timing::~adl_timing() +{ + close(); +} + +//============================================================ +// adl_timing::init +//============================================================ + +bool adl_timing::init() +{ + int ADL_Err = ADL_ERR; + + log_verbose("ATI/AMD ADL init\n"); + + ADL_Err = open(); + if (ADL_Err != ADL_OK) + { + log_verbose("ERROR: ADL Initialization error!\n"); + return false; + } + + ADL2_Adapter_NumberOfAdapters_Get = (ADL2_ADAPTER_NUMBEROFADAPTERS_GET) (void *) GetProcAddress(hDLL,"ADL2_Adapter_NumberOfAdapters_Get"); + if (ADL2_Adapter_NumberOfAdapters_Get == NULL) + { + log_verbose("ERROR: ADL2_Adapter_NumberOfAdapters_Get not available!"); + return false; + } + ADL2_Adapter_AdapterInfo_Get = (ADL2_ADAPTER_ADAPTERINFO_GET) (void *) GetProcAddress(hDLL,"ADL2_Adapter_AdapterInfo_Get"); + if (ADL2_Adapter_AdapterInfo_Get == NULL) + { + log_verbose("ERROR: ADL2_Adapter_AdapterInfo_Get not available!"); + return false; + } + ADL2_Display_DisplayInfo_Get = (ADL2_DISPLAY_DISPLAYINFO_GET) (void *) GetProcAddress(hDLL,"ADL2_Display_DisplayInfo_Get"); + if (ADL2_Display_DisplayInfo_Get == NULL) + { + log_verbose("ERROR: ADL2_Display_DisplayInfo_Get not available!"); + return false; + } + ADL2_Display_ModeTimingOverride_Get = (ADL2_DISPLAY_MODETIMINGOVERRIDE_GET) (void *) GetProcAddress(hDLL,"ADL2_Display_ModeTimingOverride_Get"); + if (ADL2_Display_ModeTimingOverride_Get == NULL) + { + log_verbose("ERROR: ADL2_Display_ModeTimingOverride_Get not available!"); + return false; + } + ADL2_Display_ModeTimingOverride_Set = (ADL2_DISPLAY_MODETIMINGOVERRIDE_SET) (void *) GetProcAddress(hDLL,"ADL2_Display_ModeTimingOverride_Set"); + if (ADL2_Display_ModeTimingOverride_Set == NULL) + { + log_verbose("ERROR: ADL2_Display_ModeTimingOverride_Set not available!"); + return false; + } + ADL2_Display_ModeTimingOverrideList_Get = (ADL2_DISPLAY_MODETIMINGOVERRIDELIST_GET) (void *) GetProcAddress(hDLL,"ADL2_Display_ModeTimingOverrideList_Get"); + if (ADL2_Display_ModeTimingOverrideList_Get == NULL) + { + log_verbose("ERROR: ADL2_Display_ModeTimingOverrideList_Get not available!"); + return false; + } + + ADL2_Flush_Driver_Data = (ADL2_FLUSH_DRIVER_DATA) (void *) GetProcAddress(hDLL,"ADL2_Flush_Driver_Data"); + if (ADL2_Flush_Driver_Data == NULL) + { + log_verbose("ERROR: ADL2_Flush_Driver_Data not available!"); + return false; + } + + if (!enum_displays()) + { + log_error("ADL error enumerating displays.\n"); + return false; + } + + if (!get_device_mapping_from_display_name()) + { + log_error("ADL error mapping display.\n"); + return false; + } + + if (!get_driver_version(m_device_key)) + { + log_error("ADL driver version unknown!.\n"); + } + + if (!get_timing_list()) + { + log_error("ADL error getting list of timing overrides.\n"); + } + + log_verbose("ADL functions retrieved successfully.\n"); + return true; +} + +//============================================================ +// adl_timing::adl_open +//============================================================ + +int adl_timing::open() +{ + ADL2_MAIN_CONTROL_CREATE ADL2_Main_Control_Create; + int ADL_Err = ADL_ERR; + + hDLL = LoadLibraryA("atiadlxx.dll"); + if (hDLL == NULL) hDLL = LoadLibraryA("atiadlxy.dll"); + + if (hDLL != NULL) + { + ADL2_Main_Control_Create = (ADL2_MAIN_CONTROL_CREATE) (void *) GetProcAddress(hDLL, "ADL2_Main_Control_Create"); + if (ADL2_Main_Control_Create != NULL) + ADL_Err = ADL2_Main_Control_Create(ADL_Main_Memory_Alloc, 1, &m_adl); + } + else + { + log_verbose("ADL Library not found!\n"); + } + + return ADL_Err; +} + +//============================================================ +// adl_timing::close +//============================================================ + +void adl_timing::close() +{ + ADL2_MAIN_CONTROL_DESTROY ADL2_Main_Control_Destroy; + + log_verbose("ATI/AMD ADL close\n"); + + for (int i = 0; i <= iNumberAdapters - 1; i++) + ADL_Main_Memory_Free((void **)&lpAdapter[i].m_display_list); + + ADL_Main_Memory_Free((void **)&lpAdapterInfo); + ADL_Main_Memory_Free((void **)&lpAdapter); + + ADL2_Main_Control_Destroy = (ADL2_MAIN_CONTROL_DESTROY) (void *) GetProcAddress(hDLL, "ADL2_Main_Control_Destroy"); + if (ADL2_Main_Control_Destroy != NULL) + ADL2_Main_Control_Destroy(m_adl); + + FreeLibrary(hDLL); +} + +//============================================================ +// adl_timing::get_driver_version +//============================================================ + +bool adl_timing::get_driver_version(char *device_key) +{ + HKEY hkey; + bool found = false; + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, device_key, 0, KEY_READ , &hkey) == ERROR_SUCCESS) + { + BYTE cat_ver[32]; + DWORD length = sizeof(cat_ver); + if ((RegQueryValueExA(hkey, "Catalyst_Version", NULL, NULL, cat_ver, &length) == ERROR_SUCCESS) || + (RegQueryValueExA(hkey, "RadeonSoftwareVersion", NULL, NULL, cat_ver, &length) == ERROR_SUCCESS) || + (RegQueryValueExA(hkey, "DriverVersion", NULL, NULL, cat_ver, &length) == ERROR_SUCCESS)) + { + found = true; + is_patched = (RegQueryValueExA(hkey, "CalamityRelease", NULL, NULL, NULL, NULL) == ERROR_SUCCESS); + sscanf((char *)cat_ver, "%d.%d", &cat_version, &sub_version); + log_verbose("AMD driver version %d.%d%s\n", cat_version, sub_version, is_patched? "(patched)":""); + } + RegCloseKey(hkey); + } + return found; +} + +//============================================================ +// adl_timing::enum_displays +//============================================================ + +bool adl_timing::enum_displays() +{ + ADL2_Adapter_NumberOfAdapters_Get(m_adl, &iNumberAdapters); + + lpAdapterInfo = (LPAdapterInfo)malloc(sizeof(AdapterInfo) * iNumberAdapters); + memset(lpAdapterInfo, '\0', sizeof(AdapterInfo) * iNumberAdapters); + ADL2_Adapter_AdapterInfo_Get(m_adl, lpAdapterInfo, sizeof(AdapterInfo) * iNumberAdapters); + + lpAdapter = (LPAdapterList)malloc(sizeof(AdapterList) * iNumberAdapters); + for (int i = 0; i <= iNumberAdapters - 1; i++) + { + lpAdapter[i].m_index = lpAdapterInfo[i].iAdapterIndex; + lpAdapter[i].m_bus = lpAdapterInfo[i].iBusNumber; + memcpy(&lpAdapter[i].m_name, &lpAdapterInfo[i].strAdapterName, ADL_MAX_PATH); + memcpy(&lpAdapter[i].m_display_name, &lpAdapterInfo[i].strDisplayName, ADL_MAX_PATH); + lpAdapter[i].m_num_of_displays = 0; + lpAdapter[i].m_display_list = 0; + + // Only get display info from target adapter (this api is very slow!) + if (!strcmp(lpAdapter[i].m_display_name, m_display_name)) + ADL2_Display_DisplayInfo_Get(m_adl, lpAdapter[i].m_index, &lpAdapter[i].m_num_of_displays, &lpAdapter[i].m_display_list, 1); + } + return true; +} + +//============================================================ +// adl_timing::get_device_mapping_from_display_name +//============================================================ + +bool adl_timing::get_device_mapping_from_display_name() +{ + for (int i = 0; i <= iNumberAdapters -1; i++) + { + if (!strcmp(m_display_name, lpAdapter[i].m_display_name)) + { + ADLDisplayInfo *display_list; + display_list = lpAdapter[i].m_display_list; + + for (int j = 0; j <= lpAdapter[i].m_num_of_displays - 1; j++) + { + if (lpAdapter[i].m_index == display_list[j].displayID.iDisplayLogicalAdapterIndex) + { + m_adapter_index = lpAdapter[i].m_index; + m_display_index = display_list[j].displayID.iDisplayLogicalIndex; + return true; + } + } + } + } + return false; +} + +//============================================================ +// adl_timing::display_mode_info_to_modeline +//============================================================ + +bool adl_timing::display_mode_info_to_modeline(ADLDisplayModeInfo *dmi, modeline *m) +{ + if (dmi->sDetailedTiming.sHTotal == 0) return false; + + ADLDetailedTiming dt; + memcpy(&dt, &dmi->sDetailedTiming, sizeof(ADLDetailedTiming)); + + if (dt.sHTotal == 0) return false; + + m->htotal = dt.sHTotal; + m->hactive = dt.sHDisplay; + m->hbegin = dt.sHSyncStart; + m->hend = dt.sHSyncWidth + m->hbegin; + m->vtotal = dt.sVTotal; + m->vactive = dt.sVDisplay; + m->vbegin = dt.sVSyncStart; + m->vend = dt.sVSyncWidth + m->vbegin; + m->interlace = (dt.sTimingFlags & ADL_DL_TIMINGFLAG_INTERLACED)? 1 : 0; + m->doublescan = (dt.sTimingFlags & ADL_DL_TIMINGFLAG_DOUBLE_SCAN)? 1 : 0; + m->hsync = ((dt.sTimingFlags & ADL_DL_TIMINGFLAG_H_SYNC_POLARITY)? 1 : 0) ^ invert_pol(1); + m->vsync = ((dt.sTimingFlags & ADL_DL_TIMINGFLAG_V_SYNC_POLARITY)? 1 : 0) ^ invert_pol(1) ; + m->pclock = dt.sPixelClock * 10000; + + m->height = m->height? m->height : dmi->iPelsHeight; + m->width = m->width? m->width : dmi->iPelsWidth; + m->refresh = m->refresh? m->refresh : dmi->iRefreshRate / interlace_factor(m->interlace, 1);; + m->hfreq = float(m->pclock / m->htotal); + m->vfreq = float(m->hfreq / m->vtotal) * (m->interlace? 2 : 1); + + return true; +} + +//============================================================ +// adl_timing::get_timing_list +//============================================================ + +bool adl_timing::get_timing_list() +{ + if (ADL2_Display_ModeTimingOverrideList_Get(m_adl, m_adapter_index, m_display_index, MAX_MODELINES, adl_mode, &m_num_of_adl_modes) != ADL_OK) return false; + + return true; +} + +//============================================================ +// adl_timing::get_timing_from_cache +//============================================================ + +bool adl_timing::get_timing_from_cache(modeline *m) +{ + ADLDisplayModeInfo *mode = 0; + + for (int i = 0; i < m_num_of_adl_modes; i++) + { + mode = &adl_mode[i]; + if (mode->iPelsWidth == m->width && mode->iPelsHeight == m->height && mode->iRefreshRate == m->refresh) + { + if ((m->interlace) && !(mode->sDetailedTiming.sTimingFlags & ADL_DL_TIMINGFLAG_INTERLACED)) + continue; + goto found; + } + } + + return false; + + found: + if (display_mode_info_to_modeline(mode, m)) return true; + + return false; +} + +//============================================================ +// adl_timing::get_timing +//============================================================ + +bool adl_timing::get_timing(modeline *m) +{ + ADLDisplayMode mode_in; + ADLDisplayModeInfo mode_info_out; + modeline m_temp = *m; + + //modeline to ADLDisplayMode + mode_in.iPelsHeight = m->height; + mode_in.iPelsWidth = m->width; + mode_in.iBitsPerPel = 32; + mode_in.iDisplayFrequency = m->refresh * interlace_factor(m->interlace, 1); + + if (ADL2_Display_ModeTimingOverride_Get(m_adl, m_adapter_index, m_display_index, &mode_in, &mode_info_out) != ADL_OK) goto not_found; + if (display_mode_info_to_modeline(&mode_info_out, &m_temp)) + { + if (m_temp.interlace == m->interlace) + { + memcpy(m, &m_temp, sizeof(modeline)); + m->type |= CUSTOM_VIDEO_TIMING_ATI_ADL; + return true; + } + } + + not_found: + + // Try to get timing from our cache (interlaced modes are not properly retrieved by ADL_Display_ModeTimingOverride_Get) + if (get_timing_from_cache(m)) + { + m->type |= CUSTOM_VIDEO_TIMING_ATI_ADL; + return true; + } + + return false; +} + +//============================================================ +// adl_timing::set_timing +//============================================================ + +bool adl_timing::set_timing(modeline *m) +{ + return set_timing_override(m, TIMING_UPDATE); +} + +//============================================================ +// adl_timing::set_timing_override +//============================================================ + +bool adl_timing::set_timing_override(modeline *m, int update_mode) +{ + ADLDisplayModeInfo mode_info = {}; + ADLDetailedTiming *dt; + modeline m_temp; + + //modeline to ADLDisplayModeInfo + mode_info.iTimingStandard = (update_mode & TIMING_DELETE)? ADL_DL_MODETIMING_STANDARD_DRIVER_DEFAULT : ADL_DL_MODETIMING_STANDARD_CUSTOM; + mode_info.iPossibleStandard = 0; + mode_info.iRefreshRate = m->refresh * interlace_factor(m->interlace, 0); + mode_info.iPelsWidth = m->width; + mode_info.iPelsHeight = m->height; + + //modeline to ADLDetailedTiming + dt = &mode_info.sDetailedTiming; + dt->sTimingFlags = (m->interlace? ADL_DL_TIMINGFLAG_INTERLACED : 0) | + (m->doublescan? ADL_DL_TIMINGFLAG_DOUBLE_SCAN: 0) | + (m->hsync ^ invert_pol(0)? ADL_DL_TIMINGFLAG_H_SYNC_POLARITY : 0) | + (m->vsync ^ invert_pol(0)? ADL_DL_TIMINGFLAG_V_SYNC_POLARITY : 0); + dt->sHTotal = m->htotal; + dt->sHDisplay = m->hactive; + dt->sHSyncStart = m->hbegin; + dt->sHSyncWidth = m->hend - m->hbegin; + dt->sVTotal = m->vtotal; + dt->sVDisplay = m->vactive; + dt->sVSyncStart = m->vbegin; + dt->sVSyncWidth = m->vend - m->vbegin; + dt->sPixelClock = m->pclock / 10000; + dt->sHOverscanRight = 0; + dt->sHOverscanLeft = 0; + dt->sVOverscanBottom = 0; + dt->sVOverscanTop = 0; + + if (ADL2_Display_ModeTimingOverride_Set(m_adl, m_adapter_index, m_display_index, &mode_info, (update_mode & TIMING_UPDATE_LIST)? 1 : 0) != ADL_OK) return false; + + //ADL2_Flush_Driver_Data(m_adl, m_adapter_index); + + // read modeline to trigger timing refresh on modded drivers + memcpy(&m_temp, m, sizeof(modeline)); + if (update_mode & TIMING_UPDATE) get_timing(&m_temp); + + return true; +} + +//============================================================ +// adl_timing::add_mode +//============================================================ + +bool adl_timing::add_mode(modeline *mode) +{ + if (!set_timing_override(mode, TIMING_UPDATE_LIST)) + { + return false; + } + + m_resync.wait(); + mode->type |= CUSTOM_VIDEO_TIMING_ATI_ADL; + + return true; +} + +//============================================================ +// adl_timing::delete_mode +//============================================================ + +bool adl_timing::delete_mode(modeline *mode) +{ + if (!set_timing_override(mode, TIMING_DELETE | TIMING_UPDATE_LIST)) + { + return false; + } + + m_resync.wait(); + + return true; +} + +//============================================================ +// adl_timing::update_mode +//============================================================ + +bool adl_timing::update_mode(modeline *mode) +{ + bool refresh_required = !is_patched || (mode->type & MODE_DESKTOP); + + if (!set_timing_override(mode, refresh_required? TIMING_UPDATE_LIST : TIMING_UPDATE)) + { + return false; + } + + if (refresh_required) m_resync.wait(); + mode->type |= CUSTOM_VIDEO_TIMING_ATI_ADL; + return true; +} + +//============================================================ +// adl_timing::process_modelist +//============================================================ + +bool adl_timing::process_modelist(std::vector modelist) +{ + bool refresh_required = false; + bool error = false; + + for (auto &mode : modelist) + { + if (mode->type & MODE_DELETE || mode->type & MODE_ADD || (mode->type & MODE_UPDATE && (!is_patched || (mode->type & MODE_DESKTOP)))) + refresh_required = true; + + bool is_last = (mode == modelist.back()); + + if (!set_timing_override(mode, (mode->type & MODE_DELETE? TIMING_DELETE : TIMING_UPDATE) | (is_last && refresh_required? TIMING_UPDATE_LIST : 0))) + { + mode->type |= MODE_ERROR; + error = true; + } + else + { + mode->type &= ~MODE_ERROR; + mode->type |= CUSTOM_VIDEO_TIMING_ATI_ADL; + } + } + + if (refresh_required) m_resync.wait(); + return !error; +} diff --git a/custom_video_adl.h b/custom_video_adl.h new file mode 100644 index 00000000000..456ad9395b0 --- /dev/null +++ b/custom_video_adl.h @@ -0,0 +1,201 @@ +/************************************************************** + + custom_video_adl.h - ATI/AMD ADL library header + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include "custom_video.h" +#include "resync_windows.h" + +// Constants and structures ported from AMD ADL SDK files +#define ADL_MAX_PATH 256 +#define ADL_OK 0 +#define ADL_ERR -1 + +//ADL_DETAILED_TIMING.sTimingFlags +#define ADL_DL_TIMINGFLAG_DOUBLE_SCAN 0x0001 +#define ADL_DL_TIMINGFLAG_INTERLACED 0x0002 +#define ADL_DL_TIMINGFLAG_H_SYNC_POLARITY 0x0004 +#define ADL_DL_TIMINGFLAG_V_SYNC_POLARITY 0x0008 + +//ADL_DISPLAY_MODE_INFO.iTimingStandard +#define ADL_DL_MODETIMING_STANDARD_CVT 0x00000001 // CVT Standard +#define ADL_DL_MODETIMING_STANDARD_GTF 0x00000002 // GFT Standard +#define ADL_DL_MODETIMING_STANDARD_DMT 0x00000004 // DMT Standard +#define ADL_DL_MODETIMING_STANDARD_CUSTOM 0x00000008 // User-defined standard +#define ADL_DL_MODETIMING_STANDARD_DRIVER_DEFAULT 0x00000010 // Remove Mode from overriden list +#define ADL_DL_MODETIMING_STANDARD_CVT_RB 0x00000020 // CVT-RB Standard + +typedef struct AdapterInfo +{ + int iSize; + int iAdapterIndex; + char strUDID[ADL_MAX_PATH]; + int iBusNumber; + int iDeviceNumber; + int iFunctionNumber; + int iVendorID; + char strAdapterName[ADL_MAX_PATH]; + char strDisplayName[ADL_MAX_PATH]; + int iPresent; + int iExist; + char strDriverPath[ADL_MAX_PATH]; + char strDriverPathExt[ADL_MAX_PATH]; + char strPNPString[ADL_MAX_PATH]; + int iOSDisplayIndex; +} AdapterInfo, *LPAdapterInfo; + +typedef struct ADLDisplayID +{ + int iDisplayLogicalIndex; + int iDisplayPhysicalIndex; + int iDisplayLogicalAdapterIndex; + int iDisplayPhysicalAdapterIndex; +} ADLDisplayID, *LPADLDisplayID; + + +typedef struct ADLDisplayInfo +{ + ADLDisplayID displayID; + int iDisplayControllerIndex; + char strDisplayName[ADL_MAX_PATH]; + char strDisplayManufacturerName[ADL_MAX_PATH]; + int iDisplayType; + int iDisplayOutputType; + int iDisplayConnector; + int iDisplayInfoMask; + int iDisplayInfoValue; +} ADLDisplayInfo, *LPADLDisplayInfo; + +typedef struct ADLDisplayMode +{ + int iPelsHeight; + int iPelsWidth; + int iBitsPerPel; + int iDisplayFrequency; +} ADLDisplayMode; + +typedef struct ADLDetailedTiming +{ + int iSize; + short sTimingFlags; + short sHTotal; + short sHDisplay; + short sHSyncStart; + short sHSyncWidth; + short sVTotal; + short sVDisplay; + short sVSyncStart; + short sVSyncWidth; + unsigned short sPixelClock; + short sHOverscanRight; + short sHOverscanLeft; + short sVOverscanBottom; + short sVOverscanTop; + short sOverscan8B; + short sOverscanGR; +} ADLDetailedTiming; + +typedef struct ADLDisplayModeInfo +{ + int iTimingStandard; + int iPossibleStandard; + int iRefreshRate; + int iPelsWidth; + int iPelsHeight; + ADLDetailedTiming sDetailedTiming; +} ADLDisplayModeInfo; + +typedef struct AdapterList +{ + int m_index; + int m_bus; + char m_name[ADL_MAX_PATH]; + char m_display_name[ADL_MAX_PATH]; + int m_num_of_displays; + ADLDisplayInfo *m_display_list; +} AdapterList, *LPAdapterList; + + +typedef void* ADL_CONTEXT_HANDLE; +typedef void* (__stdcall *ADL_MAIN_MALLOC_CALLBACK)(int); +typedef int (*ADL2_MAIN_CONTROL_CREATE)(ADL_MAIN_MALLOC_CALLBACK, int, ADL_CONTEXT_HANDLE *); +typedef int (*ADL2_MAIN_CONTROL_DESTROY)(ADL_CONTEXT_HANDLE); +typedef int (*ADL2_ADAPTER_NUMBEROFADAPTERS_GET) (ADL_CONTEXT_HANDLE, int*); +typedef int (*ADL2_ADAPTER_ADAPTERINFO_GET) (ADL_CONTEXT_HANDLE, LPAdapterInfo, int); +typedef int (*ADL2_DISPLAY_DISPLAYINFO_GET) (ADL_CONTEXT_HANDLE, int, int *, ADLDisplayInfo **, int); +typedef int (*ADL2_DISPLAY_MODETIMINGOVERRIDE_GET) (ADL_CONTEXT_HANDLE, int iAdapterIndex, int iDisplayIndex, ADLDisplayMode *lpModeIn, ADLDisplayModeInfo *lpModeInfoOut); +typedef int (*ADL2_DISPLAY_MODETIMINGOVERRIDE_SET) (ADL_CONTEXT_HANDLE, int iAdapterIndex, int iDisplayIndex, ADLDisplayModeInfo *lpMode, int iForceUpdate); +typedef int (*ADL2_DISPLAY_MODETIMINGOVERRIDELIST_GET) (ADL_CONTEXT_HANDLE, int iAdapterIndex, int iDisplayIndex, int iMaxNumOfOverrides, ADLDisplayModeInfo *lpModeInfoList, int *lpNumOfOverrides); +typedef int (*ADL2_FLUSH_DRIVER_DATA) (ADL_CONTEXT_HANDLE, int iAdapterIndex); + + +class adl_timing : public custom_video +{ + public: + adl_timing(char *display_name, custom_video_settings *vs); + ~adl_timing(); + const char *api_name() { return "AMD ADL"; } + bool init(); + void close(); + int caps() { return allow_hardware_refresh()? CUSTOM_VIDEO_CAPS_UPDATE | CUSTOM_VIDEO_CAPS_ADD | CUSTOM_VIDEO_CAPS_DESKTOP_EDITABLE : is_patched? CUSTOM_VIDEO_CAPS_UPDATE : 0; } + + bool add_mode(modeline *mode); + bool delete_mode(modeline *mode); + bool update_mode(modeline *mode); + + bool get_timing(modeline *m); + bool set_timing(modeline *m); + + bool process_modelist(std::vector); + + private: + int open(); + bool get_driver_version(char *device_key); + bool enum_displays(); + bool get_device_mapping_from_display_name(); + bool display_mode_info_to_modeline(ADLDisplayModeInfo *dmi, modeline *m); + bool get_timing_list(); + bool get_timing_from_cache(modeline *m); + bool set_timing_override(modeline *m, int update_mode); + + char m_display_name[32]; + char m_device_key[128]; + + int m_adapter_index = 0; + int m_display_index = 0; + + ADL2_ADAPTER_NUMBEROFADAPTERS_GET ADL2_Adapter_NumberOfAdapters_Get; + ADL2_ADAPTER_ADAPTERINFO_GET ADL2_Adapter_AdapterInfo_Get; + ADL2_DISPLAY_DISPLAYINFO_GET ADL2_Display_DisplayInfo_Get; + ADL2_DISPLAY_MODETIMINGOVERRIDE_GET ADL2_Display_ModeTimingOverride_Get; + ADL2_DISPLAY_MODETIMINGOVERRIDE_SET ADL2_Display_ModeTimingOverride_Set; + ADL2_DISPLAY_MODETIMINGOVERRIDELIST_GET ADL2_Display_ModeTimingOverrideList_Get; + ADL2_FLUSH_DRIVER_DATA ADL2_Flush_Driver_Data; + + HINSTANCE hDLL; + LPAdapterInfo lpAdapterInfo = NULL; + LPAdapterList lpAdapter = NULL;; + int iNumberAdapters = 0; + int cat_version = 0; + int sub_version = 0; + bool is_patched = false; + + ADL_CONTEXT_HANDLE m_adl = 0; + ADLDisplayModeInfo adl_mode[MAX_MODELINES]; + int m_num_of_adl_modes = 0; + + resync_handler m_resync; + + int invert_pol(bool on_read) { return ((cat_version <= 12) || (cat_version >= 15 && on_read)); } + int interlace_factor(bool interlace, bool on_read) { return interlace && ((cat_version <= 12) || (cat_version >= 15 && on_read))? 2 : 1; } +}; diff --git a/custom_video_ati.cpp b/custom_video_ati.cpp new file mode 100644 index 00000000000..488a65a0b9c --- /dev/null +++ b/custom_video_ati.cpp @@ -0,0 +1,343 @@ +/************************************************************** + + custom_video_ati.cpp - ATI legacy library + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include "custom_video_ati.h" +#include "log.h" + + +//============================================================ +// ati_timing::ati_timing +//============================================================ + +ati_timing::ati_timing(char *device_name, custom_video_settings *vs) +{ + m_vs = *vs; + strcpy (m_device_name, device_name); + strcpy (m_device_key, m_vs.device_reg_key); +} + +//============================================================ +// ati_timing::ati_timing +//============================================================ + +bool ati_timing::init() +{ + log_verbose("ATI legacy init\n"); + + // Get Windows version + win_version = os_version(); + + if (win_version > 5 && !is_elevated()) + { + log_error("ATI legacy error: the program needs administrator rights.\n"); + return false; + } + + return true; +} + +//============================================================ +// ati_timing::get_timing +//============================================================ + +bool ati_timing::get_timing(modeline *mode) +{ + HKEY hKey; + char lp_name[1024]; + char lp_data[68]; + DWORD length; + bool found = false; + int refresh_label = mode->refresh_label? mode->refresh_label : mode->refresh * win_interlace_factor(mode); + int vfreq_incr = 0; + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, m_device_key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + { + sprintf(lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label); + length = sizeof(lp_data); + + if (RegQueryValueExA(hKey, lp_name, NULL, NULL, (LPBYTE)lp_data, &length) == ERROR_SUCCESS && length == sizeof(lp_data)) + found = true; + else if (win_version > 5 && mode->interlace) + { + vfreq_incr = 1; + sprintf(lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label + vfreq_incr); + if (RegQueryValueExA(hKey, lp_name, NULL, NULL, (LPBYTE)lp_data, &length) == ERROR_SUCCESS && length == sizeof(lp_data)) + found = true; + } + if (found) + { + mode->pclock = get_DWORD_BCD(36, lp_data) * 10000; + mode->hactive = get_DWORD_BCD(8, lp_data); + mode->hbegin = get_DWORD_BCD(12, lp_data); + mode->hend = get_DWORD_BCD(16, lp_data) + mode->hbegin; + mode->htotal = get_DWORD_BCD(4, lp_data); + mode->vactive = get_DWORD_BCD(24, lp_data); + mode->vbegin = get_DWORD_BCD(28, lp_data); + mode->vend = get_DWORD_BCD(32, lp_data) + mode->vbegin; + mode->vtotal = get_DWORD_BCD(20, lp_data); + mode->interlace = (get_DWORD(0, lp_data) & CRTC_INTERLACED)?1:0; + mode->hsync = (get_DWORD(0, lp_data) & CRTC_H_SYNC_POLARITY)?0:1; + mode->vsync = (get_DWORD(0, lp_data) & CRTC_V_SYNC_POLARITY)?0:1; + mode->hfreq = mode->pclock / mode->htotal; + mode->vfreq = mode->hfreq / mode->vtotal * (mode->interlace?2:1); + mode->refresh_label = refresh_label; + mode->type |= CUSTOM_VIDEO_TIMING_ATI_LEGACY; + + int checksum = 65535 - get_DWORD(0, lp_data) - mode->htotal - mode->hactive - mode->hend + - mode->vtotal - mode->vactive - mode->vend - mode->pclock/10000; + if (checksum != get_DWORD(64, lp_data)) + log_verbose("bad checksum! "); + } + RegCloseKey(hKey); + return (found); + } + log_verbose("Failed opening registry entry for mode. "); + return false; +} + +//============================================================ +// ati_timing::set_timing +//============================================================ + +bool ati_timing::set_timing(modeline *mode) +{ + HKEY hKey; + char lp_name[1024]; + char lp_data[68]; + long checksum; + bool found = false; + int refresh_label = mode->refresh_label? mode->refresh_label : mode->refresh * win_interlace_factor(mode); + int vfreq_incr = 0; + + memset(lp_data, 0, sizeof(lp_data)); + set_DWORD_BCD(lp_data, (int)mode->pclock/10000, 36); + set_DWORD_BCD(lp_data, mode->hactive, 8); + set_DWORD_BCD(lp_data, mode->hbegin, 12); + set_DWORD_BCD(lp_data, mode->hend - mode->hbegin, 16); + set_DWORD_BCD(lp_data, mode->htotal, 4); + set_DWORD_BCD(lp_data, mode->vactive, 24); + set_DWORD_BCD(lp_data, mode->vbegin, 28); + set_DWORD_BCD(lp_data, mode->vend - mode->vbegin, 32); + set_DWORD_BCD(lp_data, mode->vtotal, 20); + set_DWORD(lp_data, (mode->interlace?CRTC_INTERLACED:0) | (mode->hsync?0:CRTC_H_SYNC_POLARITY) | (mode->vsync?0:CRTC_V_SYNC_POLARITY), 0); + + checksum = 65535 - get_DWORD(0, lp_data) - mode->htotal - mode->hactive - mode->hend + - mode->vtotal - mode->vactive - mode->vend - mode->pclock/10000; + set_DWORD(lp_data, checksum, 64); + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, m_device_key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + { + sprintf (lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label); + + if (RegQueryValueExA(hKey, lp_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + found = true; + else if (win_version > 5 && mode->interlace) + { + vfreq_incr = 1; + sprintf(lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label + vfreq_incr); + if (RegQueryValueExA(hKey, lp_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + found = true; + } + + if (!(found && RegSetValueExA(hKey, lp_name, 0, REG_BINARY, (LPBYTE)lp_data, 68) == ERROR_SUCCESS)) + log_info("Failed saving registry entry %s\n", lp_name); + + RegCloseKey(hKey); + return (found); + } + + log_info("Failed updating registry entry for mode.\n"); + return 0; +} + +//============================================================ +// ati_timing::update_mode +//============================================================ + +bool ati_timing::update_mode(modeline *mode) +{ + if (!set_timing(mode)) + return false; + + mode->type |= CUSTOM_VIDEO_TIMING_ATI_LEGACY; + + // ATI needs a call to EnumDisplaySettings to refresh timings + refresh_timings(); + + return true; +} + +//============================================================ +// ati_refresh_timings +//============================================================ + +void ati_timing::refresh_timings(void) +{ + int iModeNum = 0; + DEVMODEA lpDevMode; + + memset(&lpDevMode, 0, sizeof(DEVMODEA)); + lpDevMode.dmSize = sizeof(DEVMODEA); + + while (EnumDisplaySettingsExA(m_device_name, iModeNum, &lpDevMode, 0) != 0) + iModeNum++; +} + +//============================================================ +// adl_timing::process_modelist +//============================================================ + +bool ati_timing::process_modelist(std::vector modelist) +{ + bool error = false; + + for (auto &mode : modelist) + { + if (!set_timing(mode)) + { + mode->type |= MODE_ERROR; + error = true; + } + else + { + mode->type &= ~MODE_ERROR; + mode->type |= CUSTOM_VIDEO_TIMING_ATI_LEGACY; + } + } + + refresh_timings(); + return !error; +} + +//============================================================ +// get_DWORD +//============================================================ + +int ati_timing::get_DWORD(int i, char *lp_data) +{ + char out[32] = ""; + UINT32 x; + + sprintf(out, "%02X%02X%02X%02X", lp_data[i]&0xFF, lp_data[i+1]&0xFF, lp_data[i+2]&0xFF, lp_data[i+3]&0xFF); + sscanf(out, "%08X", &x); + return x; +} + +//============================================================ +// get_DWORD_BCD +//============================================================ + +int ati_timing::get_DWORD_BCD(int i, char *lp_data) +{ + char out[32] = ""; + UINT32 x; + + sprintf(out, "%02X%02X%02X%02X", lp_data[i]&0xFF, lp_data[i+1]&0xFF, lp_data[i+2]&0xFF, lp_data[i+3]&0xFF); + sscanf(out, "%d", &x); + return x; +} + +//============================================================ +// set_DWORD +//============================================================ + +void ati_timing::set_DWORD(char *data_string, UINT32 data_dword, int offset) +{ + char *p_dword = (char*)&data_dword; + + data_string[offset] = p_dword[3]&0xFF; + data_string[offset+1] = p_dword[2]&0xFF; + data_string[offset+2] = p_dword[1]&0xFF; + data_string[offset+3] = p_dword[0]&0xFF; +} + +//============================================================ +// set_DWORD_BCD +//============================================================ + +void ati_timing::set_DWORD_BCD(char *data_string, UINT32 data_dword, int offset) +{ + if (data_dword < 100000000) + { + int low_word, high_word; + int a, b, c, d; + char out[32] = ""; + + low_word = data_dword % 10000; + high_word = data_dword / 10000; + + sprintf(out, "%d %d %d %d", high_word / 100, high_word % 100 , low_word / 100, low_word % 100); + sscanf(out, "%02X %02X %02X %02X", &a, &b, &c, &d); + + data_string[offset] = a; + data_string[offset+1] = b; + data_string[offset+2] = c; + data_string[offset+3] = d; + } +} + +//============================================================ +// os_version +//============================================================ + +int ati_timing::os_version(void) +{ + OSVERSIONINFOA lpVersionInfo; + + memset(&lpVersionInfo, 0, sizeof(OSVERSIONINFOA)); + lpVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + GetVersionExA (&lpVersionInfo); + + return lpVersionInfo.dwMajorVersion; +} + +//============================================================ +// is_elevated +//============================================================ + +bool ati_timing::is_elevated() +{ + HANDLE htoken; + bool result = false; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken)) + return false; + + TOKEN_ELEVATION te = {0}; + DWORD dw_return_length; + + if (GetTokenInformation(htoken, TokenElevation, &te, sizeof(te), &dw_return_length)) + { + if (te.TokenIsElevated) + { + result = true; + } + } + + CloseHandle(htoken); + return (result); +} + +//============================================================ +// win_interlace_factor +//============================================================ + +int ati_timing::win_interlace_factor(modeline *mode) +{ + if (win_version > 5 && mode->interlace) + return 2; + + return 1; +} diff --git a/custom_video_ati.h b/custom_video_ati.h new file mode 100644 index 00000000000..37d7775cef7 --- /dev/null +++ b/custom_video_ati.h @@ -0,0 +1,53 @@ +/************************************************************** + + custom_video_ati.h - ATI legacy library header + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include "custom_video.h" + +#define CRTC_DOUBLE_SCAN 0x0001 +#define CRTC_INTERLACED 0x0002 +#define CRTC_H_SYNC_POLARITY 0x0004 +#define CRTC_V_SYNC_POLARITY 0x0008 + +class ati_timing : public custom_video +{ + public: + ati_timing(char *device_name, custom_video_settings *vs); + ~ati_timing() {}; + const char *api_name() { return "ATI Legacy"; } + bool init(); + int caps() { return CUSTOM_VIDEO_CAPS_UPDATE | CUSTOM_VIDEO_CAPS_SCAN_EDITABLE; } + + bool update_mode(modeline *mode); + + bool get_timing(modeline *mode); + bool set_timing(modeline *mode); + + bool process_modelist(std::vector); + + private: + void refresh_timings(void); + + int get_DWORD(int i, char *lp_data); + int get_DWORD_BCD(int i, char *lp_data); + void set_DWORD(char *data_string, UINT32 data_word, int offset); + void set_DWORD_BCD(char *data_string, UINT32 data_word, int offset); + int os_version(void); + bool is_elevated(); + int win_interlace_factor(modeline *mode); + + char m_device_name[32]; + char m_device_key[256]; + int win_version; +}; diff --git a/custom_video_ati_family.cpp b/custom_video_ati_family.cpp new file mode 100644 index 00000000000..324617e9cc7 --- /dev/null +++ b/custom_video_ati_family.cpp @@ -0,0 +1,848 @@ +/************************************************************** + + custom_video_ati_family.cpp - ATI/AMD Radeon family + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +/* Constants and structures ported from Linux open source drivers: + drivers\gpu\drm\radeon\radeon.h + drivers\gpu\drm\radeon\radeon_family.h + include\drm\drm_pciids.h +*/ + +#ifndef RADEON_FAMILY_H +#define RADEON_FAMILY_H + +struct pci_device_id +{ + int vendor, device; + int subvendor, subdevice; + int _class, _class_mask; + int driver_data; +}; + +enum radeon_family +{ + CHIP_R100 = 0, + CHIP_RV100, + CHIP_RS100, + CHIP_RV200, + CHIP_RS200, + CHIP_R200, + CHIP_RV250, + CHIP_RS300, + CHIP_RV280, + CHIP_R300, + CHIP_R350, + CHIP_RV350, + CHIP_RV380, + CHIP_R420, + CHIP_R423, + CHIP_RV410, + CHIP_RS400, + CHIP_RS480, + CHIP_RS600, + CHIP_RS690, + CHIP_RS740, + CHIP_RV515, + CHIP_R520, + CHIP_RV530, + CHIP_RV560, + CHIP_RV570, + CHIP_R580, + CHIP_R600, + CHIP_RV610, + CHIP_RV630, + CHIP_RV670, + CHIP_RV620, + CHIP_RV635, + CHIP_RS780, + CHIP_RS880, + CHIP_RV770, + CHIP_RV730, + CHIP_RV710, + CHIP_RV740, + CHIP_CEDAR, + CHIP_REDWOOD, + CHIP_JUNIPER, + CHIP_CYPRESS, + CHIP_HEMLOCK, + CHIP_PALM, + CHIP_SUMO, + CHIP_SUMO2, + CHIP_BARTS, + CHIP_TURKS, + CHIP_CAICOS, + CHIP_CAYMAN, + CHIP_ARUBA, + CHIP_TAHITI, + CHIP_PITCAIRN, + CHIP_VERDE, + CHIP_OLAND, + CHIP_HAINAN, + CHIP_BONAIRE, + CHIP_KAVERI, + CHIP_KABINI, + CHIP_HAWAII, + CHIP_MULLINS, + CHIP_LAST, +}; + +enum radeon_chip_flags +{ + RADEON_FAMILY_MASK = 0x0000ffffUL, + RADEON_FLAGS_MASK = 0xffff0000UL, + RADEON_IS_MOBILITY = 0x00010000UL, + RADEON_IS_IGP = 0x00020000UL, + RADEON_SINGLE_CRTC = 0x00040000UL, + RADEON_IS_AGP = 0x00080000UL, + RADEON_HAS_HIERZ = 0x00100000UL, + RADEON_IS_PCIE = 0x00200000UL, + RADEON_NEW_MEMMAP = 0x00400000UL, + RADEON_IS_PCI = 0x00800000UL, + RADEON_IS_IGPGART = 0x01000000UL, + RADEON_IS_PX = 0x02000000UL, +}; + +#define PCI_ANY_ID (~0) + +#define radeon_PCI_IDS \ + {0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1306, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1309, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x130A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x130B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x130C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x130D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x130E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x130F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1313, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ + {0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \ + {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ + {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ + {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ + {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ + {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ + {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4B48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ + {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ + {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ + {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ + {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ + {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ + {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ + {0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ + {0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ + {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ + {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ + {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \ + {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ + {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \ + {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6600, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6602, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6603, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6604, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6606, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6607, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6665, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6667, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x666F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6703, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6704, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6705, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6706, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6707, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6708, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6709, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6718, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6719, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x671c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x671d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x671f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6721, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6722, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6723, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6725, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6726, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6727, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6728, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6729, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6739, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x673e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6740, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6741, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6743, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6745, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6746, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6747, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x674A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6763, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6764, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6765, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6766, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6771, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x677B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6784, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x678A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6790, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6791, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6792, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67A8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67A9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67AA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67B0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67B8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67BA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x67BE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6822, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6826, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x683B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x683D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x683F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6843, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6849, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x684C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x688A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x688C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x688D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6898, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6899, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x689b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x689c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x689d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x689e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68a0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68a8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68a9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68ba, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68be, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68bf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68c8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68c9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68e0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68e1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68e5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68e8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68e9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68f1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68f8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68f9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x710A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x710B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x710C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x710E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x710F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7143, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x714A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x714B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x714C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x714D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x714E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x714F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x715E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x715F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7183, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7186, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7187, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7188, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x718A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x718B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x718C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x718D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x718F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7193, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x719B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x719F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71D2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71D4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71D5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7248, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x724A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x724B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x724C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x724D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x724E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x724F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7280, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7283, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7284, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x728B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x728C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7291, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7293, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7297, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x793f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7941, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7942, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x796c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x796d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x796e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x796f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9402, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9403, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94A3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9444, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x944A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x944B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x944C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x944E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x945E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x947B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9487, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9488, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9489, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x948A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x948F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9490, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9491, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9495, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9498, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x949C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x949E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x949F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x94CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9504, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9505, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9506, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9507, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9508, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9509, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x950F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9515, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9517, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9540, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9541, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9542, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x954E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x954F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9553, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9555, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9557, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x955f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9580, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9581, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9583, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9586, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9587, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9588, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9589, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x958A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x958B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x958C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x958D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x958E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x958F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9590, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9593, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9595, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9596, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9597, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9599, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x959B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x95CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x9610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9616, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9642, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x964e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x964f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9804, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9851, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9852, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9853, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9854, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9856, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9857, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x985A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x985B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x985C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x985D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x985E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9904, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9905, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9906, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9908, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9909, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x990A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x990B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x990C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x990D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x990E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x990F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9910, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9913, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9917, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9990, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9991, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9993, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9994, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9995, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9996, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9997, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9998, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9999, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0, 0, 0, 0, 0, 0, 0} + +static struct pci_device_id pciidlist[] = {radeon_PCI_IDS}; + +//============================================================ +// ati_family +//============================================================ + +int ati_family(int vendor, int device) +{ + int i = 0; + while (pciidlist[i].vendor) + { + if (pciidlist[i].vendor == vendor && pciidlist[i].device == device) + return (pciidlist[i].driver_data & RADEON_FAMILY_MASK); + i++; + } + // Not found, must be newer + if (vendor == 0x1002) + return CHIP_LAST; + + return 0; +} + +//============================================================ +// ati_is_legacy +//============================================================ + +bool ati_is_legacy(int vendor, int device) +{ + return (ati_family(vendor, device) < CHIP_CEDAR); +} + +#endif diff --git a/custom_video_drmkms.cpp b/custom_video_drmkms.cpp new file mode 100755 index 00000000000..f71c49ca1d6 --- /dev/null +++ b/custom_video_drmkms.cpp @@ -0,0 +1,1276 @@ +/************************************************************** + + custom_video_drmkms.cpp - Linux DRM/KMS video management layer + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "custom_video_drmkms.h" +#include "log.h" + +#define drmGetVersion p_drmGetVersion +#define drmFreeVersion p_drmFreeVersion +#define drmModeGetResources p_drmModeGetResources +#define drmModeGetConnector p_drmModeGetConnector +#define drmModeGetConnectorCurrent p_drmModeGetConnectorCurrent +#define drmModeFreeConnector p_drmModeFreeConnector +#define drmModeFreeResources p_drmModeFreeResources +#define drmModeGetEncoder p_drmModeGetEncoder +#define drmModeFreeEncoder p_drmModeFreeEncoder +#define drmModeGetCrtc p_drmModeGetCrtc +#define drmModeSetCrtc p_drmModeSetCrtc +#define drmModeFreeCrtc p_drmModeFreeCrtc +#define drmModeAttachMode p_drmModeAttachMode +#define drmModeDetachMode p_drmModeDetachMode +#define drmModeAddFB p_drmModeAddFB +#define drmModeRmFB p_drmModeRmFB +#define drmModeGetFB p_drmModeGetFB +#define drmModeFreeFB p_drmModeFreeFB +#define drmPrimeHandleToFD p_drmPrimeHandleToFD +#define drmModeGetPlaneResources p_drmModeGetPlaneResources +#define drmModeFreePlaneResources p_drmModeFreePlaneResources +#define drmIoctl p_drmIoctl +#define drmGetCap p_drmGetCap +#define drmIsMaster p_drmIsMaster +#define drmSetMaster p_drmSetMaster +#define drmDropMaster p_drmDropMaster + +# define MAX_CARD_ID 10 + +//============================================================ +// shared the privileges of the master fd +//============================================================ + +// If 2 displays use the same GPU but a different connector, let's share the +// FD indexed on the card ID + +static int s_shared_fd[MAX_CARD_ID] = {}; + +// The active shares on a fd, per card id + +static int s_shared_count[MAX_CARD_ID] = {}; + +// What we're missing here, is also a list of the connector ids associated with +// the screen number, otherwise SR will try to use (again) the first connector +// that has an monitor plugged to it + +static unsigned int s_shared_conn[MAX_CARD_ID] = {}; + +//============================================================ +// id for class object (static) +//============================================================ + +// This helps to trace counts of active displays accross vaious instances +// ++'ed at constructor, --'ed at destructor +// m_id will use the ++-ed value + +static int static_id = 0; + +//============================================================ +// list connector types +//============================================================ + +const char *get_connector_name(int mode) +{ + switch (mode) + { + case DRM_MODE_CONNECTOR_Unknown: + return "Unknown"; + case DRM_MODE_CONNECTOR_VGA: + return "VGA-"; + case DRM_MODE_CONNECTOR_DVII: + return "DVI-I-"; + case DRM_MODE_CONNECTOR_DVID: + return "DVI-D-"; + case DRM_MODE_CONNECTOR_DVIA: + return "DVI-A-"; + case DRM_MODE_CONNECTOR_Composite: + return "Composite-"; + case DRM_MODE_CONNECTOR_SVIDEO: + return "SVIDEO-"; + case DRM_MODE_CONNECTOR_LVDS: + return "LVDS-"; + case DRM_MODE_CONNECTOR_Component: + return "Component-"; + case DRM_MODE_CONNECTOR_9PinDIN: + return "9PinDIN-"; + case DRM_MODE_CONNECTOR_DisplayPort: + return "DisplayPort-"; + case DRM_MODE_CONNECTOR_HDMIA: + return "HDMI-A-"; + case DRM_MODE_CONNECTOR_HDMIB: + return "HDMI-B-"; + case DRM_MODE_CONNECTOR_TV: + return "TV-"; + case DRM_MODE_CONNECTOR_eDP: + return "eDP-"; + case DRM_MODE_CONNECTOR_VIRTUAL: + return "VIRTUAL-"; + case DRM_MODE_CONNECTOR_DSI: + return "DSI-"; + case DRM_MODE_CONNECTOR_DPI: + return "DPI-"; + default: + return "not_defined-"; + } +} + +//============================================================ +// Check if a connector is not used on a previous display +//============================================================ + +bool connector_already_used(unsigned int conn_id) +{ + // Don't remap to an already used connector + for (int c = 1 ; c < static_id ; c++) + { + if (s_shared_conn[c] == conn_id) + return true; + } + return false; +} + +//============================================================ +// Convert a SR modeline to a DRM modeline +//============================================================ + +void modeline_to_drm_modeline(int id, modeline *mode, drmModeModeInfo *drmmode) +{ + // Clear struct + memset(drmmode, 0, sizeof(drmModeModeInfo)); + + // Create specific mode name + snprintf(drmmode->name, 32, "SR-%d_%dx%d@%.02f%s", id, mode->hactive, mode->vactive, mode->vfreq, mode->interlace ? "i" : ""); + drmmode->clock = mode->pclock / 1000; + drmmode->hdisplay = mode->hactive; + drmmode->hsync_start = mode->hbegin; + drmmode->hsync_end = mode->hend; + drmmode->htotal = mode->htotal; + drmmode->vdisplay = mode->vactive; + drmmode->vsync_start = mode->vbegin; + drmmode->vsync_end = mode->vend; + drmmode->vtotal = mode->vtotal; + drmmode->flags = (mode->interlace ? DRM_MODE_FLAG_INTERLACE : 0) | (mode->doublescan ? DRM_MODE_FLAG_DBLSCAN : 0) | (mode->hsync ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC) | (mode->vsync ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC); + + drmmode->hskew = 0; + drmmode->vscan = 0; + + drmmode->vrefresh = mode->refresh; // Used only for human readable output +} + +//============================================================ +// drmkms_timing::test_kernel_user_modes +//============================================================ + +bool drmkms_timing::test_kernel_user_modes() +{ + int ret = 0, first_modes_count = 0, second_modes_count = 0; + int fd; + drmModeModeInfo mode = {}; + const char* my_name = "KMS Test mode"; + drmModeConnector *conn; + + // Make sure we are master, that is required for the IOCTL + fd = get_master_fd(); + if (fd < 0) + { + log_verbose("DRM/KMS: <%d> (%s) Need master to test kernel user modes\n", m_id, __FUNCTION__); + return false; + } + + // Create a dummy modeline with a pixel clock higher than 25MHz to avoid + // drivers checks rejecting the mode. Use a modeline that no one would + // ever use hopefully + strcpy(mode.name, my_name); + mode.clock = 25212; + mode.hdisplay = 1234; + mode.hsync_start = 1290; + mode.hsync_end = 1408; + mode.htotal = 1610; + mode.vdisplay = 234; + mode.vsync_start = 238; + mode.vsync_end = 241; + mode.vtotal = 261; + mode.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC; + + // Count the number of existing modes, so it should be +1 when attaching + // a new mode. Could also check the mode name, still better + conn = drmModeGetConnector(fd, m_desktop_output); + first_modes_count = conn->count_modes; + ret = drmModeAttachMode(fd, m_desktop_output, &mode); + drmModeFreeConnector(conn); + + // This case can only happen if we're not drmMaster. If the kernel doesn't + // support adding new modes, the IOCTL will still return 0, not an error + if (ret < 0) + { + // Let's fail, no need to go further + log_verbose("DRM/KMS: <%d> (%s) Cannot add new kernel user mode\n", m_id, __FUNCTION__); + m_kernel_user_modes = false; + return false; + } + + // Not using drmModeGetConnectorCurrent here since we need to force a + // modelist connector refresh, so the kernel will probe the connector + conn = drmModeGetConnector(fd, m_desktop_output); + second_modes_count = conn->count_modes; + if (first_modes_count != second_modes_count) + { + log_verbose("DRM/KMS: <%d> (%s) Kernel supports user modes (%d vs %d)\n", m_id, __FUNCTION__, first_modes_count, second_modes_count); + m_kernel_user_modes = true; + drmModeDetachMode(fd, m_desktop_output, &mode); + if (fd != m_hook_fd) + drmDropMaster(fd); + } + else + log_verbose("DRM/KMS: <%d> (%s) Kernel doesn't supports user modes\n", m_id, __FUNCTION__); + + drmModeFreeConnector(conn); + return m_kernel_user_modes; +} + +//============================================================ +// drmkms_timing::drmkms_timing +//============================================================ + +drmkms_timing::drmkms_timing(char *device_name, custom_video_settings *vs) +{ + m_vs = *vs; + m_id = ++static_id; + + log_verbose("DRM/KMS: <%d> (drmkms_timing) creation (%s)\n", m_id, device_name); + // Copy screen device name and limit size + if ((strlen(device_name) + 1) > 32) + { + strncpy(m_device_name, device_name, 31); + log_error("DRM/KMS: <%d> (drmkms_timing) [ERROR] the devine name is too long it has been trucated to %s\n", m_id, m_device_name); + } + else + strcpy(m_device_name, device_name); +} + +//============================================================ +// drmkms_timing::~drmkms_timing +//============================================================ + +drmkms_timing::~drmkms_timing() +{ + // Remove kernel user modes + if (m_kernel_user_modes) + { + int i = 0, ret = 0; + int fd; + drmModeConnector *conn; + + fd = get_master_fd(); + if (fd >= 0) + { + conn = drmModeGetConnectorCurrent(fd, m_desktop_output); + drmSetMaster(fd); + for (i = 0; i < conn->count_modes; i++) + { + drmModeModeInfo *mode = &conn->modes[i]; + log_verbose("DRM/KMS: <%d> (%s) Checking kernel mode: %s\n", m_id, __FUNCTION__, mode->name); + ret = strncmp(mode->name, "SR-", 3); + if (ret == 0) + { + log_verbose("DRM/KMS: <%d> (%s) Removing kernel user mode: %s\n", m_id, __FUNCTION__, mode->name); + drmModeDetachMode(fd, m_desktop_output, mode); + } + } + if (fd != m_hook_fd) + drmDropMaster(fd); + + drmModeFreeConnector(conn); + if (fd != m_drm_fd and fd != m_hook_fd) + close(fd); + } + } + + // Free the connector used + s_shared_conn[m_id] = -1; + + // close DRM/KMS library + if (mp_drm_handle) + dlclose(mp_drm_handle); + + if (m_drm_fd > 0) + { + if (!--s_shared_count[m_card_id]) + close(m_drm_fd); + } + + // Reset static data + static_id = 0; + memset(s_shared_fd, 0, sizeof(s_shared_fd)); + memset(s_shared_count, 0, sizeof(s_shared_count)); + memset(s_shared_conn, 0, sizeof(s_shared_conn)); +} + +//============================================================ +// drmkms_timing::init +//============================================================ + +bool drmkms_timing::init() +{ + log_verbose("DRM/KMS: <%d> (init) loading DRM/KMS library\n", m_id); + mp_drm_handle = dlopen("libdrm.so", RTLD_NOW); + if (mp_drm_handle) + { + p_drmGetVersion = (__typeof__(drmGetVersion)) dlsym(mp_drm_handle, "drmGetVersion"); + if (p_drmGetVersion == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmGetVersion", "DRM_LIBRARY"); + return false; + } + + p_drmFreeVersion = (__typeof__(drmFreeVersion)) dlsym(mp_drm_handle, "drmFreeVersion"); + if (p_drmFreeVersion == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmFreeVersion", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetResources = (__typeof__(drmModeGetResources)) dlsym(mp_drm_handle, "drmModeGetResources"); + if (p_drmModeGetResources == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetResources", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetConnector = (__typeof__(drmModeGetConnector)) dlsym(RTLD_DEFAULT, "drmModeGetConnector"); + if (p_drmModeGetConnector == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetConnector", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetConnectorCurrent = (__typeof__(drmModeGetConnectorCurrent)) dlsym(RTLD_DEFAULT, "drmModeGetConnectorCurrent"); + if (p_drmModeGetConnectorCurrent == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetConnectorCurrent", "DRM_LIBRARY"); + return false; + } + + p_drmModeFreeConnector = (__typeof__(drmModeFreeConnector)) dlsym(RTLD_DEFAULT, "drmModeFreeConnector"); + if (p_drmModeFreeConnector == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeFreeConnector", "DRM_LIBRARY"); + return false; + } + + p_drmModeFreeResources = (__typeof__(drmModeFreeResources)) dlsym(mp_drm_handle, "drmModeFreeResources"); + if (p_drmModeFreeResources == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeFreeResources", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetEncoder = (__typeof__(drmModeGetEncoder)) dlsym(mp_drm_handle, "drmModeGetEncoder"); + if (p_drmModeGetEncoder == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetEncoder", "DRM_LIBRARY"); + return false; + } + + p_drmModeFreeEncoder = (__typeof__(drmModeFreeEncoder)) dlsym(mp_drm_handle, "drmModeFreeEncoder"); + if (p_drmModeFreeEncoder == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeFreeEncoder", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetCrtc = (__typeof__(drmModeGetCrtc)) dlsym(mp_drm_handle, "drmModeGetCrtc"); + if (p_drmModeGetCrtc == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetCrtc", "DRM_LIBRARY"); + return false; + } + + p_drmModeSetCrtc = (__typeof__(drmModeSetCrtc)) dlsym(mp_drm_handle, "drmModeSetCrtc"); + if (p_drmModeSetCrtc == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeSetCrtc", "DRM_LIBRARY"); + return false; + } + + p_drmModeFreeCrtc = (__typeof__(drmModeFreeCrtc)) dlsym(mp_drm_handle, "drmModeFreeCrtc"); + if (p_drmModeFreeCrtc == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeFreeCrtc", "DRM_LIBRARY"); + return false; + } + + p_drmModeAttachMode = (__typeof__(drmModeAttachMode)) dlsym(mp_drm_handle, "drmModeAttachMode"); + if (p_drmModeAttachMode == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeAttachMode", "DRM_LIBRARY"); + return false; + } + + p_drmModeDetachMode = (__typeof__(drmModeDetachMode)) dlsym(mp_drm_handle, "drmModeDetachMode"); + if (p_drmModeDetachMode == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeDetachMode", "DRM_LIBRARY"); + return false; + } + + p_drmModeAddFB = (__typeof__(drmModeAddFB)) dlsym(mp_drm_handle, "drmModeAddFB"); + if (p_drmModeAddFB == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeAddFB", "DRM_LIBRARY"); + return false; + } + + p_drmModeRmFB = (__typeof__(drmModeRmFB)) dlsym(mp_drm_handle, "drmModeRmFB"); + if (p_drmModeRmFB == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeRmFB", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetFB = (__typeof__(drmModeGetFB)) dlsym(mp_drm_handle, "drmModeGetFB"); + if (p_drmModeGetFB == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetFB", "DRM_LIBRARY"); + return false; + } + + p_drmModeFreeFB = (__typeof__(drmModeFreeFB)) dlsym(mp_drm_handle, "drmModeFreeFB"); + if (p_drmModeFreeFB == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeFreeFB", "DRM_LIBRARY"); + return false; + } + + p_drmPrimeHandleToFD = (__typeof__(drmPrimeHandleToFD)) dlsym(mp_drm_handle, "drmPrimeHandleToFD"); + if (p_drmPrimeHandleToFD == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmPrimeHandleToFD", "DRM_LIBRARY"); + return false; + } + + p_drmModeGetPlaneResources = (__typeof__(drmModeGetPlaneResources)) dlsym(mp_drm_handle, "drmModeGetPlaneResources"); + if (p_drmModeGetPlaneResources == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeGetPlaneResources", "DRM_LIBRARY"); + return false; + } + + p_drmModeFreePlaneResources = (__typeof__(drmModeFreePlaneResources)) dlsym(mp_drm_handle, "drmModeFreePlaneResources"); + if (p_drmModeFreePlaneResources == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmModeFreePlaneResources", "DRM_LIBRARY"); + return false; + } + + p_drmIoctl = (__typeof__(drmIoctl)) dlsym(mp_drm_handle, "drmIoctl"); + if (p_drmIoctl == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmIoctl", "DRM_LIBRARY"); + return false; + } + + p_drmGetCap = (__typeof__(drmGetCap)) dlsym(mp_drm_handle, "drmGetCap"); + if (p_drmGetCap == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmGetCap", "DRM_LIBRARY"); + return false; + } + + p_drmIsMaster = (__typeof__(drmIsMaster)) dlsym(mp_drm_handle, "drmIsMaster"); + if (p_drmIsMaster == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmIsMaster", "DRM_LIBRARY"); + return false; + } + + p_drmSetMaster = (__typeof__(drmSetMaster)) dlsym(mp_drm_handle, "drmSetMaster"); + if (p_drmSetMaster == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmSetMaster", "DRM_LIBRARY"); + return false; + } + + p_drmDropMaster = (__typeof__(drmDropMaster)) dlsym(mp_drm_handle, "drmDropMaster"); + if (p_drmDropMaster == NULL) + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing func %s in %s", m_id, "drmDropMaster", "DRM_LIBRARY"); + return false; + } + } + else + { + log_error("DRM/KMS: <%d> (init) [ERROR] missing %s library\n", m_id, "DRM/KMS_LIBRARY"); + return false; + } + + int screen_pos = -1; + + // Handle the screen name, "auto", "screen[0-9]" and device name + if (strlen(m_device_name) == 7 && !strncmp(m_device_name, "screen", 6) && m_device_name[6] >= '0' && m_device_name[6] <= '9') + screen_pos = m_device_name[6] - '0'; + else if (strlen(m_device_name) == 1 && m_device_name[0] >= '0' && m_device_name[0] <= '9') + screen_pos = m_device_name[0] - '0'; + + char drm_name[15] = "/dev/dri/card_"; + drmModeRes *p_res; + drmModeConnector *p_connector; + + int output_position = 0; + for (int num = 0; !m_desktop_output && num < MAX_CARD_ID; num++) + { + drm_name[13] = '0' + num; + + if (!access(drm_name, F_OK) == 0) + { + log_error("DRM/KMS: <%d> (init) [ERROR] cannot open device %s\n", m_id, drm_name); + break; + } + m_drm_fd = open(drm_name, O_RDWR | O_CLOEXEC); + + drmVersion *version = drmGetVersion(m_drm_fd); + log_verbose("DRM/KMS: <%d> (init) version %d.%d.%d type %s\n", m_id, version->version_major, version->version_minor, version->version_patchlevel, version->name); + drmFreeVersion(version); + + uint64_t check_dumb = 0; + if (drmGetCap(m_drm_fd, DRM_CAP_DUMB_BUFFER, &check_dumb) < 0) + log_error("DRM/KMS: <%d> (init) [ERROR] ioctl DRM_CAP_DUMB_BUFFER\n", m_id); + + if (!check_dumb) + log_error("DRM/KMS: <%d> (init) [ERROR] dumb buffer not supported\n", m_id); + + p_res = drmModeGetResources(m_drm_fd); + + for (int i = 0; i < p_res->count_connectors; i++) + { + p_connector = drmModeGetConnectorCurrent(m_drm_fd, p_res->connectors[i]); + if (!p_connector) + { + log_error("DRM/KMS: <%d> (init) [ERROR] card %d connector %d - %d\n", m_id, num, i, p_res->connectors[i]); + continue; + } + char connector_name[32]; + snprintf(connector_name, 32, "%s%d", get_connector_name(p_connector->connector_type), p_connector->connector_type_id); + log_verbose("DRM/KMS: <%d> (init) card %d connector %d id %d name %s status %d - modes %d\n", m_id, num, i, p_connector->connector_id, connector_name, p_connector->connection, p_connector->count_modes); + // detect desktop connector + if (!m_desktop_output && p_connector->connection == DRM_MODE_CONNECTED) + { + if (!strcmp(m_device_name, "auto") || !strcmp(m_device_name, connector_name) || output_position == screen_pos) + { + // In a multihead setup, skip already used connectors + if (connector_already_used(p_connector->connector_id)) + { + drmModeFreeConnector(p_connector); + continue; + } + m_desktop_output = p_connector->connector_id; + m_card_id = num; + log_verbose("DRM/KMS: <%d> (init) card %d connector %d id %d name %s selected as primary output\n", m_id, num, i, m_desktop_output, connector_name); + + drmModeEncoder *p_encoder = drmModeGetEncoder(m_drm_fd, p_connector->encoder_id); + + if (p_encoder) + { + for (int e = 0; e < p_res->count_crtcs; e++) + { + mp_crtc_desktop = drmModeGetCrtc(m_drm_fd, p_res->crtcs[e]); + + if (mp_crtc_desktop->crtc_id == p_encoder->crtc_id) + { + log_verbose("DRM/KMS: <%d> (init) desktop mode name %s crtc %d fb %d valid %d\n", m_id, mp_crtc_desktop->mode.name, mp_crtc_desktop->crtc_id, mp_crtc_desktop->buffer_id, mp_crtc_desktop->mode_valid); + break; + } + drmModeFreeCrtc(mp_crtc_desktop); + } + } + if (!mp_crtc_desktop) + log_error("DRM/KMS: <%d> (init) [ERROR] no crtc found\n", m_id); + drmModeFreeEncoder(p_encoder); + } + output_position++; + } + drmModeFreeConnector(p_connector); + } + drmModeFreeResources(p_res); + if (!m_desktop_output) + close(m_drm_fd); + else + { + if (drmIsMaster(m_drm_fd)) + { + // We've never called drmSetMaster before. This means we're the first app + // opening the device, so the kernel sets us as master by default. + // We drop master so other apps can become master + log_verbose("DRM/KMS: <%d> (%s) Already DRM master\n", m_id, __FUNCTION__); + s_shared_fd[m_card_id] = m_drm_fd; + s_shared_count[m_card_id] = 1; + drmDropMaster(m_drm_fd); + } + else + { + if (s_shared_count[m_card_id] > 0) + { + log_verbose("DRM/KMS: <%d> (%s : %d) The drm FD was substituted, expect the unexpected\n", m_id, __FUNCTION__, __LINE__); + close(m_drm_fd); + m_drm_fd = s_shared_fd[m_card_id]; + s_shared_count[m_card_id]++; + } + else if (m_id == 1) + { + log_verbose("DRM/KMS: <%d> (%s) looking for the DRM master\n", m_id, __FUNCTION__); + int fd = get_master_fd(); + if (fd >= 0) + { + close(m_drm_fd); + // This statement is dangerous, as drmIsMaster can return 1 + // on m_drm_fd if there is no master left, but it doesn't + // check if m_drm_fd is a valid fd + + m_drm_fd = fd; + s_shared_fd[m_card_id] = m_drm_fd; + // start at 2 to disable closing the fd + s_shared_count[m_card_id] = 2; + } + if (!drmIsMaster(m_drm_fd)) + log_error("DRM/KMS: <%d> (%s) [ERROR] limited DRM rights on this screen\n", m_id, __FUNCTION__); + } + } + } + } + + // Handle no screen detected case + if (!m_desktop_output) + { + log_error("DRM/KMS: <%d> (init) [ERROR] no screen detected\n", m_id); + return false; + } + else + { + } + + // Check if we have a libdrm hook + if (drmModeGetConnectorCurrent(-1, 0) != NULL) + { + log_verbose("DRM/KMS: libdrm hook found!\n"); + m_caps |= CUSTOM_VIDEO_CAPS_UPDATE; + } + // Check if the kernel handles user modes + else if (test_kernel_user_modes()) + m_caps |= CUSTOM_VIDEO_CAPS_ADD; + + if (drmIsMaster(m_drm_fd) and m_drm_fd != m_hook_fd) + drmDropMaster(m_drm_fd); + + return true; +} + +//============================================================ +// drmkms_timing::get_master_fd +//============================================================ +// BACKGROUND +// This is written as of Linux 5.14, 5.15 is just out, not yet tested. +// There are a few unexpected behaviours so far in DRM: +// - drmSetMaster seems to always return -1 on 5.4, but ok on 5.14 +// - drmIsMaster doesn't care if the FD exists and will always return 1 +// if the there is no master on the DRI device +// That's why we can't trust drmIsMaster if we didn't make sure before that +// the FD does exist. +// get_master_fd will always return a valid master FD, or return -1 if it's +// impossible + +int drmkms_timing::get_master_fd() +{ + const size_t path_length = 15; + char dev_path[path_length]; + char procpath[50]; + char fullpath[512]; + char* actualpath; + struct stat st; + int fd; + + // CASE 1: m_drm_fd is a valid FD + if (fstat(m_drm_fd, &st) == 0) + { + if (drmIsMaster(m_drm_fd)) + return m_drm_fd; + if (drmSetMaster(m_drm_fd) == 0) + return m_drm_fd; + } + + // CASE 2: m_drm_fd can't be master, find the master FD + if (m_card_id > MAX_CARD_ID - 1 or m_card_id < 0) + { + log_error("DRM/KMS: <%d> (%s) [ERROR] card id (%d) out of bounds (0 to %d)\n", m_id, __FUNCTION__, m_card_id, MAX_CARD_ID - 1); + return -1; + } + + snprintf(dev_path, path_length, "/dev/dri/card%d", m_card_id); + if (!access(dev_path, F_OK) == 0) + { + log_error("DRM/KMS: <%d> (%s) [ERROR] Device %s doesn't exist\n", m_id, __FUNCTION__, dev_path); + return -1; + } + + sprintf(procpath, "/proc/%d/fd", getpid()); + auto dir = opendir(procpath); + if (!dir) + return -1; + while (auto f = readdir(dir)) + { + // Skip everything that starts with a dot + if (f->d_name[0] == '.') + continue; + // Only symlinks matter + if (f-> d_type != DT_LNK) + continue; + + //log_verbose("File: %s\n", f->d_name); + sprintf(fullpath, "%s/%s", procpath, f->d_name); + if (stat(fullpath, &st)) + continue; + if (!S_ISCHR(st.st_mode)) + continue; + actualpath = realpath(fullpath, NULL); + // Only check the device we expect + if (strncmp(dev_path, actualpath, path_length) != 0) + { + free(actualpath); + continue; + } + fd = atoi(f->d_name); + //log_verbose("File: %s -> %s %d\n", fullpath, actualpath, fd); + free(actualpath); + + if (drmIsMaster(fd)) + { + log_verbose("DRM/KMS: <%d> (%s) DRM hook created on FD %d\n", m_id, __FUNCTION__, fd); + closedir(dir); + m_hook_fd = fd; + return fd; + } + } + closedir(dir); + + // CASE 3: m_drm_fd is not a master (and probably not even a valid FD), the currend pid doesn't have master rights + // Or master is owned by a 3rd party app (like a frontend ...) + log_verbose("DRM/KMS: <%d> (%s) Couldn't find a master FD, opening default /dev/dri/card%d\n", m_id, __FUNCTION__, m_card_id); + + // mark our former hook as invalid + m_hook_fd = -1; + + fd = open(dev_path, O_RDWR | O_CLOEXEC); + if (fd < 0) + { + // Oh, we're totally screwed here, worst possible scenario + log_error("DRM/KMS: <%d> (%s) Can't open /dev/dri/card%d, can't get master rights\n", m_id, __FUNCTION__, m_card_id); + return -1; + } + + // Hardly any chance we reach here. I don't even know when to close the FD ... + if (drmIsMaster(fd) or drmSetMaster(fd) == 0) + return fd; + + // There is definitely no way we get master ... + close(fd); + log_error("DRM/KMS: <%d> (%s) No way to get master rights!\n", m_id, __FUNCTION__); + return -1; +} + +//============================================================ +// drmkms_timing::update_mode +//============================================================ + +bool drmkms_timing::update_mode(modeline *mode) +{ + if (!mode) + return false; + + if (!m_desktop_output) + { + log_error("DRM/KMS: <%d> (update_mode) [ERROR] no screen detected\n", m_id); + return false; + } + + // Without libdrm hook, the update method isn't natively supported, so we must delete + // the mode and readd it with updated timings. + if (!(m_caps & CUSTOM_VIDEO_CAPS_UPDATE)) + { + if (!delete_mode(mode)) + { + log_error("DRM/KMS: <%d> (update_mode) [ERROR] delete operation not successful", m_id); + return false; + } + if (!add_mode(mode)) + { + log_error("DRM/KMS: <%d> (update_mode) [ERROR] add operation not successful", m_id); + return false; + } + return true; + } + + // libdrn hook case, we can update timings directly in the connector's data + drmModeConnector *conn = drmModeGetConnectorCurrent(m_drm_fd, m_desktop_output); + if (conn) + { + for (int i = 0; i < conn->count_modes; i++) + { + drmModeModeInfo *drmmode = &conn->modes[i]; + if ((int)mode->platform_data == i) + { + int m_type = drmmode->type; + modeline_to_drm_modeline(m_id, mode, drmmode); + drmmode->type = m_type; + return true; + } + } + } + + return false; +} + +//============================================================ +// drmkms_timing::add_mode +//============================================================ + +bool drmkms_timing::add_mode(modeline *mode) +{ + if (!mode) + return false; + + // Handle no screen detected case + if (!m_desktop_output) + { + log_error("DRM/KMS: <%d> (add_mode) [ERROR] no screen detected\n", m_id); + return false; + } + + if (!mp_crtc_desktop) + { + log_error("DRM/KMS: <%d> (add_mode) [ERROR] no desktop crtc\n", m_id); + return false; + } + + if (!mode) + return false; + + if (m_kernel_user_modes) + { + int ret = 0, fd = m_drm_fd; + drmModeModeInfo drmmode; + + if (!drmIsMaster(fd)) + fd = get_master_fd(); + + if (!drmIsMaster(fd)) + { + log_error("DRM/KMS: <%d> (%s) Need master to add a kernel mode (%d)\n", m_id, __FUNCTION__, ret); + return false; + } + + modeline_to_drm_modeline(m_id, mode, &drmmode); + drmmode.type = DRM_MODE_TYPE_USERDEF; + + log_verbose("DRM/KMS: <%d> (add_mode) [DEBUG] Adding a mode to the kernel: %dx%d %s\n", m_id, drmmode.hdisplay, drmmode.vdisplay, drmmode.name); + // Calling drmModeGetConnector forces a refresh of the connector modes, which is slow, so don't do it + ret = drmModeAttachMode(fd, m_desktop_output, &drmmode); + if (ret != 0) + { + // This case hardly has any chance to happen, since at this point + // we are drmMaster, and we have already checked that the kernel + // supports user modes. If any error, it's on the kernel side + log_verbose("DRM/KMS: <%d> (%s) Couldn't add mode (ret=%d)\n", m_id, __FUNCTION__, ret); + if (fd != m_hook_fd) + drmDropMaster(fd); + return false; + } + log_verbose("DRM/KMS: <%d> (%s) Mode added\n", m_id, __FUNCTION__); + if (fd != m_hook_fd) + drmDropMaster(fd); + } + + return true; +} + +//============================================================ +// drmkms_timing::set_timing +//============================================================ + +bool drmkms_timing::set_timing(modeline *mode) +{ + if (!mode) + return false; + + // Handle no screen detected case + if (!m_desktop_output) + { + log_error("DRM/KMS: <%d> (set_timing) [ERROR] no screen detected\n", m_id); + return false; + } + + if (!kms_has_mode(mode)) + add_mode(mode); + + // If we can't be master, no need to go further + drmSetMaster(m_drm_fd); + if (!drmIsMaster(m_drm_fd)) + return false; + + // Setup the DRM mode structure + drmModeModeInfo dmode = {}; + + // Create specific mode name + snprintf(dmode.name, 32, "SR-%d_%dx%d@%.02f%s", m_id, mode->hactive, mode->vactive, mode->vfreq, mode->interlace ? "i" : ""); + dmode.clock = mode->pclock / 1000; + dmode.hdisplay = mode->hactive; + dmode.hsync_start = mode->hbegin; + dmode.hsync_end = mode->hend; + dmode.htotal = mode->htotal; + dmode.vdisplay = mode->vactive; + dmode.vsync_start = mode->vbegin; + dmode.vsync_end = mode->vend; + dmode.vtotal = mode->vtotal; + dmode.flags = (mode->interlace ? DRM_MODE_FLAG_INTERLACE : 0) | (mode->doublescan ? DRM_MODE_FLAG_DBLSCAN : 0) | (mode->hsync ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC) | (mode->vsync ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC); + + dmode.hskew = 0; + dmode.vscan = 0; + + dmode.vrefresh = mode->refresh; // Used only for human readable output + + dmode.type = DRM_MODE_TYPE_USERDEF; //DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + mode->type |= CUSTOM_VIDEO_TIMING_DRMKMS; + + if (mode->type & MODE_DESKTOP) + { + log_verbose("DRM/KMS: <%d> (set_timing) restore desktop mode\n", m_id); + drmModeSetCrtc(m_drm_fd, mp_crtc_desktop->crtc_id, mp_crtc_desktop->buffer_id, mp_crtc_desktop->x, mp_crtc_desktop->y, &m_desktop_output, 1, &mp_crtc_desktop->mode); + if (m_dumb_handle) + { + int ret = ioctl(m_drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &m_dumb_handle); + if (ret) + log_verbose("DRM/KMS: <%d> (set_timing) [ERROR] ioctl DRM_IOCTL_MODE_DESTROY_DUMB %d\n", m_id, ret); + m_dumb_handle = 0; + } + if (m_framebuffer_id && m_framebuffer_id != mp_crtc_desktop->buffer_id) + { + if (drmModeRmFB(m_drm_fd, m_framebuffer_id)) + log_verbose("DRM/KMS: <%d> (set_timing) [ERROR] remove frame buffer\n", m_id); + m_framebuffer_id = 0; + } + } + else + { + unsigned int old_dumb_handle = m_dumb_handle; + + drmModeFB *pframebuffer = drmModeGetFB(m_drm_fd, mp_crtc_desktop->buffer_id); + log_verbose("DRM/KMS: <%d> (set_timing) existing frame buffer id %d size %dx%d bpp %d\n", m_id, mp_crtc_desktop->buffer_id, pframebuffer->width, pframebuffer->height, pframebuffer->bpp); + //drmModePlaneRes *pplanes = drmModeGetPlaneResources(m_drm_fd); + //log_verbose("DRM/KMS: <%d> (add_mode) total planes %d\n", m_id, pplanes->count_planes); + //drmModeFreePlaneResources(pplanes); + + unsigned int framebuffer_id = mp_crtc_desktop->buffer_id; + + //if (pframebuffer->width < dmode.hdisplay || pframebuffer->height < dmode.vdisplay) + if (1) + { + log_verbose("DRM/KMS: <%d> (set_timing) creating new frame buffer with size %dx%d\n", m_id, dmode.hdisplay, dmode.vdisplay); + + // create a new dumb fb (not driver specefic) + drm_mode_create_dumb create_dumb = {}; + create_dumb.width = dmode.hdisplay; + create_dumb.height = dmode.vdisplay; + create_dumb.bpp = pframebuffer->bpp; + + int ret = ioctl(m_drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + if (ret) + log_verbose("DRM/KMS: <%d> (set_timing) [ERROR] ioctl DRM_IOCTL_MODE_CREATE_DUMB %d\n", m_id, ret); + + if (drmModeAddFB(m_drm_fd, dmode.hdisplay, dmode.vdisplay, pframebuffer->depth, pframebuffer->bpp, create_dumb.pitch, create_dumb.handle, &framebuffer_id)) + log_error("DRM/KMS: <%d> (set_timing) [ERROR] cannot add frame buffer\n", m_id); + else + m_dumb_handle = create_dumb.handle; + + drm_mode_map_dumb map_dumb = {}; + map_dumb.handle = create_dumb.handle; + + ret = drmIoctl(m_drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); + if (ret) + log_verbose("DRM/KMS: <%d> (set_timing) [ERROR] ioctl DRM_IOCTL_MODE_MAP_DUMB %d\n", m_id, ret); + + void *map = mmap(0, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED, m_drm_fd, map_dumb.offset); + if (map != MAP_FAILED) + { + // clear the frame buffer + memset(map, 0, create_dumb.size); + } + else + log_verbose("DRM/KMS: <%d> (set_timing) [ERROR] failed to map frame buffer %p\n", m_id, map); + } + else + log_verbose("DRM/KMS: <%d> (set_timing) use existing frame buffer\n", m_id); + + drmModeFreeFB(pframebuffer); + + pframebuffer = drmModeGetFB(m_drm_fd, framebuffer_id); + log_verbose("DRM/KMS: <%d> (set_timing) frame buffer id %d size %dx%d bpp %d\n", m_id, framebuffer_id, pframebuffer->width, pframebuffer->height, pframebuffer->bpp); + drmModeFreeFB(pframebuffer); + + // set the mode on the crtc + if (drmModeSetCrtc(m_drm_fd, mp_crtc_desktop->crtc_id, framebuffer_id, 0, 0, &m_desktop_output, 1, &dmode)) + log_error("DRM/KMS: <%d> (set_timing) [ERROR] cannot attach the mode to the crtc %d frame buffer %d\n", m_id, mp_crtc_desktop->crtc_id, framebuffer_id); + else + { + if (old_dumb_handle) + { + log_verbose("DRM/KMS: <%d> (set_timing) remove old dumb %d\n", m_id, old_dumb_handle); + int ret = ioctl(m_drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &old_dumb_handle); + if (ret) + log_verbose("DRM/KMS: <%d> (set_timing) [ERROR] ioctl DRM_IOCTL_MODE_DESTROY_DUMB %d\n", m_id, ret); + old_dumb_handle = 0; + } + if (m_framebuffer_id && framebuffer_id != mp_crtc_desktop->buffer_id) + { + log_verbose("DRM/KMS: <%d> (set_timing) remove old frame buffer %d\n", m_id, m_framebuffer_id); + drmModeRmFB(m_drm_fd, m_framebuffer_id); + m_framebuffer_id = 0; + } + m_framebuffer_id = framebuffer_id; + } + } + if (can_drop_master) + drmDropMaster(m_drm_fd); + + return true; +} + +//============================================================ +// drmkms_timing::delete_mode +//============================================================ + +bool drmkms_timing::delete_mode(modeline *mode) +{ + if (!mode) + return false; + + // Handle no screen detected case + if (!m_desktop_output) + { + log_error("DRM/KMS: <%d> (delete_mode) [ERROR] no screen detected\n", m_id); + return false; + } + + if (m_kernel_user_modes) + { + int i = 0, ret = 0, fd = -1; + drmModeConnector *conn; + + // If SR was initilized before SDL2 for instance, SR lost the DRM + fd = get_master_fd(); + if (fd < 0) + { + log_verbose("DRM/KMS: <%d> (%s) Need master to remove kernel user modes\n", m_id, __FUNCTION__); + return false; + } + + drmModeModeInfo srmode; + conn = drmModeGetConnectorCurrent(fd, m_desktop_output); + modeline_to_drm_modeline(m_id, mode, &srmode); + for (i = 0; i < conn->count_modes; i++) + { + drmModeModeInfo *drmmode = &conn->modes[i]; + ret = strcmp(drmmode->name, srmode.name); + if (ret != 0) + continue; + ret = drmModeDetachMode(fd, m_desktop_output, drmmode); + if (fd != m_hook_fd) + drmDropMaster(m_drm_fd); + drmModeFreeConnector(conn); + if (ret != 0) + { + log_verbose("DRM/KMS: <%d> (%s) Failed removing kernel user mode: %s (ret=%d)\n", m_id, __FUNCTION__, drmmode->name, ret); + return false; + } + return true; + } + } + + return true; +} + +//============================================================ +// drmkms_timing::get_timing +//============================================================ + +bool drmkms_timing::get_timing(modeline *mode) +{ + // Handle no screen detected case + if (!m_desktop_output) + { + log_error("DRM/KMS: <%d> (get_timing) [ERROR] no screen detected\n", m_id); + return false; + } + + // INFO: not used vrefresh, hskew, vscan + drmModeRes *p_res = drmModeGetResources(m_drm_fd); + + for (int i = 0; i < p_res->count_connectors; i++) + { + drmModeConnector *p_connector = drmModeGetConnectorCurrent(m_drm_fd, p_res->connectors[i]); + + // Cycle through the modelines and report them back to the display manager + if (p_connector && m_desktop_output == p_connector->connector_id) + { + if (m_video_modes_position < p_connector->count_modes) + { + drmModeModeInfo *pdmode = &p_connector->modes[m_video_modes_position++]; + + // Use mode position as index + mode->platform_data = m_video_modes_position - 1; + + mode->pclock = pdmode->clock * 1000; + mode->hactive = pdmode->hdisplay; + mode->hbegin = pdmode->hsync_start; + mode->hend = pdmode->hsync_end; + mode->htotal = pdmode->htotal; + mode->vactive = pdmode->vdisplay; + mode->vbegin = pdmode->vsync_start; + mode->vend = pdmode->vsync_end; + mode->vtotal = pdmode->vtotal; + mode->interlace = (pdmode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; + mode->doublescan = (pdmode->flags & DRM_MODE_FLAG_DBLSCAN) ? 1 : 0; + mode->hsync = (pdmode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; + mode->vsync = (pdmode->flags & DRM_MODE_FLAG_PVSYNC) ? 1 : 0; + + mode->hfreq = mode->pclock / mode->htotal; + mode->vfreq = mode->hfreq / mode->vtotal * (mode->interlace ? 2 : 1); + + // Store drm's integer refresh to make sure we use the same rounding + mode->refresh = pdmode->vrefresh; + + mode->width = pdmode->hdisplay; + mode->height = pdmode->vdisplay; + + // Add the rotation flag from the plane (DRM_MODE_ROTATE_xxx) + // TODO: mode->type |= MODE_ROTATED; + + mode->type |= CUSTOM_VIDEO_TIMING_DRMKMS; + + // Check if this is a dummy mode + if (pdmode->type & (1<<7)) mode->type |= XYV_EDITABLE | SCAN_EDITABLE; + + if (strncmp(pdmode->name, "SR-", 3) == 0) + log_verbose("DRM/KMS: <%d> (get_timing) [WARNING] modeline %s detected\n", m_id, pdmode->name); + else if (!strcmp(pdmode->name, mp_crtc_desktop->mode.name) && pdmode->clock == mp_crtc_desktop->mode.clock && pdmode->vrefresh == mp_crtc_desktop->mode.vrefresh) + { + // Add the desktop flag to desktop modeline + log_verbose("DRM/KMS: <%d> (get_timing) desktop mode name %s refresh %d found\n", m_id, mp_crtc_desktop->mode.name, mp_crtc_desktop->mode.vrefresh); + mode->type |= MODE_DESKTOP; + } + } + else + { + // Inititalise the position for the modeline list + m_video_modes_position = 0; + } + } + drmModeFreeConnector(p_connector); + } + drmModeFreeResources(p_res); + + return true; +} + +//============================================================ +// drmkms_timing::process_modelist +//============================================================ + +bool drmkms_timing::process_modelist(std::vector modelist) +{ + bool error = false; + bool result = false; + + for (auto &mode : modelist) + { + if (mode->type & MODE_DELETE) + result = delete_mode(mode); + + else if (mode->type & MODE_ADD) + result = add_mode(mode); + + else if (mode->type & MODE_UPDATE) + result = update_mode(mode); + + if (!result) + { + mode->type |= MODE_ERROR; + error = true; + } + else + // succeed + mode->type &= ~MODE_ERROR; + } + + return !error; +} + +void drmkms_timing::list_drm_modes() +{ + int i = 0; + drmModeConnector *conn; + drmModeModeInfo *drmmode; + + conn = drmModeGetConnectorCurrent(m_drm_fd, m_desktop_output); + for (i = 0; i < conn->count_modes; i++) + { + drmmode = &conn->modes[i]; + log_verbose("DRM/KMS: <%d> (%s) DRM mode: %dx%d %s\n", m_id, __FUNCTION__, drmmode->hdisplay, drmmode->vdisplay, drmmode->name); + } + drmModeFreeConnector(conn); +} + +//============================================================ +// drmkms_timing::kms_has_mode +//============================================================ + +bool drmkms_timing::kms_has_mode(modeline* mode) +{ + int i = 0; + drmModeConnector *conn; + drmModeModeInfo drmmode; + + // To avoid matching issues, we just compare the relevant timing fields + int size_to_compare = sizeof(drmModeModeInfo) - sizeof(drmModeModeInfo::type) - sizeof(drmModeModeInfo::name); + + modeline_to_drm_modeline(m_id, mode, &drmmode); + + conn = drmModeGetConnectorCurrent(m_drm_fd, m_desktop_output); + for (i = 0; i < conn->count_modes; i++) + { + if (memcmp(&drmmode, &conn->modes[i], size_to_compare) == 0) + { + log_verbose("DRM/KMS: <%d> (%s) Found the mode in the connector\n", m_id, __FUNCTION__); + drmModeFreeConnector(conn); + return true; + } + } + log_verbose("DRM/KMS: <%d> (%s) Couldn't find the mode in the connector\n", m_id, __FUNCTION__); + drmModeFreeConnector(conn); + return false; +} diff --git a/custom_video_drmkms.h b/custom_video_drmkms.h new file mode 100755 index 00000000000..43e2a3acf47 --- /dev/null +++ b/custom_video_drmkms.h @@ -0,0 +1,97 @@ +/************************************************************** + + custom_video_drmkms.h - Linux DRM/KMS video management layer + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __CUSTOM_VIDEO_DRMKMS_ +#define __CUSTOM_VIDEO_DRMKMS_ + +// DRM headers +#include +#include +#include "custom_video.h" + +class drmkms_timing : public custom_video +{ + public: + drmkms_timing(char *device_name, custom_video_settings *vs); + ~drmkms_timing(); + const char *api_name() { return "DRMKMS"; } + int caps() { return m_caps; } + bool init(); + + bool add_mode(modeline *mode); + bool delete_mode(modeline *mode); + bool update_mode(modeline *mode); + + bool process_modelist(std::vector); + + bool get_timing(modeline *mode); + bool set_timing(modeline *mode); + + private: + /* + * Consider m_id as the "display number": 1 for the 1st, 2 for the second etc... + */ + int m_id = 0; + + int m_drm_fd = -1; + drmModeCrtc *mp_crtc_desktop = NULL; + int m_card_id = 0; + bool m_kernel_user_modes = false; + bool can_drop_master = true; + int m_hook_fd = -1; + int m_caps = 0; + + char m_device_name[32]; + unsigned int m_desktop_output = 0; + int m_video_modes_position = 0; + + void *mp_drm_handle = NULL; + unsigned int m_dumb_handle = 0; + unsigned int m_framebuffer_id = 0; + + __typeof__(drmGetVersion) *p_drmGetVersion; + __typeof__(drmFreeVersion) *p_drmFreeVersion; + __typeof__(drmModeGetResources) *p_drmModeGetResources; + __typeof__(drmModeGetConnector) *p_drmModeGetConnector; + __typeof__(drmModeGetConnectorCurrent) *p_drmModeGetConnectorCurrent; + __typeof__(drmModeFreeConnector) *p_drmModeFreeConnector; + __typeof__(drmModeFreeResources) *p_drmModeFreeResources; + __typeof__(drmModeGetEncoder) *p_drmModeGetEncoder; + __typeof__(drmModeFreeEncoder) *p_drmModeFreeEncoder; + __typeof__(drmModeGetCrtc) *p_drmModeGetCrtc; + __typeof__(drmModeSetCrtc) *p_drmModeSetCrtc; + __typeof__(drmModeFreeCrtc) *p_drmModeFreeCrtc; + __typeof__(drmModeAttachMode) *p_drmModeAttachMode; + __typeof__(drmModeDetachMode) *p_drmModeDetachMode; + __typeof__(drmModeAddFB) *p_drmModeAddFB; + __typeof__(drmModeRmFB) *p_drmModeRmFB; + __typeof__(drmModeGetFB) *p_drmModeGetFB; + __typeof__(drmModeFreeFB) *p_drmModeFreeFB; + __typeof__(drmPrimeHandleToFD) *p_drmPrimeHandleToFD; + __typeof__(drmModeGetPlaneResources) *p_drmModeGetPlaneResources; + __typeof__(drmModeFreePlaneResources) *p_drmModeFreePlaneResources; + __typeof__(drmIoctl) *p_drmIoctl; + __typeof__(drmGetCap) *p_drmGetCap; + __typeof__(drmIsMaster) *p_drmIsMaster; + __typeof__(drmSetMaster) *p_drmSetMaster; + __typeof__(drmDropMaster) *p_drmDropMaster; + + bool test_kernel_user_modes(); + bool kms_has_mode(modeline*); + void list_drm_modes(); + int get_master_fd(); + +}; + +#endif diff --git a/custom_video_pstrip.cpp b/custom_video_pstrip.cpp new file mode 100644 index 00000000000..f7542bfe92f --- /dev/null +++ b/custom_video_pstrip.cpp @@ -0,0 +1,628 @@ +/************************************************************** + + custom_video_pstrip.cpp - PowerStrip interface routines + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +/* http://forums.entechtaiwan.com/index.php?topic=5534.msg20902;topicseen#msg20902 + + UM_SETCUSTOMTIMING = WM_USER+200; + wparam = monitor number, zero-based + lparam = atom for string pointer + lresult = -1 for failure else current pixel clock (integer in Hz) + Note: pass full PowerStrip timing string* + + UM_SETREFRESHRATE = WM_USER+201; + wparam = monitor number, zero-based + lparam = refresh rate (integer in Hz), or 0 for read-only + lresult = -1 for failure else current refresh rate (integer in Hz) + + UM_SETPOLARITY = WM_USER+202; + wparam = monitor number, zero-based + lparam = polarity bits + lresult = -1 for failure else current polarity bits+1 + + UM_REMOTECONTROL = WM_USER+210; + wparam = 99 + lparam = + 0 to hide tray icon + 1 to show tray icon, + 2 to get build number + 10 to show Performance profiles + 11 to show Color profiles + 12 to show Display profiles + 13 to show Application profiles + 14 to show Adapter information + 15 to show Monitor information + 16 to show Hotkey manager + 17 to show Resource manager + 18 to show Preferences + 19 to show Online services + 20 to show About screen + 21 to show Tip-of-the-day + 22 to show Setup wizard + 23 to show Screen fonts + 24 to show Advanced timing options + 25 to show Custom resolutions + 99 to close PS + lresult = -1 for failure else lparam+1 for success or build number (e.g., 335) + if lparam was 2 + + UM_SETGAMMARAMP = WM_USER+203; + wparam = monitor number, zero-based + lparam = atom for string pointer + lresult = -1 for failure, 1 for success + + UM_CREATERESOLUTION = WM_USER+204; + wparam = monitor number, zero-based + lparam = atom for string pointer + lresult = -1 for failure, 1 for success + Note: pass full PowerStrip timing string*; reboot is usually necessary to see if + the resolution is accepted by the display driver + + UM_GETTIMING = WM_USER+205; + wparam = monitor number, zero-based + lresult = -1 for failure else GlobalAtom number identifiying the timing string* + Note: be sure to call GlobalDeleteAtom after reading the string associated with + the atom + + UM_GETSETCLOCKS = WM_USER+206; + wparam = monitor number, zero-based + lparam = atom for string pointer + lresult = -1 for failure else GlobalAtom number identifiying the performance + string** + Note: pass full PowerStrip performance string** to set the clocks, and ull to + get clocks; be sure to call GlobalDeleteAtom after reading the string associated + with the atom + + NegativeHorizontalPolarity = 0x02; + NegativeVerticalPolarity = 0x04; + + *Timing string parameter definition: + 1 = horizontal active pixels + 2 = horizontal front porch + 3 = horizontal sync width + 4 = horizontal back porch + 5 = vertical active pixels + 6 = vertical front porch + 7 = vertical sync width + 8 = vertical back porch + 9 = pixel clock in hertz + 10 = timing flags, where bit: + 1 = negative horizontal porlarity + 2 = negative vertical polarity + 3 = interlaced + 5 = composite sync + 7 = sync-on-green + all other bits reserved + + **Performance string parameter definition: + 1 = memory clock in hertz + 2 = engine clock in hertz + 3 = reserved + 4 = reserved + 5 = reserved + 6 = reserved + 7 = reserved + 8 = reserved + 9 = 2D memory clock in hertz (if different from 3D) + 10 = 2D engine clock in hertz (if different from 3D) */ + +#include +#include + +#include "custom_video_pstrip.h" +#include "log.h" + +//============================================================ +// CONSTANTS +//============================================================ + +#define UM_SETCUSTOMTIMING (WM_USER+200) +#define UM_SETREFRESHRATE (WM_USER+201) +#define UM_SETPOLARITY (WM_USER+202) +#define UM_REMOTECONTROL (WM_USER+210) +#define UM_SETGAMMARAMP (WM_USER+203) +#define UM_CREATERESOLUTION (WM_USER+204) +#define UM_GETTIMING (WM_USER+205) +#define UM_GETSETCLOCKS (WM_USER+206) +#define UM_SETCUSTOMTIMINGFAST (WM_USER+211) // glitches vertical sync with PS 3.65 build 568 + +#define NegativeHorizontalPolarity 0x02 +#define NegativeVerticalPolarity 0x04 +#define Interlace 0x08 + +#define HideTrayIcon 0x00 +#define ShowTrayIcon 0x01 +#define ClosePowerStrip 0x63 + +//============================================================ +// pstrip_timing::pstrip_timing +//============================================================ + +pstrip_timing::pstrip_timing(char *device_name, custom_video_settings *vs) +{ + m_vs = *vs; + strcpy (m_device_name, device_name); + strcpy (m_ps_timing, m_vs.custom_timing); +} + +//============================================================ +// pstrip_timing::~pstrip_timing() +//============================================================ + +pstrip_timing::~pstrip_timing() +{ + ps_reset(); +} + +//============================================================ +// pstrip_timing::init +//============================================================ + +bool pstrip_timing::init() +{ + m_monitor_index = ps_monitor_index(m_device_name); + + hPSWnd = FindWindowA("TPShidden", NULL); + + if (hPSWnd) + { + log_verbose("PStrip: PowerStrip found!\n"); + + // Save current settings + ps_get_monitor_timing(&m_timing_backup); + + // If we have a -ps_timing string defined, use it as user defined modeline + if (strcmp(m_ps_timing, "auto")) + { + MonitorTiming timing; + if (ps_read_timing_string(m_ps_timing, &timing)) + { + ps_pstiming_to_modeline(&timing, &m_user_mode); + m_user_mode.type |= CUSTOM_VIDEO_TIMING_POWERSTRIP; + + char modeline_txt[256]={'\x00'}; + log_verbose("SwitchRes: ps_string: %s (%s)\n", m_ps_timing, modeline_print(&m_user_mode, modeline_txt, MS_PARAMS)); + } + else + log_verbose("Switchres: ps_timing string with invalid format\n"); + } + } + else + { + log_verbose("PStrip: Could not get PowerStrip API interface\n"); + return false; + } + + return true; +} + +//============================================================ +// pstrip_timing::get_timing +//============================================================ + +bool pstrip_timing::get_timing(modeline *mode) +{ + // If we have an user defined mode (ps_timing), lock any non matching mode + if (m_user_mode.hactive) + { + if (mode->width != m_user_mode.width || mode->height != m_user_mode.height) + { + mode->type |= MODE_DISABLED; + return false; + } + } + + modeline m_temp = {}; + if (ps_get_modeline(&m_temp)) + { + // We can only get the timings of the current desktop mode, so filter out anything different + if (m_temp.width == mode->width && m_temp.height == mode->height && m_temp.refresh == mode->refresh) + { + *mode = m_temp; + } + mode->type |= CUSTOM_VIDEO_TIMING_POWERSTRIP; + return true; + } + + return false; +} + +//============================================================ +// pstrip_timing::set_timing +//============================================================ + +bool pstrip_timing::set_timing(modeline *mode) +{ + // In case -ps_timing is provided, pass it as raw string + if (m_user_mode.hactive) + ps_set_monitor_timing_string(m_ps_timing); + + // Otherwise pass it as modeline + else + ps_set_modeline(mode); + + Sleep(100); + return true; +} + + +//============================================================ +// pstrip_timing::ps_reset +//============================================================ + +int pstrip_timing::ps_reset() +{ + return ps_set_monitor_timing(&m_timing_backup); +} + +//============================================================ +// ps_get_modeline +//============================================================ + +int pstrip_timing::ps_get_modeline(modeline *modeline) +{ + MonitorTiming timing = {}; + + if (ps_get_monitor_timing(&timing)) + { + ps_pstiming_to_modeline(&timing, modeline); + return 1; + } + else return 0; +} + +//============================================================ +// pstrip_timing::ps_set_modeline +//============================================================ + +bool pstrip_timing::ps_set_modeline(modeline *modeline) +{ + MonitorTiming timing = {}; + + if (!ps_modeline_to_pstiming(modeline, &timing)) + return false; + + timing.PixelClockInKiloHertz = ps_best_pclock(&timing, timing.PixelClockInKiloHertz); + + if (ps_set_monitor_timing(&timing)) + return true; + else + return false; +} + +//============================================================ +// pstrip_timing::ps_get_monitor_timing +//============================================================ + +int pstrip_timing::ps_get_monitor_timing(MonitorTiming *timing) +{ + LRESULT lresult; + char in[256]; + + if (!hPSWnd) return 0; + + lresult = SendMessage(hPSWnd, UM_GETTIMING, m_monitor_index, 0); + + if (lresult == -1) + { + log_verbose("PStrip: Could not get PowerStrip timing string\n"); + return 0; + } + + if (!GlobalGetAtomNameA(lresult, in, sizeof(in))) + { + log_verbose("PStrip: GlobalGetAtomName failed\n"); + return 0; + } + + log_verbose("PStrip: ps_get_monitor_timing(%d): %s\n", m_monitor_index, in); + + ps_read_timing_string(in, timing); + + GlobalDeleteAtom(lresult); // delete atom created by PowerStrip + + return 1; +} + +//============================================================ +// pstrip_timing::ps_set_monitor_timing +//============================================================ + +int pstrip_timing::ps_set_monitor_timing(MonitorTiming *timing) +{ + LRESULT lresult; + ATOM atom; + char out[256]; + + if (!hPSWnd) return 0; + + ps_fill_timing_string(out, timing); + atom = GlobalAddAtomA(out); + + if (atom) + { + lresult = SendMessage(hPSWnd, UM_SETCUSTOMTIMING, m_monitor_index, atom); + + if (lresult < 0) + { + log_verbose("PStrip: SendMessage failed\n"); + GlobalDeleteAtom(atom); + } + else + { + log_verbose("PStrip: ps_set_monitor_timing(%d): %s\n", m_monitor_index, out); + return 1; + } + } + else log_verbose("PStrip: ps_set_monitor_timing atom creation failed\n"); + + return 0; +} + +//============================================================ +// pstrip_timing::ps_set_monitor_timing_string +//============================================================ + +int pstrip_timing::ps_set_monitor_timing_string(char *in) +{ + MonitorTiming timing = {}; + + ps_read_timing_string(in, &timing); + return ps_set_monitor_timing(&timing); +} + +//============================================================ +// pstrip_timing::ps_set_refresh +//============================================================ + +int pstrip_timing::ps_set_refresh(double vfreq) +{ + MonitorTiming timing = {}; + int hht, vvt, new_vvt; + int desired_pClock; + int best_pClock; + + memcpy(&timing, &m_timing_backup, sizeof(MonitorTiming)); + + hht = timing.HorizontalActivePixels + + timing.HorizontalFrontPorch + + timing.HorizontalSyncWidth + + timing.HorizontalBackPorch; + + vvt = timing.VerticalActivePixels + + timing.VerticalFrontPorch + + timing.VerticalSyncWidth + + timing.VerticalBackPorch; + + desired_pClock = hht * vvt * vfreq / 1000; + best_pClock = ps_best_pclock(&timing, desired_pClock); + + new_vvt = best_pClock * 1000 / (vfreq * hht); + + timing.VerticalBackPorch += (new_vvt - vvt); + timing.PixelClockInKiloHertz = best_pClock; + + ps_set_monitor_timing(&timing); + ps_get_monitor_timing(&timing); + + return 1; +} + +//============================================================ +// pstrip_timing::ps_best_pclock +//============================================================ + +int pstrip_timing::ps_best_pclock(MonitorTiming *timing, int desired_pclock) +{ + MonitorTiming timing_read = {}; + int best_pclock = 0; + + log_verbose("PStrip: ps_best_pclock(%d), getting stable dotclocks for %d...\n", m_monitor_index, desired_pclock); + + for (int i = -50; i <= 50; i += 25) + { + timing->PixelClockInKiloHertz = desired_pclock + i; + + ps_set_monitor_timing(timing); + ps_get_monitor_timing(&timing_read); + + if (abs(timing_read.PixelClockInKiloHertz - desired_pclock) < abs(desired_pclock - best_pclock)) + best_pclock = timing_read.PixelClockInKiloHertz; + } + + log_verbose("PStrip: ps_best_pclock(%d), new dotclock: %d\n", m_monitor_index, best_pclock); + + return best_pclock; +} + +//============================================================ +// pstrip_timing::ps_create_resolution +//============================================================ + +int pstrip_timing::ps_create_resolution(modeline *modeline) +{ + LRESULT lresult; + ATOM atom; + char out[256]; + MonitorTiming timing = {}; + + if (!hPSWnd) return 0; + + ps_modeline_to_pstiming(modeline, &timing); + + ps_fill_timing_string(out, &timing); + atom = GlobalAddAtomA(out); + + if (atom) + { + lresult = SendMessage(hPSWnd, UM_CREATERESOLUTION, m_monitor_index, atom); + + if (lresult < 0) + { + log_verbose("PStrip: SendMessage failed\n"); + GlobalDeleteAtom(atom); + } + else + { + log_verbose("PStrip: ps_create_resolution(%d): %dx%d succeded \n", + modeline->width, modeline->height, m_monitor_index); + return 1; + } + } + else log_verbose("PStrip: ps_create_resolution atom creation failed\n"); + + return 0; +} + +//============================================================ +// pstrip_timing::ps_read_timing_string +//============================================================ + +bool pstrip_timing::ps_read_timing_string(char *in, MonitorTiming *timing) +{ + if (sscanf(in,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &timing->HorizontalActivePixels, + &timing->HorizontalFrontPorch, + &timing->HorizontalSyncWidth, + &timing->HorizontalBackPorch, + &timing->VerticalActivePixels, + &timing->VerticalFrontPorch, + &timing->VerticalSyncWidth, + &timing->VerticalBackPorch, + &timing->PixelClockInKiloHertz, + &timing->TimingFlags.w) == 10) return true; + + return false; +} + +//============================================================ +// pstrip_timing::ps_fill_timing_string +//============================================================ + +void pstrip_timing::ps_fill_timing_string(char *out, MonitorTiming *timing) +{ + sprintf(out, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + timing->HorizontalActivePixels, + timing->HorizontalFrontPorch, + timing->HorizontalSyncWidth, + timing->HorizontalBackPorch, + timing->VerticalActivePixels, + timing->VerticalFrontPorch, + timing->VerticalSyncWidth, + timing->VerticalBackPorch, + timing->PixelClockInKiloHertz, + timing->TimingFlags.w); +} + +//============================================================ +// pstrip_timing::ps_modeline_to_pstiming +//============================================================ + +bool pstrip_timing::ps_modeline_to_pstiming(modeline *modeline, MonitorTiming *timing) +{ + if (modeline->pclock == 0 || modeline->hactive == 0 || modeline->vactive == 0) + { + log_verbose("ps_modeline_to_pstiming error: invalid modeline\n"); + return false; + } + + timing->HorizontalActivePixels = modeline->hactive; + timing->HorizontalFrontPorch = modeline->hbegin - modeline->hactive; + timing->HorizontalSyncWidth = modeline->hend - modeline->hbegin; + timing->HorizontalBackPorch = modeline->htotal - modeline->hend; + + timing->VerticalActivePixels = modeline->vactive; + timing->VerticalFrontPorch = modeline->vbegin - modeline->vactive; + timing->VerticalSyncWidth = modeline->vend - modeline->vbegin; + timing->VerticalBackPorch = modeline->vtotal - modeline->vend; + + timing->PixelClockInKiloHertz = modeline->pclock / 1000; + + if (modeline->hsync == 0) + timing->TimingFlags.w |= NegativeHorizontalPolarity; + if (modeline->vsync == 0) + timing->TimingFlags.w |= NegativeVerticalPolarity; + if (modeline->interlace) + timing->TimingFlags.w |= Interlace; + + return true; +} + +//============================================================ +// pstrip_timing::ps_pstiming_to_modeline +//============================================================ + +int pstrip_timing::ps_pstiming_to_modeline(MonitorTiming *timing, modeline *modeline) +{ + modeline->hactive = timing->HorizontalActivePixels; + modeline->hbegin = modeline->hactive + timing->HorizontalFrontPorch; + modeline->hend = modeline->hbegin + timing->HorizontalSyncWidth; + modeline->htotal = modeline->hend + timing->HorizontalBackPorch; + + modeline->vactive = timing->VerticalActivePixels; + modeline->vbegin = modeline->vactive + timing->VerticalFrontPorch; + modeline->vend = modeline->vbegin + timing->VerticalSyncWidth; + modeline->vtotal = modeline->vend + timing->VerticalBackPorch; + + modeline->width = modeline->hactive; + modeline->height = modeline->vactive; + + modeline->pclock = timing->PixelClockInKiloHertz * 1000; + + if (!(timing->TimingFlags.w & NegativeHorizontalPolarity)) + modeline->hsync = 1; + + if (!(timing->TimingFlags.w & NegativeVerticalPolarity)) + modeline->vsync = 1; + + if ((timing->TimingFlags.w & Interlace)) + modeline->interlace = 1; + + modeline->hfreq = modeline->pclock / modeline->htotal; + modeline->vfreq = modeline->hfreq / modeline->vtotal * (modeline->interlace?2:1); + modeline->refresh = int(modeline->vfreq); + + return 0; +} + +//============================================================ +// pstrip_timing::ps_monitor_index +//============================================================ + +int pstrip_timing::ps_monitor_index (const char *display_name) +{ + int monitor_index = 0; + char sub_index[2]; + + sub_index[0] = display_name[strlen(display_name)-1]; + sub_index[1] = 0; + if (sscanf(sub_index,"%d", &monitor_index) == 1) + monitor_index --; + + return monitor_index; +} + +//============================================================ +// pstrip_timing::update_mode +//============================================================ + +bool pstrip_timing::update_mode(modeline *mode) +{ + if (!set_timing(mode)) + { + return false; + } + + mode->type |= CUSTOM_VIDEO_TIMING_POWERSTRIP; + return true; +} diff --git a/custom_video_pstrip.h b/custom_video_pstrip.h new file mode 100644 index 00000000000..5c32f7cfa6d --- /dev/null +++ b/custom_video_pstrip.h @@ -0,0 +1,83 @@ +/************************************************************** + + custom_video_powerstrip.h - PowerStrip interface routines + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include "custom_video.h" + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +typedef struct +{ + int HorizontalActivePixels; + int HorizontalFrontPorch; + int HorizontalSyncWidth; + int HorizontalBackPorch; + int VerticalActivePixels; + int VerticalFrontPorch; + int VerticalSyncWidth; + int VerticalBackPorch; + int PixelClockInKiloHertz; + union + { + int w; + struct + { + unsigned :1; + unsigned HorizontalPolarityNegative:1; + unsigned VerticalPolarityNegative:1; + unsigned :29; + } b; + } TimingFlags; +} MonitorTiming; + + +class pstrip_timing : public custom_video +{ + public: + pstrip_timing(char *device_name, custom_video_settings *vs); + ~pstrip_timing(); + const char *api_name() { return "PowerStrip"; } + bool init(); + int caps() { return CUSTOM_VIDEO_CAPS_UPDATE | CUSTOM_VIDEO_CAPS_SCAN_EDITABLE | CUSTOM_VIDEO_CAPS_DESKTOP_EDITABLE; } + + bool update_mode(modeline *mode); + + bool get_timing(modeline *mode); + bool set_timing(modeline *m); + + private: + + int ps_reset(); + int ps_get_modeline(modeline *modeline); + bool ps_set_modeline(modeline *modeline); + int ps_get_monitor_timing(MonitorTiming *timing); + int ps_set_monitor_timing(MonitorTiming *timing); + int ps_set_monitor_timing_string(char *in); + int ps_set_refresh(double vfreq); + int ps_best_pclock(MonitorTiming *timing, int desired_pclock); + int ps_create_resolution(modeline *modeline); + bool ps_read_timing_string(char *in, MonitorTiming *timing); + void ps_fill_timing_string(char *out, MonitorTiming *timing); + bool ps_modeline_to_pstiming(modeline *modeline, MonitorTiming *timing); + int ps_pstiming_to_modeline(MonitorTiming *timing, modeline *modeline); + int ps_monitor_index (const char *display_name); + + char m_device_name[32]; + char m_ps_timing[256]; + int m_monitor_index = 0; + modeline m_user_mode = {}; + MonitorTiming m_timing_backup = {}; + HWND hPSWnd = 0; +}; diff --git a/custom_video_xrandr.cpp b/custom_video_xrandr.cpp new file mode 100644 index 00000000000..83b163e6811 --- /dev/null +++ b/custom_video_xrandr.cpp @@ -0,0 +1,1204 @@ +/************************************************************** + + custom_video_xrandr.cpp - Linux XRANDR video management layer + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include +#include "custom_video_xrandr.h" +#include "log.h" + +//============================================================ +// library functions +//============================================================ + +#define XRRAddOutputMode p_XRRAddOutputMode +#define XRRConfigCurrentConfiguration p_XRRConfigCurrentConfiguration +#define XRRCreateMode p_XRRCreateMode +#define XRRDeleteOutputMode p_XRRDeleteOutputMode +#define XRRDestroyMode p_XRRDestroyMode +#define XRRFreeCrtcInfo p_XRRFreeCrtcInfo +#define XRRFreeOutputInfo p_XRRFreeOutputInfo +#define XRRFreeScreenConfigInfo p_XRRFreeScreenConfigInfo +#define XRRFreeScreenResources p_XRRFreeScreenResources +#define XRRGetCrtcInfo p_XRRGetCrtcInfo +#define XRRGetOutputInfo p_XRRGetOutputInfo +#define XRRGetScreenInfo p_XRRGetScreenInfo +#define XRRGetScreenResourcesCurrent p_XRRGetScreenResourcesCurrent +#define XRRQueryVersion p_XRRQueryVersion +#define XRRSetCrtcConfig p_XRRSetCrtcConfig +#define XRRSetScreenSize p_XRRSetScreenSize +#define XRRGetScreenSizeRange p_XRRGetScreenSizeRange + +#define XCloseDisplay p_XCloseDisplay +#define XGrabServer p_XGrabServer +#define XOpenDisplay p_XOpenDisplay +#define XSync p_XSync +#define XUngrabServer p_XUngrabServer +#define XSetErrorHandler p_XSetErrorHandler +#define XClearWindow p_XClearWindow +#define XFillRectangle p_XFillRectangle +#define XCreateGC p_XCreateGC + +//============================================================ +// error_handler +// xorg error handler (static) +//============================================================ + +int xrandr_timing::ms_xerrors = 0; +int xrandr_timing::ms_xerrors_flag = 0; +static int (*old_error_handler)(Display *, XErrorEvent *); + +static __typeof__(XGetErrorText) *p_XGetErrorText; +#define XGetErrorText p_XGetErrorText + +static int error_handler(Display *dpy, XErrorEvent *err) +{ + char buf[64]; + XGetErrorText(dpy, err->error_code, buf, 64); + buf[0] = '\0'; + xrandr_timing::ms_xerrors |= xrandr_timing::ms_xerrors_flag; + old_error_handler(dpy, err); + log_error("XRANDR: <-> (error_handler) [ERROR] %s error code %d flags %02x\n", buf, err->error_code, xrandr_timing::ms_xerrors); + return 0; +} + +//============================================================ +// id for class object (static) +//============================================================ + +static int s_id = 0; + +//============================================================ +// screen management exclusivity array (static) +//============================================================ + +static int s_total_managed_screen = 0; +static int *sp_shared_screen_manager = NULL; + +//============================================================ +// desktop screen positions (static) +//============================================================ + +static XRRCrtcInfo *sp_desktop_crtc = NULL; + +//============================================================ +// xrandr_timing::xrandr_timing +//============================================================ + +xrandr_timing::xrandr_timing(char *device_name, custom_video_settings *vs) +{ + m_vs = *vs; + + // Increment id for each new screen + m_id = ++s_id; + + log_verbose("XRANDR: <%d> (xrandr_timing) creation (%s)\n", m_id, device_name); + // Copy screen device name and limit size + if ((strlen(device_name) + 1) > 32) + { + strncpy(m_device_name, device_name, 31); + log_error("XRANDR: <%d> (xrandr_timing) [ERROR] the device name is too long it has been trucated to %s\n", m_id, m_device_name); + } + else + strcpy(m_device_name, device_name); + + if (m_vs.screen_reordering) + { + if (m_id == 1) + m_enable_screen_reordering = 1; + } + else if (m_vs.screen_compositing) + m_enable_screen_compositing = 1; + + log_verbose("XRANDR: <%d> (xrandr_timing) checking X availability (early stub)\n", m_id); + + m_x11_handle = dlopen("libX11.so", RTLD_NOW); + + if (m_x11_handle) + { + p_XOpenDisplay = (__typeof__(XOpenDisplay)) dlsym(m_x11_handle, "XOpenDisplay"); + if (p_XOpenDisplay == NULL) + { + log_error("XRANDR: <%d> (xrandr_timing) [ERROR] missing func %s in %s\n", m_id, "XOpenDisplay", "X11_LIBRARY"); + throw std::exception(); + } + else + { + if (!XOpenDisplay(NULL)) + { + log_verbose("XRANDR: <%d> (xrandr_timing) X server not found\n", m_id); + throw std::exception(); + } + } + } + else + { + log_error("XRANDR: <%d> (xrandr_timing) [ERROR] missing %s library\n", m_id, "X11_LIBRARY"); + throw std::exception(); + } + + s_total_managed_screen++; +} + +//============================================================ +// xrandr_timing::~xrandr_timing +//============================================================ + +xrandr_timing::~xrandr_timing() +{ + s_total_managed_screen--; + if (s_total_managed_screen == 0) + { + s_id = 0; + + if (sp_desktop_crtc) + delete[]sp_desktop_crtc; + + if (sp_shared_screen_manager) + delete[]sp_shared_screen_manager; + + // Restore default desktop background + XClearWindow(m_pdisplay, m_root); + } + + // Free the display + if (m_pdisplay != NULL) + XCloseDisplay(m_pdisplay); + + // close Xrandr library + if (m_xrandr_handle) + dlclose(m_xrandr_handle); + + // close X11 library + if (m_x11_handle) + dlclose(m_x11_handle); +} + +//============================================================ +// xrandr_timing::init +//============================================================ + +bool xrandr_timing::init() +{ + log_verbose("XRANDR: <%d> (init) loading Xrandr library\n", m_id); + if (!m_xrandr_handle) + m_xrandr_handle = dlopen("libXrandr.so", RTLD_NOW); + if (m_xrandr_handle) + { + p_XRRAddOutputMode = (__typeof__(XRRAddOutputMode)) dlsym(m_xrandr_handle, "XRRAddOutputMode"); + if (p_XRRAddOutputMode == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRAddOutputMode", "XRANDR_LIBRARY"); + return false; + } + + p_XRRConfigCurrentConfiguration = (__typeof__(XRRConfigCurrentConfiguration)) dlsym(m_xrandr_handle, "XRRConfigCurrentConfiguration"); + if (p_XRRConfigCurrentConfiguration == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRConfigCurrentConfiguration", "XRANDR_LIBRARY"); + return false; + } + + p_XRRCreateMode = (__typeof__(XRRCreateMode)) dlsym(m_xrandr_handle, "XRRCreateMode"); + if (p_XRRCreateMode == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRCreateMode", "XRANDR_LIBRARY"); + return false; + } + + p_XRRDeleteOutputMode = (__typeof__(XRRDeleteOutputMode)) dlsym(m_xrandr_handle, "XRRDeleteOutputMode"); + if (p_XRRDeleteOutputMode == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRDeleteOutputMode", "XRANDR_LIBRARY"); + return false; + } + + p_XRRDestroyMode = (__typeof__(XRRDestroyMode)) dlsym(m_xrandr_handle, "XRRDestroyMode"); + if (p_XRRDestroyMode == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRDestroyMode", "XRANDR_LIBRARY"); + return false; + } + + p_XRRFreeCrtcInfo = (__typeof__(XRRFreeCrtcInfo)) dlsym(m_xrandr_handle, "XRRFreeCrtcInfo"); + if (p_XRRFreeCrtcInfo == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRFreeCrtcInfo", "XRANDR_LIBRARY"); + return false; + } + + p_XRRFreeOutputInfo = (__typeof__(XRRFreeOutputInfo)) dlsym(m_xrandr_handle, "XRRFreeOutputInfo"); + if (p_XRRFreeOutputInfo == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRFreeOutputInfo", "XRANDR_LIBRARY"); + return false; + } + + p_XRRFreeScreenConfigInfo = (__typeof__(XRRFreeScreenConfigInfo)) dlsym(m_xrandr_handle, "XRRFreeScreenConfigInfo"); + if (p_XRRFreeScreenConfigInfo == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRFreeScreenConfigInfo", "XRANDR_LIBRARY"); + return false; + } + + p_XRRFreeScreenResources = (__typeof__(XRRFreeScreenResources)) dlsym(m_xrandr_handle, "XRRFreeScreenResources"); + if (p_XRRFreeScreenResources == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRFreeScreenResources", "XRANDR_LIBRARY"); + return false; + } + + p_XRRGetCrtcInfo = (__typeof__(XRRGetCrtcInfo)) dlsym(m_xrandr_handle, "XRRGetCrtcInfo"); + if (p_XRRGetCrtcInfo == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRGetCrtcInfo", "XRANDR_LIBRARY"); + return false; + } + + p_XRRGetOutputInfo = (__typeof__(XRRGetOutputInfo)) dlsym(m_xrandr_handle, "XRRGetOutputInfo"); + if (p_XRRGetOutputInfo == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRGetOutputInfo", "XRANDR_LIBRARY"); + return false; + } + + p_XRRGetScreenInfo = (__typeof__(XRRGetScreenInfo)) dlsym(m_xrandr_handle, "XRRGetScreenInfo"); + if (p_XRRGetScreenInfo == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRGetScreenInfo", "XRANDR_LIBRARY"); + return false; + } + + p_XRRGetScreenResourcesCurrent = (__typeof__(XRRGetScreenResourcesCurrent)) dlsym(m_xrandr_handle, "XRRGetScreenResourcesCurrent"); + if (p_XRRGetScreenResourcesCurrent == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRGetScreenResourcesCurrent", "XRANDR_LIBRARY"); + return false; + } + + p_XRRQueryVersion = (__typeof__(XRRQueryVersion)) dlsym(m_xrandr_handle, "XRRQueryVersion"); + if (p_XRRQueryVersion == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRQueryVersion", "XRANDR_LIBRARY"); + return false; + } + + p_XRRSetCrtcConfig = (__typeof__(XRRSetCrtcConfig)) dlsym(m_xrandr_handle, "XRRSetCrtcConfig"); + if (p_XRRSetCrtcConfig == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRSetCrtcConfig", "XRANDR_LIBRARY"); + return false; + } + + p_XRRSetScreenSize = (__typeof__(XRRSetScreenSize)) dlsym(m_xrandr_handle, "XRRSetScreenSize"); + if (p_XRRSetScreenSize == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRSetScreenSize", "XRANDR_LIBRARY"); + return false; + } + + p_XRRGetScreenSizeRange = (__typeof__(XRRGetScreenSizeRange)) dlsym(m_xrandr_handle, "XRRGetScreenSizeRange"); + if (p_XRRGetScreenSizeRange == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XRRSetScreenSize", "XRANDR_LIBRARY"); + return false; + } + } + else + { + log_error("XRANDR: <%d> (init) [ERROR] missing %s library\n", m_id, "XRANDR_LIBRARY"); + return false; + } + + log_verbose("XRANDR: <%d> (init) loading X11 library\n", m_id); + if (!m_x11_handle) + m_x11_handle = dlopen("libX11.so", RTLD_NOW); + if (m_x11_handle) + { + p_XCloseDisplay = (__typeof__(XCloseDisplay)) dlsym(m_x11_handle, "XCloseDisplay"); + if (p_XCloseDisplay == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XCloseDisplay", "X11_LIBRARY"); + return false; + } + + p_XGrabServer = (__typeof__(XGrabServer)) dlsym(m_x11_handle, "XGrabServer"); + if (p_XGrabServer == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XGrabServer", "X11_LIBRARY"); + return false; + } + + p_XOpenDisplay = (__typeof__(XOpenDisplay)) dlsym(m_x11_handle, "XOpenDisplay"); + if (p_XOpenDisplay == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XOpenDisplay", "X11_LIBRARY"); + return false; + } + + p_XSync = (__typeof__(XSync)) dlsym(m_x11_handle, "XSync"); + if (p_XSync == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XSync", "X11_LIBRARY"); + return false; + } + + p_XUngrabServer = (__typeof__(XUngrabServer)) dlsym(m_x11_handle, "XUngrabServer"); + if (p_XUngrabServer == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XUngrabServer", "X11_LIBRARY"); + return false; + } + + p_XSetErrorHandler = (__typeof__(XSetErrorHandler)) dlsym(m_x11_handle, "XSetErrorHandler"); + if (p_XSetErrorHandler == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XSetErrorHandler", "X11_LIBRARY"); + return false; + } + + p_XGetErrorText = (__typeof__(XGetErrorText)) dlsym(m_x11_handle, "XGetErrorText"); + if (p_XGetErrorText == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s\n", m_id, "XGetErrorText", "X11_LIBRARY"); + return false; + } + + p_XClearWindow = (__typeof__(XClearWindow)) dlsym(m_x11_handle, "XClearWindow"); + if (p_XClearWindow == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XClearWindow", "X11_LIBRARY"); + return false; + } + + p_XFillRectangle = (__typeof__(XFillRectangle)) dlsym(m_x11_handle, "XFillRectangle"); + if (p_XFillRectangle == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XFillRectangle", "X11_LIBRARY"); + return false; + } + + p_XCreateGC = (__typeof__(XCreateGC)) dlsym(m_x11_handle, "XCreateGC"); + if (p_XCreateGC == NULL) + { + log_error("XRANDR: <%d> (init) [ERROR] missing func %s in %s", m_id, "XCreateGC", "X11_LIBRARY"); + return false; + } + } + else + { + log_error("XRANDR: <%d> (init) [ERROR] missing %s library\n", m_id, "X11_LIBRARY"); + return false; + } + + // Select current display and root window + // m_pdisplay is global to reduce open/close calls, resource is freed when class is destroyed + if (!m_pdisplay) + m_pdisplay = XOpenDisplay(NULL); + + if (!m_pdisplay) + { + log_error("XRANDR: <%d> (init) [ERROR] failed to connect to the X server\n", m_id); + return false; + } + + // Display XRANDR version + int major_version, minor_version; + XRRQueryVersion(m_pdisplay, &major_version, &minor_version); + log_verbose("XRANDR: <%d> (init) version %d.%d\n", m_id, major_version, minor_version); + + if (major_version < 1 || (major_version == 1 && minor_version < 2)) + { + log_error("XRANDR: <%d> (init) [ERROR] Xrandr version 1.2 or above is required\n", m_id); + return false; + } + + // screen_pos defines screen position, 0 is default first screen position and equivalent to 'auto' + int screen_pos = -1; + bool detected = false; + + // Handle the screen name, "auto", "screen[0-9]" and XRANDR device name + if (strlen(m_device_name) == 7 && !strncmp(m_device_name, "screen", 6) && m_device_name[6] >= '0' && m_device_name[6] <= '9') + screen_pos = m_device_name[6] - '0'; + else if (strlen(m_device_name) == 1 && m_device_name[0] >= '0' && m_device_name[0] <= '9') + screen_pos = m_device_name[0] - '0'; + + if (ScreenCount(m_pdisplay) > 1) + log_verbose("XRANDR: <%d> (init) [WARNING] screen count is %d, unpredictable behavior to be expected\n", m_id, ScreenCount(m_pdisplay)); + + for (int screen = 0; !detected && screen < ScreenCount(m_pdisplay); screen++) + { + log_verbose("XRANDR: <%d> (init) check screen number %d\n", m_id, screen); + m_screen = screen; + m_root = RootWindow(m_pdisplay, screen); + + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + + if (m_id == 1) + { + // Prepare the shared screen array + sp_shared_screen_manager = new int[resources->noutput]; + for (int o = 0; o < resources->noutput; o++) + sp_shared_screen_manager[o] = 0; + + // Save all active crtc positions + sp_desktop_crtc = new XRRCrtcInfo[resources->ncrtc]; + for (int c = 0; c < resources->ncrtc; c++) + memcpy(&sp_desktop_crtc[c], XRRGetCrtcInfo(m_pdisplay, resources, resources->crtcs[c]), sizeof(XRRCrtcInfo)); + } + + // Get default screen rotation from screen configuration + XRRScreenConfiguration *sc = XRRGetScreenInfo(m_pdisplay, m_root); + XRRConfigCurrentConfiguration(sc, &m_desktop_rotation); + XRRFreeScreenConfigInfo(sc); + + Rotation current_rotation = 0; + int output_position = 0; + for (int o = 0; o < resources->noutput; o++) + { + XRROutputInfo *output_info = XRRGetOutputInfo(m_pdisplay, resources, resources->outputs[o]); + if (!output_info) + { + log_error("XRANDR: <%d> (init) [ERROR] could not get output 0x%x information\n", m_id, (unsigned int)resources->outputs[o]); + continue; + } + // Check all connected output + if (m_desktop_output == -1 && output_info->connection == RR_Connected && output_info->crtc) + { + + if (!strcmp(m_device_name, "auto") || !strcmp(m_device_name, output_info->name) || output_position == screen_pos) + { + // store the output connector + m_desktop_output = o; + + // store screen minium and maximum resolutions + int min_width; + int max_width; + int min_height; + int max_height; + XRRGetScreenSizeRange (m_pdisplay, m_root, &min_width, &min_height, &max_width, &max_height); + m_min_width = min_width; + m_max_width = max_width; + m_min_height = min_height; + m_max_height = max_height; + + if (sp_shared_screen_manager[m_desktop_output] == 0) + { + sp_shared_screen_manager[m_desktop_output] = m_id; + m_managed = 1; + } + + // identify the current modeline and rotation + XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(m_pdisplay, resources, output_info->crtc); + current_rotation = crtc_info->rotation; + for (int m = 0; m < resources->nmode && m_desktop_mode.id == 0; m++) + { + // Get screen mode + if (crtc_info->mode == resources->modes[m].id) + { + m_desktop_mode = resources->modes[m]; + m_last_crtc = *crtc_info; + } + } + XRRFreeCrtcInfo(crtc_info); + + // check screen rotation (left or right) + if (current_rotation & 0xe) + { + m_crtc_flags = MODE_ROTATED; + log_verbose("XRANDR: <%d> (init) desktop rotation is %s\n", m_id, (current_rotation & 0x2) ? "left" : ((current_rotation & 0x8) ? "right" : "inverted")); + } + } + output_position++; + } + log_verbose("XRANDR: <%d> (init) check output connector '%s' active %d crtc %d %s\n", m_id, output_info->name, output_info->connection == RR_Connected ? 1 : 0, output_info->crtc ? 1 : 0, m_desktop_output == o ? (m_managed ? "[SELECTED]" : "[UNMANAGED]") : ""); + XRRFreeOutputInfo(output_info); + } + XRRFreeScreenResources(resources); + + // Check if screen has been detected + detected = m_desktop_output != -1; + } + + if (!detected) + log_error("XRANDR: <%d> (init) [ERROR] no screen detected\n", m_id); + + else if (m_enable_screen_reordering) + { + // Global screen placement + modeline mode = {}; + mode.type = MODE_DESKTOP; + set_timing(&mode, XRANDR_ENABLE_SCREEN_REORDERING); + } + + return detected; +} + +//============================================================ +// xrandr_timing::update_mode +//============================================================ + +bool xrandr_timing::update_mode(modeline *mode) +{ + if (!mode) + return false; + + // Handle no screen detected case + if (m_desktop_output == -1) + { + log_error("XRANDR: <%d> (update_mode) [ERROR] no screen detected\n", m_id); + return false; + } + + if (!delete_mode(mode)) + { + log_error("XRANDR: <%d> (update_mode) [ERROR] delete operation not successful", m_id); + return false; + } + + if (!add_mode(mode)) + { + log_error("XRANDR: <%d> (update_mode) [ERROR] add operation not successful", m_id); + return false; + } + + return true; +} + +//============================================================ +// xrandr_timing::add_mode +//============================================================ + +bool xrandr_timing::add_mode(modeline *mode) +{ + if (!mode) + return false; + + // Handle no screen detected case + if (m_desktop_output == -1) + { + log_error("XRANDR: <%d> (add_mode) [ERROR] no screen detected\n", m_id); + return false; + } + + if (!m_managed) + { + log_error("XRANDR: <%d> (add_mode) [WARNING] this screen is managed by <%d>\n", m_id, sp_shared_screen_manager[m_desktop_output]); + return false; + } + + // Check if mode is available from the plaftform_data mode id + XRRModeInfo *pxmode = find_mode(mode); + if (pxmode != NULL) + { + log_error("XRANDR: <%d> (add_mode) [WARNING] mode already exist\n", m_id); + return true; + } + + // Create specific mode name + char name[48]; + sprintf(name, "SR-%d_%dx%d@%.02f%s", m_id, mode->hactive, mode->vactive, mode->vfreq, mode->interlace ? "i" : ""); + + // Check if mode is available from the SR name (should not be the case, otherwise it means that we recevied twice the same mode request) + pxmode = find_mode_by_name(name); + if (pxmode != NULL) + { + log_error("XRANDR: <%d> (add_mode) [WARNING] mode already exist (duplicate request)\n", m_id); + mode->platform_data = pxmode->id; + return true; + } + + log_verbose("XRANDR: <%d> (add_mode) create mode %s\n", m_id, name); + + // Setup the xrandr mode structure + XRRModeInfo xmode = {}; + + xmode.name = name; + xmode.nameLength = strlen(name); + xmode.dotClock = mode->pclock; + xmode.width = mode->hactive; + xmode.hSyncStart = mode->hbegin; + xmode.hSyncEnd = mode->hend; + xmode.hTotal = mode->htotal; + xmode.height = mode->vactive; + xmode.vSyncStart = mode->vbegin; + xmode.vSyncEnd = mode->vend; + xmode.vTotal = mode->vtotal; + xmode.modeFlags = (mode->interlace ? RR_Interlace : 0) | (mode->doublescan ? RR_DoubleScan : 0) | (mode->hsync ? RR_HSyncPositive : RR_HSyncNegative) | (mode->vsync ? RR_VSyncPositive : RR_VSyncNegative); + xmode.hSkew = 0; + + mode->type |= CUSTOM_VIDEO_TIMING_XRANDR; + + // Create the modeline + XSync(m_pdisplay, False); + ms_xerrors = 0; + ms_xerrors_flag = 0x01; + old_error_handler = XSetErrorHandler(error_handler); + RRMode gmid = XRRCreateMode(m_pdisplay, m_root, &xmode); + XSync(m_pdisplay, False); + XSetErrorHandler(old_error_handler); + if (ms_xerrors & ms_xerrors_flag) + { + log_error("XRANDR: <%d> (add_mode) [ERROR] in %s\n", m_id, "XRRCreateMode"); + return false; + } + + mode->platform_data = gmid; + + // Add new modeline to primary output + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + + XSync(m_pdisplay, False); + ms_xerrors_flag = 0x02; + old_error_handler = XSetErrorHandler(error_handler); + XRRAddOutputMode(m_pdisplay, resources->outputs[m_desktop_output], mode->platform_data); + XSync(m_pdisplay, False); + XSetErrorHandler(old_error_handler); + + XRRFreeScreenResources(resources); + + if (ms_xerrors & ms_xerrors_flag) + { + log_error("XRANDR: <%d> (add_mode) [ERROR] in %s\n", m_id, "XRRAddOutputMode"); + + // remove unlinked modeline + if (mode->platform_data) + { + log_error("XRANDR: <%d> (add_mode) [ERROR] remove mode [%04lx]\n", m_id, mode->platform_data); + XRRDestroyMode(m_pdisplay, mode->platform_data); + mode->platform_data = 0; + } + } + else + log_verbose("XRANDR: <%d> (add_mode) mode %04lx %dx%d refresh %.6f added\n", m_id, mode->platform_data, mode->hactive, mode->vactive, mode->vfreq); + + return ms_xerrors == 0; +} + +//============================================================ +// xrandr_timing::find_mode_by_name +//============================================================ + +XRRModeInfo *xrandr_timing::find_mode_by_name(char *name) +{ + XRRModeInfo *pxmode = NULL; + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + + // use SR name to return the mode + for (int m = 0; m < resources->nmode; m++) + { + if (strcmp(resources->modes[m].name, name) == 0) + { + pxmode = &resources->modes[m]; + break; + } + } + + XRRFreeScreenResources(resources); + + return pxmode; +} + +//============================================================ +// xrandr_timing::find_mode +//============================================================ + +XRRModeInfo *xrandr_timing::find_mode(modeline *mode) +{ + XRRModeInfo *pxmode = NULL; + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + + // use platform_data (mode id) to return the mode + for (int m = 0; m < resources->nmode; m++) + { + if (mode->platform_data == resources->modes[m].id) + { + pxmode = &resources->modes[m]; + break; + } + } + + XRRFreeScreenResources(resources); + + return pxmode; +} + +//============================================================ +// xrandr_timing::set_timing +//============================================================ + +bool xrandr_timing::set_timing(modeline *mode) +{ + if (m_enable_screen_compositing) + return set_timing(mode, 0); + + return set_timing(mode, XRANDR_DISABLE_CRTC_RELOCATION); +} + +//============================================================ +// xrandr_timing::set_timing +//============================================================ + +bool xrandr_timing::set_timing(modeline *mode, int flags) +{ + // Handle no screen detected case + if (m_desktop_output == -1) + { + log_error("XRANDR: <%d> (set_timing) [ERROR] no screen detected\n", m_id); + return false; + } + + if (!m_managed) + { + log_error("XRANDR: <%d> (set_timing) [WARNING] this screen is managed by <%d>\n", m_id, sp_shared_screen_manager[m_desktop_output]); + return false; + } + + if (m_id != 1 && (flags & XRANDR_ENABLE_SCREEN_REORDERING)) + flags = XRANDR_DISABLE_CRTC_RELOCATION; // only master can do global screen preparation + + XRRModeInfo *pxmode = NULL; + + if (mode->type & MODE_DESKTOP) + pxmode = &m_desktop_mode; + else + pxmode = find_mode(mode); + + if (pxmode == NULL) + { + log_error("XRANDR: <%d> (set_timing) [ERROR] mode not found\n", m_id); + return false; + } + + // Use xrandr to switch to new mode. + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + XRROutputInfo *output_info = XRRGetOutputInfo(m_pdisplay, resources, resources->outputs[m_desktop_output]); + XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(m_pdisplay, resources, output_info->crtc); + + if (flags & XRANDR_DISABLE_CRTC_RELOCATION) + log_verbose("XRANDR: <%d> (set_timing) DISABLE crtc relocation\n", m_id); + + if (flags & XRANDR_ENABLE_SCREEN_REORDERING) + log_verbose("XRANDR: <%d> (set_timing) GLOBAL desktop screen preparation\n", m_id); + else if (m_last_crtc.mode == crtc_info->mode && m_last_crtc.x == crtc_info->x && m_last_crtc.y == crtc_info->y && pxmode->id == crtc_info->mode) + log_verbose("XRANDR: <%d> (set_timing) requested mode is already active [%04lx] %ux%u+%d+%d\n", m_id, crtc_info->mode, crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y); + else if (m_last_crtc.mode != crtc_info->mode) + { + log_verbose("XRANDR: <%d> (set_timing) [WARNING] unexpected active modeline detected (last:[%04lx] now:[%04lx] %ux%u+%d+%d want:[%04lx])\n", m_id, m_last_crtc.mode, crtc_info->mode, crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y, pxmode->id); + *crtc_info = m_last_crtc; + } + + // Grab X server to prevent unwanted interaction from the window manager + XGrabServer(m_pdisplay); + + unsigned int width = m_min_width; + unsigned int height = m_min_height; + + unsigned int active_crtc = 0; + + unsigned int reordering_last_y = 0; + + ms_xerrors = 0; + + XRRCrtcInfo *global_crtc = new XRRCrtcInfo[resources->ncrtc]; + XRRCrtcInfo *original_crtc = new XRRCrtcInfo[resources->ncrtc]; + + // caculate necessary screen size and of crtc neighborhood if they have at least one side aligned with the mode changed crtc + for (int c = 0; c < resources->ncrtc; c++) + { + // Prepare crtc references + memcpy(&original_crtc[c], XRRGetCrtcInfo(m_pdisplay, resources, resources->crtcs[c]), sizeof(XRRCrtcInfo)); + memcpy(&global_crtc[c], XRRGetCrtcInfo(m_pdisplay, resources, resources->crtcs[c]), sizeof(XRRCrtcInfo)); + // Original state + XRRCrtcInfo *crtc_info0 = &original_crtc[c]; + // Modified state + XRRCrtcInfo *crtc_info1 = &global_crtc[c]; + // clear timestamp + crtc_info1->timestamp = 0; + + // Skip unused crtc + if (output_info->crtc != 0 && crtc_info0->mode != 0) + { + if (flags & XRANDR_ENABLE_SCREEN_REORDERING) + { + // Relocate all crtcs + // Super resolution placement, vertical stacking, reserved XRANDR_REORDERING_MAXIMUM_HEIGHT pixels + crtc_info1->x = 0; + crtc_info1->y = reordering_last_y; + if (crtc_info1->height > XRANDR_REORDERING_MAXIMUM_HEIGHT) + reordering_last_y += crtc_info1->height; + else + reordering_last_y += XRANDR_REORDERING_MAXIMUM_HEIGHT; + crtc_info1->timestamp |= XRANDR_SETMODE_UPDATE_REORDERING; + active_crtc++; + } + // Switchres selected desktop output + else if (resources->crtcs[c] == output_info->crtc) + { + crtc_info1->timestamp |= XRANDR_SETMODE_IS_DESKTOP; + crtc_info1->mode = pxmode->id; + crtc_info1->width = pxmode->width; + crtc_info1->height = pxmode->height; + + if (mode->type & MODE_DESKTOP) + { + if (!m_enable_screen_compositing && (crtc_info1->x != sp_desktop_crtc[c].x || crtc_info1->y != sp_desktop_crtc[c].y)) + { + // Restore original desktop position + crtc_info1->x = sp_desktop_crtc[c].x; + crtc_info1->y = sp_desktop_crtc[c].y; + crtc_info1->timestamp |= XRANDR_SETMODE_RESTORE_DESKTOP; + } + } + else + { + // Use curent position + crtc_info1->x = crtc_info->x; + crtc_info1->y = crtc_info->y; + } + + if (crtc_info0->mode != crtc_info1->mode || crtc_info0->width != crtc_info1->width || crtc_info0->height != crtc_info1->height || crtc_info0->x != crtc_info1->x || crtc_info0->y != crtc_info1->y) + crtc_info1->timestamp |= XRANDR_SETMODE_UPDATE_DESKTOP_CRTC; + } + else if (mode->type & MODE_DESKTOP && m_enable_screen_reordering && (crtc_info1->x != sp_desktop_crtc[c].x || crtc_info1->y != sp_desktop_crtc[c].y)) + { + crtc_info1->x = sp_desktop_crtc[c].x; + crtc_info1->y = sp_desktop_crtc[c].y; + crtc_info1->timestamp |= (XRANDR_SETMODE_RESTORE_DESKTOP | XRANDR_SETMODE_UPDATE_REORDERING); + } + } + } + + for (int c = 0; c < resources->ncrtc; c++) + { + // Original state + XRRCrtcInfo *crtc_info0 = &original_crtc[c]; + // Modified state + XRRCrtcInfo *crtc_info1 = &global_crtc[c]; + + // Skip unused crtc + if (output_info->crtc != 0 && crtc_info0->mode != 0) + { + if ((flags & XRANDR_DISABLE_CRTC_RELOCATION) == 0 && (crtc_info1->timestamp & XRANDR_SETMODE_IS_DESKTOP) == 0) + { + // relocate crtc impacted by new width + if (crtc_info1->x >= crtc_info->x + (int)crtc_info->width) + { + crtc_info1->x += pxmode->width - crtc_info->width; + crtc_info1->timestamp |= XRANDR_SETMODE_UPDATE_OTHER_CRTC; + } + + // relocate crtc impacted by new height + if (crtc_info1->y >= crtc_info->y + (int)crtc_info->height) + { + crtc_info1->y += pxmode->height - crtc_info->height; + crtc_info1->timestamp |= XRANDR_SETMODE_UPDATE_OTHER_CRTC; + } + } + + // Calculate overall screen size based on crtcs placement + if (crtc_info1->x + crtc_info1->width > width) + width = crtc_info1->x + crtc_info1->width; + + if (crtc_info1->y + crtc_info1->height > height) + height = crtc_info1->y + crtc_info1->height; + + if (width > m_max_width) + { + log_error("XRANDR: <%d> (set_timing) [ERROR] width is above allowed maximum (%d > %d)\n", m_id, width, m_max_width); + width = m_max_width; + } + + if (height > m_max_height) + { + log_error("XRANDR: <%d> (set_timing) [ERROR] height is above allowed maximum (%d > %d)\n", m_id, height, m_max_height); + height = m_max_height; + } + + if (crtc_info1->timestamp & XRANDR_SETMODE_UPDATE_MASK) + log_verbose("XRANDR: <%d> (set_timing) crtc %d%s [%04lx] %ux%u+%d+%d --> [%04lx] %ux%u+%d+%d flags [%02lx]\n", m_id, c, crtc_info1->timestamp & 1 ? "*" : " ", crtc_info0->mode, crtc_info0->width, crtc_info0->height, crtc_info0->x, crtc_info0->y, crtc_info1->mode, crtc_info1->width, crtc_info1->height, crtc_info1->x, crtc_info1->y, crtc_info1->timestamp); + else if (crtc_info1->timestamp & XRANDR_SETMODE_INFO_MASK) + log_verbose("XRANDR: <%d> (set_timing) crtc %d%s [%04lx] %ux%u+%d+%d flags [%02lx]\n", m_id, c, crtc_info1->timestamp & 1 ? "*" : " ", crtc_info1->mode, crtc_info1->width, crtc_info1->height, crtc_info1->x, crtc_info1->y, crtc_info1->timestamp); + else + log_verbose("XRANDR: <%d> (set_timing) crtc %d [%04lx] %ux%u+%d+%d\n", m_id, c, crtc_info1->mode, crtc_info1->width, crtc_info1->height, crtc_info1->x, crtc_info1->y); + } + } + + // Disable crtc with pending modification + for (int c = 0; c < resources->ncrtc; c++) + { + // Modified state + if (global_crtc[c].timestamp & XRANDR_SETMODE_UPDATE_MASK) + { + if (XRRSetCrtcConfig(m_pdisplay, resources, resources->crtcs[c], CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != RRSetConfigSuccess) + { + log_error("XRANDR: <%d> (set_timing) [ERROR] when disabling crtc %d\n", m_id, c); + ms_xerrors_flag = 0x01; + ms_xerrors |= ms_xerrors_flag; + } + } + } + + // Set the framebuffer screen size to enable all crtc + if (ms_xerrors == 0) + { + log_verbose("XRANDR: <%d> (set_timing) setting screen size to %d x %d\n", m_id, width, height); + XSync(m_pdisplay, False); + ms_xerrors_flag = 0x02; + old_error_handler = XSetErrorHandler(error_handler); + XRRSetScreenSize(m_pdisplay, m_root, width, height, (int) ((25.4 * width) / 96.0), (int) ((25.4 * height) / 96.0)); + XSync(m_pdisplay, False); + XSetErrorHandler(old_error_handler); + if (ms_xerrors & ms_xerrors_flag) + log_error("XRANDR: <%d> (set_timing) [ERROR] in %s\n", m_id, "XRRSetScreenSize"); + } + + // Refresh all crtc, switch modeline and set new placement + for (int c = 0; c < resources->ncrtc; c++) + { + // Modified state + XRRCrtcInfo *crtc_info1 = &global_crtc[c]; + if (crtc_info1->timestamp & XRANDR_SETMODE_UPDATE_MASK) + { + if (crtc_info1->timestamp & XRANDR_SETMODE_IS_DESKTOP) + XFillRectangle(m_pdisplay, m_root, XCreateGC(m_pdisplay, m_root, 0, 0), crtc_info1->x, crtc_info1->y, crtc_info1->width, crtc_info1->height); + // enable crtc with updated parameters + XSync(m_pdisplay, False); + ms_xerrors_flag = 0x14; + old_error_handler = XSetErrorHandler(error_handler); + XRRSetCrtcConfig(m_pdisplay, resources, resources->crtcs[c], CurrentTime, crtc_info1->x, crtc_info1->y, crtc_info1->mode, crtc_info1->rotation, crtc_info1->outputs, crtc_info1->noutput); + XSync(m_pdisplay, False); + XSetErrorHandler(old_error_handler); + if (ms_xerrors & 0x10) + { + log_error("XRANDR: <%d> (set_timing) [ERROR] in %s crtc %d set modeline %04lx\n", m_id, "XRRSetCrtcConfig", c, crtc_info1->mode); + ms_xerrors &= 0xEF; + } + } + } + delete[]original_crtc; + delete[]global_crtc; + + // Release X server, events can be processed now + XUngrabServer(m_pdisplay); + + if (ms_xerrors & ms_xerrors_flag) + log_error("XRANDR: <%d> (set_timing) [ERROR] in %s\n", m_id, "XRRSetCrtcConfig"); + + // Recall the impacted crtc to settle parameters + XRRFreeCrtcInfo(crtc_info); + crtc_info = XRRGetCrtcInfo(m_pdisplay, resources, output_info->crtc); + + // crtc config modeline change fail + if (crtc_info->mode == 0) + log_error("XRANDR: <%d> (set_timing) [ERROR] switching resolution failed, no modeline is set\n", m_id); + else + // save last crtc + m_last_crtc = *crtc_info; + + XRRFreeCrtcInfo(crtc_info); + XRRFreeOutputInfo(output_info); + XRRFreeScreenResources(resources); + + return (ms_xerrors == 0 && crtc_info->mode != 0); +} + +//============================================================ +// xrandr_timing::delete_mode +//============================================================ + +bool xrandr_timing::delete_mode(modeline *mode) +{ + // Handle no screen detected case + if (m_desktop_output == -1) + { + log_error("XRANDR: <%d> (delete_mode) [ERROR] no screen detected\n", m_id); + return false; + } + + if (!m_managed) + { + log_error("XRANDR: <%d> (delete_mode) [WARNING] this screen is managed by <%d>\n", m_id, sp_shared_screen_manager[m_desktop_output]); + return false; + } + + if (!mode) + return false; + + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + + int total_xerrors = 0; + // Delete modeline + for (int m = 0; m < resources->nmode && mode->platform_data != 0; m++) + { + if (mode->platform_data == resources->modes[m].id) + { + XRROutputInfo *output_info = XRRGetOutputInfo(m_pdisplay, resources, resources->outputs[m_desktop_output]); + XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(m_pdisplay, resources, output_info->crtc); + if (resources->modes[m].id == crtc_info->mode) + { + log_verbose("XRANDR: <%d> (delete_mode) [WARNING] modeline [%04lx] is currently active, restoring desktop mode first\n", m_id, resources->modes[m].id); + modeline desktop_mode = {}; + desktop_mode.type |= MODE_DESKTOP; + if (!set_timing(&desktop_mode, 0)) + { + log_error("XRANDR: <%d> (delete_mode) [ERROR] Could not restore desktop mode\n", m_id); + return false; + } + } + + XRRFreeCrtcInfo(crtc_info); + XRRFreeOutputInfo(output_info); + + log_verbose("XRANDR: <%d> (delete_mode) remove mode %s\n", m_id, resources->modes[m].name); + + XSync(m_pdisplay, False); + ms_xerrors = 0; + ms_xerrors_flag = 0x01; + old_error_handler = XSetErrorHandler(error_handler); + XRRDeleteOutputMode(m_pdisplay, resources->outputs[m_desktop_output], resources->modes[m].id); + if (ms_xerrors & ms_xerrors_flag) + { + log_error("XRANDR: <%d> (delete_mode) [ERROR] in %s\n", m_id, "XRRDeleteOutputMode"); + total_xerrors++; + } + + ms_xerrors_flag = 0x02; + XRRDestroyMode(m_pdisplay, resources->modes[m].id); + XSync(m_pdisplay, False); + XSetErrorHandler(old_error_handler); + if (ms_xerrors & ms_xerrors_flag) + { + log_error("XRANDR: <%d> (delete_mode) [ERROR] in %s\n", m_id, "XRRDestroyMode"); + total_xerrors++; + } + mode->platform_data = 0; + } + } + + XRRFreeScreenResources(resources); + + return total_xerrors == 0; +} + +//============================================================ +// xrandr_timing::get_timing +//============================================================ + +bool xrandr_timing::get_timing(modeline *mode) +{ + // Handle no screen detected case + if (m_desktop_output == -1) + { + log_error("XRANDR: <%d> (get_timing) [ERROR] no screen detected\n", m_id); + return false; + } + + XRRScreenResources *resources = XRRGetScreenResourcesCurrent(m_pdisplay, m_root); + XRROutputInfo *output_info = XRRGetOutputInfo(m_pdisplay, resources, resources->outputs[m_desktop_output]); + + // Cycle through the modelines and report them back to the display manager + if (m_video_modes_position < output_info->nmode) + { + for (int m = 0; m < resources->nmode; m++) + { + XRRModeInfo *pxmode = &resources->modes[m]; + + if (pxmode->id == output_info->modes[m_video_modes_position]) + { + mode->platform_data = pxmode->id; + + mode->pclock = pxmode->dotClock; + mode->hactive = pxmode->width; + mode->hbegin = pxmode->hSyncStart; + mode->hend = pxmode->hSyncEnd; + mode->htotal = pxmode->hTotal; + mode->vactive = pxmode->height; + mode->vbegin = pxmode->vSyncStart; + mode->vend = pxmode->vSyncEnd; + mode->vtotal = pxmode->vTotal; + mode->interlace = (pxmode->modeFlags & RR_Interlace) ? 1 : 0; + mode->doublescan = (pxmode->modeFlags & RR_DoubleScan) ? 1 : 0; + mode->hsync = (pxmode->modeFlags & RR_HSyncPositive) ? 1 : 0; + mode->vsync = (pxmode->modeFlags & RR_VSyncPositive) ? 1 : 0; + + mode->hfreq = mode->pclock / mode->htotal; + mode->vfreq = mode->hfreq / mode->vtotal * (mode->interlace ? 2 : 1); + mode->refresh = mode->vfreq; + + mode->width = pxmode->width; + mode->height = pxmode->height; + + // Add the rotation flag from the crtc + mode->type |= m_crtc_flags; + + mode->type |= CUSTOM_VIDEO_TIMING_XRANDR; + + if (strncmp(pxmode->name, "SR-", 3) == 0) + log_verbose("XRANDR: <%d> (get_timing) [WARNING] modeline %s detected\n", m_id, pxmode->name); + + // Add the desktop flag to desktop modeline + if (m_desktop_mode.id == pxmode->id) + mode->type |= MODE_DESKTOP; + + log_verbose("XRANDR: <%d> (get_timing) mode %04lx %dx%d refresh %.6f added\n", m_id, pxmode->id, pxmode->width, pxmode->height, mode->vfreq); + } + } + m_video_modes_position++; + } + else + { + // Inititalise the position for the modeline list + m_video_modes_position = 0; + } + + XRRFreeOutputInfo(output_info); + XRRFreeScreenResources(resources); + + return true; +} + +//============================================================ +// xrandr_timing::process_modelist +//============================================================ + +bool xrandr_timing::process_modelist(std::vector modelist) +{ + bool error = false; + bool result = false; + + for (auto &mode : modelist) + { + if (mode->type & MODE_DELETE) + result = delete_mode(mode); + + else if (mode->type & MODE_ADD) + result = add_mode(mode); + + else if (mode->type & MODE_UPDATE) + result = update_mode(mode); + + if (!result) + { + mode->type |= MODE_ERROR; + error = true; + } + else + // succeed + mode->type &= ~MODE_ERROR; + } + + return !error; +} diff --git a/custom_video_xrandr.h b/custom_video_xrandr.h new file mode 100644 index 00000000000..d2cf795275b --- /dev/null +++ b/custom_video_xrandr.h @@ -0,0 +1,123 @@ +/************************************************************** + + custom_video_xrandr.h - Linux XRANDR video management layer + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __CUSTOM_VIDEO_XRANDR__ +#define __CUSTOM_VIDEO_XRANDR__ + +// X11 Xrandr headers +#include +#include "custom_video.h" + +// Set timing option flags +#define XRANDR_DISABLE_CRTC_RELOCATION 0x00000001 +#define XRANDR_ENABLE_SCREEN_REORDERING 0x00000002 + +// Set timing internal flags +#define XRANDR_SETMODE_IS_DESKTOP 0x00000001 +#define XRANDR_SETMODE_RESTORE_DESKTOP 0x00000002 +#define XRANDR_SETMODE_UPDATE_DESKTOP_CRTC 0x00000010 +#define XRANDR_SETMODE_UPDATE_OTHER_CRTC 0x00000020 +#define XRANDR_SETMODE_UPDATE_REORDERING 0x00000040 + +#define XRANDR_SETMODE_INFO_MASK 0x0000000F +#define XRANDR_SETMODE_UPDATE_MASK 0x000000F0 + +// Super resolution placement, vertical stacking, reserved XRANDR_REORDERING_MAXIMUM_HEIGHT pixels +//TODO confirm 1024 height is sufficient +#define XRANDR_REORDERING_MAXIMUM_HEIGHT 1024 + +class xrandr_timing : public custom_video +{ + public: + xrandr_timing(char *device_name, custom_video_settings *vs); + ~xrandr_timing(); + const char *api_name() { return "XRANDR"; } + int caps() { return CUSTOM_VIDEO_CAPS_ADD; } + bool init(); + + bool add_mode(modeline *mode); + bool delete_mode(modeline *mode); + bool update_mode(modeline *mode); + + bool get_timing(modeline *mode); + bool set_timing(modeline *mode); + + bool process_modelist(std::vector); + + static int ms_xerrors; + static int ms_xerrors_flag; + + private: + int m_id = 0; + int m_managed = 0; + int m_enable_screen_reordering = 0; + int m_enable_screen_compositing = 0; + + XRRModeInfo *find_mode(modeline *mode); + XRRModeInfo *find_mode_by_name(char *name); + + bool set_timing(modeline *mode, int flags); + + int m_video_modes_position = 0; + char m_device_name[32]; + Rotation m_desktop_rotation; + unsigned int m_min_width; + unsigned int m_max_width; + unsigned int m_min_height; + unsigned int m_max_height; + + Display *m_pdisplay = NULL; + Window m_root; + int m_screen; + + int m_desktop_output = -1; + XRRModeInfo m_desktop_mode = {}; + int m_crtc_flags = 0; + + XRRCrtcInfo m_last_crtc = {}; + + void *m_xrandr_handle = 0; + + __typeof__(XRRAddOutputMode) *p_XRRAddOutputMode; + __typeof__(XRRConfigCurrentConfiguration) *p_XRRConfigCurrentConfiguration; + __typeof__(XRRCreateMode) *p_XRRCreateMode; + __typeof__(XRRDeleteOutputMode) *p_XRRDeleteOutputMode; + __typeof__(XRRDestroyMode) *p_XRRDestroyMode; + __typeof__(XRRFreeCrtcInfo) *p_XRRFreeCrtcInfo; + __typeof__(XRRFreeOutputInfo) *p_XRRFreeOutputInfo; + __typeof__(XRRFreeScreenConfigInfo) *p_XRRFreeScreenConfigInfo; + __typeof__(XRRFreeScreenResources) *p_XRRFreeScreenResources; + __typeof__(XRRGetCrtcInfo) *p_XRRGetCrtcInfo; + __typeof__(XRRGetOutputInfo) *p_XRRGetOutputInfo; + __typeof__(XRRGetScreenInfo) *p_XRRGetScreenInfo; + __typeof__(XRRGetScreenResourcesCurrent) *p_XRRGetScreenResourcesCurrent; + __typeof__(XRRQueryVersion) *p_XRRQueryVersion; + __typeof__(XRRSetCrtcConfig) *p_XRRSetCrtcConfig; + __typeof__(XRRSetScreenSize) *p_XRRSetScreenSize; + __typeof__(XRRGetScreenSizeRange) *p_XRRGetScreenSizeRange; + + void *m_x11_handle = 0; + + __typeof__(XCloseDisplay) *p_XCloseDisplay; + __typeof__(XGrabServer) *p_XGrabServer; + __typeof__(XOpenDisplay) *p_XOpenDisplay; + __typeof__(XSync) *p_XSync; + __typeof__(XUngrabServer) *p_XUngrabServer; + __typeof__(XSetErrorHandler) *p_XSetErrorHandler; + __typeof__(XClearWindow) *p_XClearWindow; + __typeof__(XFillRectangle) *p_XFillRectangle; + __typeof__(XCreateGC) *p_XCreateGC; +}; + +#endif diff --git a/display.cpp b/display.cpp new file mode 100644 index 00000000000..2fc58634bcf --- /dev/null +++ b/display.cpp @@ -0,0 +1,547 @@ +/************************************************************** + + display.cpp - Display manager + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include "display.h" +#if defined(_WIN32) +#include "display_windows.h" +#elif defined(__linux__) +#include "display_linux.h" +#endif +#ifdef SR_WITH_SDL2 +#include "display_sdl2.h" +#endif + +#include "log.h" + +//============================================================ +// display_manager::make +//============================================================ + +display_manager *display_manager::make(display_settings *ds) +{ + display_manager *display = nullptr; + + if (!strcmp(ds->screen, "dummy")) + { + display = new dummy_display(ds); + return display; + } + +#ifdef SR_WITH_SDL2 + try + { + display = new sdl2_display(ds); + } + catch (...) {}; + if (!display) + { +#endif + +#if defined(_WIN32) + display = new windows_display(ds); +#elif defined(__linux__) + display = new linux_display(ds); +#endif + +#ifdef SR_WITH_SDL2 + } +#endif + + return display; +} + +//============================================================ +// display_manager::parse_options +//============================================================ + +void display_manager::parse_options() +{ + log_verbose("Switchres: display[%d] options: monitor[%s] generation[%s]\n", + m_index, m_ds.monitor, m_ds.modeline_generation?"on":"off"); + + // Get user_mode as x@ + set_user_mode(&m_ds.user_mode); + + // Get user defined modeline (overrides user_mode) + modeline user_mode = {}; + if (m_ds.modeline_generation) + { + if (modeline_parse(m_ds.user_modeline, &user_mode)) + { + memset(&range[0], 0, sizeof(struct monitor_range) * MAX_RANGES); + user_mode.type |= MODE_USER_DEF; + set_user_mode(&user_mode); + } + } + + // Get monitor specs + if (user_mode.hactive) + { + modeline_to_monitor_range(range, &user_mode); + monitor_show_range(range); + } + else + set_preset(m_ds.monitor); +} + +//============================================================ +// display_manager::set_preset +//============================================================ + +void display_manager::set_preset(const char *preset) +{ + strncpy(m_ds.monitor, preset, sizeof(m_ds.monitor)-1); + for (size_t i = 0; i < strlen(m_ds.monitor); i++) m_ds.monitor[i] = tolower(m_ds.monitor[i]); + + memset(&range[0], 0, sizeof(struct monitor_range) * MAX_RANGES); + + if (!strcmp(preset, "custom")) + for (int i = 0; i < MAX_RANGES; i++) monitor_fill_range(&range[i], m_ds.crt_range[i]); + + else if (!strcmp(preset, "lcd")) + monitor_fill_lcd_range(&range[0], m_ds.lcd_range); + + else if (monitor_set_preset(preset, range) == 0) + monitor_set_preset("generic_15", range); +} + +//============================================================ +// display_manager::init +//============================================================ + +bool display_manager::init(void* pf_data) +{ + sprintf(m_ds.screen, "ram"); + m_pf_data = pf_data; + + return true; +} + +//============================================================ +// display_manager::caps +//============================================================ + +int display_manager::caps() +{ + if (video() != nullptr) + return video()->caps(); + else + return CUSTOM_VIDEO_CAPS_ADD; +} + +//============================================================ +// display_manager::add_mode +//============================================================ + +bool display_manager::add_mode(modeline *mode) +{ + // Add new mode + if (video() != nullptr && !video()->add_mode(mode)) + { + log_verbose("Switchres: error adding mode "); + log_mode(mode); + return false; + } + + mode->type &= ~MODE_ADD; + + log_verbose("Switchres: added "); + log_mode(mode); + + return true; +} + +//============================================================ +// display_manager::delete_mode +//============================================================ + +bool display_manager::delete_mode(modeline *mode) +{ + if (video() != nullptr && !video()->delete_mode(mode)) + { + log_verbose("Switchres: error deleting mode "); + log_mode(mode); + return false; + } + + log_verbose("Switchres: deleted "); + log_mode(mode); + + ptrdiff_t i = mode - &video_modes[0]; + video_modes.erase(video_modes.begin() + i); + + return true; +} + +//============================================================ +// display_manager::update_mode +//============================================================ + +bool display_manager::update_mode(modeline *mode) +{ + // Apply new timings + if (video() != nullptr && !video()->update_mode(mode)) + { + log_verbose("Switchres: error updating mode "); + log_mode(mode); + return false; + } + + mode->type &= ~MODE_UPDATE; + + log_verbose("Switchres: updated "); + log_mode(mode); + return true; +} + +//============================================================ +// display_manager::set_mode +//============================================================ + +bool display_manager::set_mode(modeline *) +{ + return false; +} + +//============================================================ +// display_manager::log_mode +//============================================================ + +void display_manager::log_mode(modeline *mode) +{ + char modeline_txt[256]; + log_verbose("%s timing %s\n", video() != nullptr? video()->api_name() : "dummy", modeline_print(mode, modeline_txt, MS_FULL)); +} + +//============================================================ +// display_manager::restore_modes +//============================================================ + +bool display_manager::restore_modes() +{ + // Compare each mode in our table with its original state + for (unsigned i = video_modes.size(); i-- > 0; ) + { + // First, delete all modes we've added + if (i + 1 > backup_modes.size()) + video_modes[i].type |= MODE_DELETE; + + // Now restore all modes which timings have been modified + else if (modeline_is_different(&video_modes[i], &backup_modes[i])) + { + video_modes[i] = backup_modes[i]; + video_modes[i].type |= MODE_UPDATE; + } + } + // Finally, flush pending changes to driver + return flush_modes(); +} + +//============================================================ +// display_manager::flush_modes +//============================================================ + +bool display_manager::flush_modes() +{ + bool error = false; + std::vector modified_modes = {}; + + // Loop through our mode table to collect all pending changes + for (auto &mode : video_modes) + if (mode.type & (MODE_UPDATE | MODE_ADD | MODE_DELETE)) + modified_modes.push_back(&mode); + + // Flush pending changes to driver + if (modified_modes.size() > 0) + { + if (video() != nullptr) + video()->process_modelist(modified_modes); + + // Log error/success result for each mode + for (auto &mode : modified_modes) + { + log_verbose("Switchres: %s %s mode ", mode->type & MODE_ERROR? "error" : "success", mode->type & MODE_DELETE? "deleting" : mode->type & MODE_ADD? "adding" : "updating"); + log_mode(mode); + + if (mode->type & MODE_ERROR) + error = true; + } + + // Update our internal mode table to reflect the changes + for (unsigned i = video_modes.size(); i-- > 0; ) + { + if (video_modes[i].type & MODE_ERROR) + continue; + + if (video_modes[i].type & MODE_DELETE) + { + video_modes.erase(video_modes.begin() + i); + m_selected_mode = 0; + } + else + video_modes[i].type &= ~(MODE_UPDATE | MODE_ADD); + } + } + + return !error; +} + +//============================================================ +// display_manager::filter_modes +//============================================================ + +bool display_manager::filter_modes() +{ + for (auto &mode : video_modes) + { + // apply options to mode type + if (m_ds.refresh_dont_care) + mode.type |= V_FREQ_EDITABLE; + + if ((caps() & CUSTOM_VIDEO_CAPS_UPDATE)) + mode.type |= V_FREQ_EDITABLE; + + if (caps() & CUSTOM_VIDEO_CAPS_SCAN_EDITABLE) + mode.type |= SCAN_EDITABLE; + + if (!m_ds.modeline_generation) + mode.type &= ~(XYV_EDITABLE | SCAN_EDITABLE); + + if ((mode.type & MODE_DESKTOP) && !(caps() & CUSTOM_VIDEO_CAPS_DESKTOP_EDITABLE)) + mode.type &= ~V_FREQ_EDITABLE; + + if (m_ds.lock_system_modes && (mode.type & CUSTOM_VIDEO_TIMING_SYSTEM)) + mode.type |= MODE_DISABLED; + + // Make sure to unlock the desktop mode as fallback + if (mode.type & MODE_DESKTOP) + mode.type &= ~MODE_DISABLED; + + // Lock all modes that don't match the user's -resolution rules + if (m_user_mode.width != 0 || m_user_mode.height != 0 || m_user_mode.refresh == !0) + { + if (!( (mode.width == m_user_mode.width || (mode.type & X_RES_EDITABLE) || m_user_mode.width == 0) + && (mode.height == m_user_mode.height || (mode.type & Y_RES_EDITABLE) || m_user_mode.height == 0) + && (mode.refresh == m_user_mode.refresh || (mode.type & V_FREQ_EDITABLE) || m_user_mode.refresh == 0) )) + mode.type |= MODE_DISABLED; + else + mode.type &= ~MODE_DISABLED; + } + } + + return true; +} + +//============================================================ +// display_manager::get_video_mode +//============================================================ + +modeline *display_manager::get_mode(int width, int height, float refresh, int flags) +{ + modeline s_mode = {}; + modeline t_mode = {}; + modeline best_mode = {}; + char result[256]={'\x00'}; + + bool rotated = flags & SR_MODE_ROTATED; + bool interlaced = flags & SR_MODE_INTERLACED; + + log_info("Switchres: Calculating best video mode for %dx%d@%.6f%s orientation: %s\n", + width, height, refresh, interlaced?"i":"", rotated?"rotated":"normal"); + + best_mode.result.weight |= R_OUT_OF_RANGE; + + s_mode.interlace = interlaced; + s_mode.vfreq = refresh; + + s_mode.hactive = width; + s_mode.vactive = height; + + if (rotated) + { + std::swap(s_mode.hactive, s_mode.vactive); + s_mode.type |= MODE_ROTATED; + } + + // Create a dummy mode entry if allowed + if (caps() & CUSTOM_VIDEO_CAPS_ADD && m_ds.modeline_generation) + { + modeline new_mode = {}; + new_mode.type = XYV_EDITABLE | V_FREQ_EDITABLE | SCAN_EDITABLE | MODE_ADD | (desktop_is_rotated()? MODE_ROTATED : MODE_OK); + video_modes.push_back(new_mode); + } + + // Run through our mode list and find the most suitable mode + for (auto &mode : video_modes) + { + log_verbose("\nSwitchres: %s%4d%sx%s%4d%s_%s%d=%.6fHz%s%s\n", + mode.type & X_RES_EDITABLE?"(":"[", mode.width, mode.type & X_RES_EDITABLE?")":"]", + mode.type & Y_RES_EDITABLE?"(":"[", mode.height, mode.type & Y_RES_EDITABLE?")":"]", + mode.type & V_FREQ_EDITABLE?"(":"[", mode.refresh, mode.vfreq, mode.type & V_FREQ_EDITABLE?")":"]", + mode.type & MODE_DISABLED?" - locked":""); + + // now get the mode if allowed + if (mode.type & MODE_DISABLED) + continue; + + for (int i = 0 ; i < MAX_RANGES ; i++) + { + if (range[i].hfreq_min == 0) + continue; + + t_mode = mode; + + // init all editable fields with source or user values + if (t_mode.type & X_RES_EDITABLE) + t_mode.hactive = m_user_mode.width? m_user_mode.width : s_mode.hactive; + + if (t_mode.type & Y_RES_EDITABLE) + t_mode.vactive = m_user_mode.height? m_user_mode.height : s_mode.vactive; + + if (t_mode.type & V_FREQ_EDITABLE) + { + // If user's vfreq is defined, it means we have an user modeline, so force it + if (m_user_mode.vfreq) + modeline_copy_timings(&t_mode, &m_user_mode); + else + t_mode.vfreq = s_mode.vfreq; + } + + // lock resolution fields if required + if (m_user_mode.width) t_mode.type &= ~X_RES_EDITABLE; + if (m_user_mode.height) t_mode.type &= ~Y_RES_EDITABLE; + if (m_user_mode.vfreq) t_mode.type &= ~V_FREQ_EDITABLE; + + modeline_create(&s_mode, &t_mode, &range[i], &m_ds.gs); + t_mode.range = i; + + log_verbose("%s\n", modeline_result(&t_mode, result)); + + if (modeline_compare(&t_mode, &best_mode)) + { + best_mode = t_mode; + m_selected_mode = &mode; + } + } + } + + // If we didn't need to create a new mode, remove our dummy entry + if (caps() & CUSTOM_VIDEO_CAPS_ADD && m_ds.modeline_generation && m_selected_mode != &video_modes.back()) + video_modes.pop_back(); + + // If we didn't find a suitable mode, exit now + if (best_mode.result.weight & R_OUT_OF_RANGE) + { + m_selected_mode = 0; + log_error("Switchres: could not find a video mode that meets your specs\n"); + return nullptr; + } + + if ((best_mode.type & V_FREQ_EDITABLE) && !(best_mode.result.weight & R_OUT_OF_RANGE)) + modeline_adjust(&best_mode, range[best_mode.range].hfreq_max, &m_ds.gs); + + log_verbose("\nSwitchres: %s (%dx%d@%.6f)->(%dx%d@%.6f)\n", rotated?"rotated":"normal", + width, height, refresh, best_mode.hactive, best_mode.vactive, best_mode.vfreq); + + log_verbose("%s\n", modeline_result(&best_mode, result)); + + // Copy the new modeline to our mode list + if (m_ds.modeline_generation) + { + if (best_mode.type & MODE_ADD) + { + best_mode.width = best_mode.hactive; + best_mode.height = best_mode.vactive; + best_mode.refresh = int(best_mode.vfreq); + // lock new mode + best_mode.type &= ~(X_RES_EDITABLE | Y_RES_EDITABLE); + } + else if (modeline_is_different(&best_mode, m_selected_mode) != 0) + best_mode.type |= MODE_UPDATE; + + char modeline[256]={'\x00'}; + log_info("Switchres: Modeline %s\n", modeline_print(&best_mode, modeline, MS_FULL)); + } + + // Check if new best mode is different than previous one + m_switching_required = (m_current_mode != m_selected_mode || best_mode.type & MODE_UPDATE); + + // Add id to mode + if (best_mode.id == 0) + best_mode.id = ++m_id_counter; + + *m_selected_mode = best_mode; + return m_selected_mode; +} + +//============================================================ +// display_manager::auto_specs +//============================================================ + +bool display_manager::auto_specs() +{ + // Make sure we have a valid mode + if (desktop_mode.width == 0 || desktop_mode.height == 0 || desktop_mode.refresh == 0) + { + log_error("Switchres: Invalid desktop mode %dx%d@%d\n", desktop_mode.width, desktop_mode.height, desktop_mode.refresh); + return false; + } + + log_verbose("Switchres: Creating automatic specs for LCD based on %s\n", (desktop_mode.type & CUSTOM_VIDEO_TIMING_SYSTEM)? "VESA GTF" : "current timings"); + + // Make sure our current refresh is within range if set to auto + if (!strcmp(m_ds.lcd_range, "auto")) + { + sprintf(m_ds.lcd_range, "%d-%d", desktop_mode.refresh - 1, desktop_mode.refresh + 1); + monitor_fill_lcd_range(range, m_ds.lcd_range); + } + + // Create a working range with the best possible information + if (desktop_mode.type & CUSTOM_VIDEO_TIMING_SYSTEM) modeline_vesa_gtf(&desktop_mode); + modeline_to_monitor_range(range, &desktop_mode); + monitor_show_range(range); + + // Force our resolution to LCD's native one + modeline user_mode = {}; + user_mode.width = desktop_mode.width; + user_mode.height = desktop_mode.height; + user_mode.refresh = desktop_mode.refresh; + set_user_mode(&user_mode); + + return true; +} + +//============================================================ +// display_manager::get_aspect +//============================================================ + +double display_manager::get_aspect(const char* aspect) +{ + int num, den; + if (sscanf(aspect, "%d:%d", &num, &den) == 2) + { + if (den == 0) + { + log_error("Error: denominator can't be zero\n"); + return STANDARD_CRT_ASPECT; + } + return (double(num)/double(den)); + } + + log_error("Error: use format --aspect \n"); + return STANDARD_CRT_ASPECT; +} diff --git a/display.h b/display.h new file mode 100644 index 00000000000..ddcaf3e3d02 --- /dev/null +++ b/display.h @@ -0,0 +1,225 @@ +/************************************************************** + + display.h - Display manager + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __DISPLAY_H__ +#define __DISPLAY_H__ + +#include +#include "modeline.h" +#include "custom_video.h" + +// Mode flags +#define SR_MODE_INTERLACED 1<<0 +#define SR_MODE_ROTATED 1<<1 + +typedef struct display_settings +{ + char screen[32]; + char api[32]; + bool modeline_generation; + bool lock_unsupported_modes; + bool lock_system_modes; + bool refresh_dont_care; + bool keep_changes; + char monitor[32]; + char crt_range[MAX_RANGES][256]; + char lcd_range[256]; + char user_modeline[256]; + modeline user_mode; + + generator_settings gs; + custom_video_settings vs; +} display_settings; + + +class display_manager +{ +public: + + display_manager() {}; + virtual ~display_manager() + { + if (!m_ds.keep_changes) restore_modes(); + if (m_factory) delete m_factory; + }; + + display_manager *make(display_settings *ds); + void parse_options(); + virtual bool init(void* = nullptr); + virtual int caps(); + + // getters + int index() const { return m_index; } + custom_video *factory() const { return m_factory; } + custom_video *video() const { return m_video; } + bool has_ini() const { return m_has_ini; } + + // getters (modes) + modeline user_mode() const { return m_user_mode; } + modeline *selected_mode() const { return m_selected_mode; } + modeline *current_mode() const { return m_current_mode; } + + // getters (display manager) + const char *monitor() { return (const char*) &m_ds.monitor; } + const char *user_modeline() { return (const char*) &m_ds.user_modeline; } + const char *crt_range(int i) { return (const char*) &m_ds.crt_range[i]; } + const char *lcd_range() { return (const char*) &m_ds.lcd_range; } + const char *screen() { return (const char*) &m_ds.screen; } + const char *api() { return (const char*) &m_ds.api; } + bool modeline_generation() { return m_ds.modeline_generation; } + bool lock_unsupported_modes() { return m_ds.lock_unsupported_modes; } + bool lock_system_modes() { return m_ds.lock_system_modes; } + bool refresh_dont_care() { return m_ds.refresh_dont_care; } + bool keep_changes() { return m_ds.keep_changes; } + bool desktop_is_rotated() const { return m_desktop_is_rotated; } + + // getters (modeline generator) + bool interlace() { return m_ds.gs.interlace; } + bool doublescan() { return m_ds.gs.doublescan; } + double dotclock_min() { return m_ds.gs.pclock_min; } + double refresh_tolerance() { return m_ds.gs.refresh_tolerance; } + int super_width() { return m_ds.gs.super_width; } + double monitor_aspect() { return m_ds.gs.monitor_aspect; } + double h_size() { return m_ds.gs.h_size; } + int h_shift() { return m_ds.gs.h_shift; } + int v_shift() { return m_ds.gs.v_shift; } + int v_shift_correct() { return m_ds.gs.v_shift_correct; } + int pixel_precision() { return m_ds.gs.pixel_precision; } + int interlace_force_even() { return m_ds.gs.interlace_force_even; } + + // getters (modeline result) + bool got_mode() { return (m_selected_mode != nullptr); } + int width() { return m_selected_mode != nullptr? m_selected_mode->width : 0; } + int height() { return m_selected_mode != nullptr? m_selected_mode->height : 0; } + int refresh() { return m_selected_mode != nullptr? m_selected_mode->refresh : 0; } + double v_freq() { return m_selected_mode != nullptr? m_selected_mode->vfreq : 0; } + double h_freq() { return m_selected_mode != nullptr? m_selected_mode->hfreq : 0; } + double x_scale() { return m_selected_mode != nullptr? m_selected_mode->result.x_scale : 0; } + double y_scale() { return m_selected_mode != nullptr? m_selected_mode->result.y_scale : 0; } + double v_scale() { return m_selected_mode != nullptr? m_selected_mode->result.v_scale : 0; } + bool is_interlaced() { return m_selected_mode != nullptr? m_selected_mode->interlace : false; } + bool is_doublescanned() { return m_selected_mode != nullptr? m_selected_mode->doublescan : false; } + bool is_stretched() { return m_selected_mode != nullptr? m_selected_mode->result.weight & R_RES_STRETCH : false; } + bool is_refresh_off() { return m_selected_mode != nullptr? m_selected_mode->result.weight & R_V_FREQ_OFF : false; } + bool is_switching_required() { return m_switching_required; } + bool is_mode_updated() { return m_selected_mode != nullptr? m_selected_mode->type & MODE_UPDATE : false; } + bool is_mode_new() { return m_selected_mode != nullptr? m_selected_mode->type & MODE_ADD : false; } + + // getters (custom_video backend) + bool screen_compositing() { return m_ds.vs.screen_compositing; } + bool screen_reordering() { return m_ds.vs.screen_reordering; } + bool allow_hardware_refresh() { return m_ds.vs.allow_hardware_refresh; } + const char *custom_timing() { return (const char*) &m_ds.vs.custom_timing; } + + // setters + void set_index(int index) { m_index = index; } + void set_factory(custom_video *factory) { m_factory = factory; } + void set_custom_video(custom_video *video) { m_video = video; } + void set_has_ini(bool value) { m_has_ini = value; } + + // setters (modes) + void set_user_mode(modeline *mode) { m_ds.user_mode = m_user_mode = *mode; filter_modes(); } + void set_selected_mode(modeline *mode) { m_selected_mode = mode; } + void set_current_mode(modeline *mode) { m_current_mode = mode; } + + // setters (display_manager) + void set_monitor(const char *preset) { set_preset(preset); } + void set_modeline(const char *modeline) { strncpy(m_ds.user_modeline, modeline, sizeof(m_ds.user_modeline)-1); } + void set_crt_range(int i, const char *range) { strncpy(m_ds.crt_range[i], range, sizeof(m_ds.crt_range[i])-1); } + void set_lcd_range(const char *range) { strncpy(m_ds.lcd_range, range, sizeof(m_ds.lcd_range)-1); } + void set_screen(const char *screen) { strncpy(m_ds.screen, screen, sizeof(m_ds.screen)-1); } + void set_api(const char *api) { strncpy(m_ds.api, api, sizeof(m_ds.api)-1); } + void set_modeline_generation(bool value) { m_ds.modeline_generation = value; } + void set_lock_unsupported_modes(bool value) { m_ds.lock_unsupported_modes = value; } + void set_lock_system_modes(bool value) { m_ds.lock_system_modes = value; } + void set_refresh_dont_care(bool value) { m_ds.refresh_dont_care = value; } + void set_keep_changes(bool value) { m_ds.keep_changes = value; } + void set_desktop_is_rotated(bool value) { m_desktop_is_rotated = value; } + + // setters (modeline generator) + void set_interlace(bool value) { m_ds.gs.interlace = value; } + void set_doublescan(bool value) { m_ds.gs.doublescan = value; } + void set_dotclock_min(double value) { m_ds.gs.pclock_min = value * 1000000; } + void set_refresh_tolerance(double value) { m_ds.gs.refresh_tolerance = value; } + void set_super_width(int value) { m_ds.gs.super_width = value; } + void set_monitor_aspect(double value) { m_ds.gs.monitor_aspect = value; } + void set_monitor_aspect(const char* aspect) { set_monitor_aspect(get_aspect(aspect)); } + void set_h_size(double value) { m_ds.gs.h_size = value; } + void set_h_shift(int value) { m_ds.gs.h_shift = value; } + void set_v_shift(int value) { m_ds.gs.v_shift = value; } + void set_v_shift_correct(int value) { m_ds.gs.v_shift_correct = value; } + void set_pixel_precision(int value) { m_ds.gs.pixel_precision = value; } + void set_interlace_force_even(int value) { m_ds.gs.interlace_force_even = value; } + + // setters (custom_video backend) + void set_screen_compositing(bool value) { m_ds.vs.screen_compositing = value; } + void set_screen_reordering(bool value) { m_ds.vs.screen_reordering = value; } + void set_allow_hardware_refresh(bool value) { m_ds.vs.allow_hardware_refresh = value; } + void set_custom_timing(const char *custom_timing) { strncpy(m_ds.vs.custom_timing, custom_timing, sizeof(m_ds.vs.custom_timing)-1); } + + // options + display_settings m_ds = {}; + + // mode setting interface + modeline *get_mode(int width, int height, float refresh, int flags); + bool add_mode(modeline *mode); + bool delete_mode(modeline *mode); + bool update_mode(modeline *mode); + virtual bool set_mode(modeline *); + void log_mode(modeline *mode); + + // mode list handling + bool filter_modes(); + bool restore_modes(); + bool flush_modes(); + bool auto_specs(); + + // mode list + std::vector video_modes = {}; + std::vector backup_modes = {}; + modeline desktop_mode = {}; + + // monitor preset + monitor_range range[MAX_RANGES]; + +private: + + // custom video backend + custom_video *m_factory = 0; + custom_video *m_video = 0; + + modeline m_user_mode = {}; + modeline *m_selected_mode = 0; + modeline *m_current_mode = 0; + + int m_index = 0; + bool m_desktop_is_rotated = 0; + bool m_switching_required = 0; + bool m_has_ini = 0; + int m_id_counter = 0; + + void set_preset(const char *preset); + double get_aspect(const char* aspect); + +protected: + void* m_pf_data = nullptr; +}; + +class dummy_display : public display_manager +{ + public: + dummy_display(display_settings *ds) { m_ds = *ds; }; +}; + +#endif diff --git a/display_linux.cpp b/display_linux.cpp new file mode 100644 index 00000000000..470647f3e38 --- /dev/null +++ b/display_linux.cpp @@ -0,0 +1,171 @@ +/************************************************************** + + display_linux.cpp - Display manager for Linux + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include + +#include "display_linux.h" +#include "log.h" + +//============================================================ +// linux_display::linux_display +//============================================================ + +linux_display::linux_display(display_settings *ds) +{ + // Get display settings + m_ds = *ds; +} + +//============================================================ +// linux_display::~linux_display +//============================================================ + +linux_display::~linux_display() +{ + if (!m_ds.keep_changes) + restore_desktop_mode(); +} + +//============================================================ +// linux_display::init +//============================================================ + +bool linux_display::init(void* pfdata) +{ + m_pf_data = pfdata; + // Initialize custom video + int method = CUSTOM_VIDEO_TIMING_AUTO; + +#ifdef SR_WITH_XRANDR + if (!strcmp(m_ds.api, "xrandr")) + method = CUSTOM_VIDEO_TIMING_XRANDR; +#endif +#ifdef SR_WITH_KMSDRM + if (!strcmp(m_ds.api, "drmkms")) + method = CUSTOM_VIDEO_TIMING_DRMKMS; +#endif + + set_factory(new custom_video); + set_custom_video(factory()->make(m_ds.screen, NULL, method, &m_ds.vs)); + if (!video() or !video()->init()) + return false; + + // Build our display's mode list + video_modes.clear(); + backup_modes.clear(); + get_desktop_mode(); + get_available_video_modes(); + + if (!strcmp(m_ds.monitor, "lcd")) auto_specs(); + filter_modes(); + + return true; +} + +//============================================================ +// linux_display::set_mode +//============================================================ + +bool linux_display::set_mode(modeline *mode) +{ + if (mode && set_desktop_mode(mode, 0)) + { + set_current_mode(mode); + return true; + } + return false; +} + +//============================================================ +// linux_display::get_desktop_mode +//============================================================ + +bool linux_display::get_desktop_mode() +{ + if (video() == NULL) + return false; + + return true; +} + +//============================================================ +// linux_display::set_desktop_mode +//============================================================ + +bool linux_display::set_desktop_mode(modeline *mode, int flags) +{ + if (!mode) + return false; + + if (video() == NULL) + return false; + + if (flags != 0) + log_info("Set desktop mode flags value is 0x%x.\n", flags); + + return video()->set_timing(mode); +} + +//============================================================ +// linux_display::restore_desktop_mode +//============================================================ + +bool linux_display::restore_desktop_mode() +{ + if (video() == NULL) + return false; + + return video()->set_timing(&desktop_mode); +} + +//============================================================ +// linux_display::get_available_video_modes +//============================================================ + +int linux_display::get_available_video_modes() +{ + if (video() == NULL) + return false; + + // loop through all modes until NULL mode type is received + for (;;) + { + modeline mode; + memset(&mode, 0, sizeof(struct modeline)); + + // get next mode + video()->get_timing(&mode); + if (mode.type == 0) + break; + + // set the desktop mode + if (mode.type & MODE_DESKTOP) + { + memcpy(&desktop_mode, &mode, sizeof(modeline)); + if (current_mode() == nullptr) + set_current_mode(&mode); + + if (mode.type & MODE_ROTATED) set_desktop_is_rotated(true); + } + + video_modes.push_back(mode); + backup_modes.push_back(mode); + + log_verbose("Switchres: [%3ld] %4dx%4d @%3d%s%s %s: ", video_modes.size(), mode.width, mode.height, mode.refresh, mode.interlace ? "i" : "p", mode.type & MODE_DESKTOP ? "*" : "", mode.type & MODE_ROTATED ? "rot" : ""); + log_mode(&mode); + }; + + return true; +} diff --git a/display_linux.h b/display_linux.h new file mode 100644 index 00000000000..f56faa84338 --- /dev/null +++ b/display_linux.h @@ -0,0 +1,30 @@ +/************************************************************** + + display_linux.h - Display manager for Linux + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include "display.h" + +class linux_display : public display_manager +{ + public: + linux_display(display_settings *ds); + ~linux_display(); + bool init(void* = nullptr); + bool set_mode(modeline *mode); + + private: + bool get_desktop_mode(); + bool set_desktop_mode(modeline *mode, int flags); + bool restore_desktop_mode(); + int get_available_video_modes(); +}; diff --git a/display_sdl2.cpp b/display_sdl2.cpp new file mode 100644 index 00000000000..5416fe17a43 --- /dev/null +++ b/display_sdl2.cpp @@ -0,0 +1,304 @@ +/************************************************************** + + display_linux.cpp - Display manager for Linux + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include + +#include "display_sdl2.h" +#include "log.h" + +//============================================================ +// custom_video::get_sdl_hwinfo_from_sdl_window +//============================================================ +void get_sdl_hwinfo_from_sdl_window(SDL_Window* window) +{ + SDL_SysWMinfo m_sdlwminfo; + + SDL_VERSION(&m_sdlwminfo.version); + if(! SDL_GetWindowWMInfo(window, &m_sdlwminfo)) + { + log_error("Couldn't get the SDL WMInfo\n"); + return; + } + const char *subsystem = "an unsupported or unknown system!"; + switch((int)m_sdlwminfo.subsystem) + { + case SDL_SYSWM_UNKNOWN: + case SDL_SYSWM_COCOA: + case SDL_SYSWM_UIKIT: +#if SDL_VERSION_ATLEAST(2, 0, 2) + case SDL_SYSWM_WAYLAND: +#endif + case SDL_SYSWM_MIR: +#if SDL_VERSION_ATLEAST(2, 0, 3) + case SDL_SYSWM_WINRT: +#endif +#if SDL_VERSION_ATLEAST(2, 0, 4) + case SDL_SYSWM_ANDROID: +#endif +#if SDL_VERSION_ATLEAST(2, 0, 5) + case SDL_SYSWM_VIVANTE: +#endif +#if SDL_VERSION_ATLEAST(2, 0, 6) + case SDL_SYSWM_OS2: +#endif +#if SDL_VERSION_ATLEAST(2, 0, 12) + case SDL_SYSWM_HAIKU: +#endif + case SDL_SYSWM_DIRECTFB: + break; + case SDL_SYSWM_WINDOWS: + subsystem = "Microsoft Windows(TM)"; + break; + case SDL_SYSWM_X11: + subsystem = "X Window System"; + break; +#if SDL_VERSION_ATLEAST(2, 0, 16) + case SDL_SYSWM_KMSDRM: + subsystem = "KMSDRM"; + break; +#endif + } + log_info("Switchres/SDL2: Detected SDL version %d.%d.%d on %s\n", + (int)m_sdlwminfo.version.major, + (int)m_sdlwminfo.version.minor, + (int)m_sdlwminfo.version.patch, + subsystem); +} + + +//============================================================ +// sdl2_display::sdl2_display +//============================================================ + +sdl2_display::sdl2_display(display_settings *ds) +{ + // First, we need to fin an active SDL2 window + if (SDL_WasInit(SDL_INIT_VIDEO) != 0) { + log_verbose("Switchres/SDL2: (%s): SDL2 video is initialized\n", __FUNCTION__); + } + else + { + log_verbose("Switchres/SDL2: (%s): SDL2 video wasn't initialized\n", __FUNCTION__); + throw std::exception(); + } + // For now, only allow the SDL2 display manager for the KMSDRM backend + if ( strcmp("KMSDRM", SDL_GetCurrentVideoDriver()) != 0 ) + { + log_info("Switchres/SDL2: (%s): SDL2 is only available for KMSDRM for now.\n", __FUNCTION__); + throw std::exception(); + } + + // Get display settings + m_ds = *ds; +} + +//============================================================ +// sdl2_display::~sdl2_display +//============================================================ + +sdl2_display::~sdl2_display() +{ +} + +//============================================================ +// sdl2_display::init +//============================================================ + +bool sdl2_display::init(void* pf_data) +{ + m_sdlwindow = (SDL_Window*) pf_data; + + // Initialize custom video + int method = CUSTOM_VIDEO_TIMING_AUTO; + +#ifdef SR_WITH_XRANDR + if (!strcmp(m_ds.api, "xrandr")) + method = CUSTOM_VIDEO_TIMING_XRANDR; +#endif +#ifdef SR_WITH_KMSDRM + if (!strcmp(m_ds.api, "drmkms")) + method = CUSTOM_VIDEO_TIMING_DRMKMS; +#endif + set_factory(new custom_video); + set_custom_video(factory()->make(m_ds.screen, NULL, method, &m_ds.vs)); + if (!video() or !video()->init()) + return false; + // Build our display's mode list + video_modes.clear(); + backup_modes.clear(); + //No need to call get_desktop_mode() SDL2 will restore the desktop mode itself + get_available_video_modes(); + + if (!strcmp(m_ds.monitor, "lcd")) auto_specs(); + filter_modes(); + + //SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG); + + SDL_Window* window = NULL; + Uint32 id = 0; + + /* + // Alternative method, only when the render has been created + if( SDL_GL_GetCurrentWindow() != NULL) + log_verbose("Swithres/SDL2: (%s) SDL_GL_GetCurrentWindow(); OK !\n", __FUNCTION__); + */ + if (pf_data == nullptr or pf_data == NULL) + { + int screen = atoi(m_ds.screen); + + while( (window = SDL_GetWindowFromID(++id)) ) + { + log_verbose("Switchres/SDL2: (%s:%d) SDL display id vs SR display id: %d vs %d (window id: %d)\n", __FUNCTION__, __LINE__, SDL_GetWindowDisplayIndex(window), screen, id); + if (SDL_GetWindowDisplayIndex(window) == screen) + { + log_verbose("Switchres/SDL2: (%s:%d) Found a display-matching SDL window\n ", __FUNCTION__, __LINE__); + m_sdlwindow = window; + return true; + } + } + + log_verbose("Switchres/SDL2: (%s:%d) No SDL window matching the display found\n ", __FUNCTION__, __LINE__); + + } + else + { + id = SDL_GetWindowID((SDL_Window*)pf_data); + if( id ) + { + log_verbose("Switchres/SDL2: (%s:%d) got a valid SDL_Window pointer (window id: %d)\n", __FUNCTION__, __LINE__, id); + m_sdlwindow = (SDL_Window*)pf_data; + } + else + log_verbose("Switchres/SDL2: (%s:%d) No SDL2 window found, don't expect things to work good\n", __FUNCTION__, __LINE__); + } + + if(m_sdlwindow) + get_sdl_hwinfo_from_sdl_window(m_sdlwindow); + + // Need a check to see if SDL2 can refresh the modelist + return true; +} + +//============================================================ +// sdl2_display::set_mode +//============================================================ + +bool sdl2_display::set_mode(modeline *mode) +{ + // Call SDL2 + SDL_DisplayMode target, closest; + target.w = mode->width; + target.h = mode->height; + target.format = 0; // don't care + target.refresh_rate = mode->refresh; + + /* + * Circumventing an annoying choice of SDL2: fullscreen modes are mutually exclusive + * which means you can't switch from one to another. If required, need to remove the flag, then + * set the new one. This will sadly trigger a window resizing + */ + if ( (SDL_GetWindowFlags(m_sdlwindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) + { + if ( SDL_SetWindowFullscreen(m_sdlwindow, 0) != 0 ) + { + log_error("Swithres/SDL2: (%s) Couldn't reset the fullscreen mode. %s\n", __FUNCTION__, SDL_GetError()); + return false; + } + } + + if ( (SDL_GetWindowFlags(m_sdlwindow) & SDL_WINDOW_FULLSCREEN) != SDL_WINDOW_FULLSCREEN ) + { + // Now we set the right mode that allows SDL2 modeswitches + if ( SDL_SetWindowFullscreen(m_sdlwindow, SDL_WINDOW_FULLSCREEN) != 0 ) + { + log_error("Swithres/SDL2: (%s) Couldn't set the window to FULLSCREEN. %s\n", __FUNCTION__, SDL_GetError()); + return false; + } + } + + // We may first check if the mode was already added, so we don't force a probe of all modes + if ( SDL_GetClosestDisplayMode(SDL_GetWindowDisplayIndex(m_sdlwindow), &target, &closest) == NULL ) + { + // If the returned pointer is null, no match was found. + log_error("Swithres/SDL2: (%s) No suitable display mode was found! %s\n\n", __FUNCTION__, SDL_GetError()); + return false; + } + log_verbose(" Received: \t%dx%dpx @ %dhz \n", closest.w, closest.h, closest.refresh_rate); + + if ( SDL_SetWindowDisplayMode(m_sdlwindow, &closest) != 0 ) + { + log_error("Swithres/SDL2: (%s) Failed to switch mode: %s\n", __FUNCTION__, SDL_GetError()); + return false; + } + + log_verbose("Swithres/SDL2: (%s) SDL2 display mode changed for window/display %d/%d!\n", __FUNCTION__, SDL_GetWindowID(m_sdlwindow), SDL_GetWindowDisplayIndex(m_sdlwindow)); + log_verbose(" to %dx%d@%d\n",closest.w, closest.h, closest.refresh_rate); + + set_current_mode(mode); + return true; +} + +//============================================================ +// sdl2_display::get_desktop_mode +//============================================================ + +bool sdl2_display::get_desktop_mode() +{ + if (video() == NULL) + return false; + + return true; +} + +//============================================================ +// sdl2_display::get_available_video_modes +//============================================================ + +int sdl2_display::get_available_video_modes() +{ + if (video() == NULL) + return false; + + // loop through all modes until NULL mode type is received + for (;;) + { + modeline mode; + memset(&mode, 0, sizeof(struct modeline)); + + // get next mode + video()->get_timing(&mode); + if (mode.type == 0) + break; + + // set the desktop mode + if (mode.type & MODE_DESKTOP) + { + memcpy(&desktop_mode, &mode, sizeof(modeline)); + if (current_mode() == nullptr) + set_current_mode(&mode); + + if (mode.type & MODE_ROTATED) set_desktop_is_rotated(true); + } + + video_modes.push_back(mode); + backup_modes.push_back(mode); + + log_verbose("Switchres/SDL2: [%3ld] %4dx%4d @%3d%s%s %s: ", video_modes.size(), mode.width, mode.height, mode.refresh, mode.interlace ? "i" : "p", mode.type & MODE_DESKTOP ? "*" : "", mode.type & MODE_ROTATED ? "rot" : ""); + log_mode(&mode); + }; + + return true; +} diff --git a/display_sdl2.h b/display_sdl2.h new file mode 100644 index 00000000000..1051841d898 --- /dev/null +++ b/display_sdl2.h @@ -0,0 +1,32 @@ +/************************************************************** + + display_linux.h - Display manager for Linux + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include "display.h" +#include "SDL.h" +#include "SDL_syswm.h" + +class sdl2_display : public display_manager +{ + public: + sdl2_display(display_settings *ds); + ~sdl2_display(); + bool init(void* pf_data); + bool set_mode(modeline *mode); + + private: + SDL_Window* m_sdlwindow = NULL; + + bool get_desktop_mode(); + int get_available_video_modes(); +}; diff --git a/display_windows.cpp b/display_windows.cpp new file mode 100644 index 00000000000..7d23f2a64cd --- /dev/null +++ b/display_windows.cpp @@ -0,0 +1,311 @@ +/************************************************************** + + display_windows.cpp - Display manager for Windows + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include "display_windows.h" +#include "log.h" + +typedef struct ENUM_INFO +{ + int index; + HMONITOR h_monitor; +} ENUM_INFO; + +//============================================================ +// windows_display::windows_display +//============================================================ + +windows_display::windows_display(display_settings *ds) +{ + // Get display settings + m_ds = *ds; +} + +//============================================================ +// windows_display::~windows_display +//============================================================ + +windows_display::~windows_display() +{ + // Restore previous settings + if (!m_ds.keep_changes) ChangeDisplaySettingsExA(m_device_name, NULL, NULL, 0, 0); +} + +//============================================================ +// windows_display::init +//============================================================ + +int CALLBACK monitor_by_index(HMONITOR h_monitor, HDC, LPRECT, LPARAM data) +{ + ENUM_INFO *mon_info = (ENUM_INFO*) data; + if (--mon_info->index < 0) + { + mon_info->h_monitor = h_monitor; + return false; + } + return true; +} + +bool windows_display::init(void*) +{ + char display[32] = {}; + + // If monitor is passed by index, find the matching device + if (strlen(m_ds.screen) == 1) + { + int monitor_index = m_ds.screen[0] - '0'; + if (monitor_index < 0 || monitor_index > 9) + { + log_error("Switchres: bad monitor index %d\n", monitor_index); + return false; + } + + ENUM_INFO mon_info; + mon_info.index = monitor_index; + mon_info.h_monitor = NULL; + + EnumDisplayMonitors(NULL, NULL, monitor_by_index, (LPARAM)&mon_info); + if (mon_info.h_monitor != NULL) + { + MONITORINFOEXA info = {}; + info.cbSize = sizeof(info); + GetMonitorInfoA(mon_info.h_monitor, &info); + snprintf(display, sizeof(display) -1, "%s", info.szDevice); + log_info("display %s\n", display); + } + else + { + log_error("Swichres: couldn't find handle for monitor index %d\n", monitor_index); + return false; + } + } + else + strncpy(display, m_ds.screen, sizeof(display)-1); + + // Find the display by device name, or "auto" for primary display + DISPLAY_DEVICEA lpDisplayDevice[DISPLAY_MAX]; + int idev = 0; + int found = -1; + + while (idev < DISPLAY_MAX) + { + memset(&lpDisplayDevice[idev], 0, sizeof(DISPLAY_DEVICEA)); + lpDisplayDevice[idev].cb = sizeof(DISPLAY_DEVICEA); + + if (EnumDisplayDevicesA(NULL, idev, &lpDisplayDevice[idev], 0) == FALSE) + break; + + if ((!strcmp(display, "auto") && (lpDisplayDevice[idev].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) + || !strcmp(display, lpDisplayDevice[idev].DeviceName)) + found = idev; + + idev++; + } + if (found != -1) + { + strncpy(m_device_name, lpDisplayDevice[found].DeviceName, sizeof(m_device_name) -1); + strncpy(m_device_id, lpDisplayDevice[found].DeviceID, sizeof(m_device_id) -1); + log_verbose("Switchres: %s: %s (%s)\n", m_device_name, lpDisplayDevice[found].DeviceString, m_device_id); + + char *pch; + int i; + for (i = 0; i < idev; i++) + { + pch = strstr(lpDisplayDevice[i].DeviceString, lpDisplayDevice[found].DeviceString); + if (pch) + { + found = i; + break; + } + } + + char *chsrc, *chdst; + chdst = m_device_key; + + for (chsrc = lpDisplayDevice[i].DeviceKey + 18; *chsrc != 0; chsrc++) + *chdst++ = *chsrc; + + *chdst = 0; + } + else + { + log_verbose("Switchres: Failed obtaining default video registry key\n"); + return false; + } + + log_verbose("Switchres: Device key: %s\n", m_device_key); + + // Initialize custom video + int method = CUSTOM_VIDEO_TIMING_AUTO; + if(!strcmp(m_ds.api, "powerstrip")) method = CUSTOM_VIDEO_TIMING_POWERSTRIP; + strcpy(m_ds.vs.device_reg_key, m_device_key); + + // Create custom video backend + set_factory(new custom_video); + set_custom_video(factory()->make(m_device_name, m_device_id, method, &m_ds.vs)); + if (video()) video()->init(); + + // Build our display's mode list + video_modes.clear(); + backup_modes.clear(); + get_desktop_mode(); + get_available_video_modes(); + if (!strcmp(m_ds.monitor, "lcd")) auto_specs(); + filter_modes(); + + return true; +} + +//============================================================ +// windows_display::set_mode +//============================================================ + +bool windows_display::set_mode(modeline *mode) +{ + if (mode && set_desktop_mode(mode, (m_ds.keep_changes? CDS_UPDATEREGISTRY : CDS_FULLSCREEN) | CDS_RESET)) + { + set_current_mode(mode); + return true; + } + + return false; +} + +//============================================================ +// windows_display::get_desktop_mode +//============================================================ + +bool windows_display::get_desktop_mode() +{ + memset(&m_devmode, 0, sizeof(DEVMODEA)); + m_devmode.dmSize = sizeof(DEVMODEA); + + if (EnumDisplaySettingsExA(!strcmp(m_device_name, "auto")?NULL:m_device_name, ENUM_CURRENT_SETTINGS, &m_devmode, 0)) + { + desktop_mode.width = m_devmode.dmDisplayOrientation == DMDO_DEFAULT || m_devmode.dmDisplayOrientation == DMDO_180? m_devmode.dmPelsWidth:m_devmode.dmPelsHeight; + desktop_mode.height = m_devmode.dmDisplayOrientation == DMDO_DEFAULT || m_devmode.dmDisplayOrientation == DMDO_180? m_devmode.dmPelsHeight:m_devmode.dmPelsWidth; + desktop_mode.refresh = m_devmode.dmDisplayFrequency; + desktop_mode.interlace = (m_devmode.dmDisplayFlags & DM_INTERLACED)?1:0; + return true; + } + return false; +} + +//============================================================ +// windows_display::set_desktop_mode +//============================================================ + +bool windows_display::set_desktop_mode(modeline *mode, int flags) +{ + if (mode) + { + DEVMODEA lpDevMode; + memset(&lpDevMode, 0, sizeof(DEVMODEA)); + lpDevMode.dmSize = sizeof(DEVMODEA); + lpDevMode.dmPelsWidth = mode->type & MODE_ROTATED? mode->height : mode->width; + lpDevMode.dmPelsHeight = mode->type & MODE_ROTATED? mode->width : mode->height; + lpDevMode.dmDisplayFrequency = (int)mode->refresh; + lpDevMode.dmDisplayFlags = mode->interlace? DM_INTERLACED : 0; + lpDevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; + + log_info("set_desktop_mode: %s (%dx%d@%d) flags(%x)\n", m_device_name, (int)lpDevMode.dmPelsWidth, (int)lpDevMode.dmPelsHeight, (int)lpDevMode.dmDisplayFrequency, (int)lpDevMode.dmDisplayFlags); + + int result = ChangeDisplaySettingsExA(m_device_name, &lpDevMode, NULL, flags, 0); + if (result == DISP_CHANGE_SUCCESSFUL) + return true; + + log_error("ChangeDisplaySettingsExA error(%x)\n", (int)result); + } + return false; +} + +//============================================================ +// windows_display::restore_desktop_mode +//============================================================ + +bool windows_display::restore_desktop_mode() +{ + if (ChangeDisplaySettingsExA(m_device_name, &m_devmode, NULL, 0, 0) == DISP_CHANGE_SUCCESSFUL) + return true; + + return false; +} + +//============================================================ +// windows_display::get_available_video_modes +//============================================================ + +int windows_display::get_available_video_modes() +{ + int iModeNum = 0, j = 0, k = 0; + DEVMODEA lpDevMode; + + memset(&lpDevMode, 0, sizeof(DEVMODEA)); + lpDevMode.dmSize = sizeof(DEVMODEA); + + log_verbose("Switchres: Searching for custom video modes...\n"); + + while (EnumDisplaySettingsExA(m_device_name, iModeNum, &lpDevMode, m_ds.lock_unsupported_modes?0:EDS_RAWMODE) != 0) + { + if (lpDevMode.dmBitsPerPel == 32 && lpDevMode.dmDisplayFixedOutput == DMDFO_DEFAULT) + { + modeline m; + memset(&m, 0, sizeof(struct modeline)); + m.interlace = (lpDevMode.dmDisplayFlags & DM_INTERLACED)?1:0; + m.width = lpDevMode.dmDisplayOrientation == DMDO_DEFAULT || lpDevMode.dmDisplayOrientation == DMDO_180? lpDevMode.dmPelsWidth:lpDevMode.dmPelsHeight; + m.height = lpDevMode.dmDisplayOrientation == DMDO_DEFAULT || lpDevMode.dmDisplayOrientation == DMDO_180? lpDevMode.dmPelsHeight:lpDevMode.dmPelsWidth; + m.refresh = lpDevMode.dmDisplayFrequency; + m.hactive = m.width; + m.vactive = m.height; + m.vfreq = m.refresh; + m.type |= lpDevMode.dmDisplayOrientation == DMDO_90 || lpDevMode.dmDisplayOrientation == DMDO_270? MODE_ROTATED : MODE_OK; + + for (auto &mode : video_modes) if (mode.width == m.width && mode.height == m.height && mode.refresh == m.refresh && m.interlace == mode.interlace) goto found; + + if (m.width == desktop_mode.width && m.height == desktop_mode.height && m.refresh == desktop_mode.refresh && m.interlace == desktop_mode.interlace) + { + m.type |= MODE_DESKTOP; + if (m.type & MODE_ROTATED) set_desktop_is_rotated(true); + if (current_mode() == nullptr) + set_current_mode(&m); + } + + log_verbose("Switchres: [%3d] %4dx%4d @%3d%s%s %s: ", k, m.width, m.height, m.refresh, m.interlace?"i":"p", m.type & MODE_DESKTOP?"*":"", m.type & MODE_ROTATED?"rot":""); + + if (video() && video()->get_timing(&m)) + { + j++; + log_mode(&m); + } + else + { + m.type |= CUSTOM_VIDEO_TIMING_SYSTEM; + log_verbose("system mode\n"); + } + + // Save our desktop mode now that we queried detailed timings + if (m.type & MODE_DESKTOP) desktop_mode = m; + + video_modes.push_back(m); + backup_modes.push_back(m); + k++; + } + found: + iModeNum++; + } + k--; + log_verbose("Switchres: Found %d custom of %d active video modes\n", j, k); + return k; +} + diff --git a/display_windows.h b/display_windows.h new file mode 100644 index 00000000000..760381f3c0d --- /dev/null +++ b/display_windows.h @@ -0,0 +1,45 @@ +/************************************************************** + + display_windows.h - Display manager for Windows + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include "display.h" + +//============================================================ +// PARAMETERS +//============================================================ + +// display modes +#define DM_INTERLACED 0x00000002 +#define DISPLAY_MAX 16 + + +class windows_display : public display_manager +{ + public: + windows_display(display_settings *ds); + ~windows_display(); + bool init(void* = nullptr); + bool set_mode(modeline *mode); + + private: + bool get_desktop_mode(); + bool set_desktop_mode(modeline *mode, int flags); + bool restore_desktop_mode(); + int get_available_video_modes(); + + char m_device_name[32]; + char m_device_id[128]; + char m_device_key[128]; + DEVMODEA m_devmode; +}; diff --git a/drm_hook.cpp b/drm_hook.cpp new file mode 100644 index 00000000000..ca63571bbe5 --- /dev/null +++ b/drm_hook.cpp @@ -0,0 +1,211 @@ +/************************************************************** + + drm_hook.cpp - Linux DRM/KMS library hook + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2022 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include + +// DRM headers +#include +#include + +#define MAX_CONNECTORS 10 + +bool hook_connector(drmModeConnectorPtr conn); +drmModeConnectorPtr get_connector(uint32_t connector_id); + +typedef struct connector_hook +{ + drmModeConnector conn; + drmModeModeInfo modes[128]; + uint32_t props[128]; + uint64_t prop_values[128]; + uint32_t encoders[128]; +} connector_hook; + +connector_hook connector[MAX_CONNECTORS]; +int m_num_connectors = 0; + +//============================================================ +// drmModeGetConnector +//============================================================ + +drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) +{ + static void* (*my_get_connector)(int, uint32_t) = NULL; + + if (!my_get_connector) + my_get_connector = (void*(*)(int, uint32_t))dlsym(RTLD_NEXT, "drmModeGetConnector"); + + // Allow hook detection (original func would return NULL) + if (fd == -1) + return &connector[0].conn; + + drmModeConnectorPtr conn = get_connector(connector_id); + + if (conn != NULL) + // already hooked + return conn; + + else + { + // attempt connector hook + conn = (drmModeConnectorPtr)my_get_connector(fd, connector_id); + if (!conn) return NULL; + + if (hook_connector(conn)) + { + conn = get_connector(connector_id); + printf("Switchres: returning hooked connector %d\n", conn->connector_id); + } + } + + return conn; +} + +//============================================================ +// drmModeGetConnectorCurrent +//============================================================ + +drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id) +{ + static void* (*my_get_connector_current)(int, uint32_t) = NULL; + + if (!my_get_connector_current) + my_get_connector_current = (void*(*)(int, uint32_t))dlsym(RTLD_NEXT, "drmModeGetConnectorCurrent"); + + // Allow hook detection (original func would return NULL) + if (fd == -1) + return &connector[0].conn; + + drmModeConnectorPtr conn = get_connector(connector_id); + + if (conn != NULL) + // already hooked + return conn; + + else + { + // attempt connector hook + conn = (drmModeConnectorPtr)my_get_connector_current(fd, connector_id); + if (!conn) return NULL; + + if (hook_connector(conn)) + { + conn = get_connector(connector_id); + printf("Switchres: returning hooked connector %d\n", conn->connector_id); + } + } + + return conn; +} + +//============================================================ +// drmModeFreeConnector +//============================================================ + +void drmModeFreeConnector(drmModeConnectorPtr ptr) +{ + static void (*my_free_connector)(drmModeConnectorPtr) = NULL; + + if (!my_free_connector) + my_free_connector = (void (*)(drmModeConnectorPtr)) dlsym(RTLD_NEXT, "drmModeFreeConnector"); + + // Skip our hooked connector + for (int i = 0; i < m_num_connectors; i++) + if (ptr == &connector[i].conn) + return; + + my_free_connector(ptr); +} + +//============================================================ +// hook_connector +//============================================================ + +bool hook_connector(drmModeConnectorPtr conn) +{ + if (conn == NULL) + return false; + + if (m_num_connectors >= MAX_CONNECTORS) + return false; + + if (conn->count_modes == 0) + return false; + + connector_hook *conn_hook = &connector[m_num_connectors++]; + drmModeConnectorPtr my_conn = &conn_hook->conn; + + printf("Switchres: hooking connector %d\n", conn->connector_id); + *my_conn = *conn; + + drmModeModeInfo *my_modes = conn_hook->modes; + memcpy(my_modes, conn->modes, sizeof(drmModeModeInfo) * conn->count_modes); + my_conn->modes = my_modes; + + uint32_t *my_encoders = conn_hook->encoders; + memcpy(my_encoders, conn->encoders, sizeof(uint32_t) * conn->count_encoders); + my_conn->encoders = my_encoders; + + uint32_t *my_props = conn_hook->props; + memcpy(my_props, conn->props, sizeof(uint32_t) * conn->count_props); + my_conn->props = my_props; + + uint64_t *my_prop_values = conn_hook->prop_values; + memcpy(my_prop_values, conn->prop_values, sizeof(uint64_t) * conn->count_props); + my_conn->prop_values = my_prop_values; + + drmModeFreeConnector(conn); + + bool found = false; + drmModeModeInfo *mode = NULL; + for (int i = 0; i < my_conn->count_modes; i++) + { + mode = &my_modes[i]; + if (mode->type & DRM_MODE_TYPE_PREFERRED) + { + found = true; + break; + } + } + + // If preferred mode not found, default to first entry + if (!found) + mode = &my_modes[0]; + + // Add dummy mode to mode list (preferred mode with hdisplay +1, vfresh +1) + drmModeModeInfo *dummy_mode = &my_modes[my_conn->count_modes]; + *dummy_mode = *mode; + dummy_mode->vrefresh++; + dummy_mode->hdisplay++; + dummy_mode->type |= (1<<7); + my_conn->count_modes++; + + return true; +} + +//============================================================ +// get_connector +//============================================================ + +drmModeConnectorPtr get_connector(uint32_t connector_id) +{ + for (int i = 0; i < m_num_connectors; i++) + if (connector[i].conn.connector_id == connector_id) + return &connector[i].conn; + + return NULL; +} diff --git a/edid.cpp b/edid.cpp new file mode 100644 index 00000000000..3b27a6cfa9c --- /dev/null +++ b/edid.cpp @@ -0,0 +1,244 @@ +/************************************************************** + + edid.c - Basic EDID generation + (based on edid.S: EDID data template by Carsten Emde) + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include "switchres.h" +#include "edid.h" + +//============================================================ +// edid_from_modeline +//============================================================ + +int edid_from_modeline(modeline *mode, monitor_range *range, const char *name, edid_block *edid) +{ + if (!edid) return 0; + + // header + edid->b[0] = 0x00; + edid->b[1] = 0xff; + edid->b[2] = 0xff; + edid->b[3] = 0xff; + edid->b[4] = 0xff; + edid->b[5] = 0xff; + edid->b[6] = 0xff; + edid->b[7] = 0x00; + + // Manufacturer ID = "SWR" + edid->b[8] = 0x4e; + edid->b[9] = 0xf2; + + // Manufacturer product code + edid->b[10] = 0x00; + edid->b[11] = 0x00; + + // Serial number + edid->b[12] = 0x00; + edid->b[13] = 0x00; + edid->b[14] = 0x00; + edid->b[15] = 0x00; + + // Week of manufacture + edid->b[16] = 5; + + // Year of manufacture + edid->b[17] = 2021 - 1990; + + // EDID version and revision + edid->b[18] = 1; + edid->b[19] = 3; + + // video params + edid->b[20] = 0x6d; + + // Maximum H & V size in cm + edid->b[21] = 48; + edid->b[22] = 36; + + // Gamma + edid->b[23] = 120; + + // Display features + edid->b[24] = 0x0A; + + // Chromacity coordinates; + edid->b[25] = 0x5e; + edid->b[26] = 0xc0; + edid->b[27] = 0xa4; + edid->b[28] = 0x59; + edid->b[29] = 0x4a; + edid->b[30] = 0x98; + edid->b[31] = 0x25; + edid->b[32] = 0x20; + edid->b[33] = 0x50; + edid->b[34] = 0x54; + + // Established timings + edid->b[35] = 0x00; + edid->b[36] = 0x00; + edid->b[37] = 0x00; + + // Standard timing information + edid->b[38] = 0x01; + edid->b[39] = 0x01; + edid->b[40] = 0x01; + edid->b[41] = 0x01; + edid->b[42] = 0x01; + edid->b[43] = 0x01; + edid->b[44] = 0x01; + edid->b[45] = 0x01; + edid->b[46] = 0x01; + edid->b[47] = 0x01; + edid->b[48] = 0x01; + edid->b[49] = 0x01; + edid->b[50] = 0x01; + edid->b[51] = 0x01; + edid->b[52] = 0x01; + edid->b[53] = 0x01; + + // Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) + edid->b[54] = (mode->pclock / 10000) & 0xff; + edid->b[55] = (mode->pclock / 10000) >> 8; + + int h_active = mode->hactive; + int h_blank = mode->htotal - mode->hactive; + int h_offset = mode->hbegin - mode->hactive; + int h_pulse = mode->hend - mode->hbegin; + + int v_active = mode->vactive; + int v_blank = (int)mode->vtotal - mode->vactive; + int v_offset = mode->vbegin - mode->vactive; + int v_pulse = mode->vend - mode->vbegin; + + // Horizontal active pixels 8 lsbits (0-4095) + edid->b[56] = h_active & 0xff; + + // Horizontal blanking pixels 8 lsbits (0-4095) + edid->b[57] = h_blank & 0xff; + + // Bits 7-4 Horizontal active pixels 4 msbits + // Bits 3-0 Horizontal blanking pixels 4 msbits + edid->b[58] = (((h_active >> 8) & 0x0f) << 4) + ((h_blank >> 8) & 0x0f); + + // Vertical active lines 8 lsbits (0-4095) + edid->b[59] = v_active & 0xff; + + // Vertical blanking lines 8 lsbits (0-4095) + edid->b[60] = v_blank & 0xff; + + // Bits 7-4 Vertical active lines 4 msbits + // Bits 3-0 Vertical blanking lines 4 msbits + edid->b[61] = (((v_active >> 8) & 0x0f) << 4) + ((v_blank >> 8) & 0x0f); + + // Horizontal sync offset pixels 8 lsbits (0-1023) From blanking start + edid->b[62] = h_offset & 0xff; + + // Horizontal sync pulse width pixels 8 lsbits (0-1023) + edid->b[63] = h_pulse & 0xff; + + // Bits 7-4 Vertical sync offset lines 4 lsbits 0-63) + // Bits 3-0 Vertical sync pulse width lines 4 lsbits 0-63) + edid->b[64] = ((v_offset & 0x0f) << 4) + (v_pulse & 0x0f); + + // Bits 7-6 Horizontal sync offset pixels 2 msbits + // Bits 5-4 Horizontal sync pulse width pixels 2 msbits + // Bits 3-2 Vertical sync offset lines 2 msbits + // Bits 1-0 Vertical sync pulse width lines 2 msbits + edid->b[65] = (((h_offset >> 8) & 0x03) << 6) + + (((h_pulse >> 8) & 0x03) << 4) + + (((v_offset >> 8) & 0x03) << 2) + + ((v_pulse >> 8) & 0x03); + + // Horizontal display size, mm, 8 lsbits (0-4095 mm, 161 in) + edid->b[66] = 485 & 0xff; + + // Vertical display size, mm, 8 lsbits (0-4095 mm, 161 in) + edid->b[67] = 364 & 0xff; + + // Bits 7-4 Horizontal display size, mm, 4 msbits + // Bits 3-0 Vertical display size, mm, 4 msbits + edid->b[68] = (((485 >> 8) & 0x0f) << 4) + ((364 >> 8) & 0x0f); + + // Horizontal border pixels (each side; total is twice this) + edid->b[69] = 0; + + // Vertical border lines (each side; total is twice this) + edid->b[70] = 0; + + // Features bitmap + edid->b[71] = ((mode->interlace & 0x01) << 7) + 0x18 + (mode->vsync << 2) + (mode->hsync << 2); + + + // Descriptor: monitor serial number + edid->b[72] = 0; + edid->b[73] = 0; + edid->b[74] = 0; + edid->b[75] = 0xff; + edid->b[76] = 0; + edid->b[77] = 'S'; + edid->b[78] = 'w'; + edid->b[79] = 'i'; + edid->b[80] = 't'; + edid->b[81] = 'c'; + edid->b[82] = 'h'; + edid->b[83] = 'r'; + edid->b[84] = 'e'; + edid->b[85] = 's'; + edid->b[86] = '2'; + edid->b[87] = '0'; + edid->b[88] = '0'; + edid->b[89] = 0x0a; + + // Descriptor: monitor range limits + edid->b[90] = 0; + edid->b[91] = 0; + edid->b[92] = 0; + edid->b[93] = 0xfd; + edid->b[94] = 0; + edid->b[95] = ((int)range->vfreq_min) & 0xff; + edid->b[96] = ((int)range->vfreq_max) & 0xff; + edid->b[97] = ((int)range->hfreq_min / 1000) & 0xff; + edid->b[98] = ((int)range->hfreq_max / 1000) & 0xff; + edid->b[99] = 0xff; + edid->b[100] = 0; + edid->b[101] = 0x0a; + edid->b[102] = 0x20; + edid->b[103] = 0x20; + edid->b[104] = 0x20; + edid->b[105] = 0x20; + edid->b[106] = 0x20; + edid->b[107] = 0x20; + + // Descriptor: text + edid->b[108] = 0; + edid->b[109] = 0; + edid->b[110] = 0; + edid->b[111] = 0xfc; + edid->b[112] = 0; + snprintf(&edid->b[113], 13, "%s", name); + edid->b[125] = 0x0a; + + // Extensions to follow + edid->b[126] = 0; + + // Compute checksum + char checksum = 0; + int i; + for (i = 0; i <= 126; i++) + checksum += edid->b[i]; + edid->b[127] = 256 - checksum; + + return 1; +} diff --git a/edid.h b/edid.h new file mode 100644 index 00000000000..66bffa1184c --- /dev/null +++ b/edid.h @@ -0,0 +1,37 @@ +/************************************************************** + + edid.h - Basic EDID generation + (based on edid.S: EDID data template by Carsten Emde) + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __EDID_H__ +#define __EDID_H__ + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +typedef struct edid_block +{ + char b[128]; +/* char ext1[128]; + char ext2[128]; + char ext3[128];*/ +} edid_block; + +//============================================================ +// PROTOTYPES +//============================================================ + +int edid_from_modeline(modeline *mode, monitor_range *range, const char *name, edid_block *edid); + +#endif diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000000..fc9bcda1dac --- /dev/null +++ b/examples/README.md @@ -0,0 +1,56 @@ +# ANY OS - BASIC INFORMATION + +## Build libswitchres + +It supports cross compilation, and will build both dynamic and static libs as per the target OS +```bash +make libswitchres +``` +## Basic usage as a client with examples +libswitchres can be called in 2 different ways (with example code): + * `test_dlopen.c` -> by explicitely opening a .so/.dll, import the srlib object and call associated functions + * `test_liblink.c` -> by simply linking libswitchres at build time + +These options are generic whether you build for Linux or Windows + * -I ../ (to get libswitchres_wrapper.h) + * -L ../ or -L ./ (for win32, when the dll has been copied in the examples folder) + * -lswitchres to link the lib if not manually opening it in the code + +#please note#: static libs aven't been tested yet + +# LINUX + +You'll need a few extra parameters for gcc: + * -ldl (will try later to find a way to statically link libdl.a) + +When running, dont forget to add before the binary LD_LIBRARY_PATH=:$LD_LIBRARY_PATH + +## Examples: +```bash +make libswitchres +cd examples +g++ -o linux_dl_test test_dlopen.cpp -I ../ -ldl +LD_LIBRARY_PATH=../:$LD_LIBRARY_PATH ./linux_dl_test + +g++ -o linux_link_lib test_liblink.cpp -I ../ -L../ -lswitchres -ldl +LD_LIBRARY_PATH=../:$LD_LIBRARY_PATH ./linux_link_lib +``` + +# WINDOWS + +Pretty much the same as Linux, but with mingw64. The resulting exe and dll can be tested with wine + +## Examples (cross-building from windows) + +``` +make PLATFORM=NT CROSS_COMPILE=x86_64-w64-mingw32- libswitchres +(copy the dll to examples) + +x86_64-w64-mingw32-g++-win32 test_dlopen.cpp -o w32_loaddll.exe -I ../ -static-libgcc -static-libstdc++ +w32_loaddll.exe + +x86_64-w64-mingw32-g++-win32 test_liblink.cpp -o w32_linkdll.exe -I ../ -static-libgcc -static-libstdc++ -L ./ -lswitchres +w32_linkdll.exe +``` + +Note that, when building w32_linkdll.exe, I couldn't point to another dir else than ./ with -L diff --git a/examples/multi_monitor.cpp b/examples/multi_monitor.cpp new file mode 100644 index 00000000000..853aec349f4 --- /dev/null +++ b/examples/multi_monitor.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +int main(int argc, char** argv) +{ + sr_mode srm; + int ret; + + sr_init(); + sr_set_log_level(3); + + sr_set_disp(-1); + sr_set_monitor("arcade_31"); + sr_init_disp("0", NULL); + + sr_set_disp(-1); + sr_set_monitor("pc_31_120"); + sr_init_disp("1", NULL); + + sr_set_disp(0); + ret = sr_switch_to_mode(640, 480, 57, 0, &srm); + + sr_set_disp(1); + ret = sr_switch_to_mode(320, 240, 58, 0, &srm); + + printf("Press any key to quit.\n"); + getchar(); + + sr_deinit(); +} diff --git a/examples/test_dlopen.cpp b/examples/test_dlopen.cpp new file mode 100644 index 00000000000..46a01a929b7 --- /dev/null +++ b/examples/test_dlopen.cpp @@ -0,0 +1,84 @@ +#include +#include +#ifdef __cplusplus +#include // required for strcpy +#endif + +#ifdef __linux__ +#define LIBSWR "libswitchres.so" +#elif _WIN32 +#define LIBSWR "libswitchres.dll" +#endif + +#include + +int main(int argc, char** argv) +{ + const char* err_msg; + + printf("About to open %s.\n", LIBSWR); + + // Load the lib + LIBTYPE dlp = OPENLIB(LIBSWR); + + // Loading failed, inform and exit + if (!dlp) + { + printf("Loading %s failed.\n", LIBSWR); + printf("Error: %s\n", LIBERROR()); + exit(EXIT_FAILURE); + } + + printf("Loading %s succeded.\n", LIBSWR); + + + // Load the init() + LIBERROR(); + srAPI* SRobj = (srAPI*) LIBFUNC(dlp, "srlib"); + if ((err_msg = LIBERROR()) != NULL) + { + printf("Failed to load srAPI: %s\n", err_msg); + CLOSELIB(dlp); + exit(EXIT_FAILURE); + } + + // Testing the function + printf("Init a new switchres_manager object:\n"); + SRobj->init(); + SRobj->init_disp(NULL, NULL); + + // Call mode + get result values + int w = 384, h = 224; + double rr = 59.583393; + int interlace = 0, ret; + sr_mode srm; + + printf("Original requested mode: %dx%d@%f%s\n", w, h, rr, interlace? "i":""); + + ret = SRobj->add_mode(w, h, rr, interlace, &srm); + if (!ret) + { + printf("ERROR: Couldn't add the required mode. Exiting!\n"); + SRobj->deinit(); + exit(1); + } + printf("Got mode: %dx%d%c@%f\n", srm.width, srm.height, srm.interlace, srm.refresh); + printf("Press any key to switch to new mode\n"); + getchar(); + + ret = SRobj->switch_to_mode(srm.width, srm.height, rr, srm.interlace, &srm); + if (!ret) + { + printf("ERROR: Couldn't switch to the required mode. Exiting!\n"); + SRobj->deinit(); + exit(1); + } + printf("Press any key to quit.\n"); + getchar(); + + // Clean the mess, kiss goodnight SR + SRobj->deinit(); + + // We're done, let's close + CLOSELIB(dlp); +} diff --git a/examples/test_liblink.cpp b/examples/test_liblink.cpp new file mode 100644 index 00000000000..01534a9cdca --- /dev/null +++ b/examples/test_liblink.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int main(int argc, char** argv) +{ + sr_mode srm; + int ret; + + sr_init(); + sr_init_disp(NULL, NULL); + + ret = sr_add_mode(384, 224, 59.63, 0, &srm); + if (!ret) + { + printf("ERROR: Couldn't add the required mode. Exiting!\n"); + sr_deinit(); + exit(1); + } + printf("SR returned resolution: %dx%d@%f%s\n", srm.width, srm.height, srm.refresh, srm.interlace? "i" : ""); + printf("Press any key to switch to new mode\n"); + getchar(); + + ret = sr_switch_to_mode(384, 224, 59.63, 0, &srm); + if (!ret) + { + printf("ERROR: Couldn't switch to the required mode. Exiting!\n"); + sr_deinit(); + exit(1); + } + + printf("Press any key to quit.\n"); + getchar(); + + sr_deinit(); +} diff --git a/font.h b/font.h new file mode 100644 index 00000000000..3a24c6dbe7b --- /dev/null +++ b/font.h @@ -0,0 +1,3776 @@ +#ifndef ATTRACTPLUS_TTF_H +#define ATTRACTPLUS_TTF_H + +static const unsigned char ATTRACTPLUS_TTF[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60, + 0x46, 0x46, 0x54, 0x4d, 0x6f, 0x57, 0x60, 0x3a, 0x00, 0x00, 0xb0, 0x8c, + 0x00, 0x00, 0x00, 0x1c, 0x47, 0x44, 0x45, 0x46, 0x01, 0xaf, 0x00, 0x24, + 0x00, 0x00, 0xb0, 0x64, 0x00, 0x00, 0x00, 0x28, 0x4f, 0x53, 0x2f, 0x32, + 0x68, 0xca, 0x32, 0x45, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x00, 0x56, + 0x63, 0x6d, 0x61, 0x70, 0xdb, 0x66, 0xe8, 0x57, 0x00, 0x00, 0x07, 0xc0, + 0x00, 0x00, 0x03, 0x76, 0x63, 0x76, 0x74, 0x20, 0x00, 0x22, 0x02, 0x88, + 0x00, 0x00, 0x0b, 0x38, 0x00, 0x00, 0x00, 0x04, 0x67, 0x61, 0x73, 0x70, + 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0xb0, 0x5c, 0x00, 0x00, 0x00, 0x08, + 0x67, 0x6c, 0x79, 0x66, 0xec, 0xb7, 0xc3, 0x0d, 0x00, 0x00, 0x0e, 0x40, + 0x00, 0x00, 0x97, 0x78, 0x68, 0x65, 0x61, 0x64, 0x22, 0x08, 0x4c, 0x17, + 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61, + 0x09, 0x73, 0x06, 0x93, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x24, + 0x68, 0x6d, 0x74, 0x78, 0x43, 0xc7, 0x01, 0x45, 0x00, 0x00, 0x01, 0xc0, + 0x00, 0x00, 0x06, 0x00, 0x6c, 0x6f, 0x63, 0x61, 0xa3, 0x69, 0x7c, 0x14, + 0x00, 0x00, 0x0b, 0x3c, 0x00, 0x00, 0x03, 0x02, 0x6d, 0x61, 0x78, 0x70, + 0x01, 0xd4, 0x00, 0xa5, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x20, + 0x6e, 0x61, 0x6d, 0x65, 0x36, 0xa7, 0x1a, 0x86, 0x00, 0x00, 0xa5, 0xb8, + 0x00, 0x00, 0x01, 0xda, 0x70, 0x6f, 0x73, 0x74, 0xc8, 0xb1, 0x50, 0x66, + 0x00, 0x00, 0xa7, 0x94, 0x00, 0x00, 0x08, 0xc7, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xe1, 0x5c, 0xf2, 0x43, 0x5f, 0x0f, 0x3c, 0xf5, + 0x00, 0x1f, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xe0, 0x84, 0x1a, + 0x00, 0x00, 0x00, 0x00, 0xde, 0xe0, 0x84, 0x1a, 0x00, 0x00, 0xfe, 0xe9, + 0x05, 0x14, 0x03, 0xfd, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x46, 0xff, 0x46, + 0x01, 0x17, 0x05, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x05, 0x14, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, 0x00, 0x00, 0x01, 0x80, 0x00, 0x74, + 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x97, 0x01, 0xf4, 0x00, 0x05, 0x00, 0x00, 0x02, 0x99, + 0x02, 0xcc, 0x00, 0x00, 0x00, 0x8f, 0x02, 0x99, 0x02, 0xcc, 0x00, 0x00, + 0x01, 0xeb, 0x00, 0x33, 0x01, 0x09, 0x00, 0x00, 0x02, 0x00, 0x06, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x07, 0x00, 0x01, + 0xe0, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x74, + 0x74, 0x66, 0x00, 0x40, 0x00, 0x20, 0x30, 0x00, 0x03, 0x46, 0xff, 0x46, + 0x01, 0x17, 0x03, 0x46, 0x01, 0xd1, 0x40, 0x00, 0x00, 0x93, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xee, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x5c, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0xe6, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0x16, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, + 0x01, 0x16, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, + 0x01, 0x16, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0xe6, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x00, 0x03, 0x43, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0xe6, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0x16, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, + 0x02, 0x89, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x03, 0x43, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0x16, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0xe6, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0x16, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, + 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, + 0x01, 0x73, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0x89, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0xe6, 0x00, 0x00, 0x03, 0x43, 0x00, 0x5c, 0x02, 0xe6, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x5c, 0x02, 0xe6, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x03, 0xfc, 0x00, 0x00, 0x04, 0xb6, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x05, 0x13, 0x00, 0x00, 0x04, 0xb6, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x03, 0xa0, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x03, 0xa0, 0x00, 0x00, 0x04, 0x59, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, + 0x02, 0xe6, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, + 0x03, 0xfc, 0x00, 0x00, 0x04, 0x59, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x05, 0x70, 0x00, 0x00, 0x04, 0x59, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, + 0x03, 0xa0, 0x00, 0x00, 0x05, 0x13, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x04, 0x59, 0x00, 0x00, + 0x04, 0x59, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x00, 0x04, 0x59, 0x00, 0x00, 0x04, 0x59, 0x00, 0x00, + 0x03, 0x43, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, 0x03, 0xa0, 0x00, 0x00, + 0x05, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6c, + 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x01, 0x50, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x40, 0x00, 0x05, 0x00, 0x10, 0x00, 0x7e, + 0x00, 0xac, 0x01, 0x7e, 0x20, 0x19, 0x20, 0x1d, 0x20, 0x22, 0x20, 0x26, + 0x20, 0x33, 0x20, 0x3d, 0x20, 0xac, 0x21, 0x22, 0x21, 0x93, 0x22, 0x1e, + 0x25, 0xb2, 0x25, 0xba, 0x25, 0xbc, 0x25, 0xc4, 0x26, 0x05, 0x26, 0x0e, + 0x26, 0x20, 0x26, 0x2f, 0x26, 0x3c, 0x26, 0x40, 0x26, 0x42, 0x26, 0x53, + 0x26, 0x61, 0x26, 0x63, 0x26, 0x66, 0x26, 0x6b, 0x27, 0x02, 0x27, 0x04, + 0x27, 0x09, 0x27, 0x0c, 0x27, 0x0e, 0x27, 0x10, 0x27, 0x1e, 0x27, 0x21, + 0x27, 0x3f, 0x30, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0xa0, + 0x00, 0xae, 0x20, 0x18, 0x20, 0x1c, 0x20, 0x22, 0x20, 0x26, 0x20, 0x32, + 0x20, 0x3d, 0x20, 0xac, 0x21, 0x22, 0x21, 0x90, 0x22, 0x1e, 0x25, 0xb2, + 0x25, 0xba, 0x25, 0xbc, 0x25, 0xc4, 0x26, 0x02, 0x26, 0x0e, 0x26, 0x20, + 0x26, 0x2e, 0x26, 0x39, 0x26, 0x40, 0x26, 0x42, 0x26, 0x48, 0x26, 0x60, + 0x26, 0x63, 0x26, 0x65, 0x26, 0x6a, 0x27, 0x02, 0x27, 0x04, 0x27, 0x08, + 0x27, 0x0c, 0x27, 0x0e, 0x27, 0x10, 0x27, 0x1e, 0x27, 0x21, 0x27, 0x3f, + 0x30, 0x00, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xc2, 0xff, 0xc1, 0xe1, 0x28, + 0xe1, 0x26, 0xe1, 0x22, 0xe1, 0x1f, 0xe1, 0x14, 0xe1, 0x0b, 0xe0, 0x9d, + 0xe0, 0x28, 0xdf, 0xbb, 0xdf, 0x31, 0xdb, 0x9e, 0xdb, 0x97, 0xdb, 0x96, + 0xdb, 0x8f, 0xdb, 0x52, 0xdb, 0x4a, 0xdb, 0x39, 0xdb, 0x2c, 0xdb, 0x23, + 0xdb, 0x20, 0xdb, 0x1f, 0xdb, 0x1a, 0xdb, 0x0e, 0xdb, 0x0d, 0xdb, 0x0c, + 0xdb, 0x09, 0xda, 0x73, 0xda, 0x72, 0xda, 0x6f, 0xda, 0x6d, 0xda, 0x6c, + 0xda, 0x6b, 0xda, 0x5e, 0xda, 0x5c, 0xda, 0x3f, 0xd1, 0x7f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, + 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, + 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, + 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, + 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, + 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, + 0x00, 0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, + 0x00, 0x2e, 0x00, 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, + 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, + 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, + 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, + 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, + 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, + 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, + 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, + 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0x00, 0x00, 0x85, + 0x00, 0x86, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9d, + 0x00, 0xa2, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa6, + 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xac, 0x00, 0xae, + 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb3, + 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xba, 0x00, 0xbc, + 0x00, 0xbd, 0x00, 0x00, 0x00, 0x71, 0x00, 0x64, 0x00, 0x65, 0x00, 0x69, + 0x01, 0x44, 0x00, 0x77, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0x6b, 0x01, 0x4a, + 0x00, 0x75, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x87, 0x00, 0x99, 0x01, 0x4f, + 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x76, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x7b, + 0x00, 0x00, 0x00, 0xa7, 0x00, 0xb9, 0x00, 0x80, 0x00, 0x63, 0x00, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x7c, + 0x01, 0x45, 0x00, 0x62, 0x00, 0x81, 0x00, 0x84, 0x00, 0x96, 0x01, 0x13, + 0x01, 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x43, 0x01, 0x40, + 0x01, 0x41, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x39, 0x00, 0x00, + 0x01, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x8b, + 0x00, 0x82, 0x00, 0x8c, 0x00, 0x89, 0x00, 0x8e, 0x00, 0x8f, 0x00, 0x90, + 0x00, 0x8d, 0x00, 0x94, 0x00, 0x95, 0x00, 0x00, 0x00, 0x93, 0x00, 0x9b, + 0x00, 0x9c, 0x00, 0x9a, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x88, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x90, + 0x00, 0xd4, 0x01, 0x0e, 0x01, 0x5a, 0x01, 0x6c, 0x01, 0x96, 0x01, 0xbe, + 0x01, 0xde, 0x01, 0xfa, 0x02, 0x0c, 0x02, 0x1e, 0x02, 0x2a, 0x02, 0x4a, + 0x02, 0x82, 0x02, 0x9e, 0x02, 0xd8, 0x03, 0x12, 0x03, 0x3c, 0x03, 0x6e, + 0x03, 0xa8, 0x03, 0xd0, 0x04, 0x12, 0x04, 0x4a, 0x04, 0x5c, 0x04, 0x76, + 0x04, 0xa2, 0x04, 0xc2, 0x04, 0xee, 0x05, 0x1a, 0x05, 0x72, 0x05, 0xa0, + 0x05, 0xd4, 0x05, 0xfc, 0x06, 0x2a, 0x06, 0x4e, 0x06, 0x6c, 0x06, 0x9e, + 0x06, 0xc4, 0x06, 0xe2, 0x07, 0x04, 0x07, 0x3c, 0x07, 0x56, 0x07, 0x86, + 0x07, 0xb2, 0x07, 0xe2, 0x08, 0x06, 0x08, 0x44, 0x08, 0x74, 0x08, 0xa8, + 0x08, 0xc4, 0x08, 0xee, 0x09, 0x1e, 0x09, 0x52, 0x09, 0x94, 0x09, 0xc2, + 0x09, 0xf0, 0x0a, 0x0c, 0x0a, 0x30, 0x0a, 0x4c, 0x0a, 0x74, 0x0a, 0x86, + 0x0a, 0x9e, 0x0a, 0xc8, 0x0a, 0xf0, 0x0b, 0x14, 0x0b, 0x3c, 0x0b, 0x66, + 0x0b, 0x88, 0x0b, 0xb4, 0x0b, 0xd8, 0x0b, 0xf2, 0x0c, 0x12, 0x0c, 0x40, + 0x0c, 0x58, 0x0c, 0x88, 0x0c, 0xa8, 0x0c, 0xd2, 0x0c, 0xf8, 0x0d, 0x20, + 0x0d, 0x38, 0x0d, 0x64, 0x0d, 0x84, 0x0d, 0xa6, 0x0d, 0xd0, 0x0e, 0x00, + 0x0e, 0x2e, 0x0e, 0x58, 0x0e, 0x82, 0x0e, 0xaa, 0x0e, 0xc0, 0x0e, 0xe6, + 0x0f, 0x06, 0x0f, 0x06, 0x0f, 0x1e, 0x0f, 0x50, 0x0f, 0x88, 0x0f, 0xc4, + 0x0f, 0xfe, 0x10, 0x18, 0x10, 0x66, 0x10, 0x7a, 0x10, 0xc0, 0x10, 0xe8, + 0x11, 0x28, 0x11, 0x3c, 0x11, 0x86, 0x11, 0x9c, 0x11, 0xb8, 0x11, 0xe0, + 0x12, 0x00, 0x12, 0x1a, 0x12, 0x30, 0x12, 0x52, 0x12, 0x7e, 0x12, 0x8e, + 0x12, 0xa8, 0x12, 0xc0, 0x12, 0xe4, 0x13, 0x24, 0x13, 0x66, 0x13, 0xb4, + 0x13, 0xfc, 0x14, 0x2a, 0x14, 0x62, 0x14, 0x9a, 0x14, 0xd8, 0x15, 0x1a, + 0x15, 0x52, 0x15, 0x92, 0x15, 0xcc, 0x15, 0xfe, 0x16, 0x2e, 0x16, 0x5e, + 0x16, 0x96, 0x16, 0xc6, 0x16, 0xf0, 0x17, 0x1a, 0x17, 0x4a, 0x17, 0x74, + 0x17, 0xaa, 0x17, 0xec, 0x18, 0x28, 0x18, 0x64, 0x18, 0xa6, 0x18, 0xec, + 0x19, 0x28, 0x19, 0x60, 0x19, 0x92, 0x19, 0xc6, 0x19, 0xfa, 0x1a, 0x36, + 0x1a, 0x6c, 0x1a, 0xa6, 0x1a, 0xca, 0x1b, 0x02, 0x1b, 0x38, 0x1b, 0x6e, + 0x1b, 0xac, 0x1b, 0xec, 0x1c, 0x22, 0x1c, 0x5e, 0x1c, 0xa2, 0x1c, 0xcc, + 0x1d, 0x00, 0x1d, 0x36, 0x1d, 0x72, 0x1d, 0xa8, 0x1d, 0xc8, 0x1d, 0xe8, + 0x1e, 0x0c, 0x1e, 0x2c, 0x1e, 0x64, 0x1e, 0x9a, 0x1e, 0xd0, 0x1f, 0x04, + 0x1f, 0x40, 0x1f, 0x80, 0x1f, 0xb6, 0x1f, 0xd4, 0x1f, 0xf8, 0x20, 0x26, + 0x20, 0x54, 0x20, 0x8a, 0x20, 0xb8, 0x20, 0xee, 0x21, 0x16, 0x21, 0x4e, + 0x21, 0x86, 0x21, 0xba, 0x21, 0xf8, 0x22, 0x34, 0x22, 0x6c, 0x22, 0x9e, + 0x22, 0xd2, 0x23, 0x00, 0x23, 0x3a, 0x23, 0x70, 0x23, 0x9e, 0x23, 0xc8, + 0x24, 0x00, 0x24, 0x34, 0x24, 0x74, 0x24, 0xa6, 0x24, 0xdc, 0x25, 0x0a, + 0x25, 0x3a, 0x25, 0x6e, 0x25, 0xa4, 0x25, 0xe0, 0x26, 0x0c, 0x26, 0x3e, + 0x26, 0x6a, 0x26, 0x9c, 0x26, 0xd2, 0x27, 0x0e, 0x27, 0x52, 0x27, 0x94, + 0x27, 0xd8, 0x28, 0x18, 0x28, 0x52, 0x28, 0x86, 0x28, 0xc0, 0x28, 0xf8, + 0x29, 0x30, 0x29, 0x54, 0x29, 0x86, 0x29, 0xb0, 0x29, 0xe4, 0x2a, 0x0e, + 0x2a, 0x34, 0x2a, 0x52, 0x2a, 0x80, 0x2a, 0xa4, 0x2a, 0xca, 0x2a, 0xf0, + 0x2b, 0x14, 0x2b, 0x26, 0x2b, 0x60, 0x2b, 0x96, 0x2b, 0xca, 0x2b, 0xf6, + 0x2c, 0x38, 0x2c, 0x6e, 0x2c, 0x9a, 0x2c, 0xc0, 0x2c, 0xde, 0x2d, 0x00, + 0x2d, 0x1e, 0x2d, 0x40, 0x2d, 0x5c, 0x2d, 0x7c, 0x2d, 0x96, 0x2d, 0xbc, + 0x2d, 0xd6, 0x2e, 0x0e, 0x2e, 0x38, 0x2e, 0x70, 0x2e, 0x96, 0x2e, 0xd2, + 0x2f, 0x04, 0x2f, 0x2a, 0x2f, 0x5a, 0x2f, 0x7e, 0x2f, 0xba, 0x2f, 0xee, + 0x30, 0x32, 0x30, 0x6e, 0x30, 0xb6, 0x30, 0xf6, 0x31, 0x30, 0x31, 0x78, + 0x31, 0xb2, 0x31, 0xd4, 0x32, 0x0e, 0x32, 0x32, 0x32, 0x72, 0x32, 0x9a, + 0x32, 0xda, 0x33, 0x12, 0x33, 0x58, 0x33, 0x98, 0x33, 0xd4, 0x34, 0x06, + 0x34, 0x4a, 0x34, 0x88, 0x34, 0xaa, 0x34, 0xd0, 0x34, 0xfc, 0x35, 0x2c, + 0x35, 0x4e, 0x35, 0x7c, 0x35, 0xbe, 0x35, 0xf8, 0x36, 0x2e, 0x36, 0x5c, + 0x36, 0x9a, 0x36, 0xce, 0x37, 0x0c, 0x37, 0x48, 0x37, 0x8a, 0x37, 0xc4, + 0x37, 0xfa, 0x38, 0x24, 0x38, 0x6a, 0x38, 0xac, 0x38, 0xea, 0x39, 0x2a, + 0x39, 0x62, 0x39, 0xa0, 0x39, 0xd6, 0x3a, 0x0e, 0x3a, 0x3e, 0x3a, 0x82, + 0x3a, 0xbe, 0x3a, 0xd2, 0x3a, 0xe4, 0x3b, 0x04, 0x3b, 0x24, 0x3b, 0x40, + 0x3b, 0x58, 0x3b, 0x6e, 0x3b, 0x8e, 0x3b, 0xbe, 0x3b, 0xfe, 0x3c, 0x30, + 0x3c, 0x52, 0x3c, 0x72, 0x3c, 0x94, 0x3c, 0xb4, 0x3c, 0xf2, 0x3d, 0x14, + 0x3d, 0x36, 0x3d, 0x58, 0x3d, 0x7a, 0x3d, 0xb6, 0x3e, 0x2a, 0x3e, 0x8e, + 0x3e, 0xc0, 0x3f, 0x28, 0x3f, 0xbc, 0x40, 0x1e, 0x40, 0x6e, 0x40, 0xd6, + 0x41, 0x42, 0x41, 0x86, 0x42, 0x08, 0x42, 0x42, 0x42, 0x7c, 0x42, 0xc0, + 0x43, 0x20, 0x43, 0x6c, 0x43, 0xe4, 0x44, 0x44, 0x44, 0xb4, 0x45, 0x10, + 0x45, 0x6e, 0x45, 0xac, 0x46, 0x2a, 0x46, 0x86, 0x46, 0xde, 0x47, 0x16, + 0x47, 0x6c, 0x47, 0x9c, 0x47, 0xc6, 0x47, 0xf2, 0x48, 0x16, 0x48, 0x44, + 0x48, 0xc2, 0x49, 0x30, 0x49, 0x6a, 0x49, 0xb4, 0x4a, 0x1e, 0x4a, 0x7e, + 0x4a, 0xde, 0x4b, 0x20, 0x4b, 0x82, 0x4b, 0xbc, 0x4b, 0xbc, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x31, 0x00, 0x00, 0x01, 0xbc, 0x03, 0xdd, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x2e, 0xb1, 0x01, 0x00, 0x2f, 0x3c, 0xb2, 0x07, 0x04, + 0x00, 0xed, 0x32, 0xb1, 0x06, 0x05, 0xdc, 0x3c, 0xb2, 0x03, 0x02, 0x00, + 0xed, 0x32, 0x00, 0xb1, 0x03, 0x00, 0x2f, 0x3c, 0xb2, 0x05, 0x04, 0x00, + 0xed, 0x32, 0xb2, 0x07, 0x06, 0x01, 0xfc, 0x3c, 0xb2, 0x01, 0x02, 0x00, + 0xed, 0x32, 0x33, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0x31, 0x01, + 0x8b, 0xfe, 0xa7, 0x01, 0x27, 0xfe, 0xd9, 0x03, 0xdd, 0xfc, 0x23, 0x31, + 0x03, 0x7b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x31, 0x35, 0x33, 0x15, + 0x27, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x00, 0x02, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x17, 0x03, 0x44, 0x00, 0x07, + 0x00, 0x0f, 0x00, 0x00, 0x13, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x3d, + 0x02, 0x33, 0x1d, 0x02, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x02, 0x2d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x25, + 0x00, 0x2b, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x23, 0x1d, 0x01, 0x23, 0x3d, + 0x01, 0x23, 0x35, 0x33, 0x3d, 0x01, 0x23, 0x35, 0x33, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x23, 0x1d, + 0x01, 0x33, 0x15, 0x23, 0x1d, 0x01, 0x03, 0x3d, 0x01, 0x23, 0x1d, 0x01, + 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xff, 0xa3, 0x01, 0xd0, 0x03, 0x44, 0x00, 0x2d, + 0x00, 0x33, 0x00, 0x39, 0x00, 0x00, 0x17, 0x35, 0x23, 0x35, 0x33, 0x3d, + 0x02, 0x23, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x35, 0x33, 0x15, + 0x33, 0x15, 0x33, 0x15, 0x23, 0x35, 0x23, 0x1d, 0x01, 0x33, 0x15, 0x33, + 0x1d, 0x02, 0x23, 0x3d, 0x02, 0x23, 0x1d, 0x02, 0x33, 0x15, 0x23, 0x15, + 0x27, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x13, 0x3d, 0x01, 0x23, 0x1d, 0x01, + 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5c, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1d, + 0x00, 0x25, 0x00, 0x29, 0x00, 0x00, 0x31, 0x35, 0x33, 0x15, 0x21, 0x23, + 0x3d, 0x01, 0x3b, 0x01, 0x1d, 0x01, 0x25, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x25, 0x23, + 0x3d, 0x01, 0x3b, 0x01, 0x1d, 0x01, 0x37, 0x35, 0x33, 0x15, 0x5d, 0x01, + 0x16, 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x2d, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x11, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, + 0x00, 0x31, 0x00, 0x37, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x25, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x21, 0x2b, 0x01, 0x3d, 0x01, 0x3b, 0x01, 0x15, + 0x05, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x25, 0x35, 0x33, 0x15, 0x21, + 0x23, 0x35, 0x23, 0x35, 0x3b, 0x01, 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, + 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x37, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x01, 0xd0, 0x5d, 0xfe, 0x8d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0x5d, + 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0xfe, 0xe9, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0xba, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, + 0x11, 0x35, 0x33, 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x5d, 0x5d, 0x02, + 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x00, 0x05, 0x00, 0x00, + 0xff, 0xa3, 0x01, 0x17, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x13, + 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, 0x27, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0x27, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x11, + 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x17, + 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, + 0xff, 0xa3, 0x01, 0x17, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x13, + 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, 0x3d, 0x02, + 0x33, 0x1d, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x03, 0x23, 0x3d, 0x01, + 0x33, 0x15, 0x27, 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x73, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xd0, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x13, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x23, 0x35, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x5c, 0x01, 0xd0, 0x02, 0x2d, 0x00, 0x13, 0x00, 0x00, 0x37, 0x3d, + 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3b, + 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x01, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x46, 0x00, 0xba, + 0x00, 0x5d, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, + 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x16, 0x01, 0x74, + 0x01, 0x74, 0x00, 0x09, 0x00, 0x00, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, + 0x3b, 0x01, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, + 0x73, 0x5d, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, + 0x00, 0x5d, 0x00, 0x03, 0x00, 0x00, 0x31, 0x35, 0x33, 0x15, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x17, 0x00, 0x00, + 0x31, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, + 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5c, 0x5d, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x07, 0x00, 0x2b, 0x00, 0x33, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x03, + 0x23, 0x15, 0x23, 0x15, 0x23, 0x1d, 0x01, 0x23, 0x3d, 0x05, 0x33, 0x1d, + 0x02, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x1d, 0x05, 0x03, 0x2b, + 0x02, 0x35, 0x3b, 0x02, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x2d, 0x5c, + 0x00, 0x01, 0x00, 0x5c, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x17, + 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x04, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x1d, 0x06, 0x33, 0x15, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x11, 0x00, 0x15, + 0x00, 0x19, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x2b, 0x00, 0x00, 0x11, 0x35, + 0x33, 0x15, 0x01, 0x33, 0x15, 0x2b, 0x04, 0x3d, 0x01, 0x33, 0x15, 0x3b, + 0x01, 0x27, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, + 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x02, 0x35, 0x3b, 0x02, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x02, 0x2d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0xba, 0x5c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1d, + 0x00, 0x23, 0x00, 0x2b, 0x00, 0x00, 0x11, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, + 0x23, 0x35, 0x33, 0x25, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x31, 0x3d, 0x01, + 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x02, 0x2d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x19, + 0x00, 0x21, 0x00, 0x00, 0x21, 0x3d, 0x02, 0x2b, 0x02, 0x3d, 0x01, 0x33, + 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x1d, 0x03, 0x33, 0x15, 0x23, 0x1d, + 0x02, 0x03, 0x33, 0x3d, 0x01, 0x23, 0x15, 0x23, 0x15, 0x01, 0x16, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x07, + 0x00, 0x0f, 0x00, 0x13, 0x00, 0x2b, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, + 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x35, + 0x33, 0x25, 0x2b, 0x03, 0x3d, 0x03, 0x3b, 0x04, 0x15, 0x2b, 0x03, 0x1d, + 0x01, 0x3b, 0x02, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x27, 0x00, 0x2f, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x03, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x3b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x05, 0x33, + 0x1d, 0x01, 0x3b, 0x02, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x01, 0x2b, 0x02, + 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x0b, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x00, 0x33, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, + 0x3d, 0x01, 0x2b, 0x03, 0x35, 0x3b, 0x04, 0x1d, 0x01, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, + 0xba, 0x5d, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x17, + 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x00, 0x25, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, + 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x02, + 0x31, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, + 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x07, 0x00, 0x1b, 0x00, 0x1f, + 0x00, 0x27, 0x00, 0x2f, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x3b, 0x01, 0x3d, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x02, 0x33, + 0x1d, 0x05, 0x21, 0x23, 0x35, 0x33, 0x35, 0x23, 0x3d, 0x02, 0x33, 0x1d, + 0x01, 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x16, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5d, 0x02, 0x2d, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x00, 0x3d, 0x01, 0x33, 0x15, 0x03, 0x35, 0x33, 0x15, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xff, 0x46, 0x00, 0xba, 0x02, 0x2d, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, 0x11, 0x35, + 0x33, 0x15, 0x03, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x5d, 0x5d, 0x5d, 0x5d, + 0xba, 0x5d, 0x5d, 0x02, 0x8a, 0x5d, 0x5d, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x15, + 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x27, 0x23, + 0x35, 0x33, 0x2b, 0x01, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x15, + 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x02, 0x00, 0x00, + 0x00, 0xb9, 0x01, 0xd0, 0x02, 0x2d, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x00, + 0x01, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0x13, 0x33, 0x15, 0x2b, + 0x04, 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0x16, 0x5c, 0x5c, 0x01, 0x17, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x15, 0x00, 0x19, 0x00, 0x1d, + 0x00, 0x00, 0x31, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, + 0x33, 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x27, 0x23, 0x35, 0x33, 0x2b, + 0x01, 0x35, 0x33, 0x2b, 0x01, 0x35, 0x33, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x17, + 0x00, 0x1d, 0x00, 0x00, 0x33, 0x35, 0x33, 0x15, 0x27, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x03, 0x35, 0x33, 0x15, 0x17, 0x35, 0x33, 0x15, 0x3d, 0x02, + 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x5d, 0x5d, 0x5d, + 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x01, 0x73, 0x5d, 0x5d, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x8a, 0x02, 0xe7, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x1d, + 0x00, 0x27, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x45, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x2b, 0x01, + 0x35, 0x33, 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x3b, + 0x01, 0x1d, 0x02, 0x33, 0x15, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, + 0x21, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x3d, 0x01, 0x23, 0x1d, 0x01, + 0x01, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, + 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xfe, + 0x30, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0xfe, 0xe9, 0x5d, 0x01, 0x17, 0x5d, + 0x5d, 0xfe, 0x30, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x17, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x23, 0x00, 0x2b, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, + 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, 0x02, 0x3d, + 0x01, 0x33, 0x1d, 0x06, 0x03, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x73, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x0b, + 0x00, 0x31, 0x00, 0x00, 0x25, 0x33, 0x3d, 0x02, 0x2b, 0x02, 0x1d, 0x02, + 0x33, 0x17, 0x2b, 0x02, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x33, 0x1d, 0x01, + 0x23, 0x3d, 0x01, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x02, 0x15, 0x33, 0x1d, + 0x02, 0x23, 0x15, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x09, 0x00, 0x17, 0x00, 0x21, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x2b, 0x01, + 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, + 0x01, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0x2c, 0x5c, 0x5c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x00, 0x37, 0x33, 0x35, 0x33, + 0x3d, 0x03, 0x23, 0x35, 0x2b, 0x01, 0x1d, 0x05, 0x17, 0x2b, 0x01, 0x3d, + 0x07, 0x3b, 0x02, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x03, 0x23, 0x15, 0x23, + 0x15, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x21, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, + 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x1b, + 0x00, 0x00, 0x31, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, + 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x03, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x15, + 0x00, 0x23, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x2b, 0x02, 0x35, 0x3b, 0x02, + 0x3d, 0x02, 0x2b, 0x01, 0x35, 0x3b, 0x02, 0x1d, 0x04, 0x25, 0x23, 0x3d, + 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, + 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0x2c, 0x5c, 0x5c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x27, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, + 0x03, 0x23, 0x3d, 0x07, 0x33, 0x1d, 0x02, 0x3b, 0x02, 0x3d, 0x02, 0x33, + 0x1d, 0x07, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x02, 0xe7, 0x00, 0x19, 0x00, 0x00, 0x33, 0x2b, + 0x01, 0x35, 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, + 0x05, 0x33, 0x15, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x05, 0x00, 0x15, 0x00, 0x1b, + 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x06, 0x33, + 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, + 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, 0x07, 0x33, + 0x1d, 0x02, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x23, 0x35, 0x23, 0x35, + 0x23, 0x1d, 0x03, 0x13, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, + 0x01, 0x33, 0x15, 0x01, 0x73, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x17, 0x00, 0x00, 0x25, 0x33, + 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x33, 0x1d, 0x06, 0x33, 0x01, 0x16, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x19, + 0x00, 0x2d, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x23, 0x1d, 0x01, 0x23, 0x3d, + 0x01, 0x33, 0x3d, 0x01, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x07, 0x21, 0x3d, + 0x07, 0x33, 0x1d, 0x01, 0x33, 0x1d, 0x01, 0x23, 0x1d, 0x03, 0x01, 0x73, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x13, + 0x00, 0x2b, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x23, 0x35, 0x33, 0x3d, 0x02, + 0x33, 0x1d, 0x07, 0x21, 0x3d, 0x07, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, + 0x23, 0x35, 0x23, 0x1d, 0x05, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0xfe, 0x30, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x07, 0x00, 0x15, 0x00, 0x23, 0x00, 0x2b, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, + 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0xd0, 0x5c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x23, 0x00, 0x00, 0x31, 0x3d, 0x07, 0x3b, 0x03, 0x15, + 0x33, 0x1d, 0x01, 0x23, 0x3d, 0x01, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x02, + 0x15, 0x2b, 0x02, 0x1d, 0x03, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x27, + 0x00, 0x2b, 0x00, 0x33, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x25, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x21, 0x23, 0x35, 0x33, 0x05, 0x23, 0x3d, 0x05, + 0x33, 0x1d, 0x04, 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x2b, 0x01, 0x35, + 0x33, 0x13, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, 0xfe, 0xea, + 0x5c, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x01, + 0x16, 0x5d, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x01, 0x74, 0x5c, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x09, 0x00, 0x2d, 0x00, 0x00, + 0x21, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x21, 0x3d, 0x07, 0x3b, 0x03, 0x15, + 0x33, 0x1d, 0x01, 0x23, 0x3d, 0x01, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x02, + 0x15, 0x2b, 0x02, 0x1d, 0x03, 0x01, 0x73, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x09, 0x00, 0x11, 0x00, 0x19, + 0x00, 0x1f, 0x00, 0x29, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, + 0x3b, 0x02, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x03, 0x2b, 0x02, 0x35, 0x3b, + 0x02, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x25, 0x33, 0x15, 0x2b, 0x03, + 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x19, 0x00, 0x00, 0x33, 0x3d, 0x06, 0x2b, 0x01, 0x35, + 0x3b, 0x04, 0x15, 0x2b, 0x01, 0x1d, 0x06, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x07, + 0x00, 0x17, 0x00, 0x27, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, + 0x1d, 0x05, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x0d, 0x00, 0x15, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x00, 0x33, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x2b, 0x01, 0x3d, + 0x02, 0x33, 0x1d, 0x01, 0x37, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, + 0x3d, 0x02, 0x33, 0x1d, 0x01, 0xba, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, + 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x0b, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x37, 0x3d, + 0x05, 0x33, 0x1d, 0x05, 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x07, 0x23, + 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0xb9, + 0x5d, 0xba, 0x5c, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x29, 0x00, 0x2f, + 0x00, 0x00, 0x21, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x3d, 0x02, 0x33, + 0x1d, 0x02, 0x01, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x37, 0x23, + 0x35, 0x33, 0x31, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x01, 0x73, + 0x5d, 0xfe, 0x30, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x15, + 0x00, 0x1b, 0x00, 0x21, 0x00, 0x00, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x11, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x15, + 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, + 0xba, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x17, 0x00, 0x23, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x01, 0x33, 0x15, 0x33, 0x27, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x01, 0x2b, + 0x02, 0x35, 0x3b, 0x03, 0x1d, 0x01, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, + 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xff, 0xa3, 0x00, 0xba, 0x03, 0x44, 0x00, 0x19, + 0x00, 0x00, 0x17, 0x23, 0x3d, 0x09, 0x3b, 0x01, 0x15, 0x23, 0x1d, 0x07, + 0x33, 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x11, + 0x00, 0x17, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x27, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0x27, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x27, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x01, 0x00, 0x00, + 0xff, 0xa3, 0x00, 0xba, 0x03, 0x44, 0x00, 0x19, 0x00, 0x00, 0x17, 0x23, + 0x35, 0x33, 0x3d, 0x07, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x09, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0xd0, 0x01, 0xd0, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x17, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x25, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0x05, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x37, 0x23, + 0x35, 0x33, 0x01, 0x73, 0x5d, 0xfe, 0x30, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5c, 0x5c, 0x5c, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xff, 0xa3, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x21, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0x01, 0x73, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x17, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x27, 0x23, + 0x35, 0x33, 0x2b, 0x01, 0x35, 0x33, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x11, + 0x00, 0x19, 0x00, 0x1f, 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, + 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, + 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, + 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x0b, + 0x00, 0x23, 0x00, 0x00, 0x37, 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, + 0x17, 0x2b, 0x01, 0x3d, 0x07, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x33, + 0x1d, 0x03, 0x23, 0x15, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x07, 0x00, 0x11, 0x00, 0x19, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, + 0x03, 0x33, 0x1d, 0x02, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x01, + 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x17, 0x00, 0x23, 0x00, 0x00, + 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x01, 0x3d, + 0x01, 0x33, 0x1d, 0x07, 0x27, 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, + 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0x2d, 0x00, 0x07, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x00, 0x25, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, 0x15, 0x3b, + 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, + 0x16, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x13, 0x00, 0x19, 0x00, 0x00, 0x33, 0x3d, 0x03, 0x23, + 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x23, 0x1d, 0x03, + 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0xe6, 0x5c, 0x5c, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x05, + 0x00, 0x1b, 0x00, 0x27, 0x00, 0x00, 0x17, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x35, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x02, + 0x1d, 0x06, 0x27, 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0xba, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x0b, 0x00, 0x21, 0x00, 0x00, 0x21, 0x3d, 0x04, 0x33, + 0x1d, 0x04, 0x21, 0x3d, 0x07, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, + 0x01, 0x1d, 0x04, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, + 0x02, 0xe7, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x33, 0x3d, 0x04, 0x23, + 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x03, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x00, 0x00, 0x03, 0x00, 0x00, + 0xff, 0x46, 0x00, 0xba, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, + 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, 0x11, 0x35, 0x33, 0x15, 0x03, 0x3d, + 0x05, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x06, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0xba, 0x5d, 0x5d, 0x03, 0x44, 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x21, 0x3d, 0x07, 0x33, 0x1d, 0x03, 0x33, 0x15, 0x33, 0x15, + 0x23, 0x35, 0x23, 0x1d, 0x02, 0x13, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, + 0x15, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xba, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, + 0x33, 0x35, 0x33, 0x15, 0x27, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0x2d, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x27, + 0x00, 0x2b, 0x00, 0x00, 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x21, 0x3d, + 0x04, 0x33, 0x1d, 0x04, 0x21, 0x3d, 0x05, 0x3b, 0x01, 0x15, 0x23, 0x1d, + 0x04, 0x01, 0x23, 0x35, 0x33, 0x01, 0x73, 0x5d, 0xfe, 0xea, 0x5c, 0xfe, + 0xea, 0x5d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x0b, 0x00, 0x1d, 0x00, 0x00, + 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x21, 0x3d, 0x05, 0x3b, 0x02, 0x15, + 0x2b, 0x01, 0x1d, 0x04, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x05, + 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, + 0x33, 0x1d, 0x02, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0xba, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x23, + 0x00, 0x00, 0x15, 0x3d, 0x07, 0x3b, 0x02, 0x15, 0x33, 0x1d, 0x03, 0x23, + 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, + 0x01, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x02, 0x2d, 0x00, 0x17, 0x00, 0x23, 0x00, 0x00, 0x05, 0x3d, 0x01, 0x2b, + 0x01, 0x35, 0x23, 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x02, 0x1d, 0x07, 0x03, + 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0x01, 0x16, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x01, 0x17, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x02, 0x2d, 0x00, 0x0b, + 0x00, 0x11, 0x00, 0x00, 0x31, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x13, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x07, + 0x00, 0x0d, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x00, 0x37, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x27, + 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x35, 0x33, 0x37, 0x33, 0x15, + 0x2b, 0x02, 0x35, 0x33, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x33, 0x35, 0x33, 0x15, + 0x27, 0x23, 0x3d, 0x03, 0x23, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x33, 0x15, 0x23, 0x1d, 0x02, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x00, + 0x21, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, + 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0x2d, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1d, + 0x00, 0x00, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, + 0x01, 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x37, 0x3d, 0x01, 0x33, 0x1d, + 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0x5d, 0xb9, 0x5d, + 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0x2d, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1b, 0x00, 0x25, + 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x37, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x2b, 0x01, 0x3d, 0x01, + 0x33, 0x15, 0x07, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x01, 0x16, 0x5d, + 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0xba, 0x5c, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0x2d, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1b, 0x00, 0x21, + 0x00, 0x00, 0x21, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x3d, 0x02, 0x33, + 0x1d, 0x02, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x31, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x01, 0x16, 0x5d, 0xfe, + 0x8d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x05, + 0x00, 0x19, 0x00, 0x25, 0x00, 0x00, 0x17, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x06, + 0x25, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0xba, 0x5c, 0x5c, 0x5d, 0xb9, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x0b, + 0x00, 0x0f, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, + 0x03, 0x3d, 0x01, 0x33, 0x15, 0x33, 0x27, 0x35, 0x33, 0x15, 0x3d, 0x01, + 0x33, 0x15, 0x3d, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x03, 0x1d, 0x01, 0x01, + 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x00, 0x33, 0x35, + 0x33, 0x15, 0x27, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x27, 0x23, 0x35, + 0x33, 0x31, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x11, 0x35, 0x33, 0x15, 0xba, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0xff, 0xa3, 0x00, 0x5d, 0x03, 0x44, 0x00, 0x15, 0x00, 0x00, 0x15, 0x3d, + 0x09, 0x33, 0x1d, 0x09, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1b, + 0x00, 0x00, 0x31, 0x35, 0x33, 0x15, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x11, + 0x35, 0x33, 0x15, 0x27, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x27, 0x23, + 0x35, 0x33, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x00, 0x04, 0x00, 0x00, + 0x01, 0x16, 0x02, 0x2d, 0x01, 0xd0, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0d, + 0x00, 0x13, 0x00, 0x00, 0x11, 0x35, 0x33, 0x15, 0x25, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0xfe, 0xe9, 0x5c, 0x5d, + 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x02, 0xe7, 0x00, 0x0d, + 0x00, 0x11, 0x00, 0x00, 0x31, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x03, 0x35, + 0x33, 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x1d, + 0x00, 0x21, 0x00, 0x2b, 0x00, 0x00, 0x33, 0x35, 0x23, 0x35, 0x23, 0x3d, + 0x03, 0x33, 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x23, + 0x35, 0x23, 0x1d, 0x03, 0x33, 0x15, 0x23, 0x15, 0x37, 0x35, 0x33, 0x15, + 0x21, 0x3d, 0x03, 0x23, 0x1d, 0x03, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x11, 0x00, 0x23, 0x00, 0x29, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x03, 0x33, 0x15, 0x2b, 0x04, 0x3d, 0x01, 0x33, + 0x15, 0x3b, 0x01, 0x27, 0x3d, 0x01, 0x23, 0x35, 0x33, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0xb9, 0x5d, 0x5c, 0x5c, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0xb9, 0x02, 0x2d, 0x02, 0x2d, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, + 0x00, 0x13, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, + 0x25, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x05, 0x23, 0x3d, 0x01, + 0x33, 0x15, 0x25, 0x35, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x05, + 0x23, 0x35, 0x33, 0x01, 0xd0, 0x5d, 0xfd, 0xd3, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0x16, 0x5d, + 0xba, 0x5d, 0x5c, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2d, + 0x00, 0x00, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x2b, 0x01, + 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x33, 0x3d, 0x01, 0x33, 0x1d, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x15, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x15, + 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, + 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0xa3, 0x00, 0x5d, + 0x02, 0xe7, 0x00, 0x09, 0x00, 0x13, 0x00, 0x00, 0x15, 0x3d, 0x03, 0x33, + 0x1d, 0x03, 0x03, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, + 0x00, 0x15, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2f, + 0x00, 0x37, 0x00, 0x00, 0x37, 0x35, 0x33, 0x15, 0x13, 0x35, 0x33, 0x15, + 0x03, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, + 0x01, 0x21, 0x23, 0x35, 0x33, 0x25, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x07, + 0x23, 0x3d, 0x01, 0x33, 0x15, 0x37, 0x23, 0x35, 0x33, 0x07, 0x23, 0x3d, + 0x01, 0x33, 0x15, 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0xba, 0x5c, 0x5d, + 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0xb9, + 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xba, 0x5c, + 0x5c, 0x01, 0x73, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x02, 0x89, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x33, + 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0xe6, 0x5c, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, 0x02, 0xe7, 0x00, 0x0b, + 0x00, 0x19, 0x00, 0x27, 0x00, 0x39, 0x00, 0x45, 0x00, 0x00, 0x25, 0x33, + 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x03, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x21, + 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x3d, + 0x03, 0x3b, 0x02, 0x15, 0x2b, 0x01, 0x1d, 0x01, 0x01, 0x2b, 0x04, 0x35, + 0x3b, 0x04, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0xba, 0x5d, 0xfd, 0xd3, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x17, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x74, 0x5c, 0x00, 0x03, 0x00, 0x00, + 0x01, 0x73, 0x01, 0x74, 0x03, 0x44, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1b, + 0x00, 0x00, 0x01, 0x2b, 0x01, 0x35, 0x23, 0x35, 0x33, 0x35, 0x3b, 0x01, + 0x35, 0x33, 0x1d, 0x03, 0x27, 0x33, 0x35, 0x2b, 0x01, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x01, 0x73, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, + 0x16, 0x5d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xb9, 0x02, 0x2d, + 0x02, 0x8a, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, + 0x25, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x23, 0x35, 0x33, + 0x05, 0x23, 0x35, 0x3b, 0x01, 0x23, 0x35, 0x33, 0x05, 0x23, 0x35, 0x33, + 0x21, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x25, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x01, 0xd0, 0x5d, 0xfe, 0x8d, 0x5c, 0xba, 0x5d, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5c, + 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x16, 0x01, 0xd0, 0x01, 0xd0, 0x00, 0x0d, + 0x00, 0x00, 0x01, 0x35, 0x2b, 0x03, 0x35, 0x3b, 0x04, 0x1d, 0x01, 0x01, + 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x16, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x3b, + 0x00, 0x47, 0x00, 0x00, 0x25, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, + 0x03, 0x3b, 0x02, 0x15, 0x23, 0x15, 0x23, 0x1d, 0x01, 0x17, 0x33, 0x15, + 0x2b, 0x04, 0x35, 0x3b, 0x03, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x21, 0x23, + 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, 0x04, 0x35, 0x3b, 0x04, 0x01, + 0x73, 0x5d, 0xfe, 0xea, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xba, 0x5d, 0xfd, 0xd3, 0x5d, + 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x73, 0x02, 0x8a, 0x01, 0xd0, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x33, + 0x15, 0x2b, 0x06, 0x35, 0x3b, 0x04, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, + 0x13, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x3b, + 0x01, 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0x8a, 0x00, 0x13, + 0x00, 0x1f, 0x00, 0x00, 0x37, 0x3d, 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x01, + 0x17, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x01, 0xd0, 0x01, 0x17, 0x03, 0x44, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x13, + 0x00, 0x00, 0x13, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, + 0x27, 0x35, 0x33, 0x15, 0x27, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, + 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0xd0, 0x01, 0x17, 0x03, 0x44, 0x00, 0x11, + 0x00, 0x00, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x23, 0x35, 0x23, + 0x35, 0x3b, 0x02, 0x1d, 0x03, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x11, 0x35, + 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, + 0x5c, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x21, + 0x00, 0x00, 0x15, 0x3d, 0x07, 0x33, 0x1d, 0x04, 0x3b, 0x01, 0x3d, 0x04, + 0x33, 0x1d, 0x05, 0x2b, 0x02, 0x1d, 0x01, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x1f, 0x00, 0x27, 0x00, 0x00, + 0x21, 0x3d, 0x02, 0x23, 0x1d, 0x02, 0x23, 0x3d, 0x02, 0x23, 0x35, 0x23, + 0x3d, 0x02, 0x33, 0x35, 0x3b, 0x03, 0x1d, 0x07, 0x03, 0x3d, 0x02, 0x23, + 0x1d, 0x02, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x16, 0x00, 0xba, 0x01, 0xd0, 0x00, 0x07, + 0x00, 0x00, 0x13, 0x23, 0x3d, 0x01, 0x3b, 0x01, 0x1d, 0x01, 0x5d, 0x5d, + 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x03, 0x00, 0x00, + 0x01, 0x16, 0x01, 0x17, 0x02, 0x2d, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, + 0x00, 0x00, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, + 0x27, 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5d, + 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0xd0, 0x01, 0x17, 0x03, 0x44, 0x00, 0x0f, + 0x00, 0x00, 0x13, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x23, 0x35, 0x33, 0x35, + 0x33, 0x1d, 0x02, 0x33, 0x15, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0xd0, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x01, 0xd0, 0x01, 0x74, 0x03, 0x44, 0x00, 0x05, + 0x00, 0x0b, 0x00, 0x11, 0x00, 0x17, 0x00, 0x00, 0x13, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, + 0x33, 0x15, 0x37, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0xba, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, + 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0xb9, 0x02, 0x2d, 0x02, 0x8a, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, + 0x00, 0x1f, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x25, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x25, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x25, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x23, 0x35, 0x33, + 0x05, 0x23, 0x35, 0x3b, 0x01, 0x23, 0x35, 0x33, 0x05, 0x23, 0x35, 0x33, + 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, + 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5c, 0xba, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0xb9, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xe7, 0x02, 0xe7, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x1d, + 0x00, 0x23, 0x00, 0x29, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, 0x21, 0x35, + 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x23, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x03, 0x3d, 0x01, 0x23, 0x35, 0x33, 0x35, 0x33, + 0x1d, 0x03, 0x11, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, + 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x02, 0x2d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xe7, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x19, + 0x00, 0x1f, 0x00, 0x23, 0x00, 0x29, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x39, + 0x00, 0x00, 0x33, 0x35, 0x33, 0x15, 0x03, 0x3d, 0x01, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x1d, 0x03, 0x01, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, + 0x33, 0x15, 0x25, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x25, 0x35, 0x33, 0x15, + 0x27, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x05, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xfd, 0xd4, + 0x5c, 0x01, 0x74, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x8c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x44, 0x02, 0xe7, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x17, + 0x00, 0x1d, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x39, 0x00, 0x00, 0x21, 0x35, + 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x23, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x02, 0x33, + 0x1d, 0x01, 0x25, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x23, 0x35, 0x23, + 0x35, 0x3b, 0x02, 0x1d, 0x03, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3d, + 0x01, 0x33, 0x15, 0x02, 0x8a, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfd, 0xd4, + 0x5c, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0f, + 0x00, 0x15, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x03, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x02, + 0x33, 0x1d, 0x01, 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, + 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, + 0x01, 0x3b, 0x02, 0x3d, 0x01, 0x33, 0x1d, 0x06, 0x01, 0x35, 0x33, 0x15, + 0x17, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x27, 0x23, 0x35, 0x33, 0x01, 0x73, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfe, 0xea, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x03, 0x43, 0x5d, 0x5d, 0xb9, 0x5c, 0xba, 0x5d, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, 0x03, 0x23, + 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, 0x02, 0x3d, 0x01, 0x33, 0x1d, 0x06, + 0x01, 0x35, 0x33, 0x15, 0x17, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x27, 0x35, + 0x33, 0x15, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xfe, 0xea, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xb9, 0x5c, 0xba, 0x5d, 0x5d, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x23, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x37, 0x00, 0x00, 0x21, 0x3d, + 0x03, 0x2b, 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, + 0x02, 0x3d, 0x01, 0x33, 0x1d, 0x06, 0x03, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x17, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x27, 0x23, 0x35, 0x33, + 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, + 0x5d, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, + 0xba, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x37, + 0x00, 0x3b, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, 0x03, 0x23, + 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, 0x02, 0x3d, 0x01, 0x33, 0x1d, 0x06, + 0x03, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x17, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x01, 0x73, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, 0x5d, 0xfe, + 0xea, 0x5d, 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0xba, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xa0, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x00, + 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, + 0x01, 0x3b, 0x02, 0x3d, 0x01, 0x33, 0x1d, 0x06, 0x03, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x17, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x73, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, 0x5d, 0xfe, + 0xea, 0x5d, 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, + 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x31, + 0x00, 0x35, 0x00, 0x39, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, + 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, 0x02, 0x3d, 0x01, 0x33, + 0x1d, 0x06, 0x03, 0x2b, 0x02, 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x27, + 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x23, 0x35, 0x33, 0x01, + 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, + 0x02, 0xe7, 0x00, 0x07, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x00, 0x31, 0x3d, + 0x02, 0x33, 0x1d, 0x02, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x02, 0x2b, + 0x01, 0x3d, 0x02, 0x33, 0x3d, 0x01, 0x3b, 0x04, 0x15, 0x2b, 0x02, 0x1d, + 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x03, 0x3d, 0x01, + 0x23, 0x1d, 0x01, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x11, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x00, 0x17, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x03, 0x15, 0x23, 0x15, + 0x25, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, + 0x35, 0x3b, 0x01, 0xba, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, + 0x2c, 0x5c, 0x5c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x25, 0x00, 0x29, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, + 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, + 0x11, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, + 0x43, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x25, 0x00, 0x29, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, + 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, + 0x11, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, + 0x43, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x29, 0x00, 0x2f, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, + 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, + 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, + 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, 0x5d, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0xa0, 0x00, 0x03, 0x00, 0x07, 0x00, 0x29, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, + 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x01, 0x16, 0x5d, 0xfe, + 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, + 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x21, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x2b, 0x01, 0x35, 0x33, 0x3d, + 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, 0x15, 0x03, + 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0xb9, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x03, 0xa0, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x21, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x2b, 0x01, 0x35, 0x33, 0x3d, + 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, 0x15, 0x03, + 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x03, 0xa0, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x21, + 0x00, 0x25, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, + 0x23, 0x1d, 0x05, 0x33, 0x15, 0x03, 0x23, 0x35, 0x33, 0xba, 0x5c, 0xfe, + 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x03, 0xa0, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x03, 0xa0, 0x00, 0x03, 0x00, 0x07, 0x00, 0x21, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, + 0x05, 0x33, 0x15, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, + 0xfc, 0xbd, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x2d, 0x02, 0xe7, 0x00, 0x13, 0x00, 0x2f, 0x00, 0x00, + 0x25, 0x33, 0x35, 0x33, 0x3d, 0x03, 0x23, 0x35, 0x2b, 0x01, 0x1d, 0x01, + 0x33, 0x15, 0x23, 0x1d, 0x02, 0x17, 0x2b, 0x01, 0x3d, 0x03, 0x23, 0x35, + 0x33, 0x3d, 0x02, 0x3b, 0x02, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x03, 0x23, + 0x15, 0x23, 0x15, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x13, 0x00, 0x2b, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x37, 0x00, 0x3b, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x23, + 0x35, 0x33, 0x3d, 0x02, 0x33, 0x1d, 0x07, 0x21, 0x3d, 0x07, 0x33, 0x15, + 0x33, 0x15, 0x33, 0x15, 0x23, 0x35, 0x23, 0x1d, 0x05, 0x13, 0x35, 0x33, + 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0xba, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x19, + 0x00, 0x27, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x11, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, + 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x27, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0xd0, 0x5c, 0xba, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x19, + 0x00, 0x27, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x11, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, + 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x27, 0x35, 0x33, 0x15, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x01, 0xd0, 0x5c, 0xba, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, + 0x00, 0x1d, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x37, 0x00, 0x00, 0x01, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, + 0x1d, 0x04, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x27, 0x23, 0x35, 0x33, + 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, + 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0xba, 0x5d, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, + 0x00, 0x1d, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x37, 0x00, 0x3b, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, + 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x21, 0x23, 0x3d, + 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x01, + 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, + 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, + 0xba, 0x5d, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xa0, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x2b, + 0x00, 0x33, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, + 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0xd0, 0x5c, 0x00, 0x09, 0x00, 0x00, 0x00, 0xb9, 0x01, 0xd0, + 0x02, 0x8a, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x00, 0x25, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x25, 0x23, 0x35, 0x33, 0x05, 0x35, + 0x33, 0x15, 0x37, 0x23, 0x35, 0x33, 0x31, 0x35, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, 0x73, + 0x5d, 0xfe, 0x30, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x15, 0x00, 0x31, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x06, 0x33, 0x1d, 0x03, 0x33, 0x1d, + 0x01, 0x33, 0x3d, 0x03, 0x23, 0x1d, 0x01, 0x23, 0x3d, 0x01, 0x33, 0x3d, + 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x03, 0x1d, 0x06, 0x01, 0x16, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x06, + 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x13, 0x23, + 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0xe6, 0x5d, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x1b, + 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, + 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x13, 0x35, 0x33, 0x15, 0xba, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0xb9, + 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0xe6, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, + 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x13, 0x23, 0x35, 0x33, + 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x03, 0x43, 0x5d, + 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0xe6, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xa0, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2f, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, + 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1f, + 0x00, 0x25, 0x00, 0x29, 0x00, 0x00, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x03, 0x35, 0x33, 0x15, 0x11, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x2b, 0x01, + 0x3d, 0x01, 0x33, 0x15, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0x13, 0x35, 0x33, 0x15, 0xba, 0x5c, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x01, 0xd0, 0x02, 0x8a, 0x00, 0x1f, + 0x00, 0x00, 0x3d, 0x06, 0x33, 0x15, 0x3b, 0x02, 0x15, 0x33, 0x1d, 0x01, + 0x23, 0x3d, 0x01, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x02, 0x15, 0x2b, 0x02, + 0x15, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x0f, + 0x00, 0x15, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, + 0x31, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x03, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x31, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x02, 0x35, 0x3b, 0x02, + 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0xba, 0x5c, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x15, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x2b, 0x01, 0x35, 0x23, 0x3d, + 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, + 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x27, + 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, + 0xb9, 0x5d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x15, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x23, 0x3d, + 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, + 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x27, + 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, + 0xb9, 0x5d, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, 0x00, 0x21, 0x00, 0x27, + 0x00, 0x2d, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, + 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, + 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, + 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x01, 0x73, 0x5d, 0xb9, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, + 0x00, 0x21, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x23, 0x3d, + 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, + 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0xba, 0x5c, 0xfe, 0xea, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, + 0x5c, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0xb9, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, 0x00, 0x21, 0x00, 0x27, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, + 0x04, 0x27, 0x33, 0x3d, 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, + 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x01, 0x73, 0x5d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x11, 0x00, 0x19, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, + 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, 0x01, 0x2b, + 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x3d, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x23, 0x35, 0x33, 0x01, + 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, + 0x02, 0x2d, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x29, 0x00, 0x2f, 0x00, 0x35, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x21, 0x33, 0x15, + 0x2b, 0x01, 0x35, 0x21, 0x23, 0x3d, 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x23, + 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x3b, 0x01, 0x35, + 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0xfe, 0xea, 0x5c, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x00, 0x04, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x17, + 0x00, 0x1f, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x23, 0x35, + 0x3b, 0x02, 0x15, 0x23, 0x15, 0x27, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, + 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x1d, + 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, 0x15, 0x3b, + 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x27, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, + 0x16, 0x5d, 0xb9, 0x5d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, + 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x27, 0x35, + 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x21, 0x00, 0x27, + 0x00, 0x2d, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, + 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, + 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0xd3, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, + 0x16, 0x5d, 0xb9, 0x5d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x21, 0x00, 0x27, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, 0x15, 0x3b, + 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, + 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0xd3, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, + 0x16, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, + 0x03, 0x44, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x00, 0x33, 0x3d, + 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x03, 0x35, 0x33, 0x15, 0x27, + 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x03, 0x44, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, + 0x00, 0x00, 0x33, 0x3d, 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x03, + 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x03, 0x44, 0x00, 0x0f, + 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x00, 0x33, 0x3d, 0x04, 0x23, + 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x11, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, + 0x15, 0x37, 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xfe, 0xea, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x02, 0xe7, 0x00, 0x0f, + 0x00, 0x13, 0x00, 0x17, 0x00, 0x00, 0x33, 0x3d, 0x04, 0x23, 0x35, 0x3b, + 0x01, 0x1d, 0x05, 0x11, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0xa0, 0x00, 0x05, 0x00, 0x21, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, + 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, + 0x03, 0x23, 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x05, + 0x03, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x3b, 0x01, 0x15, 0x23, 0x27, 0x23, + 0x35, 0x33, 0xba, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, + 0x2d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x0b, 0x00, 0x1d, 0x00, 0x21, + 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x3d, 0x04, 0x33, + 0x1d, 0x04, 0x21, 0x3d, 0x05, 0x3b, 0x02, 0x15, 0x2b, 0x01, 0x1d, 0x04, + 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x35, 0x33, 0x15, + 0x2b, 0x01, 0x35, 0x33, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x13, + 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x03, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x2b, 0x01, 0x35, 0x3b, + 0x01, 0x27, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x01, 0x16, 0x5d, 0xb9, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x13, + 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x11, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x2b, 0x01, 0x35, 0x3b, + 0x01, 0x27, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x02, + 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, + 0x5d, 0xb9, 0x5d, 0x5d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x2d, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x03, 0x33, + 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, + 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, + 0x16, 0x5d, 0xb9, 0x5d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, + 0x03, 0x33, 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, + 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, + 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x21, 0x00, 0x27, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, + 0x33, 0x1d, 0x02, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, + 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xb9, 0x01, 0xd0, 0x02, 0x8a, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x13, 0x00, 0x00, 0x37, 0x35, 0x33, 0x15, 0x03, 0x35, + 0x33, 0x15, 0x17, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0xba, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0xba, 0x5c, 0x5c, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x0f, + 0x00, 0x1f, 0x00, 0x00, 0x33, 0x2b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x01, + 0x33, 0x1d, 0x01, 0x33, 0x15, 0x3d, 0x02, 0x23, 0x3d, 0x01, 0x23, 0x35, + 0x3b, 0x02, 0x1d, 0x04, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x15, 0x00, 0x21, 0x00, 0x25, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x11, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, + 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x13, 0x23, 0x35, 0x33, 0xba, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x15, 0x00, 0x21, + 0x00, 0x25, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, + 0x1d, 0x03, 0x13, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, + 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0x2c, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, 0x00, 0x25, 0x00, 0x2b, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, + 0x04, 0x33, 0x1d, 0x03, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, + 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, + 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, + 0x5c, 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x02, 0x2c, 0x5d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, 0x00, 0x25, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, + 0x1d, 0x03, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, + 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x00, 0x05, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x06, 0x25, 0x23, 0x3d, 0x04, + 0x33, 0x1d, 0x03, 0x13, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5d, 0x5d, + 0x00, 0x01, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x27, + 0x00, 0x00, 0x15, 0x3d, 0x09, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x33, + 0x1d, 0x03, 0x23, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0x3b, 0x01, 0x15, + 0x2b, 0x01, 0x1d, 0x01, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, + 0x00, 0x21, 0x00, 0x2d, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x06, 0x25, 0x23, 0x3d, 0x04, + 0x33, 0x1d, 0x03, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x02, + 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xa0, 0x00, 0x23, + 0x00, 0x2b, 0x00, 0x37, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, 0x02, 0x1d, + 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, 0x02, 0x3d, 0x01, 0x33, + 0x1d, 0x06, 0x03, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x35, 0x33, 0x15, 0x2b, + 0x04, 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, + 0xba, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x11, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x00, + 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, + 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, + 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, + 0x01, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0xb9, 0x5c, 0x5c, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x23, + 0x00, 0x27, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x37, 0x00, 0x00, 0x21, 0x3d, + 0x03, 0x2b, 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, + 0x02, 0x3d, 0x01, 0x33, 0x1d, 0x06, 0x01, 0x35, 0x33, 0x15, 0x17, 0x2b, + 0x02, 0x35, 0x3b, 0x02, 0x27, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, + 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfe, + 0xea, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xb9, 0x5c, 0xba, 0x5d, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x11, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, + 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, 0x27, 0x33, 0x3d, 0x01, 0x2b, + 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x27, 0x33, 0x15, + 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, + 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0xb9, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x03, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x00, 0x05, 0x35, + 0x33, 0x15, 0x25, 0x3d, 0x06, 0x33, 0x1d, 0x01, 0x3b, 0x02, 0x3d, 0x01, + 0x33, 0x1d, 0x06, 0x23, 0x15, 0x23, 0x35, 0x33, 0x3d, 0x03, 0x2b, 0x02, + 0x1d, 0x03, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, 0xfe, + 0x30, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x00, 0x00, 0x04, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x03, 0x00, 0x17, 0x00, 0x1f, + 0x00, 0x25, 0x00, 0x00, 0x05, 0x35, 0x33, 0x15, 0x27, 0x23, 0x35, 0x23, + 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x04, + 0x23, 0x27, 0x33, 0x3d, 0x01, 0x2b, 0x01, 0x1d, 0x01, 0x13, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x25, 0x00, 0x29, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x2b, 0x01, + 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, + 0x01, 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, + 0x2c, 0x5c, 0x5c, 0xba, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x15, + 0x00, 0x1d, 0x00, 0x21, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, 0x1d, 0x02, + 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x15, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x73, 0x5d, 0x5d, + 0xb9, 0x5d, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x3d, 0x05, + 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x35, + 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, + 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5c, 0x5c, 0xba, 0x5d, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x21, 0x00, 0x27, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, + 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x33, 0x37, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, + 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x73, 0x5d, 0x5d, 0xb9, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xa0, 0x00, 0x03, + 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x25, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x3d, 0x05, + 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0xba, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x03, 0x43, 0x5d, + 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5c, 0x5c, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x07, 0x00, 0x11, 0x00, 0x19, + 0x00, 0x1f, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, + 0x01, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x33, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x01, 0x16, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x01, 0x73, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x1b, + 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x3d, 0x05, + 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x3d, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x03, 0x43, 0x5d, + 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5c, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x07, + 0x00, 0x11, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, + 0x1d, 0x02, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x35, 0x33, 0x15, + 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, + 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x73, + 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x31, + 0x00, 0x35, 0x00, 0x39, 0x00, 0x00, 0x37, 0x33, 0x35, 0x33, 0x3d, 0x03, + 0x23, 0x35, 0x2b, 0x01, 0x1d, 0x05, 0x17, 0x2b, 0x01, 0x3d, 0x07, 0x3b, + 0x02, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x03, 0x23, 0x15, 0x23, 0x15, 0x03, + 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, + 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0xa0, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x2d, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x00, 0x01, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x01, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x03, 0x33, + 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, 0x07, 0x27, 0x33, 0x3d, 0x03, + 0x2b, 0x01, 0x1d, 0x03, 0x01, 0xd0, 0x5d, 0xfe, 0xe9, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x02, 0x2d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xfd, 0xd3, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x2d, 0x02, 0xe7, 0x00, 0x13, 0x00, 0x2f, 0x00, 0x00, + 0x25, 0x33, 0x35, 0x33, 0x3d, 0x03, 0x23, 0x35, 0x2b, 0x01, 0x1d, 0x01, + 0x33, 0x15, 0x23, 0x1d, 0x02, 0x17, 0x2b, 0x01, 0x3d, 0x03, 0x23, 0x35, + 0x33, 0x3d, 0x02, 0x3b, 0x02, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x03, 0x23, + 0x15, 0x23, 0x15, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0x44, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x00, + 0x21, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x01, 0x35, + 0x23, 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x1d, 0x06, 0x27, + 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0x01, 0x16, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0xa0, 0x00, 0x21, 0x00, 0x2b, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, + 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, + 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x13, 0x33, 0x15, 0x2b, 0x03, 0x35, + 0x3b, 0x01, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x07, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, + 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5c, 0x5c, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0xfd, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, + 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, + 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x11, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x07, + 0x00, 0x19, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, + 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x27, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, + 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0xa0, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x3b, + 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, + 0x02, 0x33, 0x11, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x01, 0x16, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, + 0x43, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x07, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, 0x01, 0x3d, 0x03, 0x33, + 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x13, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x27, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x01, 0x16, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, + 0x16, 0x5d, 0xb9, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x27, 0x00, 0x00, + 0x05, 0x35, 0x33, 0x15, 0x27, 0x23, 0x35, 0x2b, 0x01, 0x3d, 0x07, 0x3b, + 0x03, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, + 0x02, 0x3b, 0x02, 0x15, 0x23, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x03, + 0x00, 0x0d, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x27, 0x23, 0x3d, 0x01, 0x3b, 0x02, 0x15, 0x2b, 0x01, 0x27, 0x23, 0x3d, + 0x03, 0x33, 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, 0x15, + 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0xfd, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x2b, 0x02, + 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x11, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x07, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x2b, + 0x01, 0x3d, 0x03, 0x33, 0x15, 0x3b, 0x01, 0x35, 0x33, 0x1d, 0x01, 0x2b, + 0x02, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x27, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, 0x16, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x1d, 0x00, 0x2b, 0x00, 0x35, + 0x00, 0x39, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x02, 0x2b, 0x01, 0x35, 0x3b, + 0x02, 0x1d, 0x04, 0x25, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, + 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x35, 0x23, 0x35, 0x33, 0x01, 0x16, + 0x5d, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, + 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x02, 0x2c, 0x5c, 0x5c, 0xba, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, + 0x00, 0x23, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, + 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x02, 0x1d, 0x06, + 0x27, 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, + 0x19, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x02, 0x89, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x19, 0x00, 0x27, + 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x13, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x02, 0x2b, 0x01, 0x35, 0x3b, + 0x02, 0x1d, 0x04, 0x25, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, + 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x03, 0x43, 0x5d, + 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x02, 0x2c, 0x5c, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, 0x03, 0x44, 0x00, 0x05, + 0x00, 0x1b, 0x00, 0x27, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x35, 0x00, 0x00, + 0x17, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x23, + 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x02, 0x1d, 0x06, 0x27, 0x33, 0x3d, 0x03, + 0x2b, 0x01, 0x1d, 0x03, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, + 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0xba, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x89, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xa0, 0x00, 0x03, 0x00, 0x19, 0x00, 0x27, + 0x00, 0x31, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x02, 0x35, + 0x3b, 0x02, 0x3d, 0x02, 0x2b, 0x01, 0x35, 0x3b, 0x02, 0x1d, 0x04, 0x25, + 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, + 0x3b, 0x01, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5c, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x2d, 0x00, 0x00, + 0x17, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x23, + 0x3d, 0x03, 0x33, 0x35, 0x3b, 0x02, 0x1d, 0x06, 0x27, 0x33, 0x3d, 0x03, + 0x2b, 0x01, 0x1d, 0x03, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0xba, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x89, 0x5c, 0x5c, + 0x00, 0x04, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x1b, 0x00, 0x29, 0x00, 0x33, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x3d, 0x01, 0x23, 0x35, 0x3b, 0x02, 0x3d, 0x02, 0x2b, 0x01, 0x35, 0x3b, + 0x02, 0x1d, 0x04, 0x2b, 0x01, 0x15, 0x27, 0x23, 0x3d, 0x05, 0x33, 0x1d, + 0x04, 0x01, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x02, 0x2c, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x1f, + 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x03, + 0x33, 0x35, 0x3b, 0x02, 0x1d, 0x06, 0x27, 0x33, 0x3d, 0x03, 0x2b, 0x01, + 0x1d, 0x03, 0x13, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x89, 0x5d, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x27, + 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, + 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x07, 0x33, 0x1d, 0x02, 0x3b, 0x02, 0x3d, + 0x02, 0x33, 0x1d, 0x07, 0x03, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x37, 0x23, 0x35, 0x33, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0xba, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x0b, 0x00, 0x21, 0x00, 0x00, 0x21, 0x3d, 0x04, 0x33, + 0x1d, 0x04, 0x21, 0x3d, 0x07, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, + 0x01, 0x1d, 0x04, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, + 0x02, 0xe7, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x2b, + 0x02, 0x1d, 0x03, 0x23, 0x3d, 0x05, 0x23, 0x35, 0x33, 0x35, 0x33, 0x15, + 0x3b, 0x02, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x1d, 0x05, 0x03, 0x33, + 0x35, 0x2b, 0x02, 0x15, 0x33, 0x01, 0xd0, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0x44, 0x00, 0x0b, 0x00, 0x27, 0x00, 0x00, + 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x21, 0x3d, 0x06, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x3b, 0x01, 0x15, 0x2b, 0x01, + 0x1d, 0x04, 0x01, 0x73, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x21, + 0x00, 0x25, 0x00, 0x29, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, + 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, 0x15, 0x11, 0x35, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0xa0, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, + 0x00, 0x00, 0x33, 0x3d, 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x03, + 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x37, 0x35, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0xba, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0xfe, 0xea, 0x5d, + 0xb9, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x03, 0xa0, 0x00, 0x19, 0x00, 0x21, 0x00, 0x00, 0x33, 0x2b, 0x01, 0x35, + 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, + 0x15, 0x03, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0xa0, 0x5d, 0x5d, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x02, 0xe7, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x00, + 0x33, 0x3d, 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x11, 0x33, 0x15, + 0x2b, 0x02, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x02, 0xe6, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x21, + 0x00, 0x25, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x2b, 0x01, 0x35, + 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, + 0x15, 0x03, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0xb9, 0x5d, + 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, + 0xa0, 0x5d, 0x5d, 0x5d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x00, + 0x33, 0x3d, 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x03, 0x35, 0x33, + 0x15, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x46, 0x01, 0x17, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x27, 0x23, 0x35, 0x23, 0x35, 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, + 0x15, 0x23, 0x1d, 0x05, 0x33, 0x15, 0x23, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0xff, 0x46, 0x00, 0xba, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, + 0x00, 0x1b, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, 0x03, 0x35, 0x33, 0x15, + 0x03, 0x23, 0x35, 0x33, 0x31, 0x3d, 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, + 0x05, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x03, 0x44, 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x03, 0xa0, 0x00, 0x03, + 0x00, 0x1d, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x2b, 0x01, 0x35, + 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, + 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x03, 0x43, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x02, 0x2d, 0x00, 0x0d, + 0x00, 0x00, 0x31, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe7, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x1f, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x05, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x05, 0x23, 0x35, 0x3b, + 0x02, 0x15, 0x23, 0x1d, 0x05, 0x33, 0x15, 0x25, 0x3d, 0x06, 0x33, 0x1d, + 0x06, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x01, + 0x74, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x05, 0x00, 0x00, + 0xff, 0x46, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x13, 0x00, 0x17, + 0x00, 0x1b, 0x00, 0x2d, 0x00, 0x00, 0x05, 0x35, 0x33, 0x15, 0x25, 0x3d, + 0x04, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x05, 0x13, 0x35, 0x33, 0x15, 0x21, + 0x35, 0x33, 0x15, 0x13, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x06, + 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, + 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, + 0x5c, 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, + 0x00, 0x1d, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, + 0x06, 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x13, 0x23, + 0x35, 0x33, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, + 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x02, + 0xe6, 0x5d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0xff, 0x46, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x1d, 0x00, 0x21, + 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x11, 0x3d, 0x05, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x06, 0x11, + 0x23, 0x35, 0x33, 0x5d, 0x5d, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x03, 0x44, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, + 0x19, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0xff, 0x46, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x09, 0x00, 0x25, + 0x00, 0x29, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x35, 0x00, 0x00, 0x17, 0x35, + 0x33, 0x15, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, 0x07, 0x33, + 0x1d, 0x02, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x23, 0x35, 0x23, 0x35, + 0x23, 0x1d, 0x03, 0x17, 0x35, 0x33, 0x15, 0x03, 0x35, 0x33, 0x15, 0x3d, + 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, + 0x30, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, + 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x00, 0x04, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, 0x00, 0x25, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, 0x27, 0x3d, 0x07, 0x33, + 0x1d, 0x03, 0x33, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x01, 0x23, 0x15, 0x23, + 0x35, 0x33, 0x3d, 0x01, 0x23, 0x35, 0x23, 0x1d, 0x02, 0x13, 0x35, 0x33, + 0x15, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0x2d, 0x00, 0x05, 0x00, 0x19, 0x00, 0x1d, + 0x00, 0x21, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, + 0x05, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x33, 0x15, 0x23, 0x35, 0x23, 0x1d, + 0x02, 0x13, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x01, 0x16, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x33, 0x1d, 0x06, 0x33, 0x11, 0x35, 0x33, + 0x15, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, + 0x03, 0xfd, 0x00, 0x11, 0x00, 0x15, 0x00, 0x19, 0x00, 0x00, 0x31, 0x3d, + 0x07, 0x33, 0x1d, 0x07, 0x03, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x3d, 0x01, 0x2b, 0x01, 0x3d, 0x07, 0x33, 0x1d, 0x06, 0x3b, 0x02, 0x15, + 0x23, 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xff, 0x46, 0x00, 0xba, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, 0x3d, 0x01, + 0x33, 0x15, 0x27, 0x23, 0x3d, 0x07, 0x33, 0x1d, 0x06, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x1d, 0x00, 0x00, 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x11, 0x33, + 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x33, 0x1d, 0x06, 0x33, 0xba, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5c, 0x5c, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x02, 0xe7, 0x00, 0x11, 0x00, 0x17, 0x00, 0x00, + 0x31, 0x3d, 0x07, 0x33, 0x1d, 0x07, 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x11, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x07, 0x33, 0x1d, 0x06, 0x33, 0xba, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x02, 0xe7, 0x00, 0x11, 0x00, 0x15, 0x00, 0x00, + 0x31, 0x3d, 0x07, 0x33, 0x1d, 0x07, 0x13, 0x35, 0x33, 0x15, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x1b, + 0x00, 0x1f, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x02, 0x23, + 0x35, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x33, 0x15, 0x23, 0x1d, 0x02, + 0x33, 0x11, 0x35, 0x33, 0x15, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x02, 0xe7, 0x00, 0x15, 0x00, 0x00, 0x33, 0x3d, 0x02, 0x23, 0x35, 0x33, + 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x33, 0x15, 0x23, 0x1d, 0x03, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x13, 0x00, 0x2b, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x23, 0x35, 0x33, 0x3d, 0x02, + 0x33, 0x1d, 0x07, 0x21, 0x3d, 0x07, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, + 0x23, 0x35, 0x23, 0x1d, 0x05, 0x13, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, + 0x15, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x09, + 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x33, + 0x1d, 0x03, 0x21, 0x3d, 0x04, 0x3b, 0x02, 0x15, 0x2b, 0x01, 0x1d, 0x03, + 0x11, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x01, 0x16, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x17, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x37, 0x3d, 0x03, 0x23, 0x35, 0x33, 0x3d, 0x02, 0x33, 0x1d, 0x07, 0x21, + 0x3d, 0x07, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x23, 0x35, 0x23, 0x1d, + 0x05, 0x17, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0xfe, + 0x30, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x01, 0xd0, 0x00, 0x03, 0x00, 0x21, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x27, 0x3d, 0x04, 0x3b, 0x02, 0x15, 0x33, 0x1d, 0x03, 0x23, 0x15, 0x23, + 0x35, 0x33, 0x3d, 0x03, 0x2b, 0x01, 0x1d, 0x03, 0x5d, 0x5d, 0xba, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x13, 0x00, 0x2b, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x37, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x23, 0x35, 0x33, + 0x3d, 0x02, 0x33, 0x1d, 0x07, 0x21, 0x3d, 0x07, 0x33, 0x15, 0x33, 0x15, + 0x33, 0x15, 0x23, 0x35, 0x23, 0x1d, 0x05, 0x13, 0x35, 0x33, 0x15, 0x3d, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x01, 0x73, 0x5d, 0x5d, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, + 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x09, 0x00, 0x19, 0x00, 0x1f, + 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x21, 0x3d, 0x04, 0x3b, 0x02, 0x15, 0x2b, 0x01, 0x1d, 0x03, 0x13, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, + 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x02, 0x8a, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x09, + 0x00, 0x19, 0x00, 0x1f, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x21, 0x3d, 0x04, 0x3b, 0x02, 0x15, 0x2b, 0x01, 0x1d, 0x03, 0x03, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x01, 0x73, 0x5d, 0xfe, 0x8d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x2d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x00, 0x01, 0x00, 0x00, 0xff, 0xa3, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x31, 0x00, 0x00, 0x31, 0x3d, 0x07, 0x33, 0x15, 0x33, + 0x15, 0x33, 0x15, 0x33, 0x3d, 0x02, 0x33, 0x1d, 0x07, 0x23, 0x15, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x03, 0x23, 0x35, 0x23, 0x35, 0x23, 0x1d, + 0x05, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0xa3, 0x01, 0x74, + 0x01, 0xd0, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x25, 0x3d, 0x04, 0x3b, 0x02, 0x15, 0x33, 0x1d, 0x03, 0x23, 0x3d, 0x03, + 0x2b, 0x01, 0x1d, 0x03, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xa0, 0x00, 0x07, 0x00, 0x15, 0x00, 0x23, 0x00, 0x2b, 0x00, 0x37, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, + 0x33, 0x1d, 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, + 0x02, 0x35, 0x3b, 0x02, 0x35, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0xba, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x29, + 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x03, 0x33, + 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0xba, + 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5c, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x07, + 0x00, 0x15, 0x00, 0x23, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x37, 0x00, 0x3b, + 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x05, + 0x33, 0x1d, 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x01, 0x2b, + 0x02, 0x35, 0x3b, 0x02, 0x27, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, + 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0xba, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x25, + 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, + 0x02, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x27, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x2b, + 0x00, 0x33, 0x00, 0x37, 0x00, 0x3b, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, + 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x21, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, + 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x01, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, + 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, + 0x03, 0x33, 0x1d, 0x03, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, + 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, + 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe7, 0x02, 0xe7, 0x00, 0x29, + 0x00, 0x3b, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x06, 0x35, 0x23, 0x3d, + 0x05, 0x33, 0x35, 0x3b, 0x06, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, + 0x15, 0x2b, 0x01, 0x1d, 0x02, 0x33, 0x21, 0x33, 0x3d, 0x05, 0x2b, 0x02, + 0x1d, 0x05, 0x33, 0x02, 0x8a, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x8a, 0x02, 0x2d, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x0f, + 0x00, 0x21, 0x00, 0x2b, 0x00, 0x31, 0x00, 0x37, 0x00, 0x00, 0x25, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x23, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x21, 0x35, + 0x33, 0x15, 0x21, 0x23, 0x3d, 0x03, 0x33, 0x15, 0x3b, 0x01, 0x35, 0x33, + 0x1d, 0x01, 0x2b, 0x02, 0x15, 0x05, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, + 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x01, 0xd0, 0x5d, + 0xfe, 0xe9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xea, + 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x09, 0x00, 0x2d, 0x00, 0x31, + 0x00, 0x35, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x21, 0x3d, + 0x07, 0x3b, 0x03, 0x15, 0x33, 0x1d, 0x01, 0x23, 0x3d, 0x01, 0x2b, 0x02, + 0x1d, 0x01, 0x3b, 0x02, 0x15, 0x2b, 0x02, 0x1d, 0x03, 0x13, 0x35, 0x33, + 0x15, 0x3d, 0x01, 0x33, 0x15, 0x01, 0x73, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x19, 0x00, 0x00, + 0x31, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x11, 0x35, 0x33, 0x1d, 0x01, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x37, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x00, + 0x00, 0x04, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x0d, 0x00, 0x31, 0x00, 0x35, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x37, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x21, 0x3d, 0x07, 0x3b, 0x03, 0x15, + 0x33, 0x1d, 0x01, 0x23, 0x3d, 0x01, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x02, + 0x15, 0x2b, 0x02, 0x1d, 0x03, 0x17, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0xb9, + 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, + 0xff, 0x46, 0x01, 0x17, 0x02, 0x2d, 0x00, 0x03, 0x00, 0x07, 0x00, 0x13, + 0x00, 0x19, 0x00, 0x00, 0x15, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, + 0x27, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x13, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x09, 0x00, 0x2d, 0x00, 0x31, + 0x00, 0x35, 0x00, 0x39, 0x00, 0x00, 0x21, 0x3d, 0x03, 0x33, 0x1d, 0x03, + 0x21, 0x3d, 0x07, 0x3b, 0x03, 0x15, 0x33, 0x1d, 0x01, 0x23, 0x3d, 0x01, + 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x02, 0x15, 0x2b, 0x02, 0x1d, 0x03, 0x13, + 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x01, + 0x73, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, + 0x03, 0x44, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x19, 0x00, 0x1d, + 0x00, 0x00, 0x31, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x11, 0x35, 0x33, 0x1d, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x37, 0x35, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x33, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x02, 0x8a, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x0d, 0x00, 0x15, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x31, + 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x03, 0x35, + 0x3b, 0x02, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x03, 0x2b, 0x02, 0x35, 0x3b, + 0x02, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x25, 0x33, 0x15, 0x2b, 0x03, + 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, + 0x5c, 0x5c, 0xba, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x11, + 0x00, 0x17, 0x00, 0x1b, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x01, + 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x35, + 0x33, 0x37, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x15, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x11, 0x00, 0x19, 0x00, 0x21, 0x00, 0x27, 0x00, 0x31, + 0x00, 0x35, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x02, 0x3d, 0x02, 0x33, 0x1d, + 0x02, 0x03, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x21, 0x23, 0x3d, 0x01, 0x33, + 0x15, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x35, 0x23, 0x35, + 0x33, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5c, 0xba, 0x5d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, + 0x00, 0x15, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x27, 0x00, 0x2d, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, + 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x35, 0x33, 0x37, 0x33, 0x15, 0x2b, 0x02, + 0x35, 0x33, 0x37, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, + 0xd3, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0xb9, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x25, + 0x00, 0x2f, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x2b, 0x01, + 0x35, 0x3b, 0x03, 0x15, 0x23, 0x15, 0x37, 0x3d, 0x02, 0x33, 0x1d, 0x02, + 0x03, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, + 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x01, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, + 0xb9, 0x5c, 0x5c, 0x00, 0x00, 0x06, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x02, 0x2d, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1d, + 0x00, 0x25, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x2b, 0x01, + 0x35, 0x3b, 0x02, 0x1d, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x27, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x35, 0x33, 0x37, 0x33, 0x15, 0x2b, + 0x02, 0x35, 0x33, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x15, + 0x00, 0x1d, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x35, 0x00, 0x00, + 0x13, 0x35, 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x02, + 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x03, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x21, + 0x23, 0x3d, 0x01, 0x33, 0x15, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, + 0x01, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0xba, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, + 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, + 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x07, + 0x00, 0x0d, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, + 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x27, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x2b, + 0x01, 0x35, 0x33, 0x37, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x35, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, + 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x46, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x17, 0x35, 0x33, 0x15, + 0x3d, 0x08, 0x2b, 0x01, 0x35, 0x3b, 0x04, 0x15, 0x2b, 0x01, 0x1d, 0x07, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xff, 0xa3, 0x01, 0x17, 0x02, 0xe7, 0x00, 0x05, + 0x00, 0x09, 0x00, 0x1d, 0x00, 0x00, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x35, 0x33, 0x15, 0x27, 0x23, 0x3d, 0x03, 0x23, 0x35, 0x33, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x23, 0x1d, 0x02, 0x5d, 0x5d, 0x5d, + 0x5d, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0x00, 0x00, + 0x33, 0x3d, 0x06, 0x2b, 0x01, 0x35, 0x3b, 0x04, 0x15, 0x2b, 0x01, 0x1d, + 0x06, 0x03, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x5c, 0x02, 0x8a, 0x03, 0xfd, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x29, + 0x00, 0x00, 0x25, 0x3d, 0x05, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x01, + 0x33, 0x1d, 0x02, 0x3b, 0x02, 0x15, 0x2b, 0x02, 0x1d, 0x04, 0x13, 0x35, + 0x33, 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x01, 0x16, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x89, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x1d, 0x00, 0x00, 0x33, 0x3d, + 0x04, 0x23, 0x35, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x04, 0x15, 0x2b, + 0x01, 0x15, 0x33, 0x15, 0x23, 0x1d, 0x04, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x02, 0x8a, + 0x03, 0xa0, 0x00, 0x27, 0x00, 0x00, 0x25, 0x3d, 0x02, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x3d, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x3d, 0x01, 0x33, + 0x1d, 0x02, 0x3b, 0x02, 0x15, 0x2b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, + 0x2b, 0x01, 0x1d, 0x01, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x39, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, + 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x01, 0x35, 0x33, 0x15, 0x2b, 0x02, + 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, + 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, + 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0xe6, 0x5d, 0x5d, 0x5d, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x19, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, + 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, + 0x1d, 0x03, 0x13, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0xba, 0x5c, + 0xfe, 0xea, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0xb9, 0x5d, 0xb9, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, + 0xfd, 0x76, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0x2c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xa0, 0x00, 0x07, 0x00, 0x17, 0x00, 0x27, + 0x00, 0x33, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, + 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, + 0x01, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0x01, 0x16, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x02, 0xe6, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x27, + 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, + 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x13, 0x33, 0x15, 0x2b, + 0x03, 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5c, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x07, 0x00, 0x17, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x33, + 0x00, 0x37, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, + 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, + 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x21, + 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0xe6, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x23, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, + 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, + 0x35, 0x33, 0x01, 0x16, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x1b, 0x00, 0x2b, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x37, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x11, 0x33, + 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, + 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x13, 0x35, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x23, 0x35, 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0xb9, 0x5d, 0xb9, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x02, 0xe6, 0x5d, 0x5d, 0xfd, 0x77, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x02, 0x89, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0xa0, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x23, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x31, 0x00, 0x00, 0x21, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, + 0x1d, 0x03, 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, + 0x21, 0x23, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, + 0x00, 0x1f, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x37, 0x00, 0x00, 0x01, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, 0x02, 0x35, + 0x3b, 0x01, 0x3d, 0x06, 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, + 0x1d, 0x05, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x01, 0x16, + 0x5d, 0xfe, 0x8d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0xfe, 0x8d, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, + 0xe6, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x19, + 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, 0x04, + 0x33, 0x1d, 0x05, 0x25, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x13, 0x35, + 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0xb9, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0xb9, 0x5d, 0xb9, + 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0x76, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0xfe, 0xe9, 0x01, 0xd0, + 0x02, 0xe7, 0x00, 0x05, 0x00, 0x09, 0x00, 0x13, 0x00, 0x23, 0x00, 0x33, + 0x00, 0x00, 0x05, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x31, 0x23, 0x35, 0x33, + 0x31, 0x35, 0x23, 0x35, 0x3b, 0x02, 0x15, 0x23, 0x15, 0x37, 0x3d, 0x06, + 0x33, 0x1d, 0x06, 0x21, 0x23, 0x3d, 0x06, 0x33, 0x1d, 0x05, 0x01, 0x16, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0xba, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x03, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x02, 0x2d, 0x00, 0x03, 0x00, 0x17, 0x00, 0x23, 0x00, 0x00, 0x05, 0x35, + 0x33, 0x15, 0x27, 0x23, 0x35, 0x23, 0x35, 0x3b, 0x01, 0x3d, 0x04, 0x33, + 0x1d, 0x05, 0x23, 0x27, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x01, 0x16, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0xba, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x35, 0x00, 0x39, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x13, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x2b, 0x01, + 0x3d, 0x01, 0x33, 0x15, 0x07, 0x23, 0x3d, 0x05, 0x33, 0x1d, 0x04, 0x13, + 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0xfe, + 0xea, 0x5d, 0xb9, 0x5d, 0xba, 0x5c, 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x03, 0x43, 0x5d, + 0x5d, 0x5d, 0x5d, 0xfd, 0x77, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x02, 0x8a, 0x5d, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0x44, 0x00, 0x05, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x2d, + 0x00, 0x31, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x15, + 0x07, 0x23, 0x3d, 0x03, 0x33, 0x1d, 0x02, 0x13, 0x23, 0x35, 0x33, 0x01, + 0x16, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, + 0xba, 0x5c, 0x5c, 0xb9, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x02, 0x8a, 0x5c, 0x5c, 0x5c, 0x5c, 0xfe, + 0x30, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x09, + 0x00, 0x0d, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x11, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x13, 0x23, 0x35, 0x33, 0xba, 0x5c, + 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x01, 0x16, 0x5d, 0x00, 0x06, 0x00, 0x00, 0xff, 0x46, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x21, 0x00, 0x2d, + 0x00, 0x33, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x2b, 0x01, 0x35, 0x3b, + 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x06, 0x25, 0x23, 0x3d, 0x04, 0x33, 0x1d, + 0x03, 0x13, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x16, 0x5d, 0xfe, 0x8d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, + 0x5c, 0x5c, 0xfd, 0x19, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x02, 0x2c, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xa0, 0x00, 0x09, + 0x00, 0x0d, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x29, + 0x00, 0x00, 0x33, 0x3d, 0x03, 0x33, 0x1d, 0x03, 0x11, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x2b, 0x01, + 0x3d, 0x01, 0x33, 0x15, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0x5d, 0xfe, 0xea, 0x5d, 0x5c, 0x5d, + 0xb9, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, + 0x30, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0xfd, 0x00, 0x03, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, + 0x00, 0x2d, 0x00, 0x31, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x33, + 0x15, 0x2b, 0x04, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x27, 0x35, + 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, + 0x2b, 0x03, 0x35, 0x3b, 0x04, 0x1d, 0x01, 0x03, 0x35, 0x33, 0x15, 0xba, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xb9, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0xba, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x01, 0x33, 0x15, 0x33, 0x27, 0x35, + 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x2b, 0x02, 0x35, 0x3b, + 0x03, 0x1d, 0x01, 0x03, 0x35, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0xa0, 0x00, 0x03, 0x00, 0x13, 0x00, 0x17, + 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x13, 0x33, 0x15, 0x2b, 0x04, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3b, 0x01, + 0x27, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, + 0x3d, 0x01, 0x2b, 0x03, 0x35, 0x3b, 0x04, 0x1d, 0x01, 0xba, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x23, 0x00, 0x00, 0x13, 0x35, + 0x33, 0x15, 0x11, 0x33, 0x15, 0x2b, 0x03, 0x3d, 0x01, 0x33, 0x15, 0x33, + 0x27, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x2b, 0x02, + 0x35, 0x3b, 0x03, 0x1d, 0x01, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x02, 0x8a, 0x5c, 0x5c, 0xfd, 0xd3, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x03, 0xfd, 0x00, 0x03, + 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x31, + 0x00, 0x35, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, 0x13, 0x33, 0x15, 0x2b, + 0x04, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x27, 0x35, 0x33, 0x15, + 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x2b, 0x03, + 0x35, 0x3b, 0x04, 0x1d, 0x01, 0x03, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0xb9, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xba, 0x5d, 0xb9, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0xfd, + 0x1a, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x73, 0x5d, + 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, + 0x03, 0x44, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x25, + 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x3d, + 0x01, 0x33, 0x15, 0x33, 0x27, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, + 0x3d, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x03, 0x1d, 0x01, 0x03, 0x33, 0x15, + 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, + 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x2c, 0x00, 0xba, + 0x03, 0x44, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x11, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x02, 0x2c, 0x00, 0xba, 0x03, 0x44, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, + 0x11, 0x35, 0x33, 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x5d, 0x5d, 0x02, + 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x00, 0x04, 0x00, 0x00, + 0x02, 0x2c, 0x01, 0x74, 0x03, 0x44, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x0f, + 0x00, 0x13, 0x00, 0x00, 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x37, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, + 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0xb9, 0x5d, 0x5d, 0x02, 0x2d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, + 0x00, 0x04, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x74, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x00, 0x13, 0x35, 0x33, 0x15, + 0x21, 0x35, 0x33, 0x15, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x2b, 0x01, + 0x3d, 0x01, 0x33, 0x15, 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0xb9, + 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb9, 0x01, 0xd0, + 0x02, 0x8a, 0x00, 0x13, 0x00, 0x00, 0x25, 0x2b, 0x01, 0x35, 0x23, 0x3d, + 0x02, 0x33, 0x35, 0x3b, 0x02, 0x15, 0x33, 0x1d, 0x02, 0x23, 0x15, 0x01, + 0x16, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, 0x00, 0x5d, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x02, 0x2d, 0x5d, 0xfe, 0x8c, 0x5d, + 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x17, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x11, 0x35, 0x33, 0x15, 0x3d, 0x01, + 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x5d, 0x5d, 0x5c, 0x02, 0x2d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x02, 0x2c, 0x01, 0x74, 0x03, 0x44, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x0f, + 0x00, 0x13, 0x00, 0x00, 0x13, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x37, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, + 0xba, 0x5c, 0xfe, 0xea, 0x5d, 0xb9, 0x5d, 0xb9, 0x5d, 0x5d, 0x02, 0x2d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x13, 0x00, 0x19, 0x00, 0x21, 0x00, 0x00, 0x33, 0x35, + 0x33, 0x15, 0x27, 0x3d, 0x03, 0x33, 0x15, 0x33, 0x15, 0x23, 0x1d, 0x01, + 0x01, 0x35, 0x33, 0x15, 0x05, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x27, 0x2b, + 0x02, 0x35, 0x3b, 0x02, 0xba, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0xea, + 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0x73, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x2d, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x01, 0x35, + 0x33, 0x15, 0x03, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x35, 0x33, + 0x15, 0x21, 0x23, 0x35, 0x23, 0x35, 0x33, 0x35, 0x23, 0x35, 0x33, 0x3d, + 0x01, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x15, 0x3b, 0x01, + 0x15, 0x2b, 0x01, 0x01, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0xd0, 0x5d, + 0xba, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0xba, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0x00, 0x02, 0x00, 0x00, + 0x01, 0xd0, 0x03, 0xa0, 0x03, 0x44, 0x00, 0x0f, 0x00, 0x2b, 0x00, 0x00, + 0x01, 0x3d, 0x01, 0x23, 0x15, 0x23, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, + 0x1d, 0x03, 0x21, 0x3d, 0x02, 0x2b, 0x01, 0x1d, 0x02, 0x23, 0x3d, 0x02, + 0x2b, 0x01, 0x35, 0x3b, 0x05, 0x15, 0x33, 0x15, 0x23, 0x1d, 0x01, 0x03, + 0x43, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xb9, 0x03, 0xa0, 0x02, 0x8a, 0x00, 0x1d, + 0x00, 0x00, 0x37, 0x35, 0x23, 0x35, 0x23, 0x35, 0x33, 0x35, 0x33, 0x35, + 0x33, 0x1d, 0x01, 0x3b, 0x06, 0x15, 0x2b, 0x06, 0x1d, 0x01, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0x44, 0x00, 0x1b, 0x00, 0x00, 0x33, 0x3d, + 0x05, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, + 0x33, 0x15, 0x2b, 0x01, 0x1d, 0x05, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xb9, 0x03, 0xa0, 0x02, 0x8a, 0x00, 0x1d, + 0x00, 0x00, 0x25, 0x3d, 0x01, 0x2b, 0x06, 0x35, 0x3b, 0x06, 0x3d, 0x01, + 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x15, 0x02, 0x8a, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x03, 0x44, 0x00, 0x1b, 0x00, 0x00, 0x33, 0x35, + 0x23, 0x35, 0x23, 0x35, 0x3b, 0x01, 0x3d, 0x05, 0x33, 0x1d, 0x05, 0x3b, + 0x01, 0x15, 0x23, 0x15, 0x23, 0x15, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0xb9, 0x02, 0x8a, 0x02, 0x2d, 0x00, 0x05, + 0x00, 0x0b, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x29, + 0x00, 0x00, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x23, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, + 0x33, 0x15, 0x05, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x25, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0xd0, 0x5d, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x01, 0xd0, 0x5d, 0xfe, 0xe9, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, + 0x5c, 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5c, 0x00, 0x5c, 0x02, 0xe7, + 0x02, 0xe7, 0x00, 0x1b, 0x00, 0x00, 0x25, 0x2b, 0x05, 0x3d, 0x01, 0x33, + 0x3d, 0x01, 0x33, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x15, 0x33, 0x1d, 0x01, + 0x33, 0x1d, 0x01, 0x33, 0x1d, 0x01, 0x02, 0x8a, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x02, 0x8a, 0x02, 0xe7, 0x00, 0x1b, + 0x00, 0x00, 0x37, 0x23, 0x3d, 0x06, 0x3b, 0x01, 0x15, 0x3b, 0x01, 0x15, + 0x3b, 0x01, 0x15, 0x33, 0x15, 0x23, 0x15, 0x2b, 0x01, 0x15, 0x2b, 0x01, + 0x15, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5c, + 0x00, 0x5c, 0x02, 0xe7, 0x02, 0xe7, 0x00, 0x1b, 0x00, 0x00, 0x25, 0x35, + 0x23, 0x3d, 0x01, 0x23, 0x3d, 0x01, 0x23, 0x3d, 0x01, 0x3b, 0x06, 0x1d, + 0x01, 0x23, 0x1d, 0x01, 0x23, 0x1d, 0x01, 0x23, 0x15, 0x01, 0x73, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x02, 0x8a, + 0x02, 0xe7, 0x00, 0x1b, 0x00, 0x00, 0x25, 0x23, 0x35, 0x2b, 0x01, 0x35, + 0x2b, 0x01, 0x35, 0x23, 0x35, 0x33, 0x35, 0x3b, 0x01, 0x35, 0x3b, 0x01, + 0x35, 0x3b, 0x01, 0x1d, 0x06, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x2d, 0x00, 0x31, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x13, 0x35, + 0x23, 0x15, 0x23, 0x35, 0x23, 0x1d, 0x03, 0x23, 0x3d, 0x03, 0x23, 0x15, + 0x23, 0x35, 0x23, 0x15, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x35, 0x3b, + 0x01, 0x35, 0x33, 0x15, 0x3b, 0x01, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x01, + 0x01, 0x35, 0x33, 0x15, 0x01, 0xd0, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0xa0, 0x03, 0xfd, 0x00, 0x33, + 0x00, 0x37, 0x00, 0x3b, 0x00, 0x3f, 0x00, 0x63, 0x00, 0x67, 0x00, 0x00, + 0x01, 0x35, 0x23, 0x35, 0x23, 0x15, 0x23, 0x1d, 0x01, 0x33, 0x15, 0x23, + 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x35, 0x3b, 0x03, 0x15, 0x33, + 0x15, 0x33, 0x1d, 0x01, 0x23, 0x15, 0x23, 0x15, 0x2b, 0x03, 0x35, 0x3b, + 0x03, 0x35, 0x33, 0x3d, 0x01, 0x23, 0x35, 0x23, 0x1d, 0x01, 0x37, 0x35, + 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x21, 0x35, 0x33, 0x15, 0x2b, 0x01, + 0x35, 0x23, 0x35, 0x33, 0x35, 0x2b, 0x03, 0x15, 0x33, 0x15, 0x23, 0x15, + 0x23, 0x3d, 0x02, 0x23, 0x35, 0x3b, 0x01, 0x35, 0x3b, 0x03, 0x15, 0x3b, + 0x01, 0x15, 0x23, 0x1d, 0x01, 0x05, 0x23, 0x35, 0x33, 0x01, 0xd0, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0xb9, 0x5d, 0xfd, 0x77, 0x5d, 0x5d, 0x02, 0x89, 0x5d, 0xba, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfd, 0x77, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5a, + 0x03, 0x44, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x23, 0x00, 0x29, + 0x00, 0x31, 0x00, 0x37, 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, + 0x00, 0x4d, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x02, 0x35, 0x3b, 0x01, + 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, + 0x25, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, 0x21, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x05, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x25, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x07, 0x23, 0x35, 0x33, 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x05, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, 0x3d, 0x01, 0x33, 0x15, + 0x01, 0x16, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, + 0x5d, 0x03, 0xa0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0x01, 0xd0, + 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x2b, + 0x00, 0x00, 0x21, 0x23, 0x35, 0x23, 0x35, 0x23, 0x15, 0x23, 0x15, 0x2b, + 0x01, 0x35, 0x33, 0x3d, 0x02, 0x23, 0x35, 0x23, 0x35, 0x3b, 0x02, 0x35, + 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x3b, 0x02, 0x15, 0x23, + 0x15, 0x23, 0x1d, 0x02, 0x33, 0x15, 0x02, 0x8a, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb7, + 0x02, 0xe7, 0x00, 0x37, 0x00, 0x43, 0x00, 0x51, 0x00, 0x59, 0x00, 0x5d, + 0x00, 0x61, 0x00, 0x00, 0x21, 0x2b, 0x07, 0x35, 0x23, 0x3d, 0x01, 0x33, + 0x35, 0x33, 0x35, 0x2b, 0x01, 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x0a, 0x15, + 0x33, 0x1d, 0x01, 0x2b, 0x01, 0x35, 0x23, 0x35, 0x23, 0x15, 0x33, 0x15, + 0x33, 0x15, 0x33, 0x1d, 0x02, 0x2b, 0x01, 0x15, 0x25, 0x33, 0x35, 0x2b, + 0x04, 0x15, 0x3b, 0x02, 0x37, 0x33, 0x35, 0x23, 0x35, 0x2b, 0x01, 0x15, + 0x2b, 0x01, 0x15, 0x3b, 0x02, 0x13, 0x33, 0x35, 0x2b, 0x02, 0x15, 0x33, + 0x05, 0x35, 0x23, 0x15, 0x37, 0x35, 0x23, 0x15, 0x03, 0x43, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0xfe, 0xe9, 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x17, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x5a, 0x03, 0xfd, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, + 0x00, 0x41, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x55, 0x00, 0x5f, + 0x00, 0x63, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x00, 0x21, 0x3d, 0x01, 0x3b, + 0x01, 0x15, 0x23, 0x15, 0x21, 0x35, 0x23, 0x35, 0x3b, 0x01, 0x1d, 0x01, + 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x13, 0x2b, 0x02, 0x3d, + 0x02, 0x33, 0x1d, 0x01, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, 0x02, 0x37, + 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, 0x23, 0x35, 0x33, 0x05, + 0x23, 0x35, 0x33, 0x21, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, + 0x02, 0x33, 0x1d, 0x01, 0x25, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, + 0x25, 0x35, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x03, 0x05, 0x23, 0x35, + 0x33, 0x21, 0x3d, 0x01, 0x33, 0x15, 0x33, 0x15, 0x23, 0x21, 0x2b, 0x01, + 0x35, 0x33, 0x35, 0x33, 0x15, 0x03, 0xa0, 0x5d, 0x5d, 0x5d, 0xfc, 0x60, + 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5c, 0xfe, 0x8d, 0x5d, 0xba, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0xfd, 0x1a, 0x5c, 0x02, + 0x2d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0xfd, 0x76, + 0x5c, 0x5c, 0x02, 0x2d, 0x5d, 0x5d, 0xfd, 0xd3, 0x5d, 0x01, 0xd0, 0x5d, + 0xba, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xfe, 0x30, 0x5c, + 0x5c, 0x02, 0x8a, 0x5d, 0x5d, 0x5d, 0xfc, 0xbd, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, + 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x03, 0x44, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x23, + 0x00, 0x27, 0x00, 0x33, 0x00, 0x37, 0x00, 0x3b, 0x00, 0x57, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x03, 0x35, 0x33, 0x15, 0x21, + 0x23, 0x35, 0x33, 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x2b, 0x01, 0x35, + 0x33, 0x05, 0x35, 0x33, 0x15, 0x2b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x03, + 0x21, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x37, 0x23, 0x3d, 0x03, + 0x2b, 0x01, 0x15, 0x23, 0x35, 0x33, 0x35, 0x3b, 0x04, 0x15, 0x33, 0x15, + 0x23, 0x35, 0x2b, 0x01, 0x1d, 0x02, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, 0xfd, 0xd4, 0x5d, 0x5d, 0x02, + 0x2c, 0x5d, 0xb9, 0x5d, 0x5d, 0xfe, 0x30, 0x5c, 0xb9, 0x5d, 0x5d, 0x01, + 0xd0, 0x5d, 0x5d, 0xfe, 0xe9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x37, 0x00, 0x43, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, + 0x11, 0x2b, 0x03, 0x35, 0x23, 0x35, 0x23, 0x3d, 0x04, 0x33, 0x1d, 0x01, + 0x33, 0x35, 0x3b, 0x01, 0x15, 0x33, 0x15, 0x3b, 0x01, 0x35, 0x33, 0x3d, + 0x01, 0x33, 0x1d, 0x04, 0x23, 0x15, 0x23, 0x15, 0x25, 0x35, 0x23, 0x15, + 0x01, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, 0x2b, 0x04, 0x35, + 0x3b, 0x04, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xfe, 0xe9, + 0x5d, 0x01, 0xd0, 0x5c, 0x5c, 0xfd, 0x77, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, + 0xfd, 0xd3, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0xba, 0x5c, 0x5c, 0x01, 0xd0, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x2b, + 0x00, 0x2f, 0x00, 0x3b, 0x00, 0x43, 0x00, 0x47, 0x00, 0x4b, 0x00, 0x57, + 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x01, 0x33, + 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x03, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, + 0x33, 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x2b, 0x01, 0x35, 0x33, 0x05, + 0x35, 0x33, 0x15, 0x2b, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x21, 0x2b, + 0x02, 0x35, 0x3b, 0x02, 0x13, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, + 0x25, 0x2b, 0x04, 0x35, 0x3b, 0x04, 0x02, 0x2d, 0x5d, 0xfe, 0x30, 0x5c, + 0x01, 0x17, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xba, + 0x5c, 0xfd, 0xd4, 0x5d, 0x5d, 0x02, 0x2c, 0x5d, 0xb9, 0x5d, 0x5d, 0xfe, + 0x30, 0x5c, 0xb9, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5c, 0xfd, 0x77, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, + 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x17, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, + 0x00, 0x27, 0x00, 0x2f, 0x00, 0x3b, 0x00, 0x3f, 0x00, 0x43, 0x00, 0x47, + 0x00, 0x4b, 0x00, 0x57, 0x00, 0x00, 0x01, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x01, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x03, 0x35, 0x33, + 0x15, 0x21, 0x23, 0x35, 0x33, 0x21, 0x3d, 0x04, 0x33, 0x1d, 0x04, 0x25, + 0x33, 0x15, 0x2b, 0x02, 0x35, 0x33, 0x05, 0x23, 0x3d, 0x04, 0x33, 0x1d, + 0x03, 0x21, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x01, 0x23, 0x35, + 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, 0x2b, 0x04, 0x35, 0x3b, 0x04, 0x02, + 0x2d, 0x5d, 0xfe, 0x30, 0x5c, 0x01, 0x17, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, 0xfd, 0xd4, 0x5d, 0x5d, 0x02, 0x2c, + 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, + 0x01, 0xd0, 0x5d, 0xfe, 0x8c, 0x5c, 0x5c, 0x01, 0xd0, 0x5c, 0x5c, 0xfd, + 0x77, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x17, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x03, 0x44, 0x00, 0x23, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x37, 0x00, 0x3b, + 0x00, 0x00, 0x21, 0x2b, 0x03, 0x35, 0x23, 0x35, 0x23, 0x3d, 0x04, 0x33, + 0x35, 0x33, 0x35, 0x3b, 0x04, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x04, 0x23, + 0x15, 0x23, 0x15, 0x27, 0x33, 0x35, 0x2b, 0x02, 0x35, 0x23, 0x15, 0x33, + 0x15, 0x33, 0x25, 0x35, 0x23, 0x15, 0x37, 0x35, 0x23, 0x15, 0x21, 0x35, + 0x23, 0x15, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x01, 0x17, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xba, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x10, 0x00, 0x00, + 0xff, 0xa3, 0x03, 0xfd, 0x03, 0xa0, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x2f, 0x00, 0x3b, + 0x00, 0x3f, 0x00, 0x43, 0x00, 0x47, 0x00, 0x53, 0x00, 0x57, 0x00, 0x5b, + 0x00, 0x5f, 0x00, 0x00, 0x05, 0x3d, 0x01, 0x23, 0x35, 0x3b, 0x02, 0x15, + 0x23, 0x1d, 0x01, 0x25, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, 0x25, + 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, 0x23, 0x35, 0x33, 0x05, + 0x23, 0x35, 0x33, 0x21, 0x3d, 0x02, 0x33, 0x15, 0x3b, 0x01, 0x15, 0x2b, + 0x01, 0x15, 0x21, 0x23, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x33, + 0x1d, 0x01, 0x25, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, 0x35, + 0x33, 0x15, 0x2b, 0x03, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x33, + 0x05, 0x23, 0x35, 0x33, 0x21, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, + 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0xfc, 0xbd, + 0x5d, 0x02, 0x89, 0x5d, 0x5d, 0xfd, 0x77, 0x5c, 0x01, 0xd0, 0x5c, 0x5c, + 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, + 0xd3, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0x5c, 0xfe, + 0x30, 0x5d, 0x01, 0x73, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0xfe, 0x8c, 0x5c, 0x5c, 0x02, 0x2d, 0x5d, 0xfd, 0x1a, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, + 0x03, 0x44, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x00, + 0x33, 0x3d, 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x23, 0x35, 0x3b, + 0x02, 0x15, 0x23, 0x15, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x1d, 0x01, 0x13, + 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, + 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, + 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8a, 0x03, 0x44, 0x00, 0x35, + 0x00, 0x00, 0x01, 0x3d, 0x01, 0x23, 0x1d, 0x01, 0x23, 0x15, 0x33, 0x1d, + 0x02, 0x23, 0x3d, 0x02, 0x2b, 0x02, 0x1d, 0x02, 0x3b, 0x02, 0x15, 0x2b, + 0x02, 0x35, 0x23, 0x3d, 0x02, 0x33, 0x35, 0x3b, 0x02, 0x3d, 0x01, 0x33, + 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x03, 0x1d, 0x03, 0x02, 0x2d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, + 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x11, 0x00, 0x15, 0x00, 0x19, + 0x00, 0x21, 0x00, 0x29, 0x00, 0x31, 0x00, 0x39, 0x00, 0x00, 0x21, 0x3d, + 0x07, 0x33, 0x1d, 0x07, 0x13, 0x35, 0x33, 0x15, 0x21, 0x35, 0x33, 0x15, + 0x25, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, 0x33, 0x1d, + 0x01, 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x05, 0x2b, 0x02, 0x35, 0x3b, + 0x02, 0x01, 0x73, 0x5d, 0xba, 0x5c, 0xfd, 0x77, 0x5d, 0x02, 0x2c, 0x5d, + 0xfd, 0x1a, 0x5d, 0x5d, 0x02, 0x89, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0xfe, 0x8d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x03, 0xa0, 0x03, 0x44, 0x00, 0x05, + 0x00, 0x09, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, + 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x37, 0x00, 0x3d, + 0x00, 0x43, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x35, + 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, + 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x25, 0x23, 0x35, 0x33, 0x05, 0x35, + 0x33, 0x15, 0x37, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x31, 0x35, 0x33, 0x15, + 0x21, 0x23, 0x35, 0x33, 0x21, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, + 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0xfe, 0xe9, 0x5d, 0x5d, 0x01, + 0x17, 0x5c, 0xfe, 0x30, 0x5c, 0x5c, 0x01, 0x74, 0x5d, 0x5d, 0xfe, 0x8c, + 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, 0x5d, 0x5d, 0x01, + 0x17, 0x5c, 0xfe, 0x30, 0x5c, 0x5c, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, 0xfd, + 0xd4, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0xa0, 0x03, 0x44, 0x00, 0x05, + 0x00, 0x0b, 0x00, 0x29, 0x00, 0x37, 0x00, 0x3d, 0x00, 0x43, 0x00, 0x00, + 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x21, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x21, 0x2b, 0x05, 0x35, 0x33, 0x3d, 0x04, 0x23, 0x35, 0x3b, 0x05, 0x15, + 0x23, 0x1d, 0x04, 0x33, 0x21, 0x33, 0x3d, 0x04, 0x2b, 0x01, 0x1d, 0x04, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0xfd, 0x77, 0x5d, 0x5d, 0x5d, 0x02, 0xe6, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5c, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, + 0x5d, 0x5d, 0xfd, 0xd4, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x02, 0x89, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xfd, 0x03, 0x44, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x15, + 0x00, 0x1b, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x31, 0x00, 0x37, + 0x00, 0x3d, 0x00, 0x43, 0x00, 0x49, 0x00, 0x4f, 0x00, 0x5b, 0x00, 0x00, + 0x01, 0x35, 0x33, 0x15, 0x01, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x02, + 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, + 0x05, 0x23, 0x35, 0x33, 0x25, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x21, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, + 0x3d, 0x01, 0x33, 0x15, 0x25, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x05, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x21, 0x2b, 0x04, 0x35, 0x3b, 0x04, 0x03, 0xa0, + 0x5d, 0xfe, 0x8d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0xfe, 0x30, 0x5c, 0x5d, 0x5d, 0x5c, 0x02, + 0x8a, 0x5d, 0xfe, 0xe9, 0x5c, 0x5c, 0xfd, 0x77, 0x5d, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x1a, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0x5d, 0xfd, 0x76, 0x5c, + 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x02, 0x2d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0xff, 0x46, 0x03, 0x44, 0x03, 0x44, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x15, + 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00, 0x33, 0x00, 0x3f, 0x00, 0x43, + 0x00, 0x47, 0x00, 0x4d, 0x00, 0x00, 0x05, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x31, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x25, 0x33, 0x15, 0x2b, 0x02, + 0x35, 0x3b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, + 0x33, 0x1d, 0x01, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x3d, 0x03, 0x33, + 0x1d, 0x02, 0x21, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x33, 0x1d, + 0x01, 0x25, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x37, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x02, 0xe6, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xfe, 0x8c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0xb9, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x02, + 0x2d, 0x5c, 0x5d, 0xfe, 0x30, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, + 0x73, 0x5c, 0x5c, 0xfe, 0x8d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5c, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x0a, 0x00, 0x00, + 0xff, 0x46, 0x05, 0x14, 0x03, 0x44, 0x00, 0x1b, 0x00, 0x2d, 0x00, 0x3f, + 0x00, 0x43, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x00, 0x63, 0x00, 0x6b, + 0x00, 0x6f, 0x00, 0x00, 0x05, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x3d, + 0x07, 0x33, 0x1d, 0x06, 0x33, 0x15, 0x23, 0x1d, 0x01, 0x25, 0x3d, 0x07, + 0x33, 0x1d, 0x07, 0x21, 0x3d, 0x07, 0x33, 0x1d, 0x07, 0x25, 0x35, 0x33, + 0x15, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x3d, 0x04, 0x33, 0x1d, 0x03, 0x03, + 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x05, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x05, + 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x05, 0x23, 0x35, 0x33, 0x03, 0x43, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0xfe, 0x30, 0x5d, + 0x03, 0x43, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0xfe, 0x8d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xb9, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfd, + 0x03, 0x44, 0x00, 0x17, 0x00, 0x25, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x43, + 0x00, 0x47, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, + 0x0a, 0x35, 0x3b, 0x08, 0x37, 0x33, 0x15, 0x2b, 0x04, 0x35, 0x33, 0x35, + 0x33, 0x15, 0x33, 0x05, 0x2b, 0x03, 0x35, 0x3b, 0x02, 0x35, 0x33, 0x15, + 0x33, 0x15, 0x25, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, + 0x33, 0x1d, 0x01, 0x25, 0x23, 0x35, 0x33, 0x05, 0x35, 0x33, 0x15, 0x25, + 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x03, 0xa0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0xfe, 0x30, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x01, 0x16, 0x5d, 0xfd, 0xd3, 0x5c, 0x5c, 0x01, 0xd0, 0x5c, 0x5c, + 0xfe, 0x30, 0x5d, 0x01, 0x17, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0xb9, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0xba, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x08, 0x00, 0x00, + 0xff, 0xa3, 0x05, 0x14, 0x03, 0x44, 0x00, 0x11, 0x00, 0x23, 0x00, 0x29, + 0x00, 0x37, 0x00, 0x49, 0x00, 0x51, 0x00, 0x59, 0x00, 0x5d, 0x00, 0x00, + 0x21, 0x3d, 0x07, 0x33, 0x1d, 0x07, 0x21, 0x3d, 0x07, 0x33, 0x1d, 0x07, + 0x21, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x33, 0x3d, 0x01, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x07, + 0x33, 0x1d, 0x06, 0x03, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x05, 0x2b, 0x02, + 0x35, 0x3b, 0x02, 0x05, 0x23, 0x35, 0x33, 0x01, 0xd0, 0x5d, 0xfe, 0x30, + 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, + 0x8d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x02, 0x89, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x03, 0x44, 0x00, 0x03, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x00, + 0x31, 0x35, 0x33, 0x15, 0x01, 0x35, 0x33, 0x15, 0x37, 0x3d, 0x01, 0x23, + 0x15, 0x23, 0x15, 0x23, 0x15, 0x23, 0x15, 0x23, 0x15, 0x23, 0x15, 0x23, + 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, + 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x03, 0x1d, 0x03, 0x21, 0x23, 0x35, 0x33, + 0x5d, 0x01, 0x73, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0xba, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x0f, 0x00, 0x00, + 0xff, 0x46, 0x04, 0xb7, 0x03, 0x44, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x11, + 0x00, 0x15, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x37, + 0x00, 0x3f, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x5f, + 0x00, 0x00, 0x21, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x05, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x07, 0x35, 0x33, 0x15, + 0x25, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, + 0x37, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x05, 0x23, 0x3d, 0x02, 0x33, 0x1d, + 0x01, 0x05, 0x3d, 0x02, 0x33, 0x1d, 0x02, 0x2b, 0x01, 0x3d, 0x02, 0x33, + 0x1d, 0x01, 0x25, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x05, 0x3d, 0x02, + 0x33, 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x25, 0x23, + 0x35, 0x33, 0x05, 0x23, 0x35, 0x33, 0x01, 0x16, 0x5d, 0x01, 0x17, 0x5c, + 0x5c, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x01, 0x17, 0x5c, + 0xfe, 0xea, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0xe9, 0x5d, + 0x5d, 0xfe, 0x30, 0x5d, 0xba, 0x5c, 0x5c, 0x01, 0xd0, 0x5c, 0x5c, 0xfe, + 0xea, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0xfd, 0xd3, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x5c, 0x03, 0xa0, 0x02, 0x8a, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0d, + 0x00, 0x13, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x29, 0x00, 0x2f, + 0x00, 0x33, 0x00, 0x39, 0x00, 0x3f, 0x00, 0x00, 0x3d, 0x01, 0x33, 0x15, + 0x03, 0x35, 0x33, 0x15, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x21, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x21, 0x35, 0x33, 0x15, 0x21, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x01, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x21, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x21, 0x35, 0x33, 0x15, + 0x21, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x05, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x5d, 0x5d, 0x5d, 0x02, 0x89, 0x5d, 0x5d, 0x5c, 0xfe, 0xe9, 0x5d, 0x5d, + 0x5d, 0x02, 0x2d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, 0x8c, + 0x5c, 0x5d, 0x5d, 0x5c, 0x01, 0xd0, 0x5d, 0x5d, 0x5c, 0xfe, 0xe9, 0x5d, + 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0xfe, + 0x8c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x01, 0x73, 0x5d, 0x5d, + 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x01, + 0x17, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe7, 0x03, 0x44, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x39, + 0x00, 0x3d, 0x00, 0x41, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x21, 0x35, + 0x33, 0x15, 0x25, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x05, 0x3d, 0x01, 0x33, + 0x1d, 0x01, 0x25, 0x23, 0x35, 0x2b, 0x01, 0x15, 0x23, 0x35, 0x2b, 0x01, + 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x3b, + 0x01, 0x15, 0x2b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x21, 0x23, 0x3d, + 0x01, 0x33, 0x15, 0x25, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x02, + 0x8a, 0x5c, 0xfd, 0x1a, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, 0xfd, 0xd3, 0x5d, + 0x01, 0x73, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0xfe, 0x30, 0x5d, 0x5d, 0x01, + 0xd0, 0x5c, 0xfd, 0x77, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x2f, 0x00, 0x00, 0x25, 0x33, + 0x15, 0x2b, 0x04, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x23, 0x15, 0x2b, 0x01, + 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, + 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x01, 0x23, + 0x15, 0x2b, 0x01, 0x35, 0x23, 0x1d, 0x01, 0x02, 0x2d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, 0x02, 0xe7, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1b, + 0x00, 0x1f, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x37, 0x00, 0x3f, 0x00, 0x00, + 0x21, 0x35, 0x33, 0x15, 0x03, 0x35, 0x33, 0x15, 0x11, 0x35, 0x33, 0x15, + 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, + 0x21, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x21, 0x3d, 0x02, 0x33, + 0x1d, 0x02, 0x21, 0x23, 0x3d, 0x02, 0x33, 0x1d, 0x01, 0x25, 0x2b, 0x02, + 0x35, 0x3b, 0x02, 0x05, 0x2b, 0x02, 0x35, 0x3b, 0x02, 0x01, 0x73, 0x5d, + 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0xba, 0x5d, 0xfe, 0x8c, 0x5c, 0x5c, + 0x01, 0x74, 0x5c, 0xfd, 0xd4, 0x5d, 0x5d, 0x02, 0x2c, 0x5d, 0xfd, 0x1a, + 0x5d, 0x5d, 0x02, 0x89, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xfe, 0x8d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x02, 0x2d, 0x5d, 0x5d, + 0xfe, 0x30, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5c, + 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe7, + 0x03, 0x44, 0x00, 0x29, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x05, 0x35, + 0x3b, 0x01, 0x35, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, + 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x15, 0x33, 0x1d, 0x01, 0x33, 0x15, + 0x33, 0x1d, 0x01, 0x23, 0x15, 0x2b, 0x01, 0x15, 0x02, 0x2d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x02, 0xe7, 0x00, 0x23, 0x00, 0x00, 0x21, 0x35, 0x23, 0x35, 0x23, 0x35, + 0x23, 0x35, 0x23, 0x3d, 0x02, 0x33, 0x35, 0x3b, 0x02, 0x15, 0x33, 0x35, + 0x3b, 0x02, 0x15, 0x33, 0x1d, 0x02, 0x23, 0x15, 0x23, 0x15, 0x23, 0x15, + 0x23, 0x15, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x03, 0x44, 0x00, 0x23, 0x00, 0x00, 0x21, 0x35, 0x23, 0x35, 0x23, 0x35, + 0x23, 0x35, 0x23, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, 0x33, 0x35, + 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, + 0x23, 0x15, 0x23, 0x15, 0x23, 0x15, 0x01, 0x73, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd0, 0x02, 0xe7, 0x00, 0x1d, 0x00, 0x00, 0x01, 0x3d, + 0x01, 0x23, 0x1d, 0x03, 0x23, 0x15, 0x2b, 0x01, 0x3d, 0x01, 0x3b, 0x01, + 0x3d, 0x05, 0x33, 0x15, 0x33, 0x15, 0x33, 0x1d, 0x02, 0x01, 0x73, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x8a, 0x02, 0xe7, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x23, + 0x3d, 0x01, 0x3b, 0x01, 0x3d, 0x03, 0x2b, 0x02, 0x1d, 0x04, 0x23, 0x15, + 0x2b, 0x01, 0x3d, 0x01, 0x3b, 0x01, 0x3d, 0x05, 0x3b, 0x04, 0x1d, 0x06, + 0x23, 0x15, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfd, + 0x03, 0x44, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x19, + 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x4b, 0x00, 0x51, 0x00, 0x55, + 0x00, 0x59, 0x00, 0x5f, 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x05, 0x35, 0x33, 0x15, 0x21, 0x23, + 0x35, 0x33, 0x21, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x05, 0x2b, 0x01, 0x35, + 0x33, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, 0x23, 0x35, 0x3b, 0x01, + 0x15, 0x33, 0x15, 0x33, 0x35, 0x3b, 0x01, 0x15, 0x33, 0x15, 0x23, 0x15, + 0x2b, 0x01, 0x35, 0x23, 0x15, 0x23, 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x05, 0x35, 0x23, 0x15, 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x25, 0x33, + 0x15, 0x2b, 0x01, 0x35, 0x05, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x3b, + 0x01, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0xba, 0x5c, 0x5c, 0x5d, 0x03, 0x43, + 0x5d, 0x5d, 0x5d, 0xfd, 0xd3, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x02, 0xe6, + 0x5d, 0x5c, 0x5c, 0x5d, 0xfd, 0xd3, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x02, 0x8a, 0x5d, 0x5d, 0x5d, 0xfd, 0xd3, 0x5c, 0x02, 0x2c, + 0x5d, 0x5d, 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0xfd, 0xd3, 0x5d, 0xfe, + 0xea, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x01, 0x17, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfd, + 0x03, 0x44, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x19, + 0x00, 0x39, 0x00, 0x3f, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x53, + 0x00, 0x00, 0x37, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x25, 0x33, 0x15, 0x2b, + 0x01, 0x35, 0x05, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x21, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x05, 0x2b, 0x01, 0x35, 0x33, 0x35, 0x33, 0x35, + 0x23, 0x35, 0x23, 0x35, 0x3b, 0x01, 0x15, 0x33, 0x15, 0x33, 0x35, 0x3b, + 0x01, 0x15, 0x23, 0x15, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x23, 0x15, 0x23, + 0x01, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x25, 0x33, 0x15, 0x2b, 0x01, 0x35, + 0x05, 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x3b, 0x01, 0x2b, 0x01, 0x35, + 0x3b, 0x01, 0xba, 0x5c, 0x5c, 0x5d, 0x03, 0x43, 0x5d, 0x5d, 0x5d, 0xfd, + 0xd3, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x02, 0xe6, 0x5d, 0x5c, 0x5c, 0x5d, + 0xfd, 0xd3, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, + 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0xfd, 0xd3, 0x5d, 0xfe, 0xea, 0x5d, + 0x5d, 0xb9, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x74, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xa0, 0x03, 0x44, 0x00, 0x33, 0x00, 0x00, 0x21, 0x23, + 0x35, 0x33, 0x3d, 0x01, 0x33, 0x35, 0x2b, 0x02, 0x15, 0x2b, 0x01, 0x35, + 0x33, 0x35, 0x23, 0x35, 0x3b, 0x01, 0x15, 0x3b, 0x02, 0x35, 0x23, 0x3d, + 0x01, 0x23, 0x35, 0x3b, 0x01, 0x15, 0x33, 0x1d, 0x01, 0x33, 0x15, 0x3b, + 0x02, 0x15, 0x2b, 0x02, 0x15, 0x23, 0x1d, 0x01, 0x23, 0x15, 0x01, 0x73, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5c, 0x03, 0xa0, + 0x02, 0xe7, 0x00, 0x21, 0x00, 0x51, 0x00, 0x00, 0x25, 0x2b, 0x08, 0x3d, + 0x06, 0x3b, 0x09, 0x1d, 0x06, 0x27, 0x33, 0x3d, 0x03, 0x23, 0x15, 0x23, + 0x15, 0x23, 0x35, 0x33, 0x35, 0x33, 0x35, 0x2b, 0x05, 0x15, 0x33, 0x15, + 0x33, 0x15, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x35, 0x23, 0x35, 0x23, 0x35, + 0x23, 0x1d, 0x03, 0x3b, 0x05, 0x03, 0x43, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x5d, 0xba, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xe7, 0x03, 0x44, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x11, + 0x00, 0x33, 0x00, 0x39, 0x00, 0x45, 0x00, 0x4b, 0x00, 0x51, 0x00, 0x55, + 0x00, 0x59, 0x00, 0x00, 0x25, 0x33, 0x15, 0x2b, 0x03, 0x35, 0x3b, 0x02, + 0x35, 0x33, 0x15, 0x21, 0x23, 0x35, 0x33, 0x21, 0x3d, 0x01, 0x2b, 0x01, + 0x15, 0x33, 0x15, 0x2b, 0x01, 0x35, 0x23, 0x15, 0x23, 0x35, 0x33, 0x35, + 0x33, 0x3d, 0x01, 0x33, 0x15, 0x3b, 0x01, 0x3d, 0x02, 0x33, 0x1d, 0x05, + 0x21, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x37, 0x2b, 0x01, 0x3d, 0x03, 0x33, + 0x1d, 0x02, 0x33, 0x37, 0x3d, 0x01, 0x33, 0x1d, 0x01, 0x2b, 0x01, 0x3d, + 0x01, 0x33, 0x15, 0x25, 0x23, 0x35, 0x33, 0x05, 0x23, 0x35, 0x33, 0x01, + 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0xba, 0x5d, 0xfe, 0x30, + 0x5d, 0x5d, 0x01, 0xd0, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0xfd, 0x77, 0x5d, 0x5d, 0xb9, 0x5c, 0x5d, + 0x5d, 0x5c, 0xba, 0x5d, 0xba, 0x5d, 0x5d, 0x01, 0x17, 0x5d, 0x5d, 0xfe, + 0x8c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5c, 0x03, 0xfd, + 0x03, 0x44, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x27, 0x00, 0x4f, + 0x00, 0x00, 0x25, 0x2b, 0x02, 0x35, 0x3b, 0x01, 0x35, 0x33, 0x35, 0x33, + 0x1d, 0x02, 0x25, 0x2b, 0x01, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x35, + 0x3b, 0x01, 0x15, 0x23, 0x15, 0x33, 0x25, 0x23, 0x35, 0x33, 0x05, 0x2b, + 0x01, 0x35, 0x3b, 0x01, 0x21, 0x2b, 0x01, 0x35, 0x2b, 0x01, 0x35, 0x2b, + 0x01, 0x35, 0x23, 0x15, 0x33, 0x15, 0x3b, 0x01, 0x15, 0x2b, 0x01, 0x35, + 0x2b, 0x01, 0x15, 0x23, 0x3d, 0x01, 0x33, 0x35, 0x33, 0x35, 0x3b, 0x01, + 0x15, 0x3b, 0x01, 0x15, 0x3b, 0x01, 0x15, 0x33, 0x03, 0xa0, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0xfd, 0x76, 0x5c, + 0x5d, 0x5d, 0x5c, 0x02, 0x2d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5c, 0x03, 0xfd, + 0x03, 0x44, 0x00, 0x15, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x41, + 0x00, 0x4f, 0x00, 0x00, 0x25, 0x23, 0x35, 0x33, 0x35, 0x3b, 0x01, 0x35, + 0x3b, 0x01, 0x35, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x2b, 0x01, 0x15, 0x2b, + 0x01, 0x15, 0x27, 0x23, 0x35, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x3b, 0x01, + 0x15, 0x23, 0x25, 0x2b, 0x01, 0x35, 0x3b, 0x01, 0x21, 0x35, 0x33, 0x15, + 0x21, 0x2b, 0x01, 0x35, 0x2b, 0x01, 0x15, 0x2b, 0x01, 0x35, 0x3b, 0x01, + 0x35, 0x3b, 0x01, 0x35, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x33, 0x21, 0x35, + 0x23, 0x35, 0x2b, 0x01, 0x35, 0x3b, 0x03, 0x1d, 0x02, 0x01, 0x16, 0x5c, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0xb9, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x01, 0x16, 0x5d, 0x5d, 0x5d, + 0x5d, 0x01, 0x73, 0x5d, 0xfe, 0xea, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0xa3, 0x02, 0xe7, + 0x03, 0x44, 0x00, 0x23, 0x00, 0x3b, 0x00, 0x00, 0x05, 0x2b, 0x01, 0x35, + 0x23, 0x3d, 0x02, 0x23, 0x35, 0x23, 0x3d, 0x02, 0x3b, 0x01, 0x3d, 0x01, + 0x3b, 0x02, 0x1d, 0x01, 0x3b, 0x01, 0x15, 0x33, 0x1d, 0x02, 0x2b, 0x01, + 0x1d, 0x03, 0x27, 0x3d, 0x03, 0x3b, 0x01, 0x35, 0x2b, 0x01, 0x3d, 0x01, + 0x23, 0x1d, 0x01, 0x2b, 0x01, 0x15, 0x3b, 0x01, 0x1d, 0x03, 0x01, 0xd0, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5d, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0xba, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x44, + 0x03, 0xa0, 0x00, 0x03, 0x00, 0x23, 0x00, 0x29, 0x00, 0x2f, 0x00, 0x4f, + 0x00, 0x53, 0x00, 0x00, 0x21, 0x35, 0x33, 0x15, 0x3d, 0x01, 0x23, 0x15, + 0x23, 0x35, 0x2b, 0x02, 0x3d, 0x01, 0x33, 0x15, 0x33, 0x35, 0x33, 0x15, + 0x3b, 0x02, 0x35, 0x33, 0x15, 0x33, 0x35, 0x33, 0x1d, 0x01, 0x2b, 0x02, + 0x15, 0x13, 0x23, 0x3d, 0x01, 0x33, 0x15, 0x05, 0x23, 0x3d, 0x01, 0x33, + 0x15, 0x25, 0x35, 0x23, 0x15, 0x23, 0x35, 0x2b, 0x02, 0x15, 0x23, 0x35, + 0x23, 0x15, 0x23, 0x3d, 0x01, 0x3b, 0x02, 0x35, 0x33, 0x15, 0x33, 0x35, + 0x33, 0x15, 0x3b, 0x02, 0x1d, 0x01, 0x01, 0x23, 0x35, 0x33, 0x01, 0x73, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0x5d, 0xb9, 0x5c, 0x5c, 0xfd, 0xd4, 0x5d, + 0x5d, 0x02, 0x2c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0xfe, 0x8d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x01, 0x16, 0x5d, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x44, 0x03, 0x44, 0x00, 0x25, 0x00, 0x31, 0x00, 0x00, + 0x21, 0x23, 0x35, 0x23, 0x15, 0x2b, 0x01, 0x35, 0x23, 0x3d, 0x02, 0x23, + 0x3d, 0x01, 0x33, 0x35, 0x3b, 0x01, 0x3d, 0x01, 0x3b, 0x02, 0x1d, 0x01, + 0x3b, 0x01, 0x15, 0x33, 0x1d, 0x01, 0x23, 0x1d, 0x02, 0x23, 0x15, 0x03, + 0x35, 0x33, 0x35, 0x23, 0x35, 0x23, 0x15, 0x23, 0x15, 0x33, 0x15, 0x02, + 0x2d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5c, 0xba, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, + 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5d, 0x01, 0x16, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xae, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x32, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x50, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x15, 0x00, 0x83, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0f, 0x00, 0xb9, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0xeb, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x01, 0x1c, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x42, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x2a, 0x00, 0x57, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x99, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x20, 0x00, 0xc9, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x1e, 0x00, 0xfc, 0x00, 0x4f, + 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6b, 0x00, 0x00, 0x4f, 0x6f, + 0x6d, 0x65, 0x6b, 0x00, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, + 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x4d, 0x00, 0x6f, 0x00, 0x64, + 0x00, 0x65, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x73, 0x00, 0x00, + 0x41, 0x74, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x50, + 0x6c, 0x75, 0x73, 0x00, 0x00, 0x4d, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, + 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x4d, 0x65, 0x64, 0x69, 0x75, 0x6d, + 0x00, 0x00, 0x4f, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6b, 0x00, + 0x3a, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, + 0x63, 0x00, 0x74, 0x00, 0x4d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x50, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x73, 0x00, 0x00, 0x4f, 0x6f, 0x6d, + 0x65, 0x6b, 0x3a, 0x41, 0x74, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4d, 0x6f, + 0x64, 0x65, 0x50, 0x6c, 0x75, 0x73, 0x00, 0x00, 0x41, 0x00, 0x74, 0x00, + 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x4d, 0x00, + 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x75, 0x00, + 0x73, 0x00, 0x00, 0x41, 0x74, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4d, 0x6f, + 0x64, 0x65, 0x50, 0x6c, 0x75, 0x73, 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, + 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, + 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, + 0x30, 0x00, 0x20, 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x30, 0x30, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x20, 0x00, 0x00, 0x41, + 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, + 0x00, 0x4d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x50, 0x00, 0x6c, + 0x00, 0x75, 0x00, 0x73, 0x00, 0x00, 0x41, 0x74, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x50, 0x6c, 0x75, 0x73, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, + 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, + 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, + 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, + 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, + 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2a, + 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2f, 0x00, 0x30, + 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, + 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, + 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, + 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, + 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, + 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, + 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, + 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x60, + 0x00, 0x61, 0x01, 0x02, 0x00, 0xa3, 0x00, 0x84, 0x00, 0x85, 0x00, 0xbd, + 0x00, 0x96, 0x00, 0xe8, 0x00, 0x86, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x9d, + 0x00, 0xa9, 0x00, 0xa4, 0x00, 0x8a, 0x00, 0xda, 0x00, 0x83, 0x00, 0x93, + 0x01, 0x03, 0x01, 0x04, 0x00, 0x8d, 0x01, 0x05, 0x00, 0x88, 0x00, 0xc3, + 0x00, 0xde, 0x01, 0x06, 0x00, 0x9e, 0x00, 0xaa, 0x00, 0xf5, 0x00, 0xf4, + 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xae, + 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, 0x00, 0x64, 0x00, 0xcb, 0x00, 0x65, + 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, + 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xaf, + 0x00, 0x67, 0x00, 0xf0, 0x00, 0x91, 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, + 0x00, 0x68, 0x00, 0xeb, 0x00, 0xed, 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, + 0x00, 0x6b, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, + 0x00, 0x71, 0x00, 0x70, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, + 0x00, 0x76, 0x00, 0x77, 0x00, 0xea, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, + 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0xb8, 0x00, 0xa1, 0x00, 0x7f, + 0x00, 0x7e, 0x00, 0x80, 0x00, 0x81, 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, + 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, + 0x00, 0xfd, 0x00, 0xfe, 0x01, 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01, 0x10, + 0x00, 0xff, 0x01, 0x00, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x01, + 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x01, 0x18, 0x01, 0x19, + 0x01, 0x1a, 0x01, 0x1b, 0x01, 0x1c, 0x01, 0x1d, 0x01, 0x1e, 0x01, 0x1f, + 0x00, 0xf8, 0x00, 0xf9, 0x01, 0x20, 0x01, 0x21, 0x01, 0x22, 0x01, 0x23, + 0x01, 0x24, 0x01, 0x25, 0x01, 0x26, 0x01, 0x27, 0x01, 0x28, 0x01, 0x29, + 0x01, 0x2a, 0x01, 0x2b, 0x01, 0x2c, 0x01, 0x2d, 0x01, 0x2e, 0x01, 0x2f, + 0x00, 0xfa, 0x00, 0xd7, 0x01, 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x33, + 0x01, 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37, 0x01, 0x38, 0x01, 0x39, + 0x01, 0x3a, 0x01, 0x3b, 0x01, 0x3c, 0x01, 0x3d, 0x01, 0x3e, 0x00, 0xe2, + 0x00, 0xe3, 0x01, 0x3f, 0x01, 0x40, 0x01, 0x41, 0x01, 0x42, 0x01, 0x43, + 0x01, 0x44, 0x01, 0x45, 0x01, 0x46, 0x01, 0x47, 0x01, 0x48, 0x01, 0x49, + 0x01, 0x4a, 0x01, 0x4b, 0x01, 0x4c, 0x01, 0x4d, 0x00, 0xb0, 0x00, 0xb1, + 0x01, 0x4e, 0x01, 0x4f, 0x01, 0x50, 0x01, 0x51, 0x01, 0x52, 0x01, 0x53, + 0x01, 0x54, 0x01, 0x55, 0x01, 0x56, 0x01, 0x57, 0x00, 0xfb, 0x00, 0xfc, + 0x00, 0xe4, 0x00, 0xe5, 0x01, 0x58, 0x01, 0x59, 0x01, 0x5a, 0x01, 0x5b, + 0x01, 0x5c, 0x01, 0x5d, 0x01, 0x5e, 0x01, 0x5f, 0x01, 0x60, 0x01, 0x61, + 0x01, 0x62, 0x01, 0x63, 0x01, 0x64, 0x01, 0x65, 0x01, 0x66, 0x01, 0x67, + 0x01, 0x68, 0x01, 0x69, 0x01, 0x6a, 0x01, 0x6b, 0x01, 0x6c, 0x01, 0x6d, + 0x00, 0xbb, 0x01, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x71, 0x00, 0xe6, + 0x00, 0xe7, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb4, 0x00, 0xb5, 0x00, 0x87, + 0x00, 0xab, 0x01, 0x72, 0x01, 0x73, 0x01, 0x74, 0x01, 0x75, 0x00, 0x8c, + 0x01, 0x76, 0x01, 0x77, 0x01, 0x78, 0x01, 0x79, 0x00, 0x92, 0x01, 0x7a, + 0x01, 0x7b, 0x01, 0x7c, 0x01, 0x7d, 0x01, 0x7e, 0x01, 0x7f, 0x01, 0x80, + 0x01, 0x81, 0x01, 0x82, 0x01, 0x83, 0x01, 0x84, 0x01, 0x85, 0x01, 0x86, + 0x01, 0x87, 0x01, 0x88, 0x01, 0x89, 0x01, 0x8a, 0x01, 0x8b, 0x01, 0x8c, + 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x8f, 0x01, 0x90, 0x01, 0x91, 0x01, 0x92, + 0x01, 0x93, 0x01, 0x94, 0x01, 0x95, 0x01, 0x96, 0x01, 0x97, 0x01, 0x98, + 0x01, 0x99, 0x01, 0x9a, 0x01, 0x9b, 0x01, 0x9c, 0x01, 0x9d, 0x01, 0x9e, + 0x01, 0x9f, 0x01, 0xa0, 0x01, 0xa1, 0x01, 0xa2, 0x01, 0xa3, 0x01, 0xa4, + 0x01, 0xa5, 0x01, 0xa6, 0x01, 0xa7, 0x01, 0xa8, 0x01, 0xa9, 0x07, 0x75, + 0x6e, 0x69, 0x30, 0x30, 0x41, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, + 0x42, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 0x42, 0x33, 0x07, 0x75, + 0x6e, 0x69, 0x30, 0x30, 0x42, 0x35, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, + 0x42, 0x39, 0x07, 0x41, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x61, + 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x41, 0x62, 0x72, 0x65, 0x76, + 0x65, 0x06, 0x61, 0x62, 0x72, 0x65, 0x76, 0x65, 0x07, 0x41, 0x6f, 0x67, + 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x61, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, + 0x0b, 0x43, 0x63, 0x69, 0x72, 0x63, 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, + 0x0b, 0x63, 0x63, 0x69, 0x72, 0x63, 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, + 0x0a, 0x43, 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, + 0x63, 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x44, + 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x64, 0x63, 0x61, 0x72, 0x6f, 0x6e, + 0x06, 0x44, 0x63, 0x72, 0x6f, 0x61, 0x74, 0x07, 0x45, 0x6d, 0x61, 0x63, + 0x72, 0x6f, 0x6e, 0x07, 0x65, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, + 0x45, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06, 0x65, 0x62, 0x72, 0x65, 0x76, + 0x65, 0x0a, 0x45, 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, + 0x0a, 0x65, 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, + 0x45, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x65, 0x6f, 0x67, 0x6f, + 0x6e, 0x65, 0x6b, 0x06, 0x45, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x65, + 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0b, 0x47, 0x63, 0x69, 0x72, 0x63, 0x75, + 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0b, 0x67, 0x63, 0x69, 0x72, 0x63, 0x75, + 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0a, 0x47, 0x64, 0x6f, 0x74, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x67, 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, + 0x65, 0x6e, 0x74, 0x0c, 0x47, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x67, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, + 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0b, 0x48, 0x63, 0x69, 0x72, 0x63, 0x75, + 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0b, 0x68, 0x63, 0x69, 0x72, 0x63, 0x75, + 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x04, 0x48, 0x62, 0x61, 0x72, 0x04, 0x68, + 0x62, 0x61, 0x72, 0x06, 0x49, 0x74, 0x69, 0x6c, 0x64, 0x65, 0x06, 0x69, + 0x74, 0x69, 0x6c, 0x64, 0x65, 0x07, 0x49, 0x6d, 0x61, 0x63, 0x72, 0x6f, + 0x6e, 0x07, 0x69, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x49, 0x62, + 0x72, 0x65, 0x76, 0x65, 0x06, 0x69, 0x62, 0x72, 0x65, 0x76, 0x65, 0x07, + 0x49, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x69, 0x6f, 0x67, 0x6f, + 0x6e, 0x65, 0x6b, 0x02, 0x49, 0x4a, 0x02, 0x69, 0x6a, 0x0b, 0x4a, 0x63, + 0x69, 0x72, 0x63, 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0b, 0x6a, 0x63, + 0x69, 0x72, 0x63, 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0c, 0x4b, 0x63, + 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x6b, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, + 0x6b, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x6c, 0x61, 0x6e, 0x64, 0x69, 0x63, + 0x06, 0x4c, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x6c, 0x61, 0x63, 0x75, + 0x74, 0x65, 0x0c, 0x4c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, + 0x65, 0x6e, 0x74, 0x0c, 0x6c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x06, 0x4c, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, + 0x6c, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x04, 0x4c, 0x64, 0x6f, 0x74, 0x04, + 0x6c, 0x64, 0x6f, 0x74, 0x06, 0x4e, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, + 0x6e, 0x61, 0x63, 0x75, 0x74, 0x65, 0x0c, 0x4e, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x6e, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x4e, 0x63, 0x61, + 0x72, 0x6f, 0x6e, 0x06, 0x6e, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0b, 0x6e, + 0x61, 0x70, 0x6f, 0x73, 0x74, 0x72, 0x6f, 0x70, 0x68, 0x65, 0x03, 0x45, + 0x6e, 0x67, 0x03, 0x65, 0x6e, 0x67, 0x07, 0x4f, 0x6d, 0x61, 0x63, 0x72, + 0x6f, 0x6e, 0x07, 0x6f, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x4f, + 0x62, 0x72, 0x65, 0x76, 0x65, 0x06, 0x6f, 0x62, 0x72, 0x65, 0x76, 0x65, + 0x0d, 0x4f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, 0x6c, 0x61, + 0x75, 0x74, 0x0d, 0x6f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, + 0x6c, 0x61, 0x75, 0x74, 0x06, 0x52, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, + 0x72, 0x61, 0x63, 0x75, 0x74, 0x65, 0x0c, 0x52, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x72, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x52, 0x63, 0x61, + 0x72, 0x6f, 0x6e, 0x06, 0x72, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x53, + 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x73, 0x61, 0x63, 0x75, 0x74, 0x65, + 0x0b, 0x53, 0x63, 0x69, 0x72, 0x63, 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, + 0x0b, 0x73, 0x63, 0x69, 0x72, 0x63, 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, + 0x0c, 0x54, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, + 0x74, 0x0c, 0x74, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, + 0x6e, 0x74, 0x06, 0x54, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x74, 0x63, + 0x61, 0x72, 0x6f, 0x6e, 0x04, 0x54, 0x62, 0x61, 0x72, 0x04, 0x74, 0x62, + 0x61, 0x72, 0x06, 0x55, 0x74, 0x69, 0x6c, 0x64, 0x65, 0x06, 0x75, 0x74, + 0x69, 0x6c, 0x64, 0x65, 0x07, 0x55, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, + 0x07, 0x75, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x55, 0x62, 0x72, + 0x65, 0x76, 0x65, 0x06, 0x75, 0x62, 0x72, 0x65, 0x76, 0x65, 0x05, 0x55, + 0x72, 0x69, 0x6e, 0x67, 0x05, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x0d, 0x55, + 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, 0x6c, 0x61, 0x75, 0x74, + 0x0d, 0x75, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, 0x6c, 0x61, + 0x75, 0x74, 0x07, 0x55, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x75, + 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x0b, 0x57, 0x63, 0x69, 0x72, 0x63, + 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0b, 0x77, 0x63, 0x69, 0x72, 0x63, + 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0b, 0x59, 0x63, 0x69, 0x72, 0x63, + 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x0b, 0x79, 0x63, 0x69, 0x72, 0x63, + 0x75, 0x6d, 0x66, 0x6c, 0x65, 0x78, 0x06, 0x5a, 0x61, 0x63, 0x75, 0x74, + 0x65, 0x06, 0x7a, 0x61, 0x63, 0x75, 0x74, 0x65, 0x0a, 0x5a, 0x64, 0x6f, + 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x7a, 0x64, 0x6f, 0x74, + 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x6d, 0x69, 0x6e, 0x75, 0x74, + 0x65, 0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x07, 0x75, 0x6e, 0x69, + 0x32, 0x30, 0x33, 0x44, 0x04, 0x45, 0x75, 0x72, 0x6f, 0x09, 0x61, 0x72, + 0x72, 0x6f, 0x77, 0x6c, 0x65, 0x66, 0x74, 0x07, 0x61, 0x72, 0x72, 0x6f, + 0x77, 0x75, 0x70, 0x0a, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x09, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x64, 0x6f, 0x77, 0x6e, + 0x07, 0x74, 0x72, 0x69, 0x61, 0x67, 0x75, 0x70, 0x07, 0x74, 0x72, 0x69, + 0x61, 0x67, 0x72, 0x74, 0x07, 0x74, 0x72, 0x69, 0x61, 0x67, 0x64, 0x6e, + 0x07, 0x74, 0x72, 0x69, 0x61, 0x67, 0x6c, 0x66, 0x07, 0x75, 0x6e, 0x69, + 0x32, 0x36, 0x30, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x30, 0x33, + 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x30, 0x34, 0x07, 0x75, 0x6e, 0x69, + 0x32, 0x36, 0x30, 0x35, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x30, 0x45, + 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x32, 0x30, 0x07, 0x75, 0x6e, 0x69, + 0x32, 0x36, 0x32, 0x45, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x32, 0x46, + 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x33, 0x39, 0x09, 0x73, 0x6d, 0x69, + 0x6c, 0x65, 0x66, 0x61, 0x63, 0x65, 0x0c, 0x69, 0x6e, 0x76, 0x73, 0x6d, + 0x69, 0x6c, 0x65, 0x66, 0x61, 0x63, 0x65, 0x03, 0x73, 0x75, 0x6e, 0x06, + 0x66, 0x65, 0x6d, 0x61, 0x6c, 0x65, 0x04, 0x6d, 0x61, 0x6c, 0x65, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x36, 0x34, 0x38, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x36, 0x34, 0x39, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x34, 0x41, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x36, 0x34, 0x42, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x36, 0x34, 0x43, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x34, 0x44, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x36, 0x34, 0x45, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x36, 0x34, 0x46, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x35, 0x30, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x36, 0x35, 0x31, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x36, 0x35, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x35, 0x33, 0x05, + 0x73, 0x70, 0x61, 0x64, 0x65, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x36, 0x36, + 0x31, 0x04, 0x63, 0x6c, 0x75, 0x62, 0x05, 0x68, 0x65, 0x61, 0x72, 0x74, + 0x07, 0x64, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x0b, 0x6d, 0x75, 0x73, + 0x69, 0x63, 0x61, 0x6c, 0x6e, 0x6f, 0x74, 0x65, 0x0e, 0x6d, 0x75, 0x73, + 0x69, 0x63, 0x61, 0x6c, 0x6e, 0x6f, 0x74, 0x65, 0x64, 0x62, 0x6c, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x37, 0x30, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x37, 0x30, 0x34, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x37, 0x30, 0x38, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x37, 0x30, 0x39, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x37, 0x30, 0x43, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x37, 0x30, 0x45, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x37, 0x31, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x32, + 0x37, 0x31, 0x45, 0x07, 0x75, 0x6e, 0x69, 0x32, 0x37, 0x32, 0x31, 0x07, + 0x75, 0x6e, 0x69, 0x32, 0x37, 0x33, 0x46, 0x07, 0x75, 0x6e, 0x69, 0x33, + 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x01, 0x7f, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xc7, 0xfe, 0xb0, 0xdf, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x78, 0x2b, 0x41, + 0x00, 0x00, 0x00, 0x00, 0xde, 0xe0, 0x84, 0x19 +}; + +#endif /* ATTRACTPLUS_TTF_H */ diff --git a/geometry.py b/geometry.py new file mode 100644 index 00000000000..6e1d75bbea8 --- /dev/null +++ b/geometry.py @@ -0,0 +1,324 @@ +import argparse +import subprocess +import sys +import time +import os +import logging +import platform + + +CTR_modifier = 1<<7 + +class mode: + def __init__(self, w:int = 640, h:int = 480, rr:float = 60): + self.width = int(w) + self.height = int(h) + self.refresh_rate = float(rr) + + def __str__(self): + return "{}x{}@{}".format(self.width, self.height, self.refresh_rate) + + def __repr__(self): + return "Mode: {}".format(str(self)) + + +class geometry: + def __init__(self, h_size:float = 1.0, h_shift:int = 0, v_shift:int = 0): + self.h_size = float(h_size) + self.h_shift = int(h_shift) + self.v_shift = int(v_shift) + + def __str__(self): + return "{}:{}:{}".format(self.h_size, self.h_shift, self.v_shift) + + def __eq__(self, other): + return self.h_size == other.h_size and self.h_shift == other.h_shift and self.v_shift == other.v_shift + + def set_geometry(self, h_size:float, h_shift:int, v_shift:int): + self.h_size = float(h_size) + self.h_shift = int(h_shift) + self.v_shift = int(v_shift) + + @classmethod + def set_from_string(cls, geom:str): + """ + geom should be in the form of 1.0:-5:2 + """ + hsize, hshift, vshift = geom.split(':') + return cls(hsize, hshift, vshift) + + def inc_hsize(self, step = 0.01, factor:int = 1): self.h_size += step * factor + def inc_hshift(self, step = 1, factor:int = 1): self.h_shift += step * factor + def inc_vshift(self, step = 1, factor:int = 1): self.v_shift += step * factor + def dec_hsize(self, step = 0.01, factor:int = 1): self.h_size -= step * factor + def dec_hshift(self, step = 1, factor:int = 1): self.h_shift -= step * factor + def dec_vshift(self, step = 1, factor:int = 1): self.v_shift -= step * factor + + +class crt_range: + def __init__(self, HfreqMin:float = 0.0, HfreqMax:float = 0.0, VfreqMin:float = 0.0, VfreqMax:float = 0.0, HFrontPorch:float = 0.0, HSyncPulse:float = 0.0, HBackPorch:float = 0.0, VFrontPorch:float = 0.0, VSyncPulse:float = 0.0, VBackPorch:float = 0.0, HSyncPol:int = 0, VSyncPol:int = 0, ProgressiveLinesMin:int = 0, ProgressiveLinesMax:int = 0, InterlacedLinesMin:int = 0, InterlacedLinesMax:int = 0): + self.HfreqMin = float(HfreqMin) + self.HfreqMax = float(HfreqMax) + self.VfreqMin = float(VfreqMin) + self.VfreqMax = float(VfreqMax) + self.HFrontPorch = float(HFrontPorch) + self.HSyncPulse = float(HSyncPulse) + self.HBackPorch = float(HBackPorch) + self.VFrontPorch = float(VFrontPorch) + self.VSyncPulse = float(VSyncPulse) + self.VBackPorch = float(VBackPorch) + self.HSyncPol = int(HSyncPol) + self.VSyncPol = int(VSyncPol) + self.ProgressiveLinesMin = int(ProgressiveLinesMin) + self.ProgressiveLinesMax = int(ProgressiveLinesMax) + self.InterlacedLinesMin = int(InterlacedLinesMin) + self.InterlacedLinesMax = int(InterlacedLinesMax) + + @classmethod + def set_from_string(cls, range:str): + """ + range is in the form of 15625.00-16200.00,49.50-65.00,2.000,4.700,8.000,0.064,0.192,1.024,0,0,192,288,448,576 + """ + HfreqRange, VfregRange, HFrontPorch, HSyncPulse, HBackPorch, VFrontPorch, VSyncPulse, VBackPorch, HSyncPol, VSyncPol, ProgressiveLinesMin, ProgressiveLinesMax, InterlacedLinesMin, InterlacedLinesMax = range.split(',') + HfreqMin, HfreqMax = HfreqRange.split('-') + VfreqMin, VfreqMax = VfregRange.split('-') + return cls(HfreqMin, HfreqMax, VfreqMin, VfreqMax, HFrontPorch, HSyncPulse, HBackPorch, VFrontPorch, VSyncPulse, VBackPorch, HSyncPol, VSyncPol, ProgressiveLinesMin, ProgressiveLinesMax, InterlacedLinesMin, InterlacedLinesMax) + + def new_geometry_from_string(self, adjusted_geometry: str): + """ + range is in the shape of the switchres output: "H: 2.004, 4.696, 8.015 V: 0.447, 0.383, 2.425" + """ + #hfp, self.HSyncPulse, self.HBackPorch, vfp, self.VSyncPulse, self.VBackPorch = adjusted_geometry.split(', ') + hfp, self.HSyncPulse, hbp_and_vfp, self.VSyncPulse, self.VBackPorch = adjusted_geometry.split(', ') + self.HFrontPorch = hfp[3:] + self.HBackPorch, _, self.VFrontPorch = hbp_and_vfp.split(' ') + + def __str__(self): + return "{}-{},{}-{},{},{},{},{},{},{},{},{},{},{},{},{}".format( + self.HfreqMin, self.HfreqMax, self.VfreqMin, self.VfreqMax, self.HFrontPorch, self.HSyncPulse, self.HBackPorch, self.VFrontPorch, self.VSyncPulse, self.VBackPorch, self.HSyncPol, self.VSyncPol, self.ProgressiveLinesMin, self.ProgressiveLinesMax, self.InterlacedLinesMin, self.InterlacedLinesMax) + + +def switchres_output_get_monitor_range(output:str): + for l in output.splitlines(): + # The line to parse looks like: + # Switchres: Monitor range 15625.00-16200.00,49.50-65.00,2.000,4.700,8.000,0.064,0.192,1.024,0,0,192,288,448,576 + if l[0:25] != "Switchres: Monitor range " : continue + logging.debug("Found! -> {}".format(l[25:])) + logging.debug(crt_range().set_from_string(l[25:])) + return crt_range().set_from_string(l[25:]) + logging.warning("Couldn't find the monitor range!") + return None + +def switchres_output_get_adjusted_crt_geometry(output:str): + for l in output.splitlines(): + # The line to parse looks like: + # Adjusted geometry (1.000:0:0) H: 2.004, 4.696, 8.015 V: 0.223, 0.191, 1.212 + # We need what is behind H: + if l[0:19] != "Adjusted geometry (" : continue + Hpos = l.find('H: ') + logging.debug("Found! -> {}".format(l[Hpos:])) + return l[Hpos:] + logging.warning("Couldn't find the adjusted crt geometry!") + return None + +def switchres_output_get_adjusted_geometry(output:str): + for l in output.splitlines(): + # The line to parse looks like: + # Adjusted geometry (1.000:0:0) H: 2.004, 4.696, 8.015 V: 0.223, 0.191, 1.212 + # We need what is between parenthesis + if l[0:19] != "Adjusted geometry (" : continue + Hpos = l.find('H: ') + + logging.debug("Found! -> {}".format(l[Hpos:])) + return l[19:Hpos - 2] + logging.warning("Couldn't find the adjusted geometry!") + return None + +def switchres_output_get_command_exit_code(output:str): + for l in output.splitlines(): + # The line to parse looks like: + # Process exited with value 256 + if l[0:26] != "Process exited with value " : continue + logging.debug("Found! -> {}".format(l[26:])) + return int(l[26:]) + logging.warning("Couldn't find the app exit code!") + return None + +def launch_switchres(mode:mode, geom:geometry = geometry(), switchres_command:str = "switchres", launch_command:str = "grid", display:int = 0): + return_list = dict() + + # The command line may not require launching a program, just to get the crt_range for example + cmd = [ switchres_command.split(" ")[0], str(mode.width), str(mode.height), str(mode.refresh_rate), '-v' ] + if switchres_command.split(" ")[1:]: + cmd.extend(switchres_command.split(" ")[1:]) + if display > 0: + cmd.extend(['-d', str(display)]) + if launch_command: + if display > 0: + launch_command += " {}".format(display) + cmd.extend(['-s', '-l', launch_command]) + else: + cmd.extend(['-c']) + cmd.extend(['-g', str(geom)]) + logging.debug("Calling: {} with text: {}".format(" ".join(cmd), os.getenv('GRID_TEXT'))) + return_status = subprocess.run(cmd, capture_output=True, text=True) + logging.debug(return_status.stdout) + + default_crt_range = switchres_output_get_monitor_range(return_status.stdout) + adjusted_geometry = switchres_output_get_adjusted_crt_geometry(return_status.stdout) + user_crt_range = default_crt_range + grid_return = None + + if launch_command: + grid_return = switchres_output_get_command_exit_code(return_status.stdout) + user_crt_range.new_geometry_from_string(adjusted_geometry) + return_list['exit_code'] = grid_return + return_list['new_crt_range'] = user_crt_range + return_list['default_crt_range'] = default_crt_range + return_list['geometry'] = switchres_output_get_adjusted_geometry(return_status.stdout) + + return return_list + +def update_switchres_ini(range: crt_range, inifile:str = ''): + if not inifile: + sys.exit(0) + logging.info("Updating {} with crt_range {} (NOT YET IMPLEMENTED)".format(inifile, str(range))) + +def readjust_geometry(geom: geometry, range:crt_range, return_code:int): + wanted_factor = 10 if return_code & CTR_modifier else 1 + factor_message = " with CTRL pressed" if return_code & CTR_modifier else '' + # Disable the modifier + return_code = return_code & ~CTR_modifier + # This syntax requires python >= 3.10 + match return_code: + # Pressed PAGEUP + case 68: + geom.inc_hsize(factor = wanted_factor) + # Pressed PAGEDOWN + case 69: + geom.dec_hsize(factor = wanted_factor) + # Pressed LEFT + case 64: + geom.dec_hshift(factor = wanted_factor) + # Pressed RIGHT + case 65: + geom.inc_hshift(factor = wanted_factor) + # Pressed DOWN + case 67: + geom.inc_vshift(factor = wanted_factor) + # Pressed UP + case 66: + geom.dec_vshift(factor = wanted_factor) + # Pressed ESCAPE / Q + case 1: + logging.info("Aborted!") + sys.exit(1) + # Pressed ENTER / RETURN + case 0: + logging.info("Finished!") + logging.info("Final geometry: {}".format(str(geom))) + logging.info("Final crt_range: {}".format(str(range))) + #update_switchres_ini(range, switchres_ini) + sys.exit(0) + # Pressed DEL / BACKSPACE + case 2: + geom = geometry(1.0, 0, 0) + # Pressed R + case 3: + logging.debug("Refreshing with the same geometry values if your screen was scrolling") + logging.debug("Readjusted geometry: {}".format(str(geom))) + return geom + +def set_grid_text(top_txt:str = '', bottom_txt:str = '', geom:geometry = geometry()): + help_txt = """H size: {} +H shift: {} +V shift: {} + +Arrows: shift screen - Page Up/Down: H size +ENTER: validate - ESC: cancel - DEL: reinit - R: reload +CTRL+key: step x10""".format(geom.h_size, geom.h_shift, geom.v_shift) + os.environ['GRID_TEXT'] = "\n \n{}".format("\n \n".join(filter(None, [top_txt, help_txt, bottom_txt]))) + logging.debug(os.getenv('GRID_TEXT')) + +def switchres_geometry_loop(mode: mode, switchres_command:str = "switchres", launch_command:str = "grid", display_nr:int = 0, geom:geometry = geometry()): + working_geometry = geom + top_txt = '' + + while True: + # This launch is to confirm the geometry + sr_launch_return = launch_switchres(mode, working_geometry, switchres_command, launch_command = "", display = display_nr) + ret_geom = geometry.set_from_string(sr_launch_return['geometry']) + if ret_geom != working_geometry: + top_txt = "Geometry readjusted, was out of CRT range bounds" + logging.info("Warning: you've reached a crt_range limit, can't go further in the last direction. Setting back to {}".format(str(ret_geom))) + working_geometry = ret_geom + os.environ['GRID_TEXT'] = "\n".join([os.getenv('GRID_TEXT') or "", "({})".format(str(geom))]) + set_grid_text(top_txt, '', working_geometry) + # Now is the real launch with the grid + sr_launch_return = launch_switchres(mode, working_geometry, switchres_command, launch_command, display_nr) + grid_return_code = sr_launch_return['exit_code'] + sr_geometry = geometry.set_from_string(sr_launch_return['geometry']) + working_geometry = readjust_geometry(sr_geometry, sr_launch_return['new_crt_range'], grid_return_code) + os.environ['GRID_TEXT'] = "" + top_txt = '' + time.sleep(2) + + +# +# MAIN +# + +# The default switchres.ini file depends on the platform +if platform.system() == 'Linux': + default_switchres_ini = '/etc/switchres.ini' +else: + default_switchres_ini = 'switchres.ini' + +parser = argparse.ArgumentParser(description='Switchres wrapper to adjust a crt_range for switchres.ini') +parser.add_argument('mode', metavar='N', type=float, nargs=3, + help='width height refresh_rate') +parser.add_argument('-l', '--launch', metavar='launch', type=str, default='grid', + help='The program you want to launch') +# parser.add_argument('-i', '--ini', metavar='ini', type=str, default=default_switchres_ini, + # help='The switchres.ini file to edit') +parser.add_argument('-s', '--switchres', metavar='binary', type=str, default='switchres', + help='The switchres binary to use') +parser.add_argument('-d', '--display', metavar='display', type=int, default=0, + help='Set the display to calibrate') +#parser.add_argument('-m', '--monitor', metavar='monitor', type=str, default='arcade_15', + # help='The monitor preset base, to override the switchres.ini (NOT YET IMPLEMENTED)') +parser.add_argument('-g', '--geometry', metavar='geometry', type=str, default='1.0:0:0', + help='Start with a predefined geometry') +parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbose mode') + + +if sys.version_info.major < 3: + raise Exception("Must use Python 3.7 or later") +if sys.version_info.minor < 10: + raise Exception("Must use Python 3.7 or later") + +#args = parser.parse_args(['320', '240', '59.94']) +args = parser.parse_args() + +# Set log level according to wanted verbosity +loggingLevel = logging.INFO +logging.basicConfig(stream=sys.stdout, level=loggingLevel, format='%(message)s') +if args.verbose > 0: + loggingLevel = logging.DEBUG + logger = logging.getLogger() + logger.setLevel(loggingLevel) + for handler in logger.handlers: + handler.setLevel(loggingLevel) + for handler in logging.root.handlers[:]: + logging.root.removeHandler(handler) + logging.basicConfig(stream=sys.stdout, level=loggingLevel, + format='[%(levelname)s] %(filename)s/%(funcName)s(%(lineno)d): %(message)s') +logging.debug("Specified logging level: {}".format(args.verbose)) +logging.debug("Command line arguments: {}".format(args)) + +logging.debug(args) + +command_mode = mode(args.mode[0], args.mode[1], args.mode[2]) +geometry_arg = geometry.set_from_string(args.geometry) + +switchres_geometry_loop(command_mode, args.switchres, args.launch, args.display, geometry_arg) diff --git a/grid.cpp b/grid.cpp new file mode 100644 index 00000000000..5f637fbe041 --- /dev/null +++ b/grid.cpp @@ -0,0 +1,410 @@ +/************************************************************** + + grid.cpp - Simple test grid + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2022 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse, + Radek Dutkiewicz + + **************************************************************/ + +// To add additional text lines: +// export GRID_TEXT="$(echo -e "\nArrows - screen position, Page Up/Down - H size\n\nH size: 1.0\nH position: 0\nV position: 0")" + +// To remove additional lines: +// unset GRID_TEXT + + +#define SDL_MAIN_HANDLED +#define NUM_GRIDS 2 + +#include +#include +#include "font.h" +#include +#include +#include +#include +#include + +#define FONT_SIZE 11 + +enum GRID_ADJUST +{ + LEFT = 64, + RIGHT, + UP, + DOWN, + H_SIZE_INC, + H_SIZE_DEC +}; + +typedef struct grid_display +{ + int index; + int width; + int height; + + SDL_Window *window; + SDL_Renderer *renderer; + std::vector textures; +} GRID_DISPLAY; + +SDL_Surface *surface; +TTF_Font *font; +std::vector grid_texts; + + +//============================================================ +// draw_grid +//============================================================ + +void draw_grid(int num_grid, int width, int height, SDL_Renderer *renderer, std::vector textures) +{ + // Clean the surface + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + + SDL_Rect rect {0, 0, width, height}; + + switch (num_grid) + { + case 0: + // 16 x 12 squares + { + // Fill the screen with red + rect = {0, 0, width, height}; + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + SDL_RenderFillRect(renderer, &rect); + + // Draw white rectangle + rect = {width / 32, height / 24 , width - width / 16, height - height / 12}; + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderFillRect(renderer, &rect); + + // Draw grid using black rectangles + SDL_Rect rects[16 * 12]; + + // Set the thickness of horizontal and vertical lines based on the screen resolution + int line_w = round(float(width) / 320.0); + int line_h = round(float(height) / 240.0); + if ( line_w < 1 ) line_w = 1; + if ( line_h < 1 ) line_h = 1; + + float rect_w = (width - line_w * 17) / 16.0; + float rect_h = (height - line_h * 13) / 12.0; + + for (int i = 0; i < 16; i++) + { + int x_pos1 = ceil(i * rect_w); + int x_pos2 = ceil((i+1) * rect_w); + for (int j = 0; j < 12; j++) + { + int y_pos1 = ceil(j * rect_h); + int y_pos2 = ceil((j+1) * rect_h); + rects[i + j * 16] = {x_pos1 + (i+1) * line_w , y_pos1 + (j+1) * line_h, x_pos2 - x_pos1, y_pos2 - y_pos1}; + } + } + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRects(renderer, rects, 16 * 12); + } + break; + + case 1: + // cps2 grid + + // Draw outer rectangle + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDrawRect(renderer, &rect); + + for (int i = 0; i < width / 16; i++) + { + for (int j = 0; j < height / 16; j++) + { + if (i == 0 || j == 0 || i == (width / 16) - 1 || j == (height / 16) - 1) + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + else + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + rect = {i * 16, j * 16, 16, 16}; + SDL_RenderDrawRect(renderer, &rect); + + rect = {i * 16 + 7, j * 16 + 7, 2, 2}; + SDL_RenderDrawRect(renderer, &rect); + } + } + break; + } + + // Compute text scaling factors + int text_scale_w = std::max(1, (int)floor(width / 320 + 0.5)); + int text_scale_h = std::max(1, (int)floor(height / 240 + 0.5)); + + SDL_Rect text_frame = {0, 0, 0, 0}; + + // Compute text frame size + for (SDL_Texture *t : textures) + { + int texture_width = 0; + int texture_height = 0; + + SDL_QueryTexture(t, NULL, NULL, &texture_width, &texture_height); + + text_frame.w = std::max(text_frame.w, texture_width); + text_frame.h += texture_height; + } + + text_frame.w *= text_scale_w; + text_frame.h *= text_scale_h; + + text_frame.w += FONT_SIZE * text_scale_w; // margin x + text_frame.h += FONT_SIZE * text_scale_h; // margin y + + text_frame.x = ceil((width - text_frame.w ) / 2); + text_frame.y = ceil((height - text_frame.h ) / 2); + + // Draw Text background + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRect(renderer, &text_frame); + + // Draw Text frame + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDrawRect(renderer, &text_frame); + + // Draw text lines + SDL_Rect text_rect = {0, text_frame.y + FONT_SIZE * text_scale_h / 2, 0, 0}; + + for (SDL_Texture *t : textures) + { + int texture_width = 0; + int texture_height = 0; + + SDL_QueryTexture(t, NULL, NULL, &texture_width, &texture_height); + + text_rect.w = texture_width *= text_scale_w; + text_rect.h = texture_height *= text_scale_h; + text_rect.x = ceil((width - text_rect.w ) / 2); + + SDL_RenderCopy(renderer, t, NULL, &text_rect); + + text_rect.y += text_rect.h; + } + + SDL_RenderPresent(renderer); +} + +//============================================================ +// main +//============================================================ + +int main(int argc, char **argv) +{ + SDL_Window* win_array[10] = {}; + GRID_DISPLAY display_array[10] = {}; + int display_total = 0; + + // Initialize SDL + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + printf("error initializing SDL: %s\n", SDL_GetError()); + return 1; + } + + // Get target displays + if (argc > 1) + { + // Parse command line for display indexes + int display_index = 0; + int num_displays = SDL_GetNumVideoDisplays(); + + for (int arg = 1; arg < argc; arg++) + { + sscanf(argv[arg], "%d", &display_index); + + if (display_index < 0 || display_index > num_displays - 1) + { + printf("error, bad display_index: %d\n", display_index); + return 1; + } + + display_array[display_total].index = display_index; + display_total++; + } + } + else + { + // No display specified, use default + display_array[0].index = 0; + display_total = 1; + } + + // Initialize text + TTF_Init(); + SDL_RWops* font_resource = SDL_RWFromConstMem(ATTRACTPLUS_TTF, (sizeof(ATTRACTPLUS_TTF)) / (sizeof(ATTRACTPLUS_TTF[0]))); + font = TTF_OpenFontRW(font_resource, 1, FONT_SIZE); + + grid_texts.push_back(" "); // empty line for screen resolution + + char *grid_text = getenv("GRID_TEXT"); + + if ( grid_text != NULL ) + { + char* p = strtok(grid_text, "\n"); + while(p) + { + grid_texts.push_back(p); + p = strtok(NULL, "\n"); + } + } + + // Create windows + for (int disp = 0; disp < display_total; disp++) + { + // Get target display size + SDL_DisplayMode dm; + SDL_GetCurrentDisplayMode(display_array[disp].index, &dm); + + SDL_ShowCursor(SDL_DISABLE); + + display_array[disp].width = dm.w; + display_array[disp].height = dm.h; + + // Create window + display_array[disp].window = SDL_CreateWindow("Switchres test grid", SDL_WINDOWPOS_CENTERED_DISPLAY(display_array[disp].index), SDL_WINDOWPOS_CENTERED, dm.w, dm.h, SDL_WINDOW_FULLSCREEN_DESKTOP); + + // Required by Window multi-monitor + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); + + // Create renderer + display_array[disp].renderer = SDL_CreateRenderer(display_array[disp].window, -1, SDL_RENDERER_ACCELERATED); + SDL_RenderPresent(display_array[disp].renderer); + + // Render first text + grid_texts[0] = "Mode: " + std::to_string(dm.w) + " x " + std::to_string(dm.h) + " @ " + std::to_string(dm.refresh_rate); + + for ( int i = 0; i < grid_texts.size(); i++ ) + { + surface = TTF_RenderText_Solid(font, grid_texts[i].c_str(), {255, 255, 255}); + display_array[disp].textures.push_back(SDL_CreateTextureFromSurface(display_array[disp].renderer, surface)); + } + + // Draw grid + draw_grid(0, display_array[disp].width, display_array[disp].height, display_array[disp].renderer, display_array[disp].textures); + } + + + + + // Wait for escape key + bool close = false; + int num_grid = 0; + int return_code = 0; + int CTRL_modifier = 0; + + while (!close) + { + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + close = true; + break; + + case SDL_KEYDOWN: + if (event.key.keysym.mod & KMOD_LCTRL || event.key.keysym.mod & KMOD_RCTRL) + CTRL_modifier = 1<<7; + + switch (event.key.keysym.scancode) + { + case SDL_SCANCODE_ESCAPE: + case SDL_SCANCODE_Q: + close = true; + return_code = 1; + break; + + case SDL_SCANCODE_BACKSPACE: + case SDL_SCANCODE_DELETE: + close = true; + return_code = 2; + break; + + case SDL_SCANCODE_R: + close = true; + return_code = 3; + break; + + case SDL_SCANCODE_RETURN: + case SDL_SCANCODE_KP_ENTER: + close = true; + break; + + case SDL_SCANCODE_TAB: + num_grid ++; + for (int disp = 0; disp < display_total; disp++) + draw_grid(num_grid % NUM_GRIDS, display_array[disp].width, display_array[disp].height, display_array[disp].renderer, display_array[disp].textures); + break; + + case SDL_SCANCODE_LEFT: + close = true; + return_code = GRID_ADJUST::LEFT; + break; + + case SDL_SCANCODE_RIGHT: + close = true; + return_code = GRID_ADJUST::RIGHT; + break; + + case SDL_SCANCODE_UP: + close = true; + return_code = GRID_ADJUST::UP; + break; + + case SDL_SCANCODE_DOWN: + close = true; + return_code = GRID_ADJUST::DOWN; + break; + + case SDL_SCANCODE_PAGEUP: + close = true; + return_code = GRID_ADJUST::H_SIZE_INC; + break; + + case SDL_SCANCODE_PAGEDOWN: + close = true; + return_code = GRID_ADJUST::H_SIZE_DEC; + break; + + default: + break; + } + + } + } + } + + // Destroy font + SDL_FreeSurface(surface); + TTF_CloseFont(font); + TTF_Quit(); + + // Destroy all windows + for (int disp = 0; disp < display_total; disp++) + { + for (SDL_Texture *t : display_array[disp].textures) + SDL_DestroyTexture(t); + SDL_DestroyWindow(display_array[disp].window); + } + + SDL_Quit(); + + return return_code | CTRL_modifier; +} diff --git a/log.cpp b/log.cpp new file mode 100644 index 00000000000..19bc7143404 --- /dev/null +++ b/log.cpp @@ -0,0 +1,78 @@ +/************************************************************** + + log.cpp - Simple logging for Switchres + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include "log.h" + +enum log_verbosity { NONE, SR_ERROR, SR_INFO, SR_DEBUG }; +static log_verbosity log_level = SR_INFO; + +void log_dummy(const char *, ...) {} + +LOG_VERBOSE log_verbose = &log_dummy; +LOG_INFO log_info = &log_dummy; +LOG_ERROR log_error = &log_dummy; + +/* + * These bakup pointers are here to let the user modify the log level at runtime + * We can't sadly unify a log function and test the log level to test if it should + * output a log, because it would imply frewriting log_ functions with va_args + * and wouldn't work with emulators log functions anymore + */ +LOG_VERBOSE log_verbose_bak = &log_dummy; +LOG_INFO log_info_bak = &log_dummy; +LOG_ERROR log_error_bak = &log_dummy; + + +void set_log_verbose(void *func_ptr) +{ + if (log_level >= SR_DEBUG) + log_verbose = (LOG_VERBOSE)func_ptr; + log_verbose_bak = (LOG_VERBOSE)func_ptr; +} + +void set_log_info(void *func_ptr) +{ + if (log_level >= SR_INFO) + log_info = (LOG_INFO)func_ptr; + log_info_bak = (LOG_INFO)func_ptr; +} + +void set_log_error(void *func_ptr) +{ + if (log_level >= SR_ERROR) + log_error = (LOG_ERROR)func_ptr; + log_error_bak = (LOG_ERROR)func_ptr; +} + +void set_log_verbosity(int level) +{ + // Keep the log in the enum bounds + if (level < NONE) + level = NONE; + if(level > SR_DEBUG) + level = SR_DEBUG; + + log_error = &log_dummy; + log_info = &log_dummy; + log_verbose = &log_dummy; + + if (level >= SR_ERROR) + log_error = log_error_bak; + + if (level >= SR_INFO) + log_info = log_info_bak; + + if (level >= SR_DEBUG) + log_verbose = log_verbose_bak; +} diff --git a/log.h b/log.h new file mode 100644 index 00000000000..8ac475a02d7 --- /dev/null +++ b/log.h @@ -0,0 +1,38 @@ +/************************************************************** + + log.h - Simple logging for Switchres + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __LOG__ +#define __LOG__ + +#if defined(__GNUC__) +#define ATTR_PRINTF(x,y) __attribute__((format(printf, x, y))) +#else +#define ATTR_PRINTF(x,y) +#endif + +typedef void (*LOG_VERBOSE)(const char *format, ...) ATTR_PRINTF(1,2); +extern LOG_VERBOSE log_verbose; + +typedef void (*LOG_INFO)(const char *format, ...) ATTR_PRINTF(1,2); +extern LOG_INFO log_info; + +typedef void (*LOG_ERROR)(const char *format, ...) ATTR_PRINTF(1,2); +extern LOG_ERROR log_error; + +void set_log_verbosity(int); +void set_log_verbose(void *func_ptr); +void set_log_info(void *func_ptr); +void set_log_error(void *func_ptr); + +#endif diff --git a/makefile b/makefile new file mode 100644 index 00000000000..89f52e0a782 --- /dev/null +++ b/makefile @@ -0,0 +1,159 @@ +PLATFORM := $(shell uname) + +MAIN = switchres_main +STANDALONE = switchres +TARGET_LIB = libswitchres +DRMHOOK_LIB = libdrmhook +GRID = grid +SRC = monitor.cpp modeline.cpp switchres.cpp display.cpp custom_video.cpp log.cpp switchres_wrapper.cpp edid.cpp +OBJS = $(SRC:.cpp=.o) + +CROSS_COMPILE ?= +CXX ?= g++ +AR ?= ar +LDFLAGS = -shared +FINAL_CXX=$(CROSS_COMPILE)$(CXX) +FINAL_AR=$(CROSS_COMPILE)$(AR) +CPPFLAGS = -O3 -Wall -Wextra + +PKG_CONFIG=pkg-config +INSTALL=install +LN=ln + +DESTDIR ?= +PREFIX ?= /usr +INCDIR = $(DESTDIR)$(PREFIX)/include +LIBDIR = $(DESTDIR)$(PREFIX)/lib +BINDIR = $(DESTDIR)$(PREFIX)/bin +PKGDIR = $(LIBDIR)/pkgconfig + +ifneq ($(DEBUG),) + CPPFLAGS += -g +endif + +# If the version is not set at make, read it from switchres.h +ifeq ($(VERSION),) + VERSION:=$(shell grep -E "^\#define SWITCHRES_VERSION" switchres.h | grep -oE "[0-9]+\.[0-9]+\.[0-9]+" ) +else + CPPFLAGS += -DSWITCHRES_VERSION="\"$(VERSION)\"" +endif +VERSION_MAJOR := $(firstword $(subst ., ,$(VERSION))) +VERSION_MINOR := $(word 2,$(subst ., ,$(VERSION))) +VERSION_PATCH := $(word 3,$(subst ., ,$(VERSION))) + +$(info Switchres $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)) + +# Linux +ifeq ($(PLATFORM),Linux) +SRC += display_linux.cpp + +HAS_VALID_XRANDR := $(shell $(PKG_CONFIG) --silence-errors --libs xrandr; echo $$?) +ifeq ($(HAS_VALID_XRANDR),1) + $(info Switchres needs xrandr. X support is disabled) +else + $(info X support enabled) + CPPFLAGS += -DSR_WITH_XRANDR + SRC += custom_video_xrandr.cpp +endif + +HAS_VALID_DRMKMS := $(shell $(PKG_CONFIG) --silence-errors --libs "libdrm >= 2.4.98"; echo $$?) +ifeq ($(HAS_VALID_DRMKMS),1) + $(info Switchres needs libdrm >= 2.4.98. KMS support is disabled) +else + $(info KMS support enabled) + CPPFLAGS += -DSR_WITH_KMSDRM + EXTRA_LIBS = libdrm + SRC += custom_video_drmkms.cpp +endif + +# SDL2 misses a test for drm as drm.h is required +HAS_VALID_SDL2 := $(shell $(PKG_CONFIG) --silence-errors --libs "sdl2 >= 2.0.16"; echo $$?) +ifeq ($(HAS_VALID_SDL2),1) + $(info Switchres needs SDL2 >= 2.0.16. SDL2 support is disabled) +else + $(info SDL2 support enabled) + CPPFLAGS += -DSR_WITH_SDL2 $(pkg-config --cflags sdl2) + EXTRA_LIBS += sdl2 + SRC += display_sdl2.cpp +endif + +ifneq (,$(EXTRA_LIBS)) +CPPFLAGS += $(shell $(PKG_CONFIG) --cflags $(EXTRA_LIBS)) +LIBS += $(shell $(PKG_CONFIG) --libs $(EXTRA_LIBS)) +endif + +CPPFLAGS += -fPIC +LIBS += -ldl + +REMOVE = rm -f +STATIC_LIB_EXT = a +DYNAMIC_LIB_EXT = so.$(VERSION) +LINKER_NAME := $(TARGET_LIB).so +REAL_SO_NAME := $(LINKER_NAME).$(VERSION) +SO_NAME := $(LINKER_NAME).$(VERSION_MAJOR) +LIB_CPPFLAGS := -Wl,-soname,$(SO_NAME) +# Windows +else ifneq (,$(findstring NT,$(PLATFORM))) +SRC += display_windows.cpp custom_video_ati_family.cpp custom_video_ati.cpp custom_video_adl.cpp custom_video_pstrip.cpp resync_windows.cpp +WIN_ONLY_FLAGS = -static-libgcc -static-libstdc++ +CPPFLAGS += -static $(WIN_ONLY_FLAGS) +LIBS = +#REMOVE = del /f +REMOVE = rm -f +STATIC_LIB_EXT = lib +DYNAMIC_LIB_EXT = dll +endif + +define SR_PKG_CONFIG +prefix=$(PREFIX) +exec_prefix=$${prefix} +includedir=$${prefix}/include +libdir=$${exec_prefix}/lib + +Name: libswitchres +Description: A modeline generator for CRT monitors +Version: $(VERSION) +Cflags: -I$${includedir}/switchres +Libs: -L$${libdir} -ldl -lswitchres +endef + + +%.o : %.cpp + $(FINAL_CXX) -c $(CPPFLAGS) $< -o $@ + +all: $(SRC:.cpp=.o) $(MAIN).cpp $(TARGET_LIB) prepare_pkg_config + @echo $(OSFLAG) + $(FINAL_CXX) $(CPPFLAGS) $(CXXFLAGS) $(SRC:.cpp=.o) $(MAIN).cpp $(LIBS) -o $(STANDALONE) + +$(TARGET_LIB): $(OBJS) + $(FINAL_CXX) $(LDFLAGS) $(CPPFLAGS) $(LIB_CPPFLAGS) -o $@.$(DYNAMIC_LIB_EXT) $^ + $(FINAL_CXX) -c $(CPPFLAGS) -DSR_WIN32_STATIC switchres_wrapper.cpp -o switchres_wrapper.o + $(FINAL_AR) rcs $@.$(STATIC_LIB_EXT) $(^) + +$(DRMHOOK_LIB): + $(FINAL_CXX) drm_hook.cpp -shared -ldl -fPIC -I/usr/include/libdrm -o libdrmhook.so + +$(GRID): + $(FINAL_CXX) grid.cpp $(WIN_ONLY_FLAGS) -lSDL2 -lSDL2_ttf -o grid + +clean: + $(REMOVE) $(OBJS) $(STANDALONE) $(TARGET_LIB).* + $(REMOVE) switchres.pc + +prepare_pkg_config: + $(file > switchres.pc,$(SR_PKG_CONFIG)) + +install: + $(INSTALL) -Dm644 $(TARGET_LIB).$(DYNAMIC_LIB_EXT) $(LIBDIR)/$(TARGET_LIB).$(DYNAMIC_LIB_EXT) + $(INSTALL) -Dm644 switchres_defines.h $(INCDIR)/switchres/switchres_defines.h + $(INSTALL) -Dm644 switchres_wrapper.h $(INCDIR)/switchres/switchres_wrapper.h + $(INSTALL) -Dm644 switchres.h $(INCDIR)/switchres/switchres.h + $(INSTALL) -Dm644 switchres.pc $(PKGDIR)/switchres.pc +ifneq ($(SO_NAME),) + $(LN) -s $(REAL_SO_NAME) $(LIBDIR)/$(SO_NAME) + $(LN) -s $(SO_NAME) $(LIBDIR)/$(LINKER_NAME) +endif + +uninstall: + $(REMOVE) $(LIBDIR)/$(TARGET_LIB).* + $(REMOVE) $(PKGDIR)/switchres.pc diff --git a/modeline.cpp b/modeline.cpp new file mode 100644 index 00000000000..35a19e31007 --- /dev/null +++ b/modeline.cpp @@ -0,0 +1,917 @@ +/************************************************************** + + modeline.cpp - Modeline generation and scoring routines + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include "modeline.h" +#include "log.h" + +#define max(a,b)({ __typeof__ (a) _a = (a);__typeof__ (b) _b = (b);_a > _b ? _a : _b; }) +#define min(a,b)({ __typeof__ (a) _a = (a);__typeof__ (b) _b = (b);_a < _b ? _a : _b; }) + + +//============================================================ +// PROTOTYPES +//============================================================ + +int get_line_params(modeline *mode, monitor_range *range, int char_size); +int scale_into_range (int value, int lower_limit, int higher_limit); +int scale_into_range (double value, double lower_limit, double higher_limit); +int scale_into_aspect (int source_res, int tot_res, double original_monitor_aspect, double users_monitor_aspect, double *best_diff); +int stretch_into_range(double vfreq, monitor_range *range, double borders, bool interlace_allowed, double *interlace); +int total_lines_for_yres(int yres, double vfreq, monitor_range *range, double borders, double interlace); +double max_vfreq_for_yres (int yres, monitor_range *range, double borders, double interlace); + +//============================================================ +// modeline_create +//============================================================ + +int modeline_create(modeline *s_mode, modeline *t_mode, monitor_range *range, generator_settings *cs) +{ + double vfreq_real = 0; + double interlace = 1; + double doublescan = 1; + double scan_factor = 1; + int x_scale = 0; + int y_scale = 0; + int v_scale = 0; + double x_fscale = 0; + double y_fscale = 0; + double v_fscale = 0; + double x_diff = 0; + double y_diff = 0; + double v_diff = 0; + double y_ratio = 0; + double borders = 0; + int rotation = s_mode->type & MODE_ROTATED; + double source_aspect = rotation? 1.0 / (STANDARD_CRT_ASPECT) : (STANDARD_CRT_ASPECT); + t_mode->result.weight = 0; + + // ≈≈≈ Vertical refresh ≈≈≈ + // try to fit vertical frequency into current range + v_scale = scale_into_range(t_mode->vfreq, range->vfreq_min, range->vfreq_max); + + if (!v_scale && (t_mode->type & V_FREQ_EDITABLE)) + { + t_mode->vfreq = t_mode->vfreq < range->vfreq_min? range->vfreq_min : range->vfreq_max; + v_scale = 1; + } + else if (v_scale != 1 && !(t_mode->type & V_FREQ_EDITABLE)) + { + t_mode->result.weight |= R_OUT_OF_RANGE; + return -1; + } + + // ≈≈≈ Vertical resolution ≈≈≈ + // try to fit active lines in the progressive range first + if (range->progressive_lines_min && (!t_mode->interlace || (t_mode->type & SCAN_EDITABLE))) + y_scale = scale_into_range(t_mode->vactive, range->progressive_lines_min, range->progressive_lines_max); + + // if not possible, try to fit in the interlaced range, if any + if (!y_scale && range->interlaced_lines_min && cs->interlace && (t_mode->interlace || (t_mode->type & SCAN_EDITABLE))) + { + y_scale = scale_into_range(t_mode->vactive, range->interlaced_lines_min, range->interlaced_lines_max); + interlace = 2; + } + + // if we succeeded, let's see if we can apply integer scaling + if (y_scale == 1 || (y_scale > 1 && (t_mode->type & Y_RES_EDITABLE))) + { + // check if we should apply doublescan + if (cs->doublescan && y_scale % 2 == 0) + { + y_scale /= 2; + doublescan = 0.5; + } + scan_factor = interlace * doublescan; + + // Calculate top border in case of multi-standard consumer TVs + if (cs->v_shift_correct) + borders = (range->progressive_lines_max - t_mode->vactive * y_scale / interlace) * (1.0 / range->hfreq_min) / 2; + + // calculate expected achievable refresh for this height + vfreq_real = min(t_mode->vfreq * v_scale, max_vfreq_for_yres(t_mode->vactive * y_scale, range, borders, scan_factor)); + if (vfreq_real != t_mode->vfreq * v_scale && !(t_mode->type & V_FREQ_EDITABLE)) + { + t_mode->result.weight |= R_OUT_OF_RANGE; + return -1; + } + + // calculate the ratio that our scaled yres represents with respect to the original height + y_ratio = double(t_mode->vactive) * y_scale / s_mode->vactive; + int y_source_scaled = s_mode->vactive * floor(y_ratio); + + // if our original height doesn't fit the target height, we're forced to stretch + if (!y_source_scaled) + t_mode->result.weight |= R_RES_STRETCH; + + // otherwise we try to perform integer scaling + else + { + // exclude lcd ranges from raw border computation + if (t_mode->type & V_FREQ_EDITABLE && range->progressive_lines_max - range->progressive_lines_min > 0) + { + // calculate y borders considering physical lines (instead of logical resolution) + int tot_yres = total_lines_for_yres(t_mode->vactive * y_scale, vfreq_real, range, borders, scan_factor); + int tot_source = total_lines_for_yres(y_source_scaled, t_mode->vfreq * v_scale, range, borders, scan_factor); + y_diff = tot_yres > tot_source?double(tot_yres % tot_source) / tot_yres * 100:0; + + // we penalize for the logical lines we need to add in order to meet the user's lower active lines limit + int y_min = interlace == 2?range->interlaced_lines_min:range->progressive_lines_min; + int tot_rest = (y_min >= y_source_scaled / doublescan)? y_min % int(y_source_scaled / doublescan):0; + y_diff += double(tot_rest) / tot_yres * 100; + } + else + y_diff = double((t_mode->vactive * y_scale) % y_source_scaled) / (t_mode->vactive * y_scale) * 100; + + // we save the integer ratio between source and target resolutions, this will be used for prescaling + y_scale = floor(y_ratio); + + // now if the borders obtained are low enough (< 10%) we'll finally apply integer scaling + // otherwise we'll stretch the original resolution over the target one + if (!(y_ratio >= 1.0 && y_ratio < 16.0 && y_diff < 10.0)) + t_mode->result.weight |= R_RES_STRETCH; + } + } + + // otherwise, check if we're allowed to apply fractional scaling + else if (t_mode->type & Y_RES_EDITABLE) + t_mode->result.weight |= R_RES_STRETCH; + + // if there's nothing we can do, we're out of range + else + { + t_mode->result.weight |= R_OUT_OF_RANGE; + return -1; + } + + // ≈≈≈ Horizontal resolution ≈≈≈ + // make the best possible adjustment of xres depending on what happened in the previous steps + // let's start with the SCALED case + if (!(t_mode->result.weight & R_RES_STRETCH)) + { + // apply integer scaling to yres + if (t_mode->type & Y_RES_EDITABLE) t_mode->vactive *= y_scale; + + // if we can, let's apply the same scaling to both directions + if (t_mode->type & X_RES_EDITABLE) + { + x_scale = y_scale; + double aspect_corrector = max(1.0f, cs->monitor_aspect / source_aspect); + t_mode->hactive = normalize(double(t_mode->hactive) * double(x_scale) * aspect_corrector, 8); + } + + // otherwise, try to get the best out of our current xres + else + { + x_scale = t_mode->hactive / s_mode->hactive; + // if the source width fits our xres, try applying integer scaling + if (x_scale) + { + x_scale = scale_into_aspect(s_mode->hactive, t_mode->hactive, source_aspect, cs->monitor_aspect, &x_diff); + if (x_diff > 15.0 && t_mode->hactive < cs->super_width) + t_mode->result.weight |= R_RES_STRETCH; + } + // otherwise apply fractional scaling + else + t_mode->result.weight |= R_RES_STRETCH; + } + } + + // if the result was fractional scaling in any of the previous steps, deal with it + if (t_mode->result.weight & R_RES_STRETCH) + { + if (t_mode->type & Y_RES_EDITABLE) + { + // always try to use the interlaced range first if it exists, for better resolution + t_mode->vactive = stretch_into_range(t_mode->vfreq * v_scale, range, borders, cs->interlace, &interlace); + + // check in case we couldn't achieve the desired refresh + vfreq_real = min(t_mode->vfreq * v_scale, max_vfreq_for_yres(t_mode->vactive, range, borders, interlace)); + } + + // check if we can create a normal aspect resolution + if (t_mode->type & X_RES_EDITABLE) + t_mode->hactive = max(t_mode->hactive, normalize(STANDARD_CRT_ASPECT * t_mode->vactive, 8)); + + // calculate integer scale for prescaling + x_scale = max(1, scale_into_aspect(s_mode->hactive, t_mode->hactive, source_aspect, cs->monitor_aspect, &x_diff)); + y_scale = max(1, floor(double(t_mode->vactive) / s_mode->vactive)); + + scan_factor = interlace; + doublescan = 1; + } + + x_fscale = double(t_mode->hactive) / s_mode->hactive * source_aspect / cs->monitor_aspect; + y_fscale = double(t_mode->vactive) / s_mode->vactive; + v_fscale = vfreq_real / s_mode->vfreq; + v_diff = (vfreq_real / v_scale) - s_mode->vfreq; + if (fabs(v_diff) > cs->refresh_tolerance) + t_mode->result.weight |= R_V_FREQ_OFF; + + // ≈≈≈ Modeline generation ≈≈≈ + // compute new modeline if we are allowed to + if (t_mode->type & V_FREQ_EDITABLE) + { + double margin = 0; + double vblank_lines = 0; + double vvt_ini = 0; + double interlace_incr = !cs->interlace_force_even && interlace == 2? 0.5 : 0; + + // Get resulting refresh + t_mode->vfreq = vfreq_real; + + // Get total vertical lines + vvt_ini = total_lines_for_yres(t_mode->vactive, t_mode->vfreq, range, borders, scan_factor) + interlace_incr; + + // Calculate horizontal frequency + t_mode->hfreq = t_mode->vfreq * vvt_ini; + + horizontal_values: + + // Fill horizontal part of modeline + get_line_params(t_mode, range, cs->pixel_precision? 1 : 8); + + // Calculate pixel clock + t_mode->pclock = t_mode->htotal * t_mode->hfreq; + if (t_mode->pclock <= cs->pclock_min) + { + if (t_mode->type & X_RES_EDITABLE) + { + x_scale *= 2; + x_fscale *= 2; + t_mode->hactive *= 2; + goto horizontal_values; + } + else + { + t_mode->result.weight |= R_OUT_OF_RANGE; + return -1; + } + } + + // Vertical blanking + t_mode->vtotal = vvt_ini * scan_factor; + vblank_lines = round_near(t_mode->hfreq * (range->vertical_blank + borders)) + interlace_incr; + margin = (t_mode->vtotal - t_mode->vactive - vblank_lines * scan_factor) / (cs->v_shift_correct? 1 : 2); + + double v_front_porch = margin + t_mode->hfreq * range->vfront_porch * scan_factor + interlace_incr; + int (*pf_round)(double) = interlace == 2? (cs->interlace_force_even? round_near_even : round_near_odd) : round_near; + + t_mode->vbegin = t_mode->vactive + max(pf_round(v_front_porch), 1); + t_mode->vend = t_mode->vbegin + max(round_near(t_mode->hfreq * range->vsync_pulse * scan_factor), 1); + + // Recalculate final vfreq + t_mode->vfreq = (t_mode->hfreq / t_mode->vtotal) * scan_factor; + + t_mode->hsync = range->hsync_polarity; + t_mode->vsync = range->vsync_polarity; + t_mode->interlace = interlace == 2? 1 : 0; + t_mode->doublescan = doublescan == 1? 0 : 1; + } + + // finally, store result + t_mode->result.scan_penalty = (s_mode->interlace != t_mode->interlace? 1 : 0) + (s_mode->doublescan != t_mode->doublescan? 1 : 0); + t_mode->result.x_scale = t_mode->result.weight & R_RES_STRETCH || t_mode->hactive >= cs->super_width ? x_fscale : (double)x_scale; + t_mode->result.y_scale = t_mode->result.weight & R_RES_STRETCH? y_fscale : (double)y_scale; + t_mode->result.v_scale = v_fscale; + t_mode->result.x_diff = x_diff; + t_mode->result.y_diff = y_diff; + t_mode->result.v_diff = v_diff; + + return 0; +} + +//============================================================ +// get_line_params +//============================================================ + +int get_line_params(modeline *mode, monitor_range *range, int char_size) +{ + int hhi, hhf, hht; + int hh, hs, he, ht; + double line_time, char_time, new_char_time; + double hfront_porch_min, hsync_pulse_min, hback_porch_min; + + hfront_porch_min = range->hfront_porch * .90; + hsync_pulse_min = range->hsync_pulse * .90; + hback_porch_min = range->hback_porch * .90; + + line_time = 1 / mode->hfreq * 1000000; + + hh = round(mode->hactive / char_size); + hs = he = ht = 1; + + do { + char_time = line_time / (hh + hs + he + ht); + if (hs * char_time < hfront_porch_min || + fabs((hs + 1) * char_time - range->hfront_porch) < fabs(hs * char_time - range->hfront_porch)) + hs++; + + if (he * char_time < hsync_pulse_min || + fabs((he + 1) * char_time - range->hsync_pulse) < fabs(he * char_time - range->hsync_pulse)) + he++; + + if (ht * char_time < hback_porch_min || + fabs((ht + 1) * char_time - range->hback_porch) < fabs(ht * char_time - range->hback_porch)) + ht++; + + new_char_time = line_time / (hh + hs + he + ht); + } while (new_char_time != char_time); + + hhi = (hh + hs) * char_size; + hhf = (hh + hs + he) * char_size; + hht = (hh + hs + he + ht) * char_size; + + mode->hbegin = hhi; + mode->hend = hhf; + mode->htotal = hht; + + return 0; +} + +//============================================================ +// scale_into_range +//============================================================ + +int scale_into_range (int value, int lower_limit, int higher_limit) +{ + int scale = 1; + while (value * scale < lower_limit) scale ++; + if (value * scale <= higher_limit) + return scale; + else + return 0; +} + +//============================================================ +// scale_into_range +//============================================================ + +int scale_into_range (double value, double lower_limit, double higher_limit) +{ + int scale = 1; + while (value * scale < lower_limit) scale ++; + if (value * scale <= higher_limit) + return scale; + else + return 0; +} + +//============================================================ +// scale_into_aspect +//============================================================ + +int scale_into_aspect (int source_res, int tot_res, double original_monitor_aspect, double users_monitor_aspect, double *best_diff) +{ + int scale = 1, best_scale = 1; + double diff = 0; + *best_diff = 0; + + while (source_res * scale <= tot_res) + { + diff = fabs(1.0 - (users_monitor_aspect / (double(tot_res) / double(source_res * scale) * original_monitor_aspect))) * 100.0; + if (diff < *best_diff || *best_diff == 0) + { + *best_diff = diff; + best_scale = scale; + } + scale ++; + } + return best_scale; +} + +//============================================================ +// stretch_into_range +//============================================================ + +int stretch_into_range(double vfreq, monitor_range *range, double borders, bool interlace_allowed, double *interlace) +{ + int yres, lower_limit; + + if (range->interlaced_lines_min && interlace_allowed) + { + yres = range->interlaced_lines_max; + lower_limit = range->interlaced_lines_min; + *interlace = 2; + } + else + { + yres = range->progressive_lines_max; + lower_limit = range->progressive_lines_min; + } + + while (yres > lower_limit && max_vfreq_for_yres(yres, range, borders, *interlace) < vfreq) + yres -= 8; + + return yres; +} + + +//============================================================ +// total_lines_for_yres +//============================================================ + +int total_lines_for_yres(int yres, double vfreq, monitor_range *range, double borders, double interlace) +{ + int vvt = max(yres / interlace + round_near(vfreq * yres / (interlace * (1.0 - vfreq * (range->vertical_blank + borders))) * (range->vertical_blank + borders)), 1); + while ((vfreq * vvt < range->hfreq_min) && (vfreq * (vvt + 1) < range->hfreq_max)) vvt++; + return vvt; +} + +//============================================================ +// max_vfreq_for_yres +//============================================================ + +double max_vfreq_for_yres (int yres, monitor_range *range, double borders, double interlace) +{ + return range->hfreq_max / (yres / interlace + round_near(range->hfreq_max * (range->vertical_blank + borders))); +} + +//============================================================ +// modeline_print +//============================================================ + +char * modeline_print(modeline *mode, char *modeline, int flags) +{ + char label[48]={'\x00'}; + char params[192]={'\x00'}; + + if (flags & MS_LABEL) + sprintf(label, "\"%dx%d_%d%s %.6fKHz %.6fHz\"", mode->hactive, mode->vactive, mode->refresh, mode->interlace?"i":"", mode->hfreq/1000, mode->vfreq); + + if (flags & MS_LABEL_SDL) + sprintf(label, "\"%dx%d_%.6f\"", mode->hactive, mode->vactive, mode->vfreq); + + if (flags & MS_PARAMS) + sprintf(params, " %.6f %d %d %d %d %d %d %d %d %s %s %s %s", double(mode->pclock)/1000000.0, mode->hactive, mode->hbegin, mode->hend, mode->htotal, mode->vactive, mode->vbegin, mode->vend, mode->vtotal, + mode->interlace?"interlace":"", mode->doublescan?"doublescan":"", mode->hsync?"+hsync":"-hsync", mode->vsync?"+vsync":"-vsync"); + + sprintf(modeline, "%s%s", label, params); + + return modeline; +} + +//============================================================ +// modeline_result +//============================================================ + +char * modeline_result(modeline *mode, char *result) +{ + log_verbose(" rng(%d): ", mode->range); + + if (mode->result.weight & R_OUT_OF_RANGE) + sprintf(result, " out of range"); + + else + sprintf(result, "%4d x%4d_%3.6f%s%s %3.6f [%s] scale(%.3f, %.3f, %.3f) diff(%.3f, %.3f, %.3f)", + mode->hactive, mode->vactive, mode->vfreq, mode->interlace?"i":"p", mode->doublescan?"d":"", mode->hfreq/1000, mode->result.weight & R_RES_STRETCH?"fract":"integ", + mode->result.x_scale, mode->result.y_scale, mode->result.v_scale, mode->result.x_diff, mode->result.y_diff, mode->result.v_diff); + return result; +} + +//============================================================ +// modeline_compare +//============================================================ + +int modeline_compare(modeline *t, modeline *best) +{ + bool vector = (t->hactive == (int)t->result.x_scale); + + if (t->result.weight < best->result.weight) + return 1; + + else if (t->result.weight <= best->result.weight) + { + double t_v_diff = fabs(t->result.v_diff); + double b_v_diff = fabs(best->result.v_diff); + + if (t->result.weight & R_RES_STRETCH || vector) + { + double t_y_score = t->result.y_scale * (t->interlace?(2.0/3.0):1.0); + double b_y_score = best->result.y_scale * (best->interlace?(2.0/3.0):1.0); + + if ((t_v_diff < b_v_diff) || + ((t_v_diff == b_v_diff) && (t_y_score > b_y_score)) || + ((t_v_diff == b_v_diff) && (t_y_score == b_y_score) && (t->result.x_scale > best->result.x_scale))) + return 1; + } + else + { + int t_y_score = t->result.y_scale + t->result.scan_penalty; + int b_y_score = best->result.y_scale + best->result.scan_penalty; + double xy_diff = roundf((t->result.x_diff + t->result.y_diff) * 100) / 100; + double best_xy_diff = roundf((best->result.x_diff + best->result.y_diff) * 100) / 100; + + if ((t_y_score < b_y_score) || + ((t_y_score == b_y_score) && (xy_diff < best_xy_diff)) || + ((t_y_score == b_y_score) && (xy_diff == best_xy_diff) && (t->result.x_scale < best->result.x_scale)) || + ((t_y_score == b_y_score) && (xy_diff == best_xy_diff) && (t->result.x_scale == best->result.x_scale) && (t_v_diff < b_v_diff))) + return 1; + } + } + return 0; +} + +//============================================================ +// modeline_vesa_gtf +// Based on the VESA GTF spreadsheet by Andy Morrish 1/5/97 +//============================================================ + +int modeline_vesa_gtf(modeline *m) +{ + int C, M; + int v_sync_lines, v_porch_lines_min, v_front_porch_lines, v_back_porch_lines, v_sync_v_back_porch_lines, v_total_lines; + int h_sync_width_percent, h_sync_width_pixels, h_blanking_pixels, h_front_porch_pixels, h_total_pixels; + double v_freq, v_freq_est, v_freq_real, v_sync_v_back_porch; + double h_freq, h_period, h_period_real, h_ideal_blanking; + double pixel_freq, interlace; + + // Check if there's a value defined for vfreq. We're assuming input vfreq is the total field vfreq regardless interlace + v_freq = m->vfreq? m->vfreq:double(m->refresh); + + // These values are GTF defined defaults + v_sync_lines = 3; + v_porch_lines_min = 1; + v_front_porch_lines = v_porch_lines_min; + v_sync_v_back_porch = 550; + h_sync_width_percent = 8; + M = 128.0 / 256 * 600; + C = ((40 - 20) * 128.0 / 256) + 20; + + // GTF calculation + interlace = m->interlace?0.5:0; + h_period = ((1.0 / v_freq) - (v_sync_v_back_porch / 1000000)) / ((double)m->height + v_front_porch_lines + interlace) * 1000000; + v_sync_v_back_porch_lines = round_near(v_sync_v_back_porch / h_period); + v_back_porch_lines = v_sync_v_back_porch_lines - v_sync_lines; + v_total_lines = m->height + v_front_porch_lines + v_sync_lines + v_back_porch_lines; + v_freq_est = (1.0 / h_period) / v_total_lines * 1000000; + h_period_real = h_period / (v_freq / v_freq_est); + v_freq_real = (1.0 / h_period_real) / v_total_lines * 1000000; + h_ideal_blanking = double(C - (M * h_period_real / 1000)); + h_blanking_pixels = round_near(m->width * h_ideal_blanking /(100 - h_ideal_blanking) / (2 * 8)) * (2 * 8); + h_total_pixels = m->width + h_blanking_pixels; + pixel_freq = h_total_pixels / h_period_real * 1000000; + h_freq = 1000000 / h_period_real; + h_sync_width_pixels = round_near(h_sync_width_percent * h_total_pixels / 100 / 8) * 8; + h_front_porch_pixels = (h_blanking_pixels / 2) - h_sync_width_pixels; + + // Results + m->hactive = m->width; + m->hbegin = m->hactive + h_front_porch_pixels; + m->hend = m->hbegin + h_sync_width_pixels; + m->htotal = h_total_pixels; + m->vactive = m->height; + m->vbegin = m->vactive + v_front_porch_lines; + m->vend = m->vbegin + v_sync_lines; + m->vtotal = v_total_lines; + m->hfreq = h_freq; + m->vfreq = v_freq_real; + m->pclock = pixel_freq; + m->hsync = 0; + m->vsync = 1; + + return true; +} + +//============================================================ +// modeline_parse +//============================================================ + +int modeline_parse(const char *user_modeline, modeline *mode) +{ + char modeline_txt[256]={'\x00'}; + + if (!strcmp(user_modeline, "auto")) + return false; + + // Remove quotes + char *quote_start, *quote_end; + quote_start = strstr((char*)user_modeline, "\""); + if (quote_start) + { + quote_start++; + quote_end = strstr(quote_start, "\""); + if (!quote_end || *quote_end++ == 0) + return false; + user_modeline = quote_end; + } + + // Get timing flags + mode->interlace = strstr(user_modeline, "interlace")?1:0; + mode->doublescan = strstr(user_modeline, "doublescan")?1:0; + mode->hsync = strstr(user_modeline, "+hsync")?1:0; + mode->vsync = strstr(user_modeline, "+vsync")?1:0; + + // Get timing values + double pclock; + int e = sscanf(user_modeline, " %lf %d %d %d %d %d %d %d %d", + &pclock, + &mode->hactive, &mode->hbegin, &mode->hend, &mode->htotal, + &mode->vactive, &mode->vbegin, &mode->vend, &mode->vtotal); + + if (e != 9) + { + log_error("Switchres: missing parameter in user modeline\n %s\n", user_modeline); + memset(mode, 0, sizeof(struct modeline)); + return false; + } + + // Calculate timings + mode->pclock = pclock * 1000000.0; + mode->hfreq = mode->pclock / mode->htotal; + mode->vfreq = mode->hfreq / mode->vtotal * (mode->interlace?2:1); + mode->refresh = mode->vfreq; + mode->width = mode->hactive; + mode->height = mode->vactive; + log_verbose("Switchres: user modeline %s\n", modeline_print(mode, modeline_txt, MS_FULL)); + + return true; +} + +//============================================================ +// modeline_to_monitor_range +//============================================================ + +int modeline_to_monitor_range(monitor_range *range, modeline *mode) +{ + // If Vfreq range is empty, create it around the provided vfreq + if (range->vfreq_min == 0.0f) range->vfreq_min = mode->vfreq - 0.2; + if (range->vfreq_max == 0.0f) range->vfreq_max = mode->vfreq + 0.2; + + // Make sure the range includes the target vfreq + if (mode->vfreq < range->vfreq_min || mode->vfreq > range->vfreq_max) + return 0; + + double line_time = 1 / mode->hfreq; + double pixel_time = line_time / mode->htotal * 1000000; + double interlace_factor = mode->interlace? 0.5 : 1.0; + + range->hfront_porch = pixel_time * (mode->hbegin - mode->hactive); + range->hsync_pulse = pixel_time * (mode->hend - mode->hbegin); + range->hback_porch = pixel_time * (mode->htotal - mode->hend); + + // We floor the vertical fields to remove the half line from interlaced modes, because + // the modeline generator will add it automatically. Otherwise it would be added twice. + range->vfront_porch = line_time * floor((mode->vbegin - mode->vactive) * interlace_factor); + range->vsync_pulse = line_time * floor((mode->vend - mode->vbegin) * interlace_factor); + range->vback_porch = line_time * floor((mode->vtotal - mode->vend) * interlace_factor); + range->vertical_blank = range->vfront_porch + range->vsync_pulse + range->vback_porch; + + range->hsync_polarity = mode->hsync; + range->vsync_polarity = mode->vsync; + + range->progressive_lines_min = mode->interlace? 0 : mode->vactive; + range->progressive_lines_max = mode->interlace? 0 : mode->vactive; + range->interlaced_lines_min = mode->interlace? mode->vactive : 0; + range->interlaced_lines_max= mode->interlace? mode->vactive : 0; + + range->hfreq_min = range->vfreq_min * mode->vtotal * interlace_factor; + range->hfreq_max = range->vfreq_max * mode->vtotal * interlace_factor; + + return 1; +} + +//============================================================ +// modeline_adjust +//============================================================ + +int modeline_adjust(modeline *mode, double hfreq_max, generator_settings *cs) +{ + // If input values are out of range, they are fixed within range and returned in the cs struct. + + // H size ajdustment, valid values 0.5-2.0 + if (cs->h_size != 1.0f) + { + if (cs->h_size > 2.0f) + cs->h_size = 2.0f; + else if (cs->h_size < 0.5f) + cs->h_size = 0.5f; + + monitor_range range; + memset(&range, 0, sizeof(monitor_range)); + + modeline_to_monitor_range(&range, mode); + + range.hfront_porch /= cs->h_size; + range.hback_porch /= cs->h_size; + + modeline_create(mode, mode, &range, cs); + } + + // H shift adjustment, positive or negative value + if (cs->h_shift != 0) + { + if (cs->h_shift >= mode->hbegin - mode->hactive) + cs->h_shift = mode->hbegin - mode->hactive - 1; + + else if (cs->h_shift <= mode->hend - mode->htotal) + cs->h_shift = mode->hend - mode->htotal + 1; + + mode->hbegin -= cs->h_shift; + mode->hend -= cs->h_shift; + } + + // V shift adjustment, positive or negative value + if (cs->v_shift != 0) + { + int vactive = mode->vactive; + int vbegin = mode->vbegin; + int vend = mode->vend; + int vtotal = mode->vtotal; + + if (mode->interlace) + { + vactive >>= 1; + vbegin >>= 1; + vend >>= 1; + vtotal >>= 1; + } + + int v_front_porch = vbegin - vactive; + int v_back_porch = vend - vtotal; + int max_vtotal = hfreq_max / mode->vfreq; + int border = max_vtotal - vtotal; + int padding = 0; + + // v_shift positive + if (cs->v_shift >= v_front_porch) + { + int v_front_porch_ex = v_front_porch + border; + if (cs->v_shift >= v_front_porch_ex) + cs->v_shift = v_front_porch_ex - 1; + + padding = cs->v_shift - v_front_porch + 1; + vbegin += padding; + vend += padding; + vtotal += padding; + } + + // v_shift negative + else if (cs->v_shift <= v_back_porch + 1) + { + int v_back_porch_ex = v_back_porch - border; + if (cs->v_shift <= v_back_porch_ex + 1) + cs->v_shift = v_back_porch_ex + 2; + + padding = -(cs->v_shift - v_back_porch - 2); + vtotal += padding; + } + + vbegin -= cs->v_shift; + vend -= cs->v_shift; + + if (mode->interlace) + { + vbegin = (vbegin << 1) | (mode->vbegin & 1); + vend = (vend << 1) | (mode->vend & 1); + vtotal = (vtotal << 1) | (mode->vtotal & 1); + } + + mode->vbegin = vbegin; + mode->vend = vend; + mode->vtotal = vtotal; + + if (padding != 0) + { + mode->hfreq = mode->vfreq * mode->vtotal / (mode->interlace? 2.0 : 1.0); + + monitor_range range; + memset(&range, 0, sizeof(monitor_range)); + modeline_to_monitor_range(&range, mode); + monitor_show_range(&range); + modeline_create(mode, mode, &range, cs); + } + } + + return 0; +} + +//============================================================ +// modeline_is_different +//============================================================ + +int modeline_is_different(modeline *n, modeline *p) +{ + // Remove on last fields in modeline comparison + return memcmp(n, p, offsetof(struct modeline, vfreq)); +} + +//============================================================ +// modeline_copy_timings +//============================================================ + +void modeline_copy_timings(modeline *n, modeline *p) +{ + // Only copy relevant timing fields + memcpy(n, p, offsetof(struct modeline, width)); +} + +//============================================================ +// monitor_fill_vesa_gtf +//============================================================ + +int monitor_fill_vesa_gtf(monitor_range *range, const char *max_lines) +{ + int lines = 0; + sscanf(max_lines, "vesa_%d", &lines); + + if (!lines) + return 0; + + int i = 0; + if (lines >= 480) + i += monitor_fill_vesa_range(&range[i], 384, 480); + if (lines >= 600) + i += monitor_fill_vesa_range(&range[i], 480, 600); + if (lines >= 768) + i += monitor_fill_vesa_range(&range[i], 600, 768); + if (lines >= 1024) + i += monitor_fill_vesa_range(&range[i], 768, 1024); + + return i; +} + +//============================================================ +// monitor_fill_vesa_range +//============================================================ + +int monitor_fill_vesa_range(monitor_range *range, int lines_min, int lines_max) +{ + modeline mode; + memset(&mode, 0, sizeof(modeline)); + + mode.width = real_res(STANDARD_CRT_ASPECT * lines_max); + mode.height = lines_max; + mode.refresh = 60; + range->vfreq_min = 50; + range->vfreq_max = 65; + + modeline_vesa_gtf(&mode); + modeline_to_monitor_range(range, &mode); + + range->progressive_lines_min = lines_min; + range->hfreq_min = mode.hfreq - 500; + range->hfreq_max = mode.hfreq + 500; + monitor_show_range(range); + + return 1; +} + +//============================================================ +// round_near +//============================================================ + +int round_near(double number) +{ + return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); +} + +//============================================================ +// round_near_odd +//============================================================ + +int round_near_odd(double number) +{ + return int(ceil(number)) % 2 == 0? floor(number) : ceil(number); +} + +//============================================================ +// round_near_even +//============================================================ + +int round_near_even(double number) +{ + return int(ceil(number)) % 2 == 1? floor(number) : ceil(number); +} + +//============================================================ +// normalize +//============================================================ + +int normalize(int a, int b) +{ + int c, d; + c = a % b; + d = a / b; + if (c) d++; + return d * b; +} + +//============================================================ +// real_res +//============================================================ + +int real_res(int x) {return (int) (x / 8) * 8;} diff --git a/modeline.h b/modeline.h new file mode 100644 index 00000000000..ac71ddcfb1d --- /dev/null +++ b/modeline.h @@ -0,0 +1,144 @@ +/************************************************************** + + modeline.h - Modeline generation header + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __MODELINE_H__ +#define __MODELINE_H__ + +#include +#include +#include +#include "monitor.h" + + +//============================================================ +// CONSTANTS +//============================================================ + +// Modeline print flags +#define MS_LABEL 0x00000001 +#define MS_LABEL_SDL 0x00000002 +#define MS_PARAMS 0x00000004 +#define MS_FULL MS_LABEL | MS_PARAMS + +// Modeline result +#define R_V_FREQ_OFF 0x00000001 +#define R_RES_STRETCH 0x00000002 +#define R_OUT_OF_RANGE 0x00000004 + +// Mode types +#define MODE_OK 0x00000000 +#define MODE_DESKTOP 0x01000000 +#define MODE_ROTATED 0x02000000 +#define MODE_DISABLED 0x04000000 +#define MODE_USER_DEF 0x08000000 +#define MODE_UPDATE 0x10000000 +#define MODE_ADD 0x20000000 +#define MODE_DELETE 0x40000000 +#define MODE_ERROR 0x80000000 +#define V_FREQ_EDITABLE 0x00000001 +#define X_RES_EDITABLE 0x00000002 +#define Y_RES_EDITABLE 0x00000004 +#define SCAN_EDITABLE 0x00000008 +#define XYV_EDITABLE (X_RES_EDITABLE | Y_RES_EDITABLE | V_FREQ_EDITABLE ) + +#define DUMMY_WIDTH 1234 +#define MAX_MODELINES 256 + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +typedef struct mode_result +{ + int weight; + int scan_penalty; + double x_scale; + double y_scale; + double v_scale; + double x_diff; + double y_diff; + double v_diff; +} mode_result; + +typedef struct modeline +{ + uint64_t pclock; + int hactive; + int hbegin; + int hend; + int htotal; + int vactive; + int vbegin; + int vend; + int vtotal; + int interlace; + int doublescan; + int hsync; + int vsync; + // + double vfreq; + double hfreq; + // + int width; + int height; + int refresh; + int refresh_label; + // + int id; + int type; + int range; + uint64_t platform_data; + // + mode_result result; +} modeline; + +typedef struct generator_settings +{ + int interlace; + int doublescan; + uint64_t pclock_min; + double monitor_aspect; + double refresh_tolerance; + int super_width; + double h_size; + int h_shift; + int v_shift; + int v_shift_correct; + int pixel_precision; + int interlace_force_even; +} generator_settings; + +//============================================================ +// PROTOTYPES +//============================================================ + +int modeline_create(modeline *s_mode, modeline *t_mode, monitor_range *range, generator_settings *cs); +int modeline_compare(modeline *t_mode, modeline *best_mode); +char * modeline_print(modeline *mode, char *modeline, int flags); +char * modeline_result(modeline *mode, char *result); +int modeline_vesa_gtf(modeline *m); +int modeline_parse(const char *user_modeline, modeline *mode); +int modeline_to_monitor_range(monitor_range *range, modeline *mode); +int modeline_adjust(modeline *mode, double hfreq_max, generator_settings *cs); +int modeline_is_different(modeline *n, modeline *p); +void modeline_copy_timings(modeline *n, modeline *p); + +int round_near(double number); +int round_near_odd(double number); +int round_near_even(double number); +int normalize(int a, int b); +int real_res(int x); + + +#endif diff --git a/monitor.cpp b/monitor.cpp new file mode 100644 index 00000000000..e0c24563eea --- /dev/null +++ b/monitor.cpp @@ -0,0 +1,437 @@ +/************************************************************** + + monitor.cpp - Monitor presets and custom monitor definition + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include "monitor.h" +#include "log.h" + +//============================================================ +// CONSTANTS +//============================================================ + +#define HFREQ_MIN 14000 +#define HFREQ_MAX 540672 // 8192 * 1.1 * 60 +#define VFREQ_MIN 40 +#define VFREQ_MAX 200 +#define PROGRESSIVE_LINES_MIN 128 + +//============================================================ +// monitor_fill_range +//============================================================ + +int monitor_fill_range(monitor_range *range, const char *specs_line) +{ + monitor_range new_range; + + if (strlen(specs_line) == 0) + return 0; + + if (strcmp(specs_line, "auto")) { + int e = sscanf(specs_line, "%lf-%lf,%lf-%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d,%d,%d,%d,%d", + &new_range.hfreq_min, &new_range.hfreq_max, + &new_range.vfreq_min, &new_range.vfreq_max, + &new_range.hfront_porch, &new_range.hsync_pulse, &new_range.hback_porch, + &new_range.vfront_porch, &new_range.vsync_pulse, &new_range.vback_porch, + &new_range.hsync_polarity, &new_range.vsync_polarity, + &new_range.progressive_lines_min, &new_range.progressive_lines_max, + &new_range.interlaced_lines_min, &new_range.interlaced_lines_max); + + if (e != 16) { + log_error("Switchres: Error trying to fill monitor range with\n %s\n", specs_line); + return -1; + } + + new_range.vfront_porch /= 1000; + new_range.vsync_pulse /= 1000; + new_range.vback_porch /= 1000; + new_range.vertical_blank = (new_range.vfront_porch + new_range.vsync_pulse + new_range.vback_porch); + + if (monitor_evaluate_range(&new_range)) + { + log_error("Switchres: Error in monitor range (ignoring): %s\n", specs_line); + return -1; + } + else + { + memcpy(range, &new_range, sizeof(struct monitor_range)); + monitor_show_range(range); + } + } + return 0; +} + +//============================================================ +// monitor_fill_lcd_range +//============================================================ + +int monitor_fill_lcd_range(monitor_range *range, const char *specs_line) +{ + if (strlen(specs_line) == 0) + return 0; + + if (strcmp(specs_line, "auto")) + { + if (sscanf(specs_line, "%lf-%lf", &range->vfreq_min, &range->vfreq_max) == 2) + { + log_verbose("Switchres: LCD vfreq range set by user as %f-%f\n", range->vfreq_min, range->vfreq_max); + return true; + } + else + log_error("Switchres: Error trying to fill LCD range with\n %s\n", specs_line); + } + // Use default values + range->vfreq_min = 59; + range->vfreq_max = 61; + log_verbose("Switchres: Using default vfreq range for LCD %f-%f\n", range->vfreq_min, range->vfreq_max); + + return 0; +} + +//============================================================ +// monitor_show_range +//============================================================ + +int monitor_show_range(monitor_range *range) +{ + log_verbose("Switchres: Monitor range %.2f-%.2f,%.2f-%.2f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%d,%d,%d,%d,%d,%d\n", + range->hfreq_min, range->hfreq_max, + range->vfreq_min, range->vfreq_max, + range->hfront_porch, range->hsync_pulse, range->hback_porch, + range->vfront_porch * 1000, range->vsync_pulse * 1000, range->vback_porch * 1000, + range->hsync_polarity, range->vsync_polarity, + range->progressive_lines_min, range->progressive_lines_max, + range->interlaced_lines_min, range->interlaced_lines_max); + + return 0; +} + +//============================================================ +// monitor_set_preset +//============================================================ + +int monitor_set_preset(const char *type, monitor_range *range) +{ + // PAL TV - 50 Hz/625 + if (!strcmp(type, "pal")) + { + monitor_fill_range(&range[0], "15625.00-15625.00, 50.00-50.00, 1.500, 4.700, 5.800, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); + return 1; + } + // NTSC TV - 60 Hz/525 + else if (!strcmp(type, "ntsc")) + { + monitor_fill_range(&range[0], "15734.26-15734.26, 59.94-59.94, 1.500, 4.700, 4.700, 0.191, 0.191, 0.953, 0, 0, 192, 240, 448, 480"); + return 1; + } + // Generic 15.7 kHz + else if (!strcmp(type, "generic_15")) + { + monitor_fill_range(&range[0], "15625-15750, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); + return 1; + } + // Arcade 15.7 kHz - standard resolution + else if (!strcmp(type, "arcade_15")) + { + monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); + return 1; + } + // Arcade 15.7-16.5 kHz - extended resolution + else if (!strcmp(type, "arcade_15ex")) + { + monitor_fill_range(&range[0], "15625-16500, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); + return 1; + } + // Arcade 25.0 kHz - medium resolution + else if (!strcmp(type, "arcade_25")) + { + monitor_fill_range(&range[0], "24960-24960, 49.50-65.00, 0.800, 4.000, 3.200, 0.080, 0.200, 1.000, 0, 0, 384, 400, 768, 800"); + return 1; + } + // Arcade 31.5 kHz - medium resolution + else if (!strcmp(type, "arcade_31")) + { + monitor_fill_range(&range[0], "31400-31500, 49.50-65.00, 0.940, 3.770, 1.890, 0.349, 0.064, 1.017, 0, 0, 400, 512, 0, 0"); + return 1; + } + // Arcade 15.7/25.0 kHz - dual-sync + else if (!strcmp(type, "arcade_15_25")) + { + monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "24960-24960, 49.50-65.00, 0.800, 4.000, 3.200, 0.080, 0.200, 1.000, 0, 0, 384, 400, 768, 800"); + return 2; + } + // Arcade 15.7/31.5 kHz - dual-sync + else if (!strcmp(type, "arcade_15_31")) + { + monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "31400-31500, 49.50-65.00, 0.940, 3.770, 1.890, 0.349, 0.064, 1.017, 0, 0, 400, 512, 0, 0"); + return 2; + } + // Arcade 15.7/25.0/31.5 kHz - tri-sync + else if (!strcmp(type, "arcade_15_25_31")) + { + monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "24960-24960, 49.50-65.00, 0.800, 4.000, 3.200, 0.080, 0.200, 1.000, 0, 0, 384, 400, 768, 800"); + monitor_fill_range(&range[2], "31400-31500, 49.50-65.00, 0.940, 3.770, 1.890, 0.349, 0.064, 1.017, 0, 0, 400, 512, 0, 0"); + return 3; + } + // Makvision 2929D + else if (!strcmp(type, "m2929")) + { + monitor_fill_range(&range[0], "30000-40000, 47.00-90.00, 0.600, 2.500, 2.800, 0.032, 0.096, 0.448, 0, 0, 384, 640, 0, 0"); + return 1; + } + // Wells Gardner D9800, D9400 + else if (!strcmp(type, "d9800") || !strcmp(type, "d9400")) + { + monitor_fill_range(&range[0], "15250-18000, 40-80, 2.187, 4.688, 6.719, 0.190, 0.191, 1.018, 0, 0, 224, 288, 448, 576"); + monitor_fill_range(&range[1], "18001-19000, 40-80, 2.187, 4.688, 6.719, 0.140, 0.191, 0.950, 0, 0, 288, 320, 0, 0"); + monitor_fill_range(&range[2], "20501-29000, 40-80, 2.910, 3.000, 4.440, 0.451, 0.164, 1.048, 0, 0, 320, 384, 0, 0"); + monitor_fill_range(&range[3], "29001-32000, 40-80, 0.636, 3.813, 1.906, 0.318, 0.064, 1.048, 0, 0, 384, 480, 0, 0"); + monitor_fill_range(&range[4], "32001-34000, 40-80, 0.636, 3.813, 1.906, 0.020, 0.106, 0.607, 0, 0, 480, 576, 0, 0"); + monitor_fill_range(&range[5], "34001-38000, 40-80, 1.000, 3.200, 2.200, 0.020, 0.106, 0.607, 0, 0, 576, 600, 0, 0"); + return 6; + } + // Wells Gardner D9200 + else if (!strcmp(type, "d9200")) + { + monitor_fill_range(&range[0], "15250-16500, 40-80, 2.187, 4.688, 6.719, 0.190, 0.191, 1.018, 0, 0, 224, 288, 448, 576"); + monitor_fill_range(&range[1], "23900-24420, 40-80, 2.910, 3.000, 4.440, 0.451, 0.164, 1.148, 0, 0, 384, 400, 0, 0"); + monitor_fill_range(&range[2], "31000-32000, 40-80, 0.636, 3.813, 1.906, 0.318, 0.064, 1.048, 0, 0, 400, 512, 0, 0"); + monitor_fill_range(&range[3], "37000-38000, 40-80, 1.000, 3.200, 2.200, 0.020, 0.106, 0.607, 0, 0, 512, 600, 0, 0"); + return 4; + } + // Wells Gardner K7000 + else if (!strcmp(type, "k7000")) + { + monitor_fill_range(&range[0], "15625-15800, 49.50-63.00, 2.000, 4.700, 8.000, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); + return 1; + } + // Wells Gardner 25K7131 + else if (!strcmp(type, "k7131")) + { + monitor_fill_range(&range[0], "15625-16670, 49.5-65, 2.000, 4.700, 8.000, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); + return 1; + } + // Wei-Ya M3129 + else if (!strcmp(type, "m3129")) + { + monitor_fill_range(&range[0], "15250-16500, 40-80, 2.187, 4.688, 6.719, 0.190, 0.191, 1.018, 1, 1, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "23900-24420, 40-80, 2.910, 3.000, 4.440, 0.451, 0.164, 1.048, 1, 1, 384, 400, 0, 0"); + monitor_fill_range(&range[2], "31000-32000, 40-80, 0.636, 3.813, 1.906, 0.318, 0.064, 1.048, 1, 1, 400, 512, 0, 0"); + return 3; + } + // Hantarex MTC 9110 + else if (!strcmp(type, "h9110") || !strcmp(type, "polo")) + { + monitor_fill_range(&range[0], "15625-16670, 49.5-65, 2.000, 4.700, 8.000, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); + return 1; + } + // Hantarex Polostar 25 + else if (!strcmp(type, "pstar")) + { + monitor_fill_range(&range[0], "15700-15800, 50-65, 1.800, 0.400, 7.400, 0.064, 0.160, 1.056, 0, 0, 192, 256, 0, 0"); + monitor_fill_range(&range[1], "16200-16300, 50-65, 0.200, 0.400, 8.000, 0.040, 0.040, 0.640, 0, 0, 256, 264, 512, 528"); + monitor_fill_range(&range[2], "25300-25400, 50-65, 0.200, 0.400, 8.000, 0.040, 0.040, 0.640, 0, 0, 384, 400, 768, 800"); + monitor_fill_range(&range[3], "31500-31600, 50-65, 0.170, 0.350, 5.500, 0.040, 0.040, 0.640, 0, 0, 400, 512, 0, 0"); + return 4; + } + // Nanao MS-2930, MS-2931 + else if (!strcmp(type, "ms2930")) + { + monitor_fill_range(&range[0], "15450-16050, 50-65, 3.190, 4.750, 6.450, 0.191, 0.191, 1.164, 0, 0, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "23900-24900, 50-65, 2.870, 3.000, 4.440, 0.451, 0.164, 1.148, 0, 0, 384, 400, 0, 0"); + monitor_fill_range(&range[2], "31000-32000, 50-65, 0.330, 3.580, 1.750, 0.316, 0.063, 1.137, 0, 0, 480, 512, 0, 0"); + return 3; + } + // Nanao MS9-29 + else if (!strcmp(type, "ms929")) + { + monitor_fill_range(&range[0], "15450-16050, 50-65, 3.910, 4.700, 6.850, 0.190, 0.191, 1.018, 0, 0, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "23900-24900, 50-65, 2.910, 3.000, 4.440, 0.451, 0.164, 1.048, 0, 0, 384, 400, 0, 0"); + return 2; + } + // Rodotron 666B-29 + else if (!strcmp(type, "r666b")) + { + monitor_fill_range(&range[0], "15450-16050, 50-65, 3.190, 4.750, 6.450, 0.191, 0.191, 1.164, 0, 0, 192, 288, 448, 576"); + monitor_fill_range(&range[1], "23900-24900, 50-65, 2.870, 3.000, 4.440, 0.451, 0.164, 1.148, 0, 0, 384, 400, 0, 0"); + monitor_fill_range(&range[2], "31000-32500, 50-65, 0.330, 3.580, 1.750, 0.316, 0.063, 1.137, 0, 0, 400, 512, 0, 0"); + return 3; + } + // PC CRT 70kHz/120Hz + else if (!strcmp(type, "pc_31_120")) + { + monitor_fill_range(&range[0], "31400-31600, 100-130, 0.671, 2.683, 3.353, 0.034, 0.101, 0.436, 0, 0, 200, 256, 0, 0"); + monitor_fill_range(&range[1], "31400-31600, 50-65, 0.671, 2.683, 3.353, 0.034, 0.101, 0.436, 0, 0, 400, 512, 0, 0"); + return 2; + } + // PC CRT 70kHz/120Hz + else if (!strcmp(type, "pc_70_120")) + { + monitor_fill_range(&range[0], "30000-70000, 100-130, 2.201, 0.275, 4.678, 0.063, 0.032, 0.633, 0, 0, 192, 320, 0, 0"); + monitor_fill_range(&range[1], "30000-70000, 50-65, 2.201, 0.275, 4.678, 0.063, 0.032, 0.633, 0, 0, 400, 1024, 0, 0"); + return 2; + } + // VESA GTF + else if (!strcmp(type, "vesa_480") || !strcmp(type, "vesa_600") || !strcmp(type, "vesa_768") || !strcmp(type, "vesa_1024")) + { + return monitor_fill_vesa_gtf(&range[0], type); + } + + log_error("Switchres: Monitor type unknown: %s\n", type); + return 0; +} + +//============================================================ +// monitor_evaluate_range +//============================================================ + +int monitor_evaluate_range(monitor_range *range) +{ + // First we check that all frequency ranges are reasonable + if (range->hfreq_min < HFREQ_MIN || range->hfreq_min > HFREQ_MAX) + { + log_error("Switchres: hfreq_min %.2f out of range\n", range->hfreq_min); + return 1; + } + if (range->hfreq_max < HFREQ_MIN || range->hfreq_max < range->hfreq_min || range->hfreq_max > HFREQ_MAX) + { + log_error("Switchres: hfreq_max %.2f out of range\n", range->hfreq_max); + return 1; + } + if (range->vfreq_min < VFREQ_MIN || range->vfreq_min > VFREQ_MAX) + { + log_error("Switchres: vfreq_min %.2f out of range\n", range->vfreq_min); + return 1; + } + if (range->vfreq_max < VFREQ_MIN || range->vfreq_max < range->vfreq_min || range->vfreq_max > VFREQ_MAX) + { + log_error("Switchres: vfreq_max %.2f out of range\n", range->vfreq_max); + return 1; + } + + // line_time in μs. We check that no horizontal value is longer than a whole line + double line_time = 1 / range->hfreq_max * 1000000; + + if (range->hfront_porch <= 0 || range->hfront_porch > line_time) + { + log_error("Switchres: hfront_porch %.3f out of range\n", range->hfront_porch); + return 1; + } + if (range->hsync_pulse <= 0 || range->hsync_pulse > line_time) + { + log_error("Switchres: hsync_pulse %.3f out of range\n", range->hsync_pulse); + return 1; + } + if (range->hback_porch <= 0 || range->hback_porch > line_time) + { + log_error("Switchres: hback_porch %.3f out of range\n", range->hback_porch); + return 1; + } + + // frame_time in ms. We check that no vertical value is longer than a whole frame + double frame_time = 1 / range->vfreq_max * 1000; + + if (range->vfront_porch <= 0 || range->vfront_porch > frame_time) + { + log_error("Switchres: vfront_porch %.3f out of range\n", range->vfront_porch); + return 1; + } + if (range->vsync_pulse <= 0 || range->vsync_pulse > frame_time) + { + log_error("Switchres: vsync_pulse %.3f out of range\n", range->vsync_pulse); + return 1; + } + if (range->vback_porch <= 0 || range->vback_porch > frame_time) + { + log_error("Switchres: vback_porch %.3f out of range\n", range->vback_porch); + return 1; + } + + // Now we check sync polarities + if (range->hsync_polarity != 0 && range->hsync_polarity != 1) + { + log_error("Switchres: Hsync polarity can be only 0 or 1\n"); + return 1; + } + if (range->vsync_polarity != 0 && range->vsync_polarity != 1) + { + log_error("Switchres: Vsync polarity can be only 0 or 1\n"); + return 1; + } + + // Finally we check that the line limiters are reasonable + // Progressive range: + if (range->progressive_lines_min > 0 && range->progressive_lines_min < PROGRESSIVE_LINES_MIN) + { + log_error("Switchres: progressive_lines_min must be greater than %d\n", PROGRESSIVE_LINES_MIN); + return 1; + } + if ((range->progressive_lines_min + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) + { + log_error("Switchres: progressive_lines_min %d out of range\n", range->progressive_lines_min); + return 1; + } + if (range->progressive_lines_max < range->progressive_lines_min) + { + log_error("Switchres: progressive_lines_max must greater than progressive_lines_min\n"); + return 1; + } + if ((range->progressive_lines_max + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) + { + log_error("Switchres: progressive_lines_max %d out of range\n", range->progressive_lines_max); + return 1; + } + + // Interlaced range: + if (range->interlaced_lines_min != 0) + { + if (range->interlaced_lines_min < range->progressive_lines_max) + { + log_error("Switchres: interlaced_lines_min must greater than progressive_lines_max\n"); + return 1; + } + if (range->interlaced_lines_min < PROGRESSIVE_LINES_MIN * 2) + { + log_error("Switchres: interlaced_lines_min must be greater than %d\n", PROGRESSIVE_LINES_MIN * 2); + return 1; + } + if ((range->interlaced_lines_min / 2 + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) + { + log_error("Switchres: interlaced_lines_min %d out of range\n", range->interlaced_lines_min); + return 1; + } + if (range->interlaced_lines_max < range->interlaced_lines_min) + { + log_error("Switchres: interlaced_lines_max must greater than interlaced_lines_min\n"); + return 1; + } + if ((range->interlaced_lines_max / 2 + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) + { + log_error("Switchres: interlaced_lines_max %d out of range\n", range->interlaced_lines_max); + return 1; + } + } + else + { + if (range->interlaced_lines_max != 0) + { + log_error("Switchres: interlaced_lines_max must be zero if interlaced_lines_min is not defined\n"); + return 1; + } + } + return 0; +} diff --git a/monitor.h b/monitor.h new file mode 100644 index 00000000000..3ade8d091ac --- /dev/null +++ b/monitor.h @@ -0,0 +1,64 @@ +/************************************************************** + + monitor.h - Monitor presets header + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __MONITOR_H__ +#define __MONITOR_H__ + +//============================================================ +// CONSTANTS +//============================================================ + +#define MAX_RANGES 10 +#define MONITOR_CRT 0 +#define MONITOR_LCD 1 +#define STANDARD_CRT_ASPECT 4.0/3.0 + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +typedef struct monitor_range +{ + double hfreq_min; + double hfreq_max; + double vfreq_min; + double vfreq_max; + double hfront_porch; + double hsync_pulse; + double hback_porch; + double vfront_porch; + double vsync_pulse; + double vback_porch; + int hsync_polarity; + int vsync_polarity; + int progressive_lines_min; + int progressive_lines_max; + int interlaced_lines_min; + int interlaced_lines_max; + double vertical_blank; +} monitor_range; + +//============================================================ +// PROTOTYPES +//============================================================ + +int monitor_fill_range(monitor_range *range, const char *specs_line); +int monitor_show_range(monitor_range *range); +int monitor_set_preset(const char *type, monitor_range *range); +int monitor_fill_lcd_range(monitor_range *range, const char *specs_line); +int monitor_fill_vesa_gtf(monitor_range *range, const char *max_lines); +int monitor_fill_vesa_range(monitor_range *range, int lines_min, int lines_max); +int monitor_evaluate_range(monitor_range *range); + +#endif diff --git a/resync_windows.cpp b/resync_windows.cpp new file mode 100644 index 00000000000..141c958e80a --- /dev/null +++ b/resync_windows.cpp @@ -0,0 +1,171 @@ +/************************************************************** + + resync_windows.cpp - Windows device change notifying helper + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include "resync_windows.h" +#include "log.h" + +GUID GUID_DEVINTERFACE_MONITOR = { 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }; + +//============================================================ +// resync_handler::resync_handler +//============================================================ + +resync_handler::resync_handler() +{ + m_event = CreateEvent(NULL, FALSE, FALSE, NULL); + CreateThread(NULL, 0, handler_thread, (LPVOID)this, 0, &my_thread); +} + +//============================================================ +// resync_handler::~resync_handler +//============================================================ + +resync_handler::~resync_handler() +{ + SendMessage(m_hwnd, WM_CLOSE, 0, 0); + if (m_event) CloseHandle(m_event); +} + +//============================================================ +// resync_handler::handler_thread +//============================================================ + +DWORD WINAPI resync_handler::handler_thread(LPVOID lpParameter) +{ + return ((resync_handler *)lpParameter)->handler_thread_wt(); +} + +DWORD resync_handler::handler_thread_wt() +{ + WNDCLASSEX wc; + MSG msg; + HINSTANCE hinst = GetModuleHandle(NULL); + + wc.cbSize = sizeof(wc); + wc.lpfnWndProc = this->resync_wnd_proc; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbWndExtra = 0; + wc.cbClsExtra = 0; + wc.hInstance = hinst; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + wc.lpszClassName = "resync_handler"; + wc.hIcon = NULL; + wc.hIconSm = wc.hIcon; + wc.hCursor = LoadCursor(NULL, IDC_HAND); + + RegisterClassEx(&wc); + + m_hwnd = CreateWindowEx(0, "resync_handler", NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hinst, NULL); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + + // Register notifications of display monitor events + DEV_BROADCAST_DEVICEINTERFACE filter; + ZeroMemory(&filter, sizeof(filter)); + filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + filter.dbcc_classguid = GUID_DEVINTERFACE_MONITOR; + HDEVNOTIFY hDeviceNotify = RegisterDeviceNotification(m_hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); + if (hDeviceNotify == NULL) + log_error("Error registering notification\n"); + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return -1; +} + +//============================================================ +// resync_handler::wait +//============================================================ + +void resync_handler::wait() +{ + m_is_notified_1 = false; + m_is_notified_2 = false; + + auto start = std::chrono::steady_clock::now(); + + while (!m_is_notified_1 || !m_is_notified_2) + WaitForSingleObject(m_event, 10); + + auto end = std::chrono::steady_clock::now(); + log_verbose("resync time elapsed %I64d ms\n", std::chrono::duration_cast(end-start).count()); +} + +//============================================================ +// resync_handler::resync_wnd_proc +//============================================================ + +LRESULT CALLBACK resync_handler::resync_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + resync_handler *me = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + if (me) return me->my_wnd_proc(hwnd, msg, wparam, lparam); + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +LRESULT CALLBACK resync_handler::my_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_DEVICECHANGE: + { + switch (wparam) + { + case DBT_DEVICEARRIVAL: + { + log_verbose("Message: DBT_DEVICEARRIVAL\n"); + PDEV_BROADCAST_DEVICEINTERFACE db = (PDEV_BROADCAST_DEVICEINTERFACE) lparam; + if (db != nullptr) + { + if (db->dbcc_classguid == GUID_DEVINTERFACE_MONITOR) + { + m_is_notified_1 = true; + SetEvent(m_event); + } + } + break; + } + case DBT_DEVICEREMOVECOMPLETE: + log_verbose("Message: DBT_DEVICEREMOVECOMPLETE\n"); + break; + case DBT_DEVNODES_CHANGED: + log_verbose("Message: DBT_DEVNODES_CHANGED\n"); + m_is_notified_2 = true; + SetEvent(m_event); + break; + default: + log_verbose("Message: WM_DEVICECHANGE message received, value %x unhandled.\n", (int)wparam); + break; + } + return 0; + } + break; + + case WM_CLOSE: + { + PostQuitMessage(0); + return 0; + } + + default: + return DefWindowProc(hwnd, msg, wparam, lparam); + } + return 0; +} diff --git a/resync_windows.h b/resync_windows.h new file mode 100644 index 00000000000..1b96b66b09b --- /dev/null +++ b/resync_windows.h @@ -0,0 +1,43 @@ +/************************************************************** + + resync_windows.h - Windows device change notifying helper + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __RESYNC_WINDOWS__ +#define __RESYNC_WINDOWS__ + +#include +#include +#include + +class resync_handler +{ + public: + resync_handler(); + ~resync_handler(); + + void wait(); + + private: + static LRESULT CALLBACK resync_wnd_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT CALLBACK my_wnd_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static DWORD WINAPI handler_thread(LPVOID lpParameter); + DWORD handler_thread_wt(); + + HWND m_hwnd; + DWORD my_thread; + bool m_is_notified_1; + bool m_is_notified_2; + HANDLE m_event; +}; + +#endif diff --git a/switchres.cpp b/switchres.cpp new file mode 100644 index 00000000000..64736d848e9 --- /dev/null +++ b/switchres.cpp @@ -0,0 +1,411 @@ +/************************************************************** + + switchres.cpp - Swichres manager + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include "switchres.h" +#include "log.h" + +using namespace std; +const string WHITESPACE = " \n\r\t\f\v"; + +#if defined(_WIN32) + #define SR_CONFIG_PATHS ";.\\;.\\ini\\;" +#else + #define SR_CONFIG_PATHS ";./;./ini/;/etc/;" +#endif + +//============================================================ +// logging +//============================================================ + +void switchres_manager::set_log_level(int log_level) { set_log_verbosity(log_level); } +void switchres_manager::set_log_verbose_fn(void *func_ptr) { set_log_verbose((void *)func_ptr); } +void switchres_manager::set_log_info_fn(void *func_ptr) { set_log_info((void *)func_ptr); } +void switchres_manager::set_log_error_fn(void *func_ptr) { set_log_error((void *)func_ptr); } + +//============================================================ +// File parsing helpers +//============================================================ + +string ltrim(const string& s) +{ + size_t start = s.find_first_not_of(WHITESPACE); + return (start == string::npos) ? "" : s.substr(start); +} + +string rtrim(const string& s) +{ + size_t end = s.find_last_not_of(WHITESPACE); + return (end == string::npos) ? "" : s.substr(0, end + 1); +} + +string trim(const string& s) +{ + return rtrim(ltrim(s)); +} + +bool get_value(const string& line, string& key, string& value) +{ + size_t key_end = line.find_first_of(WHITESPACE); + + key = line.substr(0, key_end); + value = ltrim(line.substr(key_end + 1)); + + if (key.length() > 0 && value.length() > 0) + return true; + + return false; +} + +constexpr unsigned int s2i(const char* str, int h = 0) +{ + return !str[h] ? 5381 : (s2i(str, h+1)*33) ^ str[h]; +} + +//============================================================ +// switchres_manager::switchres_manager +//============================================================ + +switchres_manager::switchres_manager() +{ + // Create our display manager + m_display_factory = new display_manager(); + m_current_display = m_display_factory; + + // Set display manager default options + display()->set_monitor("generic_15"); + display()->set_modeline("auto"); + display()->set_lcd_range("auto"); + for (int i = 0; i++ < MAX_RANGES;) display()->set_crt_range(i, "auto"); + display()->set_screen("auto"); + display()->set_modeline_generation(true); + display()->set_lock_unsupported_modes(true); + display()->set_lock_system_modes(true); + display()->set_refresh_dont_care(false); + + // Set modeline generator default options + display()->set_interlace(true); + display()->set_doublescan(true); + display()->set_dotclock_min(0.0f); + display()->set_monitor_aspect(STANDARD_CRT_ASPECT); + display()->set_refresh_tolerance(2.0f); + display()->set_super_width(2560); + display()->set_h_shift(0); + display()->set_v_shift(0); + display()->set_h_size(1.0f); + display()->set_v_shift_correct(0); + display()->set_pixel_precision(1); + display()->set_interlace_force_even(0); + + // Set logger properties + set_log_info_fn((void*)printf); + set_log_error_fn((void*)printf); + set_log_verbose_fn((void*)printf); + set_log_level(2); +} + +//============================================================ +// switchres_manager::~switchres_manager +//============================================================ + +switchres_manager::~switchres_manager() +{ + if (m_display_factory) delete m_display_factory; + + for (auto &display : displays) + delete display; +}; + +//============================================================ +// switchres_manager::add_display +//============================================================ + +display_manager* switchres_manager::add_display(bool parse_options) +{ + // Parse display specific ini, if it exists + char file_name[32] = {0}; + sprintf(file_name, "display%d.ini", (int)displays.size()); + bool has_ini = parse_config(file_name); + + // Create new display + display_manager *display = m_display_factory->make(&m_display_factory->m_ds); + if (display == nullptr) + { + log_error("Switchres: error adding display\n"); + return nullptr; + } + + m_current_display = display; + display->set_index(displays.size()); + display->set_has_ini(has_ini); + displays.push_back(display); + + log_verbose("Switchres(v%s) add display[%d]\n", SWITCHRES_VERSION, display->index()); + + if (parse_options) + display->parse_options(); + + return display; +} + +//============================================================ +// switchres_manager::parse_config +//============================================================ + +bool switchres_manager::parse_config(const char *file_name) +{ + ifstream config_file; + + // Search for ini file in our config paths + auto start = 0U; + while (true) + { + char full_path[256] = ""; + string paths = SR_CONFIG_PATHS; + + auto end = paths.find(";", start); + if (end == string::npos) return false; + + snprintf(full_path, sizeof(full_path), "%s%s", paths.substr(start, end - start).c_str(), file_name); + config_file.open(full_path); + + if (config_file.is_open()) + { + log_verbose("parsing %s\n", full_path); + break; + } + start = end + 1; + } + + // Ini file found, parse it + string line; + while (getline(config_file, line)) + { + line = trim(line); + if (line.length() == 0 || line.at(0) == '#') + continue; + + string key, value; + if(get_value(line, key, value)) + set_option(key.c_str(), value.c_str()); + } + config_file.close(); + return true; +} + +//============================================================ +// switchres_manager::set_option +//============================================================ + +void switchres_manager::set_option(const char* key, const char* value) +{ + switch (s2i(key)) + { + // Switchres options + case s2i("verbose"): + if (atoi(value)) set_log_verbose_fn((void*)printf); + break; + case s2i("monitor"): + display()->set_monitor(value); + break; + case s2i("crt_range0"): + display()->set_crt_range(0, value); + break; + case s2i("crt_range1"): + display()->set_crt_range(1, value); + break; + case s2i("crt_range2"): + display()->set_crt_range(2, value); + break; + case s2i("crt_range3"): + display()->set_crt_range(3, value); + break; + case s2i("crt_range4"): + display()->set_crt_range(4, value); + break; + case s2i("crt_range5"): + display()->set_crt_range(5, value); + break; + case s2i("crt_range6"): + display()->set_crt_range(6, value); + break; + case s2i("crt_range7"): + display()->set_crt_range(7, value); + break; + case s2i("crt_range8"): + display()->set_crt_range(8, value); + break; + case s2i("crt_range9"): + display()->set_crt_range(9, value); + break; + case s2i("lcd_range"): + display()->set_lcd_range(value); + break; + case s2i("modeline"): + display()->set_modeline(value); + break; + case s2i("user_mode"): + { + modeline user_mode = {}; + if (strcmp(value, "auto")) + { + if (sscanf(value, "%dx%d@%d", &user_mode.width, &user_mode.height, &user_mode.refresh) < 1) + { + log_error("Error: use format resolution x@\n"); + break; + } + } + display()->set_user_mode(&user_mode); + break; + } + + // Display options + case s2i("display"): + display()->set_screen(value); + break; + case s2i("api"): + display()->set_api(value); + break; + case s2i("modeline_generation"): + display()->set_modeline_generation(atoi(value)); + break; + case s2i("lock_unsupported_modes"): + display()->set_lock_unsupported_modes(atoi(value)); + break; + case s2i("lock_system_modes"): + display()->set_lock_system_modes(atoi(value)); + break; + case s2i("refresh_dont_care"): + display()->set_refresh_dont_care(atoi(value)); + break; + case s2i("keep_changes"): + display()->set_keep_changes(atoi(value)); + break; + + // Modeline generation options + case s2i("interlace"): + display()->set_interlace(atoi(value)); + break; + case s2i("doublescan"): + display()->set_doublescan(atoi(value)); + break; + case s2i("dotclock_min"): + { + double pclock_min = 0.0f; + sscanf(value, "%lf", &pclock_min); + display()->set_dotclock_min(pclock_min); + break; + } + case s2i("sync_refresh_tolerance"): + { + double refresh_tolerance = 0.0f; + sscanf(value, "%lf", &refresh_tolerance); + display()->set_refresh_tolerance(refresh_tolerance); + break; + } + case s2i("super_width"): + { + int super_width = 0; + sscanf(value, "%d", &super_width); + display()->set_super_width(super_width); + break; + } + case s2i("aspect"): + display()->set_monitor_aspect(value); + break; + case s2i("h_size"): + { + double h_size = 1.0f; + sscanf(value, "%lf", &h_size); + display()->set_h_size(h_size); + break; + } + case s2i("h_shift"): + { + int h_shift = 0; + sscanf(value, "%d", &h_shift); + display()->set_h_shift(h_shift); + break; + } + case s2i("v_shift"): + { + int v_shift = 0; + sscanf(value, "%d", &v_shift); + display()->set_v_shift(v_shift); + break; + } + case s2i("v_shift_correct"): + display()->set_v_shift_correct(atoi(value)); + break; + + case s2i("pixel_precision"): + display()->set_pixel_precision(atoi(value)); + break; + + case s2i("interlace_force_even"): + display()->set_interlace_force_even(atoi(value)); + break; + + // Custom video backend options + case s2i("screen_compositing"): + display()->set_screen_compositing(atoi(value)); + break; + case s2i("screen_reordering"): + display()->set_screen_reordering(atoi(value)); + break; + case s2i("allow_hardware_refresh"): + display()->set_allow_hardware_refresh(atoi(value)); + break; + case s2i("custom_timing"): + display()->set_custom_timing(value); + break; + + // Various + case s2i("verbosity"): + { + int verbosity_level = 1; + sscanf(value, "%d", &verbosity_level); + set_log_level(verbosity_level); + break; + } + + default: + log_error("Invalid option %s\n", key); + break; + } +} + +//============================================================ +// switchres_manager::set_current_display +//============================================================ + +void switchres_manager::set_current_display(int index) +{ + int disp_index; + + if (index == -1) + { + m_current_display = m_display_factory; + return; + } + else if (index < 0 || index >= (int)displays.size()) + disp_index = 0; + + else + disp_index = index; + + m_current_display = displays[disp_index]; +} diff --git a/switchres.h b/switchres.h new file mode 100644 index 00000000000..d6af27e3cfa --- /dev/null +++ b/switchres.h @@ -0,0 +1,70 @@ +/************************************************************** + + switchres.h - SwichRes general header + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#ifndef __SWITCHRES_H__ +#define __SWITCHRES_H__ + +#include +#include +#include "monitor.h" +#include "modeline.h" +#include "display.h" +#include "edid.h" + +//============================================================ +// CONSTANTS +//============================================================ + +#ifndef SWITCHRES_VERSION +#define SWITCHRES_VERSION "2.1.0" +#endif + + +class switchres_manager +{ +public: + + switchres_manager(); + ~switchres_manager(); + + // getters + display_manager *display() const { return m_current_display; } + display_manager *display(int i) const { return i < (int)displays.size()? displays[i] : nullptr; } + display_manager *display_factory() const { return m_display_factory; } + static char* get_version() { return (char*) SWITCHRES_VERSION; }; + + // setters (log manager) + void set_log_level(int log_level); + void set_log_verbose_fn(void *func_ptr); + void set_log_info_fn(void *func_ptr); + void set_log_error_fn(void *func_ptr); + + void set_current_display(int index); + void set_option(const char* key, const char* value); + + // interface + display_manager* add_display(bool parse_options = true); + bool parse_config(const char *file_name); + + // display list + std::vector displays; + +private: + + display_manager *m_display_factory = 0; + display_manager *m_current_display = 0; +}; + + +#endif diff --git a/switchres.ini b/switchres.ini new file mode 100644 index 00000000000..8c7b1ea3c7f --- /dev/null +++ b/switchres.ini @@ -0,0 +1,165 @@ +# +# Switchres config +# + +# Monitor preset. Sets typical monitor operational ranges: +# +# generic_15, ntsc, pal Generic CRT standards +# arcade_15, arcade_15ex Arcade fixed frequency +# arcade_25, arcade_31 Arcade fixed frequency +# arcade_15_25, arcade_15_25_31 Arcade multisync +# vesa_480, vesa_600, vesa_768, vesa_1024 VESA GTF +# pc_31_120, pc_70_120 PC monitor 120 Hz +# h9110, polo, pstar Hantarex +# k7000, k7131, d9200, d9800, d9400 Wells Gardner +# m2929 Makvision +# m3129 Wei-Ya +# ms2930, ms929 Nanao +# r666b Rodotron +# +# Special presets: +# custom Defines a custom preset. Use in combination with crt_range0-9 options below. +# lcd Will keep desktop's resolution but attempt variable refresh, use in combination with lcd_range +# + monitor arcade_15 + +# Define a custom preset, use monitor custom to activate +# crt_range0-9 HfreqMin-HfreqMax, VfreqMin-VfreqMax, HFrontPorch, HSyncPulse, HBackPorch, VfrontPorch, VSyncPulse, VBackPorch, HSyncPol, VSyncPol, ProgressiveLinesMin, ProgressiveLinesMax, InterlacedLinesMin, InterlacedLinesMax +# e.g.: crt_range0 15625-15750, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576 + crt_range0 auto + crt_range1 auto + crt_range2 auto + crt_range3 auto + crt_range4 auto + crt_range5 auto + crt_range6 auto + crt_range7 auto + crt_range8 auto + crt_range9 auto + +# Set the operational refresh range for LCD monitor, e.g. lcd_range 50-61 + lcd_range auto + +# Force a custom modeline, in XFree86 format. This option overrides the active monitor preset configuration. + modeline auto + +# Forces an user mode, in the format: width x height @ refresh. Here, 0 can used as a wildcard. At least one of the three values +# must be defined. E.g. user_mode 0x240 -> SR can freely choose any width based on the game's requested video mode, but will +# force height as 240. + user_mode auto + + +# +# Display config +# + +# Select target display +# auto Pick the default display +# 0, 1, 2, ... Pick a display by index +# \\.\DISPLAY1, ... Windows display name +# VGA-0, ... X11 display name + display auto + +# Choose a custom video backend when more than one is available. +# auto Let Switchres decide +# adl Windows - AMD ADL (AMD Radeon HD 5000+) +# ati Windows - ATI legacy (ATI Radeon pre-HD 5000) +# powerstrip Windows - PowerStrip (ATI, Nvidia, Matrox, etc., models up to 2012) +# xrandr Linux - X11/Xorg +# drmkms Linux - KMS/DRM (WIP) + api auto + +# [Windows] Lock video modes reported as unsupported by your monitor's EDID + lock_unsupported_modes 1 + +# Lock system (non-custom) video modes, only use modes that have full detailed timings available + lock_system_modes 0 + +# Ignore video mode's refresh reported by the OS when checking ranges + refresh_dont_care 0 + +# Keep changes on exit (warning: this skips video mode cleanup) + keep_changes 0 + + +# +# Modeline generation config +# + +# Enable on-the-fly generation of video modes + modeline_generation 1 + +# Allow interlaced modes (existing or generated) + interlace 1 + +# Allow doublescan modes (warning: doublescan support is broken in most drivers) + doublescan 0 + +# Force a minimum dotclock value, in MHz, e.g. dotclock_min 25.0 + dotclock_min 0 + +# Maximum refresh difference, in Hz, allowed in order to synchronize. Below this value, the mismatch does not involve penalization + sync_refresh_tolerance 2.0 + +# Super resolution width: above this width, fractional scaling on the horizontal axis is applied without penalization + super_width 2560 + +# Physical aspect ratio of the target monitor. Used to compensate aspect ratio when the target monitor is not 4:3 + aspect 4:3 + +# [Experimental] Attempts to compensate consumer TVs vertical centering issues + v_shift_correct 0 + +# Apply geometry correction to calculated modelines + h_size 1.0 + h_shift 0 + v_shift 0 + +# Calculate horizontal borders with 1-pixel precision, instead of the default 8-pixels blocks that were required by old drivers. +# Greatly improves horizontal centering of video modes. + pixel_precision 1 + +# Calculate all vertical values of interlaced modes as even numbers. Required by AMD APU hardware on Linux + interlace_force_even 0 + + +# +# Custom video backend config +# + +# [X11] adjusts the crtc position after a new video mode is set, maintaining the relative position of screens in a multi-monitor setup. + screen_compositing 0 + +# [X11] stacks the screens vertically on startup to allow each screen to freely resize up to the maximum width. Useful to avoid video +# glitches when using super-resolutions. screen_reordering overrides screen_compositing. + screen_reordering 0 + +# [Windows] dynamically adds new modes or updates existing ones, even on stock AMD drivers*. This feature is experimental and is +# disabled by default. It has the following limitations and problems: +# - Synchronization is not perfect yet and the new modes may not always be ready on time for mode switching, causing a wrong display +# output. +# - A plug-n-play audio notification will be present on startup and exit, if the explorer shell is used. +# - Refreshing the hardware is an expensive task that takes time, specially if the app has already entered fullscreen mode. This +# makes it unpractical for games that switch video modes more than once. +# * When used with stock AMD drivers instead of CRT Emudriver, usual limitations apply: no support for low resolutions (below 640x480) +# nor low dotclocks. +# Not a problem however if you're using a 31 kHz monitor. + allow_hardware_refresh 0 + +# Pass a custom video timing string in the native backend's format. E.g. pstring timing for Powerstrip + custom_timing auto + + +# +# Logging +# + +# Enables verbose mode (0|1) + verbose 0 + +# Set verbosity level (from 0 to 3) +# 0: no messages from SR +# 1: only errors +# 2: general information +# 3: debug messages + verbosity 2 diff --git a/switchres_defines.h b/switchres_defines.h new file mode 100644 index 00000000000..9a9e96759d3 --- /dev/null +++ b/switchres_defines.h @@ -0,0 +1,41 @@ +#define SR_DEFINES + +#define SR_OPT_MONITOR "monitor" +#define SR_OPT_CRT_RANGE0 "crt_range0" +#define SR_OPT_CRT_RANGE1 "crt_range1" +#define SR_OPT_CRT_RANGE2 "crt_range2" +#define SR_OPT_CRT_RANGE3 "crt_range3" +#define SR_OPT_CRT_RANGE4 "crt_range4" +#define SR_OPT_CRT_RANGE5 "crt_range5" +#define SR_OPT_CRT_RANGE6 "crt_range6" +#define SR_OPT_CRT_RANGE7 "crt_range7" +#define SR_OPT_CRT_RANGE8 "crt_range8" +#define SR_OPT_CRT_RANGE9 "crt_range9" +#define SR_OPT_LCD_RANGE "lcd_range" +#define SR_OPT_MODELINE "modeline" +#define SR_OPT_USER_MODE "user_mode" +#define SR_OPT_DISPLAY "display" +#define SR_OPT_API "api" +#define SR_OPT_LOCK_UNSUPPORTED_MODES "lock_unsupported_modes" +#define SR_OPT_LOCK_SYSTEM_MODES "lock_system_modes" +#define SR_OPT_REFRESH_DONT_CARE "refresh_dont_care" +#define SR_OPT_KEEP_CHANGES "keep_changes" +#define SR_OPT_MODELINE_GENERATION "modeline_generation" +#define SR_OPT_INTERLACE "interlace" +#define SR_OPT_DOUBLESCAN "doublescan" +#define SR_OPT_DOTCLOCK_MIN "dotclock_min" +#define SR_OPT_SYNC_REFRESH_TOLERANCE "sync_refresh_tolerance" +#define SR_OPT_SUPER_WIDTH "super_width" +#define SR_OPT_ASPECT "aspect" +#define SR_OPT_V_SHIFT_CORRECT "v_shift_correct" +#define SR_OPT_H_SIZE "h_size" +#define SR_OPT_H_SHIFT "h_shift" +#define SR_OPT_V_SHIFT "v_shift" +#define SR_OPT_PIXEL_PRECISION "pixel_precision" +#define SR_OPT_INTERLACE_FORCE_EVEN "interlace_force_even" +#define SR_OPT_SCREEN_COMPOSITING "screen_compositing" +#define SR_OPT_SCREEN_REORDERING "screen_reordering" +#define SR_OPT_ALLOW_HARDWARE_REFRESH "allow_hardware_refresh" +#define SR_OPT_CUSTOM_TIMING "custom_timing" +#define SR_OPT_VERBOSE "verbose" +#define SR_OPT_VERBOSITY "verbosity" \ No newline at end of file diff --git a/switchres_main.cpp b/switchres_main.cpp new file mode 100644 index 00000000000..c793cbf1a08 --- /dev/null +++ b/switchres_main.cpp @@ -0,0 +1,354 @@ +/************************************************************** + + switchres_main.cpp - Swichres standalone launcher + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#include +#include +#include "switchres.h" +#include "log.h" + +using namespace std; + +int show_version(); +int show_usage(); + +enum + { + OPT_MODELINE = 128 + }; + +//============================================================ +// main +//============================================================ + +int main(int argc, char **argv) +{ + + switchres_manager switchres; + display_manager* df = switchres.display_factory(); + + switchres.parse_config("switchres.ini"); + + int width = 0; + int height = 0; + float refresh = 0.0; + modeline user_mode = {}; + int index = 0; + + int version_flag = false; + bool help_flag = false; + bool resolution_flag = false; + bool calculate_flag = false; + bool edid_flag = false; + bool switch_flag = false; + bool launch_flag = false; + bool force_flag = false; + bool interlaced_flag = false; + bool rotated_flag = false; + bool user_ini_flag = false; + bool keep_changes_flag = false; + bool geometry_flag = false; + int status_code = 0; + + string ini_file; + string launch_command; + + while (1) + { + static struct option long_options[] = + { + {"version", no_argument, &version_flag, '1'}, + {"help", no_argument, 0, 'h'}, + {"calc", no_argument, 0, 'c'}, + {"switch", no_argument, 0, 's'}, + {"launch", required_argument, 0, 'l'}, + {"monitor", required_argument, 0, 'm'}, + {"aspect", required_argument, 0, 'a'}, + {"edid", no_argument, 0, 'e'}, + {"rotated", no_argument, 0, 'r'}, + {"display", required_argument, 0, 'd'}, + {"force", required_argument, 0, 'f'}, + {"ini", required_argument, 0, 'i'}, + {"verbose", no_argument, 0, 'v'}, + {"backend", required_argument, 0, 'b'}, + {"keep", no_argument, 0, 'k'}, + {"geometry", required_argument, 0, 'g'}, + {"modeline", required_argument, 0, OPT_MODELINE}, + {0, 0, 0, 0} + }; + + int option_index = 0; + int c = getopt_long(argc, argv, "vhcsl:m:a:erd:f:i:b:kg:", long_options, &option_index); + + if (c == -1) + break; + + if (version_flag) + { + show_version(); + return 0; + } + + switch (c) + { + case OPT_MODELINE: + df->set_modeline(optarg); + break; + + case 'v': + switchres.set_log_level(3); + switchres.set_log_error_fn((void*)printf); + switchres.set_log_info_fn((void*)printf); + switchres.set_log_verbose_fn((void*)printf); + break; + + case 'h': + help_flag = true; + break; + + case 'c': + calculate_flag = true; + break; + + case 's': + switch_flag = true; + break; + + case 'l': + launch_flag = true; + launch_command = optarg; + break; + + case 'm': + df->set_monitor(optarg); + break; + + case 'r': + rotated_flag = true; + break; + + case 'd': + // Add new display in multi-monitor case + if (index > 0) switchres.add_display(); + index ++; + df->set_screen(optarg); + break; + + case 'a': + df->set_monitor_aspect(optarg); + break; + + case 'e': + edid_flag = true; + break; + + case 'f': + force_flag = true; + if (sscanf(optarg, "%dx%d@%d", &user_mode.width, &user_mode.height, &user_mode.refresh) < 1) + log_error("Error: use format --force x@\n"); + break; + + case 'i': + user_ini_flag = true; + ini_file = optarg; + break; + + case 'b': + df->set_api(optarg); + break; + + case 'k': + keep_changes_flag = true; + df->set_keep_changes(true); + break; + + case 'g': + double h_size; int h_shift, v_shift; + if (sscanf(optarg, "%lf:%d:%d", &h_size, &h_shift, &v_shift) < 3) + log_error("Error: use format --geometry ::\n"); + geometry_flag = true; + df->set_h_size(h_size); + df->set_h_shift(h_shift); + df->set_v_shift(v_shift); + break; + + default: + return 0; + } + } + + if (help_flag) + goto usage; + + // Get user video mode information from command line + if ((argc - optind) < 3) + { + log_error("Error: missing argument\n"); + goto usage; + } + else if ((argc - optind) > 3) + { + log_error("Error: too many arguments\n"); + goto usage; + } + else + { + resolution_flag = true; + width = atoi(argv[optind]); + height = atoi(argv[optind + 1]); + refresh = atof(argv[optind + 2]); + + if (width <= 0 || height <= 0 || refresh <= 0.0f) + { + log_error("Error: wrong video mode request: %sx%s@%s\n", argv[optind], argv[optind + 1], argv[optind + 2]); + goto usage; + } + + char scan_mode = argv[optind + 2][strlen(argv[optind + 2]) -1]; + if (scan_mode == 'i') + interlaced_flag = true; + } + + if (user_ini_flag) + switchres.parse_config(ini_file.c_str()); + + if (calculate_flag) + switchres.display()->set_screen("dummy"); + + switchres.add_display(); + + if (force_flag) + switchres.display()->set_user_mode(&user_mode); + + if (!calculate_flag && !edid_flag) + { + for (auto &display : switchres.displays) + display->init(); + } + + if (resolution_flag) + { + for (auto &display : switchres.displays) + { + int flags = (interlaced_flag? SR_MODE_INTERLACED : 0) | (rotated_flag? SR_MODE_ROTATED : 0); + modeline *mode = display->get_mode(width, height, refresh, flags); + if (mode) display->flush_modes(); + + if (mode && geometry_flag) + { + monitor_range range = {}; + modeline_to_monitor_range(&range, mode); + log_info("Adjusted geometry (%.3f:%d:%d) H: %.3f, %.3f, %.3f V: %.3f, %.3f, %.3f\n", + display->h_size(), display->h_shift(), display->v_shift(), + range.hfront_porch, range.hsync_pulse, range.hback_porch, + range.vfront_porch * 1000, range.vsync_pulse * 1000, range.vback_porch * 1000); + } + } + + if (edid_flag) + { + edid_block edid = {}; + modeline *mode = switchres.display()->selected_mode(); + if (mode) + { + monitor_range *range = &switchres.display()->range[mode->range]; + edid_from_modeline(mode, range, switchres.display()->monitor(), &edid); + + char file_name[strlen(switchres.display()->monitor()) + 4]; + sprintf(file_name, "%s.bin", switchres.display()->monitor()); + + FILE *file = fopen(file_name, "wb"); + if (file) + { + fwrite(&edid, sizeof(edid), 1, file); + fclose (file); + log_info("EDID saved as %s\n", file_name); + } + } + } + + if (switch_flag) for (auto &display : switchres.displays) display->set_mode(display->selected_mode()); + + if (switch_flag && !launch_flag && !keep_changes_flag) + { + log_info("Press ENTER to exit...\n"); + cin.get(); + } + + if (launch_flag) + { + status_code = system(launch_command.c_str()); + #ifdef __linux__ + status_code = WEXITSTATUS(status_code); + #endif + log_info("Process exited with value %d\n", status_code); + } + } + + return (status_code); + +usage: + show_usage(); + return 0; +} + +//============================================================ +// show_version +//============================================================ + +int show_version() +{ + char version[] + { + "Switchres " SWITCHRES_VERSION "\n" + "Modeline generation engine for emulation\n" + "Copyright (C) 2010-2021 - Chris Kennedy, Antonio Giner, Alexandre Wodarczyk, Gil Delescluse\n" + "License GPL-2.0+\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n" + }; + + log_info("%s", version); + return 0; +} + +//============================================================ +// show_usage +//============================================================ + +int show_usage() +{ + char usage[] = + { + "Usage: switchres [options]\n" + "Options:\n" + " -c, --calc Calculate video mode and exit\n" + " -s, --switch Switch to video mode\n" + " -l, --launch Launch \n" + " -m, --monitor Monitor preset (generic_15, arcade_15, pal, ntsc, etc.)\n" + " -a, --aspect Monitor aspect ratio\n" + " -r, --rotated Original mode's native orientation is rotated\n" + " -d, --display Use target display (Windows: \\\\.\\DISPLAY1, ... Linux: VGA-0, ...)\n" + " -f, --force x@ Force a specific video mode from display mode list\n" + " -i, --ini Specify an ini file\n" + " -b, --backend Specify the api name\n" + " -e, --edid Create an EDID binary with calculated video modes\n" + " -k, --keep Keep changes on exit (warning: this disables cleanup)\n" + " -g, --geometry :: Adjust geometry of generated modeline\n" + " --modeline <\"pclk hdisp hsst hsend htot vdisp vsst vsend vtot flags\"> Force an XFree86 modeline\n" + }; + + log_info("%s", usage); + return 0; +} diff --git a/switchres_wrapper.cpp b/switchres_wrapper.cpp new file mode 100644 index 00000000000..11fef0eb49d --- /dev/null +++ b/switchres_wrapper.cpp @@ -0,0 +1,435 @@ +/************************************************************** + + switchres_wrapper.cpp - Switchres C wrapper API + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2022 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#define MODULE_API_EXPORTS +#include "switchres.h" +#include "switchres_wrapper.h" +#include "log.h" +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +#define SR_ACTION_ADD 1<<0 +#define SR_ACTION_GET_FROM_ID 1<<1 +#define SR_ACTION_FLUSH 1<<2 +#define SR_ACTION_SWITCH 1<<3 + + +//============================================================ +// PROTOTYPES +//============================================================ + +int sr_mode_internal(int width, int height, double refresh, int flags, sr_mode *srm, int action, const char *caller); +void modeline_to_sr_mode(modeline* m, sr_mode* srm); + + +//============================================================ +// GLOBALS +//============================================================ + +// Switchres manager object +switchres_manager* swr; + + +//============================================================ +// Start of Switchres API +//============================================================ + +//============================================================ +// sr_init +//============================================================ + +MODULE_API void sr_init() +{ + setlocale(LC_NUMERIC, "C"); + swr = new switchres_manager; + swr->parse_config("switchres.ini"); +} + + +//============================================================ +// sr_get_version +//============================================================ + +MODULE_API char* sr_get_version() { + return switchres_manager::get_version(); +} + +//============================================================ +// sr_deinit +//============================================================ + +MODULE_API void sr_deinit() +{ + delete swr; +} + + +//============================================================ +// sr_init_disp +//============================================================ + +MODULE_API int sr_init_disp(const char* screen, void* pfdata) +{ + if (screen) + swr->display_factory()->set_screen(screen); + + display_manager *disp = swr->add_display(); + if (disp == nullptr) + { + log_error("%s: error, couldn't add a display\n", __FUNCTION__); + return -1; + } + + if (!disp->init(pfdata)) + { + log_error("%s: error, couldn't init the display\n", __FUNCTION__); + return -1; + } + + return disp->index(); +} + + +//============================================================ +// sr_init_disp +//============================================================ + +MODULE_API void sr_set_disp(int index) +{ + swr->set_current_display(index); +} + + +//============================================================ +// sr_load_ini +//============================================================ + +MODULE_API void sr_load_ini(char* config) +{ + swr->parse_config(config); + swr->display()->parse_options(); +} + + +//============================================================ +// sr_set_option +//============================================================ + +MODULE_API void sr_set_option(const char* key, const char* value) +{ + swr->set_option(key, value); +} + + +//============================================================ +// sr_get_state +//============================================================ + +MODULE_API void sr_get_state(sr_state *state) +{ + if (state == nullptr) + return; + + *state = {}; + + sprintf(state->monitor, "%s", swr->display()->monitor()); + state->modeline_generation = swr->display()->modeline_generation(); + state->desktop_is_rotated = swr->display()->desktop_is_rotated(); + state->interlace = swr->display()->interlace(); + state->doublescan = swr->display()->doublescan(); + state->dotclock_min = swr->display()->dotclock_min(); + state->refresh_tolerance = swr->display()->refresh_tolerance(); + state->super_width = swr->display()->super_width(); + state->monitor_aspect = swr->display()->monitor_aspect(); + state->h_size = swr->display()->h_size(); + state->h_shift = swr->display()->h_shift(); + state->v_shift = swr->display()->v_shift(); + state->pixel_precision = swr->display()->pixel_precision(); + state->selected_mode = swr->display()->selected_mode() == nullptr? -1 : swr->display()->selected_mode()->id; + state->current_mode = swr->display()->current_mode() == nullptr? -1 : swr->display()->current_mode()->id; +} + + +//============================================================ +// sr_set_monitor +//============================================================ + +MODULE_API void sr_set_monitor(const char *preset) +{ + swr->display()->set_monitor(preset); +} + + +//============================================================ +// sr_set_user_mode +//============================================================ + +MODULE_API void sr_set_user_mode(int width, int height, int refresh) +{ + modeline user_mode = {}; + user_mode.width = width; + user_mode.height = height; + user_mode.refresh = refresh; + swr->display()->set_user_mode(&user_mode); +} + + +//============================================================ +// sr_get_mode +//============================================================ + +MODULE_API int sr_get_mode(int id, sr_mode *srm) +{ + if (srm == nullptr) + return 0; + + *srm = {}; + srm->id = id; + + return sr_mode_internal(0, 0, 0, 0, srm, SR_ACTION_GET_FROM_ID, __FUNCTION__); +} + + +//============================================================ +// sr_add_mode +//============================================================ + +MODULE_API int sr_add_mode(int width, int height, double refresh, int flags, sr_mode *srm) +{ + bool flush = !(flags & SR_MODE_DONT_FLUSH); + return sr_mode_internal(width, height, refresh, flags, srm, SR_ACTION_ADD | (flush? SR_ACTION_FLUSH: 0), __FUNCTION__); +} + + +//============================================================ +// sr_flush +//============================================================ + +MODULE_API int sr_flush() +{ + return sr_mode_internal(0, 0, 0, 0, 0, SR_ACTION_FLUSH, __FUNCTION__); +} + + +//============================================================ +// sr_switch_to_mode +//============================================================ + +MODULE_API int sr_switch_to_mode(int width, int height, double refresh, int flags, sr_mode *srm) +{ + return sr_mode_internal(width, height, refresh, flags, srm, SR_ACTION_ADD | SR_ACTION_FLUSH | SR_ACTION_SWITCH, __FUNCTION__); +} + + +//============================================================ +// sr_set_mode +//============================================================ + +MODULE_API int sr_set_mode(int id) +{ + sr_mode srm = {}; + srm.id = id; + + return sr_mode_internal(0, 0, 0, 0, &srm, SR_ACTION_GET_FROM_ID | SR_ACTION_SWITCH, __FUNCTION__); +} + + +//============================================================ +// sr_set_log_level +//============================================================ + +MODULE_API void sr_set_log_level(int l) +{ + swr->set_log_level(l); +} + + +//============================================================ +// sr_set_log_callbacks +//============================================================ + +MODULE_API void sr_set_log_callback_info(void * f) +{ + swr->set_log_info_fn((void *)f); +} + +MODULE_API void sr_set_log_callback_debug(void * f) +{ + swr->set_log_verbose_fn((void *)f); +} + +MODULE_API void sr_set_log_callback_error(void * f) +{ + swr->set_log_error_fn((void *)f); +} + + +//============================================================ +// srlib +//============================================================ + +MODULE_API srAPI srlib = +{ + sr_init, + sr_load_ini, + sr_get_version, + sr_deinit, + sr_init_disp, + sr_set_disp, + sr_get_mode, + sr_add_mode, + sr_switch_to_mode, + sr_flush, + sr_set_mode, + sr_set_monitor, + sr_set_user_mode, + sr_set_option, + sr_get_state, + sr_set_log_level, + sr_set_log_callback_error, + sr_set_log_callback_info, + sr_set_log_callback_debug, +}; + + +//============================================================ +// End of Switchres API +//============================================================ + +//============================================================ +// sr_mode_internal +//============================================================ + +int sr_mode_internal(int width, int height, double refresh, int flags, sr_mode *srm, int action, const char *caller) +{ + display_manager *disp = swr->display(); + if (disp == nullptr) + { + log_error("%s: error, didn't get a display\n", caller); + return 0; + } + + if (action & SR_ACTION_ADD) + { + if (srm == nullptr) + { + log_error("%s: error, invalid sr_mode pointer\n", caller); + return 0; + } + + disp->get_mode(width, height, refresh, flags); + if (disp->got_mode()) + { + log_verbose("%s: got mode %dx%d@%f type(%x)\n", caller, disp->width(), disp->height(), disp->v_freq(), disp->selected_mode()->type); + modeline_to_sr_mode(disp->selected_mode(), srm); + } + else + { + log_error("%s: error getting mode\n", caller); + return 0; + } + } + + else if (action & SR_ACTION_GET_FROM_ID) + { + bool found = false; + + for (auto mode : disp->video_modes) + { + if (mode.id == srm->id) + { + found = true; + disp->set_selected_mode(&mode); + log_verbose("%s: got mode %dx%d@%f type(%x)\n", caller, disp->width(), disp->height(), disp->v_freq(), disp->selected_mode()->type); + modeline_to_sr_mode(disp->selected_mode(), srm); + break; + } + } + + if (!found) + { + log_error("%s: mode ID %d not found\n", caller, srm->id); + return 0; + } + } + + if (action & SR_ACTION_FLUSH) + { + if (!disp->flush_modes()) + { + log_error("%s: error flushing display\n", caller); + return 0; + } + } + + if (action & SR_ACTION_SWITCH) + { + if (disp->is_switching_required() || disp->current_mode() != disp->selected_mode()) + { + if (disp->set_mode(disp->selected_mode())) + log_info("%s: successfully switched to %dx%d@%f\n", caller, disp->width(), disp->height(), disp->v_freq()); + else + { + log_error("%s: error switching to %dx%d@%f\n", caller, disp->width(), disp->height(), disp->v_freq()); + return 0; + } + } + else + log_info("%s: switching not required\n", caller); + } + + return 1; +} + + +//============================================================ +// modeline_to_sr_mode +//============================================================ + +void modeline_to_sr_mode(modeline* m, sr_mode* srm) +{ + srm->width = m->hactive; + srm->height = m->vactive; + srm->refresh = m->refresh; + // + srm->vfreq = m->vfreq; + srm->hfreq = m->hfreq; + // + srm->pclock = m->pclock; + srm->hbegin = m->hbegin; + srm->hend = m->hend; + srm->htotal = m->htotal; + srm->vbegin = m->vbegin; + srm->vend = m->vend; + srm->vtotal = m->vtotal; + srm->interlace = m->interlace; + srm->doublescan = m->doublescan; + srm->hsync = m->hsync; + srm->vsync = m->vsync; + // + srm->is_refresh_off = m->result.weight & R_V_FREQ_OFF ? 1 : 0; + srm->is_stretched = m->result.weight & R_RES_STRETCH ? 1 : 0; + srm->x_scale = m->result.x_scale; + srm->y_scale = m->result.y_scale; + srm->v_scale = m->result.v_scale; + srm->id = m->id; +} + + +#ifdef __cplusplus +} +#endif diff --git a/switchres_wrapper.h b/switchres_wrapper.h new file mode 100644 index 00000000000..fe3bc40e782 --- /dev/null +++ b/switchres_wrapper.h @@ -0,0 +1,190 @@ +/************************************************************** + + switchres_wrapper.h - Switchres C wrapper API header file + + --------------------------------------------------------- + + Switchres Modeline generation engine for emulation + + License GPL-2.0+ + Copyright 2010-2021 Chris Kennedy, Antonio Giner, + Alexandre Wodarczyk, Gil Delescluse + + **************************************************************/ + +#include +#ifndef SR_DEFINES +#include "switchres_defines.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __linux__ +#include +#define LIBTYPE void* +#define OPENLIB(libname) dlopen((libname), RTLD_LAZY) +#define LIBFUNC(libh, fn) dlsym((libh), (fn)) +#define LIBERROR dlerror +#define CLOSELIB(libh) dlclose((libh)) + +#elif defined _WIN32 +#include +#define LIBTYPE HINSTANCE +#define OPENLIB(libname) LoadLibrary(TEXT((libname))) +#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn)) + +#define CLOSELIB(libp) FreeLibrary((libp)) +#endif + +#ifdef _WIN32 +/* + * This is a trick to avoid exporting some functions thus having the binary + * flagged as a virus. If switchres_wrapper.cpp is included in the compilation + * LIBERROR() is just declared and not compiled. If switchres_wrapper.cpp is + * not compiled, LIBERROR is defined here + */ +#ifndef SR_WIN32_STATIC +char* LIBERROR() +{ + DWORD errorMessageID = GetLastError(); + if(errorMessageID == 0) + return NULL; + + LPSTR messageBuffer; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + SetLastError(0); + + static char error_msg[256] = {0}; + strncpy(error_msg, messageBuffer, sizeof(error_msg)-1); + LocalFree(messageBuffer); + return error_msg; +} +#endif /* SR_WIN32_STATIC */ + #ifndef SR_WIN32_STATIC + #define MODULE_API __declspec(dllexport) + #else + #define MODULE_API + #endif +#else + #define MODULE_API +#endif /* _WIN32 */ + +#ifdef __linux__ +#define LIBSWR "libswitchres.so" +#elif _WIN32 +#define LIBSWR "libswitchres.dll" +#endif + +/* Mode flags */ +#define SR_MODE_INTERLACED 1<<0 +#define SR_MODE_ROTATED 1<<1 +#define SR_MODE_DONT_FLUSH 1<<16 + +/* That's all the exposed data from Switchres calculation */ +typedef struct MODULE_API +{ + int width; + int height; + int refresh; + // + double vfreq; + double hfreq; + // + uint64_t pclock; + int hbegin; + int hend; + int htotal; + int vbegin; + int vend; + int vtotal; + int interlace; + int doublescan; + int hsync; + int vsync; + // + int is_refresh_off; + int is_stretched; + double x_scale; + double y_scale; + double v_scale; + int id; +} sr_mode; + +/* Used to retrieve SR settings and state */ +typedef struct MODULE_API +{ + char monitor[32]; + int modeline_generation; + int desktop_is_rotated; + int interlace; + int doublescan; + double dotclock_min; + double refresh_tolerance; + int super_width; + double monitor_aspect; + double h_size; + double h_shift; + double v_shift; + int pixel_precision; + int selected_mode; + int current_mode; +} sr_state; + +/* Declaration of the wrapper functions */ +MODULE_API void sr_init(); +MODULE_API char* sr_get_version(); +MODULE_API void sr_load_ini(char* config); +MODULE_API void sr_deinit(); +MODULE_API int sr_init_disp(const char*, void*); +MODULE_API void sr_set_disp(int); +MODULE_API int sr_get_mode(int, sr_mode*); +MODULE_API int sr_add_mode(int, int, double, int, sr_mode*); +MODULE_API int sr_switch_to_mode(int, int, double, int, sr_mode*); +MODULE_API int sr_flush(); +MODULE_API int sr_set_mode(int); +MODULE_API void sr_set_monitor(const char*); +MODULE_API void sr_set_user_mode(int, int, int); +MODULE_API void sr_set_option(const char* key, const char* value); +MODULE_API void sr_get_state(sr_state *state); + +/* Logging related functions */ +MODULE_API void sr_set_log_level(int); +MODULE_API void sr_set_log_callback_error(void *); +MODULE_API void sr_set_log_callback_info(void *); +MODULE_API void sr_set_log_callback_debug(void *); + +/* Others */ +MODULE_API void sr_set_sdl_window(void *); + +/* Inspired by https://stackoverflow.com/a/1067684 */ +typedef struct MODULE_API +{ + void (*init)(void); + void (*load_ini)(char*); + char* (*sr_get_version)(void); + void (*deinit)(void); + int (*init_disp)(const char*, void*); + void (*set_disp)(int); + int (*get_mode)(int, sr_mode*); + int (*add_mode)(int, int, double, int, sr_mode*); + int (*switch_to_mode)(int, int, double, int, sr_mode*); + int (*flush)(void); + int (*set_mode)(int); + void (*set_monitor)(const char*); + void (*set_user_mode)(int, int, int); + void (*set_option)(const char*, const char*); + void (*get_state)(sr_state*); + void (*set_log_level) (int); + void (*set_log_callback_error)(void *); + void (*set_log_callback_info)(void *); + void (*set_log_callback_debug)(void *); +} srAPI; + + +#ifdef __cplusplus +} +#endif diff --git a/tests/test_dlopen.cpp b/tests/test_dlopen.cpp new file mode 100644 index 00000000000..98f1e397d65 --- /dev/null +++ b/tests/test_dlopen.cpp @@ -0,0 +1,47 @@ +#include +#include +#ifdef __cplusplus +#include // required for strcpy +#endif + +#ifdef __linux__ +#define LIBSWR "libswitchres.so" +#elif _WIN32 +#define LIBSWR "libswitchres.dll" +#endif + +#include + +int main(int argc, char** argv) { + const char* err_msg; + + printf("About to open %s.\n", LIBSWR); + + // Load the lib + LIBTYPE dlp = OPENLIB(LIBSWR); + + // Loading failed, inform and exit + if (!dlp) { + printf("Loading %s failed.\n", LIBSWR); + printf("Error: %s\n", LIBERROR()); + exit(EXIT_FAILURE); + } + + printf("Loading %s succeded.\n", LIBSWR); + + + // Load the init() + LIBERROR(); + srAPI* SRobj = (srAPI*)LIBFUNC(dlp, "srlib"); + if ((err_msg = LIBERROR()) != NULL) { + printf("Failed to load srAPI: %s\n", err_msg); + CLOSELIB(dlp); + exit(EXIT_FAILURE); + } + + // Testing the function + printf("Switchres version: %s\n" , SRobj->sr_get_version()); + + // We're done, let's closer + CLOSELIB(dlp); +} diff --git a/tests/test_liblink.cpp b/tests/test_liblink.cpp new file mode 100644 index 00000000000..f881fb89d1b --- /dev/null +++ b/tests/test_liblink.cpp @@ -0,0 +1,7 @@ +#include +#include +#include + +int main(int argc, char** argv) { + printf("Switchres version: %s\n" , sr_get_version()); +} diff --git a/tv.ico b/tv.ico new file mode 100644 index 0000000000000000000000000000000000000000..5659431e6aabe90cb9dda02bd0c7525a8d1087db GIT binary patch literal 67646 zcmeI53%pfh`p0+as+8NfkIJ=>R3wyiFDc}b8rNZrF|Ok}GcKVR$z_NU8mY}vsZ?`8yVx1_^O9E^H%JAP{+&vhS%Sm{i3So4BpOIGkZ2&$ zK%#*}1BnI_4I~;!G>~W@(LkbsL<5Ni5)C98NHmaWAkjdgfkXp|1`-V<8b~ydXdux* zqJjVC8t}0qW!u`?ZXz@jb`f?HS|<3P+5isV0#4utj>`X4cZ^Tjfi#jR)lg_5^cT(% zh6qGQhTer^avBw?(ty;Cp?7sW%nU*bE2JE)mZW*0Rz%IM&l4;SRML_fB%`-di zymP=#JMEO&amO74cGzKu%=X)FpV@A^?E;!LYnA~`n>NifY0@NM+ikba{PLH-4A^Fy zZ8BSLy>-A=TWyuua?33sV$i(h0m-E`A{O*Yviv+>3o2W+&_ zMwtya+%TYVB7j`i1HKU2Sc{eXJ)>SaLPx^*+Mccymj z+5xp{)yk~5-g*HwYu3!vs8J(|@AUTyakN0VLpV!lC!m31@LxwZ>MDMh^z7Nwdi3aF z-Me=W=+>>9b?w?Upi7r7CQX<$VbVi@zGKovfOKKfgh>+t(u7F|<&YjsS}zEtqr=APpFh4on&dkPb{b2#^L$8Zcd-iGLIS0pj1p ze}MQm@gE@W4Tyge_W|PH#C?GHH*p^z-VKQR0P%0)-o$-?csKDLAkIykn>aUd9w5$5 zoCk<=6UPBinhRy`f1&pt6V4WP73x$s{_EPe7PqhW?%msZ_3CA=0d(M6KnD)=;95Wr zu8F8F&_}j5Tp!sQK_`kG0j?Lc;>gxaR5$3yb;DM1Bp|9G*AW`Z))88Y>PfLB=qaiz z*A}{pY732_Ee9HNouM_?8(MRqIrJ9Q9NJUt32^O2^@rxrinw--tkmnfgd>Das>{E4 zyA19RJn+E4z4PobAla72!vCcm@C9Ov_;wAvs@LZU+f|o;`TP7nefk(0z-RGO{E(RJ z@j2O+wo`F-Xxp}pUO=aePaxCEgMLcB)P+r)Z96`CkuLceb`5ybaDmSG4KmO>WL#}w(p@-Vhg9h252On&Et8MQqeUT^n z@z`>F_<}cbg6MmNye97?x1+FWBuCig5T^3&7dj0iw_uu|z=bm+z4IetxM&Ed&jr{9ht+O;j z`{KtWhvfIj>v`?_3*DkWY)kwp^caPFuUofHve^ORrE?kf*Y;@P3E^VJ?Do=kC;3OG zDxVh|zy&!bI-vF_HvjVdH2mX(a8JA;$0i@}8UVXoaPGPG%G|m3$3KR@{djCSKHSsZ zM1L##nX0^|Zb1XIB~|%ebwAsuPj6{%Z}GCdu%pmaxLcSioGSjCNZ;LmR998zcd-jx zP&W`OsWpquf4_eH(uXQu<2$s+)VpZmh$D`${{8z0=reZ4>8IP}mtSrdUv!aOd(Aa= z?m6e!Eh9$QAI?78&J*v${_+=l-ST_nv9w|S+f_YAA)g;G;7HY#ZB(OeAZ#Qw76u513;U^E*wFg+ z?N`t_VHdc76a11IfW89yh@^v}wEyz`G}ldjp+2pkG1?pIZnWnh4((djAG3>UY3$rW z{>zpcoA;=%c@6j;`7Lpaw#$#>TaHh>Azo+ymVc(ITh4`AyQ<%-&gVJz=FN8w{CJ(e z%{H6sJT{ZxZV~#MutOog!Li|jypOh@{-m-#qoVSUzmPl8N5yZ@M@65*PYv%6E7tFD z-W-$Tc|Y4vz2&#~P5StLKwZ5CrTg5TelAtHUcLh-^e4g(-=(j(SpKiLoId>U!-J2~ zwxF-F-*BzP?km&c8lQ{qi#v|*XY26q`QOp4pA-ACKNo#3`ki&{b@V!NT_gKkN4mD6 z@vpW&)PJX*daBV@->7{3ugcfK4L96Sj_Z}zgX@&*O`pkIiVK@lolZsQlCSi~ScbUTg~&F0@ybvx8S&c_m=M zf(7=^fBrLI{`~m{UViyyd+DW@0$zOaMSJ0e7s~Pc^UvE{)e6r&_gp!iefC*<=9y<~ z&YU^rm_2*8&6+jKX3m^hju|s%*!1bsZQ8VH<(N8ksy+Sm(>7(wlyW@v)KfNj^5lR? zlO`FMIB}vq`Q(!UPdxF2fyW$Q2#@NHk zV;_3xp>jN^ItQ?i_W+;s?{Eyj@uJ7)_xNqj!NEECIdZ;!?tU#?SM)l$Zft?w$is`x zzjD7cc{4hL<9YMut-)iI%P6PLr*jII4(Aju9nL9SI-FCk*?}FLOYGyEI+t$8#~yoZ z4PKpFIB;H_Teynj^&hHN@4x^4a{T@8f4BSYyU*@bP3ySlo_h@NH}3&H=ilQP52*eH zu9c`>{P$fmoEJLb8vJ@(udWT>a{br@`_WGe|H?Ot=Ksq5(j1o<6URRqz`x<#{nvfB zx?Jbu+iil4qI~01&Np_9a_&CqHjnx;oH$QxoqM=+IQPyu+q>_+JHR#II`Hqf4mhU& zUOxUgcfL#eN;^t>N_%_LO*h#H)zp7e|JlfqBki`^ZnIJ9OSw~hZu|!K=HQ?41KJj) z{)2z|f8+Rvcj7qbo89i`%K@VKfWIa$s0=)JsA%hXMMYckj>^JwlgezP$K>;z$1S(q zQr=d0d*NDS3-{z$NY0Gb%R!%KZcX zMe{dav(Iz8s%||`tjgB&$*OF#^UmlsaQ=?ywfgn5 zC6^<&!(FHkfGzUIgeS*LH-S3Q=!twjx|K3hG;RO5DuYP4m>poFcK>q~S z&Usb@K1aXVF~=NJrQhJZI6uzQ&zUXP!S#^S`!#w_&-J@4+%DLPeY6?y?)=j((N0kp z5ZjMC?zqsNQ+xYw|Ms`PwbRwl`iDRKA=DQ58~Pw2$?rLT zIOe)IAMQ!fX9pO!!u?k6OL$)gTlzzy^{m(8oICnmTfzDHx%!st$nM|adbw`yUArx? z3-*C~bOFb39_62$fcMA~h&9-iSOUkiCGbp*P5VF|0O!PB+5x^xo?dMJ)ej%;|8PFp z@!$DJ@9>Xy{T}q%%HjX&ys!)Q!A|fR$3J|d32MA(9ptqTTYv4fAb(Rw;ivG=m{MJ5 zQS!e50|unIHIf8r72i;KnoQAZsW?*HZEpX(xSMfq=3 zD`n^JoU&WnrtId{DI3vBulKHN%U*xURZ59RIYl)Sa~X)ZJBS|G6JbyYy4=PaBjS|LNl+RyqIVKkol~Z<4Zm+NEsN zo+-OsxJ??kW8b<~^6u*zl2rMBC9h1j>4&9kTK`gR;WrL5_1<#>Qg&d|wUdABQxX5f zf3FKYHy}^+T7VqU`w+brp#Ot@65@Zc`5!oNV4D1z+A0_SoGaHwn?`@P^WS09l-;?P zc$fc=6mH!^TG*$qtyuDE<;mA4SInPiQ^oz$^6jb8K|V~=`*V&=S?{%!f9!*u@E2uU|VJ4fLK+YrWE%7Q48e zxHlNbe|7Rd`ZkKqzw(eY{UveyQ+N7xv1Ke0_N!GRW$Uk(viezQqukI*v0Jx|MctTi~ohxe~i-<;bL(%uUrMl&xMPEbOD8t0mQcowpY*TEw~ER?V=?J}%EdpwOMf+O8{0zo?^#1U)fC5-z{DC8E6vl1 zNA)mUKE>>VC(Pb|JRU2j+3my5sPu6M57^CY@-b$Q42Z|Lqs$Z|dhYQ9|86IA5XZl_ z|0kVvlBw?{jE&_rea&Z{d1ml2+FJS%sL8pfM4uo!pk8DwSTXrmKY9A6=D$~sUX|h= zeLPj;fA9Z+|EG=>zi=D_VuLhLRsKEykJfv+YCgXQ#C>n>gVSCR|M7q3o);_r!@v4~ z^7=pbBWTmumivEA%|)wIPf%X92DGnsoi%)|YmKf}Qd2o$B`~JOm^Ho|ZAY?S|5WY& zrAKO7-K0VG{g}h!G4=@i{*lAQ{}1iI+le^9Sh{@eKefO215p3-SrF9%{Q!Oskoq6~ z83$TS{&gQJ@K2nHi~rpJqD^C4&VTp*mYV#Ar5;;osR^(CfJv`g>ZWmPXrNX~d3s7Y zVI|NY)u7V+|1|l39Xqr8w)XjmM)uCIcr3l9vAuguBinzc(z)5##qER+;`sOY&zuPQ zbMmzTwL&gE?L}HYM`&`9*3^l?=0i5OLk>E`Mx{pC?KN)Ci_v=j zSRs|F4DOcy4=jj(w-Y*unz3^De;ogei6f@5t&o3m zfyKfHKcLUDRc7jgv6WNHw!F@Pl4oqer?=W(i?mLd&~A~|fr>$k4_nwZL$1+}l=U4} z(6@A-`WKasR0^kcxw0Vs-A?GBBK`}h|KOi~b=Id-ds>wKU&Wy`wFosvF8&#(>U~p{ z=0BPb>UGaImzVX;Jr>_bNB`XiPua6eZm>2lwz1Yi+ZQ$eI0ic}+S#tS_=-yNe|weq zA6yjv@o~S$Pg_9V@A1Eo`j7j+%+W3;|G)XoZ_ogS2|KVRXU|#-DIpvg)`=Nt`|I&IeyZ*y2 z*oU?s9mMhP?Z4N0KGu_(&-caEfArJBKWmj1EB>E+^2vdJ`XF-oKYb63OGnde6aM4* zcRS%P%mIn>|3d3O{2%)llYgCant2bo_(u=$FO4MpXY~W+^8d>4@9lpf^&jK($iFr3 zplJRN|LOzC%fH%)5Yx~>;{Wmfk9~;!=pfGjJ^mL`{}KO-&A(z*UjCWuidJdc&_Tj~ zJpb6o?L>cmuK4f#7gGN@|5^{MX#TJBO{)(ej4{Y=|M@%Nzm)IndjPrOe`Wah_+Qof zkNE_|f7XUBHvjlHdX3{BeUQ`eIbVY?mDGQ0-2cHY*vIV@=l|8I|F~BS|5|6PX#TJE zDxHsi);u6TpiM&ux%jVc8cS_I^#d_f7a+MCjaWIPIJ!WtGVJo;}7T`Bu3Cr z6vuzQ81QrG|HCfW$L&Ntoy-5d{pWM}#{T3Q|4IKpbMEzQiK6*`!vBx&37yuZ>iz$f z<=^xFLh3)_f3f*je`T7Sh5pK1{?FP2EXm{*Qg!PI3HKr~YG{X0iF#xQ;Y^ zmihRn-66L@2ig4B(D=^=8t>6Cg8JGQ%?E!j{9_-tQyl*u{|l-Ah#AG^U*o#c+}n%e zpSfrG_^&ChfAOZ-=4IHdY`c;45Hz6WAbyVgGoB__{I5>^hyU{oLp=+kXz}0qXS`~z z_z(Zg4?uhTezyO^f0HF<+X>Ag*j}%^Epz#@$NxG1RjvP66Px-H{`FkA|0@6VQ<2-C1IC|5>;GD6=R1hw&hMEW zkOS?t@B9x|ntl45=I2i@o2!iua?ICWhxx}Y*vIV@$G^vae7P#~|G580`@*xpipjs` z^`#lJn9u*IJIMjjK{o%j#eWZR+~@t==&Jn}f2f6DmcL;3nSc&Hdb*7NtoC3X=O6pH zo#OZ}wEiPr5L@71&jc!(|HD6H`<GH+@s@8w3|4-in&s8lZ|C-kw%RlqM zD&oJ6{C|+<{Qg>VfsfCDf!a6xldr`2KYzdqy05#qnU3_?P6sh1z$|=Ud8*L+(jkMwK54W?IoNY(GcBFNDxntmew-wlyiFH~k z;=hpk5B_;3xSpw5RQ_4pgZd&@{Kx;Df8s#4|JM_(gFiF7=5w>ZXEAKz;uKN@L6mkw2IINb)kHo*3LYfl?;$&gb1 zQnh zb^X%t&zd8-_-7pw<{i?uq3dk^>x=(k>fX8e3$q(@;5zLazw%qNv^t3@!dLIv$0hUa zflu{pCV?$@aJinnw)`O*vwVz=`)pizJ!<7Bn=yHYl1_2lN7zT$LD*QRC)5%mnz%); zD?9)9l#UnKvSFq7c^3_>ZHup}Z%eM<(w5%Z%09a9K>P6S&bD|+4O^r+Asx!rf59%; z2Rq>}tf!YN{#U2|$%xQ^M9>1mu9`XeEhTS5V4=@%I1H4@jpTw-=z|NbPkNv zzDZxMGW%K`0Ttpy`}E6&HvTg`r%zy;3llz@U}IN~wFUE4Kin&x9}w7%7H$=;6)qOe z5>65ZnN2zLKh~%3cX|eUM$aN&6CFEdtb6y2uJ1eR+wVVi&z0ltn<*#T%BL@}ujX89 z-^{zizJ2*VTeaXJ`|gd&n!0|O_}BU`S^Q%k?1aC>@$dbAh17rKjPS4LDHN4|*7nNB zKkLpC+qkYD@vnP4qt(6luuA*~a^ODgoAK3Zvu{)+R)~-7^Ymhyyh6_a6xhb$i7%h9 z*IrRhdB6C5unZ4r`>-%Z7%My~j29-Ti{Y_<+t~4|v?fPxj2pK~&zRGDWAGcMnKPF7D)r+6flB1XARE{gG(>*FgNk`{PRSCw%o|jMcv9(*H91Rz*UESZ*u6e%ofQoM|%z zwsDx6o@$F1DfqzgV-@4Q3IDcn6TZ`Wdin9lxbJPjoHs4AYq$yg%JmEuEc(S@y4wUbYpphuR|Lh1v1HGW>h|FQooMGw|QCWy_-S&)UB5&w4-6 z^?&I9VL$866WeG9%Hx0k6H3>35&y@@wdbgbpC!!9!ZiK;>gs=+{Yyzgg;;6n)gRf* zU%y--=B=7%?=MwO0r#^i#wYsBw3#};3NUq=*^*b@v&@H6ZT0)J*Te_U*s6D@*!y?w zYm3GI+gGJ*{~b%$jKVJ12Rjijq>uJ})05aplsheG_{s)^SB ze9KaAE3ei);H^~N?Wot=XQ7GyK4Gc2|5!wQEaQePuXEs&IX3^jyR6^Be%4nwc;UgZ z=>AT38*%*z4LT9`uO`jf?$mj4{PWx) zVjH?H=U>;H+HzY4u5OSyOc zu@832$A5L|KgO2Bf2&rlipIa@nWR~7oPM5M@gM*1)vH&~HrK`alfnPtKS8+-unYDf z_rqV}{Ga$w>}Ne^)_JMy{6FshF}D!@_t;~PqVmu4%HsH^Uzq2PqHV5^`3HLbP*{h$ zcJ0~*cqU!Vnl%H~_Gf$+s#&hfuaWEZYiB)f?15dd4|c*|c%E9W_|Nkp3t9h#`+xX9 z&rJMp@$c(D!aq3x*T)upbB*i=ojZ3{pUVE~Tj>;@58JMt*6quJVitL8rLfaZJ6W+& z+27_ov(KHsdA=*x$8~bOe(l%+dqnNS>s;$Uk@FL48B>QZS7rVmc{u(5Tu1BHt&8UW z(qo!umT{jyJN{D(%$++otZ8<@0S5%mxwdSe3kUko1#+Xxf*4v=(C)^es>jN8p3!Ua zYjuBcd!U7`UAu-g09e~Uy1qZ_ce9>9Xv2g=hx; z+q7v@bpFv~Hvi8*|Ge=G@R=%_cvcO48`vS2eTua&YUg$BHMJjODSW;5Z2nyX)P}?X z+E&)rB(?+E1=ffpKX9;aBw9fW%+puyUsV3}jDa-Itc>Fy4G;&wv}x1Ib&6hHyPO~A z>EJqnUjtig!LU_aKKiGpmZUJI~e;sapJ@f2Z@D%XW|eW zfyYYhN=yYFPthngca6F>ou{ZSU7P6A^~e@Y0$#gj-B+Dwj+1??T>QH~bAFt=Uk6*j zwQ;R}y==LD?8H1x@{>LH+!OwX3cIS;BXXCs>aWFr2{|cx<9YAV{y#W&p5Zvkvvce` z!>@z(!uf?`K-6>?4KTJ$xgY-jowz?w*si+#i~HxPNvT)h$oqh@brAJ+*8v)E9pv(L_jA{R zYasgEd-r$p8-UNdzeoMR{Uqx1Xdqh$(KadD=UoF)UyZgy?)TmXIoI9}Iq%MWG!}R~ z@MA}P-`hp!-p`R3;PJ|@1@8SCJw6Z{Y3Dk2>=MJ%D>^o4xkh%i6bZ<e5;(k}5PIdVg_w|(nKI0l7 z4tW0Ixsc~R*1mks6ryJK^=J2rQ_V{^BA)aFq;W8bJ< z-ImxcYCp!w0p?;cW*T5e+E2#k0{UJUs|Ogf#kd{DZcyU_#_|AaI`3DYAAvg8>r$`( z>HmrLiS_8w!$9}$-K|@{^{r1~0a177;?6Xhsb^M*b z>3@>{FVxzE>9(dMKT6*A_R{_!l&p!;1CU_Pq&qEH7 zCeqSGfHaYo9s;C^v@{VQO{ArXv@{VQO{CQy6d+Bc)h867{=&30k(MUX(nNqXkp|L5 zT78OX=^`yn1gM`eEls4wdx`j;tDNu8>Sx|URMifImHn@}{3qY9dd-yBEU{UlfkXp| z1`-V<8b~ydXdux*qJcyMi3So4BpOIGkZ2&$K%#*}1BnI_4I~;!G>~W@(LkbsL<5Ni z5)C98NHmaWAkjdgfkXrU1r6vYl7HnED2a}oTTcs