diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e27bdf2..791ae9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set env vars run: | @@ -29,7 +29,7 @@ jobs: - name: Cache OpenOrbis Toolchain id: cache-oosdk - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.OO_PS4_TOOLCHAIN }} key: ${{ runner.os }}-oosdk-llvm-${{ env.llvm_ver }} @@ -39,7 +39,7 @@ jobs: run: curl -sL https://github.com/illusion0001/OpenOrbis-PS4-Toolchain/releases/download/0.0.1.416/toolchain.tar.gz | tar xz -C ./ - name: Checkout oosdk_libraries - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/oosdk_libraries path: oosdk_libraries @@ -53,63 +53,63 @@ jobs: curl https://raw.githubusercontent.com/OpenOrbis/OpenOrbis-PS4-Toolchain/master/include/orbis/_types/user.h > OpenOrbis/PS4Toolchain/include/orbis/_types/user.h - name: Checkout dbglogger - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/dbglogger path: dbglogger - name: Checkout apollo-lib - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/apollo-lib path: apollo-lib - name: Checkout SQLite - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/libSQLite-ps4 path: libSQLite-ps4 - name: Checkout SDL-PS4 - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/SDL-PS4 path: ${{ env.sdl_path }} ref: ps4 - name: Checkout mxml - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/mxml path: mxml - name: Checkout libunrar - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/libunrar-ps3 path: libunrar-ps3 - name: Checkout libun7zip - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/libun7zip path: libun7zip - name: Checkout libjbc - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/ps4-libjbc path: ps4-libjbc - name: Checkout libs3m - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: bucanero/s3mplay path: s3mplay - name: Cache LLVM and Clang id: cache-llvm - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./llvm key: llvm-${{ env.llvm_ver }} @@ -171,7 +171,7 @@ jobs: - name: Cache SDL2 id: cache-sdl2 - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.sdl_path }}/orbis/libSDL2.a key: ${{ runner.os }}-sdl2 @@ -186,7 +186,7 @@ jobs: - name: Cache curl id: cache-curl - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.curl_path }}/orbis/lib/libcurl.a key: ${{ runner.os }}-curl @@ -214,7 +214,7 @@ jobs: mv IV0000-APOL00004_00-APOLLO0000000PS4.pkg apollo-ps4-build_${{ env.sha_name }}.pkg - name: Push package artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: apollo-ps4-build_${{ env.sha_name }} path: apollo-ps4-build_${{ env.sha_name }}.pkg diff --git a/assets/images/tag_pce.png b/assets/images/tag_pce.png deleted file mode 100644 index 771677e..0000000 Binary files a/assets/images/tag_pce.png and /dev/null differ diff --git a/assets/images/tag_vmc.png b/assets/images/tag_vmc.png new file mode 100644 index 0000000..9d1b170 Binary files /dev/null and b/assets/images/tag_vmc.png differ diff --git a/include/common.h b/include/common.h index 92b70cd..dfabc2e 100644 --- a/include/common.h +++ b/include/common.h @@ -21,21 +21,6 @@ int mkdirs(const char* dir); int copy_file(const char* input, const char* output); int copy_directory(const char* startdir, const char* inputdir, const char* outputdir); int clean_directory(const char* inputdir); - -//---------------------------------------- -//CONSOLE ID UTILS -//---------------------------------------- - -int ss_aim_get_device_id(uint8_t *idps); -int ss_aim_get_open_psid(uint8_t *psid); -int sys_ss_get_open_psid(uint64_t psid[2]); -int is_ps3hen(void); - -//---------------------------------------- -//POWER UTILS -//---------------------------------------- - -int sys_shutdown(); -int sys_reboot(); +uint32_t file_crc32(const char* input); #endif diff --git a/include/font-10x20.h b/include/font-10x20.h index 393ff24..f34537b 100644 --- a/include/font-10x20.h +++ b/include/font-10x20.h @@ -1,5 +1,5 @@ // https://github.com/idispatch/raster-fonts -unsigned char console_font_10x20[] = { +static const unsigned char console_font_10x20[] = { /* * code=0, hex=0x00, ascii="^@" diff --git a/include/lzari.h b/include/lzari.h new file mode 100644 index 0000000..35067d8 --- /dev/null +++ b/include/lzari.h @@ -0,0 +1,9 @@ +#ifndef LIBRARIES_LZARI_H +#define LIBRARIES_LZARI_H + +// Compress in to out using LZARI. Returns final compressed size. +int lzari(unsigned char *in, int insz, unsigned char *out, int outsz); +// Deompress in to out using LZARI. Return final decompressed size. +int unlzari(unsigned char *in, int insz, unsigned char *out, int outsz); + +#endif diff --git a/include/mcio.h b/include/mcio.h new file mode 100644 index 0000000..52b041f --- /dev/null +++ b/include/mcio.h @@ -0,0 +1,131 @@ +/* + * ps3mca-tool - PlayStation 3 Memory Card Adaptor Software + * Copyright (C) 2011 - jimmikaelkael + * Copyright (C) 2011 - "someone who wants to stay anonymous" + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __MCIO_H__ +#define __MCIO_H__ + +#include +#include +#include + +struct sceMcStDateTime { + uint8_t Resv2; + uint8_t Sec; + uint8_t Min; + uint8_t Hour; + uint8_t Day; + uint8_t Month; + uint16_t Year; +} __attribute__((packed)); + +struct MCFsEntry { /* size = 512 */ + uint16_t mode; + uint16_t unused; + uint32_t length; + struct sceMcStDateTime created; + uint32_t cluster; + uint32_t dir_entry; + struct sceMcStDateTime modified; + uint32_t attr; + uint32_t unused2[7]; + char name[32]; + uint8_t unused3[416]; +} __attribute__((packed)); + +struct io_stat { + uint32_t mode; + uint32_t attr; + uint32_t size; + struct sceMcStDateTime ctime; + struct sceMcStDateTime mtime; +} __attribute__((packed)); + +struct io_dirent { + struct io_stat stat; + char name[256]; + uint32_t unknown; +} __attribute__((packed)); + +int mcio_vmcInit(const char* vmc); +int mcio_vmcExportImage(const char *dst, int ecc); +int mcio_vmcImportImage(const char *src); +void mcio_vmcFinish(void); +int mcio_mcDetect(void); +int mcio_mcGetInfo(int *pagesize, int *blocksize, int *cardsize, int *cardflags); +int mcio_mcGetAvailableSpace(int *cardfree); +int mcio_mcOpen(const char *filename, int flag); +int mcio_mcClose(int fd); +int mcio_mcRead(int fd, void *buf, int length); +int mcio_mcWrite(int fd, void *buf, int length); +int mcio_mcSeek(int fd, int offset, int origin); +int mcio_mcCreateCrossLinkedFile(const char *real_filename, const char *dummy_filename); +int mcio_mcDopen(const char *dirname); +int mcio_mcDclose(int fd); +int mcio_mcDread(int fd, struct io_dirent *dirent); +int mcio_mcMkDir(const char *dirname); +int mcio_mcReadPage(int pagenum, void *buf, void *ecc); +int mcio_mcUnformat(void); +int mcio_mcFormat(void); +int mcio_mcRemove(const char *filename); +int mcio_mcRmDir(const char *dirname); +int mcio_mcStat(const char *filename, struct io_dirent *dirent); +int mcio_mcSetStat(const char *filename, const struct io_dirent *dirent); + +/* MC error codes */ +#define sceMcResSucceed 0 +#define sceMcResChangedCard -1 +#define sceMcResNoFormat -2 +#define sceMcResFullDevice -3 +#define sceMcResNoEntry -4 +#define sceMcResDeniedPermit -5 +#define sceMcResNotEmpty -6 +#define sceMcResUpLimitHandle -7 +#define sceMcResFailReplace -8 +#define sceMcResFailResetAuth -11 +#define sceMcResFailDetect -12 +#define sceMcResFailDetect2 -13 +#define sceMcResFailReadCluster -21 +#define sceMcResFailCheckBackupBlocks -47 +#define sceMcResFailIO -48 +#define sceMcResFailSetDeviceSpecs -49 +#define sceMcResDeniedPS1Permit -51 +#define sceMcResFailAuth -90 +#define sceMcResNotDir -100 +#define sceMcResNotFile -101 + +/* file attributes */ +#ifndef sceMcFileAttrReadable +#define sceMcFileAttrReadable 0x0001 +#define sceMcFileAttrWriteable 0x0002 +#define sceMcFileAttrExecutable 0x0004 +#define sceMcFileAttrDupProhibit 0x0008 +#define sceMcFileAttrFile 0x0010 +#define sceMcFileAttrSubdir 0x0020 +#define sceMcFileCreateDir 0x0040 +#define sceMcFileAttrClosed 0x0080 +#define sceMcFileCreateFile 0x0200 +#define sceMcFile0400 0x0400 +#define sceMcFileAttrPDAExec 0x0800 +#define sceMcFileAttrPS1 0x1000 +#define sceMcFileAttrHidden 0x2000 +#define sceMcFileAttrExists 0x8000 +#endif + +#endif + diff --git a/include/menu.h b/include/menu.h index df4b451..c1ed5e2 100644 --- a/include/menu.h +++ b/include/menu.h @@ -25,6 +25,8 @@ enum menu_screen_ids MENU_CODE_OPTIONS, /* 10 - Code Menu (View Cheat Options) */ MENU_SAVE_DETAILS, MENU_HEX_EDITOR, + MENU_PS1VMC_SAVES, /* 13 - PS1 VMC Menu */ + MENU_PS2VMC_SAVES, /* 14 - PS2 VMC Menu */ TOTAL_MENU_IDS }; @@ -68,7 +70,7 @@ enum texture_index cat_warning_png_index, tag_lock_png_index, tag_own_png_index, - tag_pce_png_index, + tag_vmc_png_index, tag_ps1_png_index, tag_ps2_png_index, tag_ps3_png_index, @@ -252,6 +254,7 @@ extern void Draw_MainMenu_Ani(void); extern void Draw_HexEditor(const hexedit_data_t* hex); extern void Draw_HexEditor_Ani(const hexedit_data_t* hex); int LoadMenuTexture(const char* path, int idx); +void LoadVmcTexture(int width, int height, uint8_t* icon); void initMenuOptions(void); void drawScene(void); diff --git a/include/ps2icon.h b/include/ps2icon.h new file mode 100644 index 0000000..167ba27 --- /dev/null +++ b/include/ps2icon.h @@ -0,0 +1,75 @@ +/* +* +* Copyright (c) 2008 Andreas Weis (http://www.ghulbus-inc.de/) +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +//================================================================================================ +// Typedefs and Defines +//================================================================================================ + +/** File header + */ +typedef struct Icon_Header_t { + unsigned int file_id; ///< reserved; should be: 0x010000 (but does not have to ;) ) + unsigned int animation_shapes; ///< number of animation shapes per vertex + unsigned int texture_type; ///< texture type - 0x07: uncompressed, 0x06: uncompresses, 0x0f: RLE compression + unsigned int reserved; ///< reserved; should be: 0x3F800000 (but does not have to ;) ) + unsigned int n_vertices; ///< number of vertices; must be a multiple of 3 +} Icon_Header; +/** Set of vertex coordinates + * @note The f16_* fields indicate float16 data; divide by 4096.0f to convert to float32; + */ +typedef struct Vertex_Coord_t { + short f16_x; ///< vertex x coordinate in float16 + short f16_y; ///< vertex y coordinate in float16 + short f16_z; ///< vertex z coordinate in float16 + short f16_unknown; ///< unknown; seems to influence lightning? +} Vertex_Coord; +/** Set of texture coordinates + * @note The f16_* fields indicate float16 data; divide by 4096.0f to convert to float32; + */ +typedef struct Texture_Data_t { + short f16_u; ///< vertex u texture coordinate in float16 + short f16_v; ///< vertex v texture coordinate in float16 + unsigned int color; ///< vertex color (32 bit RGBA) +} Texture_Data; +/** Animation header + */ +typedef struct Animation_Header_t { + unsigned int id_tag; ///< ??? + unsigned int frame_length; ///< ??? + float anim_speed; ///< ??? + unsigned int play_offset; ///< ??? + unsigned int n_frames; ///< number of frames in the animation +} Animation_Header; +/** Per-frame animation data + */ +typedef struct Frame_Data_t { + unsigned int shape_id; ///< shape used for this frame + unsigned int n_keys; ///< number of keys corresponding to this frame +} Frame_Data; +/** Per-key animation data + */ +typedef struct Frame_Key_t { + float time; ///< ??? + float value; ///< ??? +} Frame_Key; diff --git a/include/ps2mc.h b/include/ps2mc.h new file mode 100644 index 0000000..42544a5 --- /dev/null +++ b/include/ps2mc.h @@ -0,0 +1,169 @@ +/* +* PSV file format information from: +* - https://github.com/PMStanley/PSV-Exporter +* +* PSU, MAX, CBS file format information from: +* - https://github.com/root670/CheatDevicePS2 +*/ + +#include + +#define PSV_MAGIC "\x00VSP" +#define PSV_SALT "www.bucanero.com.ar" + +typedef struct _sceMcStDateTime +{ + uint8_t Resv2; + uint8_t Sec; + uint8_t Min; + uint8_t Hour; + uint8_t Day; + uint8_t Month; + uint16_t Year; +} sceMcStDateTime; + +typedef struct // size = 512 +{ + uint16_t mode; // 0 + uint16_t unused; // 2 + uint32_t length; // 4 + sceMcStDateTime created; // 8 + uint32_t cluster; // 16 + uint32_t dir_entry; // 20 + sceMcStDateTime modified; // 24 + uint32_t attr; // 32 + uint32_t unused2[7]; // 36 + char name[32]; // 64 + uint8_t unused3[416]; // 96 +} McFsEntry; + +typedef struct +{ + char magic[4]; + uint32_t padding1; //always 0x00000000 + uint8_t salt[20]; + uint8_t signature[20]; //digital sig + uint32_t padding2; //always 0x00000000 + uint32_t padding3; //always 0x00000000 + uint32_t headerSize; //always 0x0000002C in PS2, 0x00000014 in PS1. + uint32_t saveType; //0x00000002 PS2, 0x00000001 PS1 +} psv_header_t; + +typedef struct +{ + uint32_t displaySize; //PS3 will just round this up to the neaest 1024 boundary so just make it as good as possible + uint32_t sysPos; //location in file of icon.sys + uint32_t sysSize; //icon.sys size + uint32_t icon1Pos; //position of 1st icon + uint32_t icon1Size; //size of 1st icon + uint32_t icon2Pos; //position of 2nd icon + uint32_t icon2Size; //size of 2nd icon + uint32_t icon3Pos; //position of 3rd icon + uint32_t icon3Size; //size of 3rd icon + uint32_t numberOfFiles; +} ps2_header_t; + +typedef struct +{ + sceMcStDateTime created; + sceMcStDateTime modified; + uint32_t numberOfFilesInDir; // this is likely to be number of files in dir + 2 ("." and "..") + uint32_t attribute; // (0x00008427 dir) + char filename[32]; +} ps2_MainDirInfo_t; + +typedef struct +{ + sceMcStDateTime created; + sceMcStDateTime modified; + uint32_t filesize; + uint32_t attribute; // (0x00008497 file) + char filename[32]; // 'Real' PSV files have junk in this after text. + uint32_t positionInFile; +} ps2_FileInfo_t; + +typedef struct +{ + char magic[4]; + uint16_t padding1; // 0000 + uint16_t secondLineOffset; + uint32_t padding2; // 00000000 + uint32_t transparencyVal; // 0x00 (clear) to 0x80 (opaque) + uint8_t bgColourUpperLeft[16]; + uint8_t bgColourUpperRight[16]; + uint8_t bgColourLowerLeft[16]; + uint8_t bgColourLowerRight[16]; + uint8_t light1Direction[16]; + uint8_t light2Direction[16]; + uint8_t light3Direction[16]; + uint8_t light1RGB[16]; + uint8_t light2RGB[16]; + uint8_t light3RGB[16]; + uint8_t ambientLightRGB[16]; + char title[68]; // null terminated, S-JIS + char IconName[64]; // null terminated + char copyIconName[64]; // null terminated + char deleteIconName[64]; // null terminated + uint8_t padding3[512]; +} ps2_IconSys_t; + +typedef struct maxHeader +{ + char magic[12]; + uint32_t crc; + char dirName[32]; + char iconSysName[32]; + uint32_t compressedSize; + uint32_t numFiles; + uint32_t decompressedSize; // This is actually the start of the LZARI stream, but we need it to allocate the buffer. +} maxHeader_t; + +typedef struct maxEntry +{ + uint32_t length; + char name[32]; +} maxEntry_t; + +typedef struct cbsHeader +{ + char magic[4]; + uint32_t unk1; + uint32_t dataOffset; + uint32_t decompressedSize; + uint32_t compressedSize; + char name[32]; + sceMcStDateTime created; + sceMcStDateTime modified; + uint32_t unk2; + uint32_t mode; + char unk3[16]; + char title[72]; + char description[132]; +} cbsHeader_t; + +typedef struct cbsEntry +{ + sceMcStDateTime created; + sceMcStDateTime modified; + uint32_t length; + uint32_t mode; + char unk1[8]; + char name[32]; +} cbsEntry_t; + +typedef struct __attribute__((__packed__)) xpsEntry +{ + uint16_t entry_sz; + char name[64]; + uint32_t length; + uint32_t start; + uint32_t end; + uint32_t mode; + sceMcStDateTime created; + sceMcStDateTime modified; + char unk1[4]; + char padding[12]; + char title_ascii[64]; + char title_sjis[64]; + char unk2[8]; +} xpsEntry_t; diff --git a/include/saves.h b/include/saves.h index 505147f..c9fdbc4 100644 --- a/include/saves.h +++ b/include/saves.h @@ -53,9 +53,8 @@ #define EXP_PSV_PATH_USB0 USB0_PATH PSV_SAVES_PATH_USB #define EXP_PSV_PATH_USB1 USB1_PATH PSV_SAVES_PATH_USB -#define EXP_PS2_PATH_USB0 USB0_PATH "PS2/VMC/" -#define EXP_PS2_PATH_USB1 USB1_PATH "PS2/VMC/" -#define EXP_PS2_PATH_HDD "/dev_hdd0/savedata/vmc/" +#define VMC_PS2_PATH_USB "PS2/VMC/" +#define VMC_PS2_PATH_HDD "/dev_hdd0/savedata/vmc/" #define IMP_PS2VMC_PATH_USB USB_PATH "PS2/VMC/" #define IMPORT_RAP_PATH_USB USB_PATH PS3_LICENSE_PATH @@ -99,6 +98,7 @@ enum cmd_code_enum CMD_HEX_EDIT_FILE, CMD_COPY_PFS, CMD_IMPORT_DATA_FILE, + CMD_DELETE_VMCSAVE, // Bulk commands CMD_RESIGN_SAVES, @@ -109,10 +109,14 @@ enum cmd_code_enum CMD_COPY_ALL_SAVES_HDD, CMD_DUMP_FINGERPRINTS, CMD_SAVE_WEBSERVER, + CMD_EXP_SAVES_VMC, + CMD_EXP_ALL_SAVES_VMC, // Export commands CMD_EXP_KEYSTONE, - CMD_EXP_LICS_RAPS, + CMD_EXP_PS2_VM2, + CMD_EXP_VMC2SAVE, + CMD_EXP_VM2_RAW, CMD_EXP_DATABASE, CMD_DB_REBUILD, CMD_DB_DEL_FIX, @@ -121,6 +125,7 @@ enum cmd_code_enum // Import commands CMD_IMP_KEYSTONE, CMD_IMP_DATABASE, + CMD_IMP_VMC2SAVE, CMD_CREATE_ACT_DAT, CMD_EXTRACT_ARCHIVE, CMD_URL_DOWNLOAD, @@ -140,20 +145,23 @@ enum cmd_code_enum #define SAVE_FLAG_SELECTED 4 #define SAVE_FLAG_ZIP 8 #define SAVE_FLAG_PS2 16 -#define SAVE_FLAG_PSP 32 +#define SAVE_FLAG_PS1 32 #define SAVE_FLAG_PSV 64 #define SAVE_FLAG_TROPHY 128 #define SAVE_FLAG_ONLINE 256 #define SAVE_FLAG_PS4 512 #define SAVE_FLAG_HDD 1024 +#define SAVE_FLAG_VMC 2048 +#define SAVE_FLAG_UPDATED 4096 enum save_type_enum { FILE_TYPE_NULL, - FILE_TYPE_PSV, - FILE_TYPE_TRP, FILE_TYPE_MENU, FILE_TYPE_PS4, + FILE_TYPE_PSV, + FILE_TYPE_TRP, + FILE_TYPE_VMC, // PS1 File Types FILE_TYPE_ZIP, @@ -165,8 +173,13 @@ enum save_type_enum FILE_TYPE_RAP, FILE_TYPE_ACT, - // ISO Files - FILE_TYPE_ISO, + // PS2 File Types + FILE_TYPE_PS2, + FILE_TYPE_PSU, + FILE_TYPE_MAX, + FILE_TYPE_CBS, + FILE_TYPE_XPS, + FILE_TYPE_VM2, }; enum char_flag_enum @@ -182,10 +195,10 @@ enum char_flag_enum CHAR_TAG_LOCKED, CHAR_TAG_NET, CHAR_RES_LF, - CHAR_TAG_TRANSFER, + CHAR_TAG_VMC, CHAR_TAG_ZIP, CHAR_RES_CR, - CHAR_TAG_PCE, + CHAR_TAG_TRANSFER, CHAR_TAG_WARNING, CHAR_BTN_X, CHAR_BTN_S, @@ -215,6 +228,7 @@ enum save_sort_enum SORT_DISABLED, SORT_BY_NAME, SORT_BY_TITLE_ID, + SORT_BY_TYPE, }; typedef struct save_entry @@ -245,15 +259,18 @@ list_t * ReadUserList(const char* userPath); list_t * ReadOnlineList(const char* urlPath); list_t * ReadBackupList(const char* userPath); list_t * ReadTrophyList(const char* userPath); +list_t * ReadVmc2List(const char* userPath); void UnloadGameList(list_t * list); char * readTextFile(const char * path, long* size); int sortSaveList_Compare(const void* A, const void* B); int sortSaveList_Compare_TitleID(const void* A, const void* B); +int sortSaveList_Compare_Type(const void* A, const void* B); int sortCodeList_Compare(const void* A, const void* B); int ReadCodes(save_entry_t * save); int ReadTrophies(save_entry_t * game); int ReadOnlineSaves(save_entry_t * game); int ReadBackupCodes(save_entry_t * bup); +int ReadVmc2Codes(save_entry_t * save); int http_init(void); void http_end(void); @@ -273,7 +290,7 @@ void end_progress_bar(void); int init_loading_screen(const char* message); void stop_loading_screen(void); -void disable_unpatch(); +void disable_unpatch(void); void execCodeCommand(code_entry_t* code, const char* codecmd); @@ -291,3 +308,16 @@ int get_save_details(const save_entry_t *save, char** details); int orbis_SaveUmount(const char* mountPath); int orbis_SaveMount(const save_entry_t *save, uint32_t mode, char* mountPath); int orbis_UpdateSaveParams(const char* mountPath, const char* title, const char* subtitle, const char* details, uint32_t up); + +int vmc_export_psv(const char* save, const char* out_path); +int vmc_export_psu(const char* path, const char* output); +int vmc_import_psv(const char *input); +int vmc_import_psu(const char *input); +int vmc_delete_save(const char* path); + +int ps2_xps2psv(const char *save, const char *psv_path); +int ps2_cbs2psv(const char *save, const char *psv_path); +int ps2_max2psv(const char *save, const char *psv_path); + +char* sjis2utf8(char* input); +uint8_t* getIconPS2(const char* folder, const char* iconfile); diff --git a/include/shiftjis.h b/include/shiftjis.h new file mode 100644 index 0000000..fb6a530 --- /dev/null +++ b/include/shiftjis.h @@ -0,0 +1,3141 @@ +// https://stackoverflow.com/questions/33165171/c-shiftjis-to-utf8-conversion + +static const unsigned char shiftJIS_convTable[25088] ={ + 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, 0xa5, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5f, + 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, + 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, 0x67, + 0x00, 0x68, 0x00, 0x69, 0x00, 0x6a, 0x00, 0x6b, + 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x6f, + 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, + 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x77, + 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, + 0x00, 0x7c, 0x00, 0x7d, 0x20, 0x3e, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0xff, 0x61, 0xff, 0x62, 0xff, 0x63, + 0xff, 0x64, 0xff, 0x65, 0xff, 0x66, 0xff, 0x67, + 0xff, 0x68, 0xff, 0x69, 0xff, 0x6a, 0xff, 0x6b, + 0xff, 0x6c, 0xff, 0x6d, 0xff, 0x6e, 0xff, 0x6f, + 0xff, 0x70, 0xff, 0x71, 0xff, 0x72, 0xff, 0x73, + 0xff, 0x74, 0xff, 0x75, 0xff, 0x76, 0xff, 0x77, + 0xff, 0x78, 0xff, 0x79, 0xff, 0x7a, 0xff, 0x7b, + 0xff, 0x7c, 0xff, 0x7d, 0xff, 0x7e, 0xff, 0x7f, + 0xff, 0x80, 0xff, 0x81, 0xff, 0x82, 0xff, 0x83, + 0xff, 0x84, 0xff, 0x85, 0xff, 0x86, 0xff, 0x87, + 0xff, 0x88, 0xff, 0x89, 0xff, 0x8a, 0xff, 0x8b, + 0xff, 0x8c, 0xff, 0x8d, 0xff, 0x8e, 0xff, 0x8f, + 0xff, 0x90, 0xff, 0x91, 0xff, 0x92, 0xff, 0x93, + 0xff, 0x94, 0xff, 0x95, 0xff, 0x96, 0xff, 0x97, + 0xff, 0x98, 0xff, 0x99, 0xff, 0x9a, 0xff, 0x9b, + 0xff, 0x9c, 0xff, 0x9d, 0xff, 0x9e, 0xff, 0x9f, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x30, 0x00, 0x30, 0x01, 0x30, 0x02, 0xff, 0x0c, + 0xff, 0x0e, 0x30, 0xfb, 0xff, 0x1a, 0xff, 0x1b, + 0xff, 0x1f, 0xff, 0x01, 0x30, 0x9b, 0x30, 0x9c, + 0x00, 0xb4, 0xff, 0x40, 0x00, 0xa8, 0xff, 0x3e, + 0xff, 0xe3, 0xff, 0x3f, 0x30, 0xfd, 0x30, 0xfe, + 0x30, 0x9d, 0x30, 0x9e, 0x30, 0x03, 0x4e, 0xdd, + 0x30, 0x05, 0x30, 0x06, 0x30, 0x07, 0x30, 0xfc, + 0x20, 0x15, 0x20, 0x10, 0xff, 0x0f, 0x00, 0x5c, + 0x30, 0x1c, 0x20, 0x16, 0xff, 0x5c, 0x20, 0x26, + 0x20, 0x25, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, + 0x20, 0x1d, 0xff, 0x08, 0xff, 0x09, 0x30, 0x14, + 0x30, 0x15, 0xff, 0x3b, 0xff, 0x3d, 0xff, 0x5b, + 0xff, 0x5d, 0x30, 0x08, 0x30, 0x09, 0x30, 0x0a, + 0x30, 0x0b, 0x30, 0x0c, 0x30, 0x0d, 0x30, 0x0e, + 0x30, 0x0f, 0x30, 0x10, 0x30, 0x11, 0xff, 0x0b, + 0x22, 0x12, 0x00, 0xb1, 0x00, 0xd7, 0x00, 0x20, + 0x00, 0xf7, 0xff, 0x1d, 0x22, 0x60, 0xff, 0x1c, + 0xff, 0x1e, 0x22, 0x66, 0x22, 0x67, 0x22, 0x1e, + 0x22, 0x34, 0x26, 0x42, 0x26, 0x40, 0x00, 0xb0, + 0x20, 0x32, 0x20, 0x33, 0x21, 0x03, 0xff, 0xe5, + 0xff, 0x04, 0x00, 0xa2, 0x00, 0xa3, 0xff, 0x05, + 0xff, 0x03, 0xff, 0x06, 0xff, 0x0a, 0xff, 0x20, + 0x00, 0xa7, 0x26, 0x06, 0x26, 0x05, 0x25, 0xcb, + 0x25, 0xcf, 0x25, 0xce, 0x25, 0xc7, 0x25, 0xc6, + 0x25, 0xa1, 0x25, 0xa0, 0x25, 0xb3, 0x25, 0xb2, + 0x25, 0xbd, 0x25, 0xbc, 0x20, 0x3b, 0x30, 0x12, + 0x21, 0x92, 0x21, 0x90, 0x21, 0x91, 0x21, 0x93, + 0x30, 0x13, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x22, 0x08, 0x22, 0x0b, 0x22, 0x86, 0x22, 0x87, + 0x22, 0x82, 0x22, 0x83, 0x22, 0x2a, 0x22, 0x29, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x22, 0x27, 0x22, 0x28, 0x00, 0xac, 0x21, 0xd2, + 0x21, 0xd4, 0x22, 0x00, 0x22, 0x03, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x22, 0x20, 0x22, 0xa5, + 0x23, 0x12, 0x22, 0x02, 0x22, 0x07, 0x22, 0x61, + 0x22, 0x52, 0x22, 0x6a, 0x22, 0x6b, 0x22, 0x1a, + 0x22, 0x3d, 0x22, 0x1d, 0x22, 0x35, 0x22, 0x2b, + 0x22, 0x2c, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x21, 0x2b, 0x20, 0x30, 0x26, 0x6f, 0x26, 0x6d, + 0x26, 0x6a, 0x20, 0x20, 0x20, 0x21, 0x00, 0xb6, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x25, 0xef, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0xff, 0x10, + 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, + 0xff, 0x15, 0xff, 0x16, 0xff, 0x17, 0xff, 0x18, + 0xff, 0x19, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, 0x24, + 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x28, + 0xff, 0x29, 0xff, 0x2a, 0xff, 0x2b, 0xff, 0x2c, + 0xff, 0x2d, 0xff, 0x2e, 0xff, 0x2f, 0xff, 0x30, + 0xff, 0x31, 0xff, 0x32, 0xff, 0x33, 0xff, 0x34, + 0xff, 0x35, 0xff, 0x36, 0xff, 0x37, 0xff, 0x38, + 0xff, 0x39, 0xff, 0x3a, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0xff, 0x41, 0xff, 0x42, 0xff, 0x43, + 0xff, 0x44, 0xff, 0x45, 0xff, 0x46, 0xff, 0x47, + 0xff, 0x48, 0xff, 0x49, 0xff, 0x4a, 0xff, 0x4b, + 0xff, 0x4c, 0xff, 0x4d, 0xff, 0x4e, 0xff, 0x4f, + 0xff, 0x50, 0xff, 0x51, 0xff, 0x52, 0xff, 0x53, + 0xff, 0x54, 0xff, 0x55, 0xff, 0x56, 0xff, 0x57, + 0xff, 0x58, 0xff, 0x59, 0xff, 0x5a, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x30, 0x41, + 0x30, 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, + 0x30, 0x46, 0x30, 0x47, 0x30, 0x48, 0x30, 0x49, + 0x30, 0x4a, 0x30, 0x4b, 0x30, 0x4c, 0x30, 0x4d, + 0x30, 0x4e, 0x30, 0x4f, 0x30, 0x50, 0x30, 0x51, + 0x30, 0x52, 0x30, 0x53, 0x30, 0x54, 0x30, 0x55, + 0x30, 0x56, 0x30, 0x57, 0x30, 0x58, 0x30, 0x59, + 0x30, 0x5a, 0x30, 0x5b, 0x30, 0x5c, 0x30, 0x5d, + 0x30, 0x5e, 0x30, 0x5f, 0x30, 0x60, 0x30, 0x61, + 0x30, 0x62, 0x30, 0x63, 0x30, 0x64, 0x30, 0x65, + 0x30, 0x66, 0x30, 0x67, 0x30, 0x68, 0x30, 0x69, + 0x30, 0x6a, 0x30, 0x6b, 0x30, 0x6c, 0x30, 0x6d, + 0x30, 0x6e, 0x30, 0x6f, 0x30, 0x70, 0x30, 0x71, + 0x30, 0x72, 0x30, 0x73, 0x30, 0x74, 0x30, 0x75, + 0x30, 0x76, 0x30, 0x77, 0x30, 0x78, 0x30, 0x79, + 0x30, 0x7a, 0x30, 0x7b, 0x30, 0x7c, 0x30, 0x7d, + 0x30, 0x7e, 0x30, 0x7f, 0x30, 0x80, 0x30, 0x81, + 0x30, 0x82, 0x30, 0x83, 0x30, 0x84, 0x30, 0x85, + 0x30, 0x86, 0x30, 0x87, 0x30, 0x88, 0x30, 0x89, + 0x30, 0x8a, 0x30, 0x8b, 0x30, 0x8c, 0x30, 0x8d, + 0x30, 0x8e, 0x30, 0x8f, 0x30, 0x90, 0x30, 0x91, + 0x30, 0x92, 0x30, 0x93, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x30, 0xa1, 0x30, 0xa2, 0x30, 0xa3, 0x30, 0xa4, + 0x30, 0xa5, 0x30, 0xa6, 0x30, 0xa7, 0x30, 0xa8, + 0x30, 0xa9, 0x30, 0xaa, 0x30, 0xab, 0x30, 0xac, + 0x30, 0xad, 0x30, 0xae, 0x30, 0xaf, 0x30, 0xb0, + 0x30, 0xb1, 0x30, 0xb2, 0x30, 0xb3, 0x30, 0xb4, + 0x30, 0xb5, 0x30, 0xb6, 0x30, 0xb7, 0x30, 0xb8, + 0x30, 0xb9, 0x30, 0xba, 0x30, 0xbb, 0x30, 0xbc, + 0x30, 0xbd, 0x30, 0xbe, 0x30, 0xbf, 0x30, 0xc0, + 0x30, 0xc1, 0x30, 0xc2, 0x30, 0xc3, 0x30, 0xc4, + 0x30, 0xc5, 0x30, 0xc6, 0x30, 0xc7, 0x30, 0xc8, + 0x30, 0xc9, 0x30, 0xca, 0x30, 0xcb, 0x30, 0xcc, + 0x30, 0xcd, 0x30, 0xce, 0x30, 0xcf, 0x30, 0xd0, + 0x30, 0xd1, 0x30, 0xd2, 0x30, 0xd3, 0x30, 0xd4, + 0x30, 0xd5, 0x30, 0xd6, 0x30, 0xd7, 0x30, 0xd8, + 0x30, 0xd9, 0x30, 0xda, 0x30, 0xdb, 0x30, 0xdc, + 0x30, 0xdd, 0x30, 0xde, 0x30, 0xdf, 0x00, 0x20, + 0x30, 0xe0, 0x30, 0xe1, 0x30, 0xe2, 0x30, 0xe3, + 0x30, 0xe4, 0x30, 0xe5, 0x30, 0xe6, 0x30, 0xe7, + 0x30, 0xe8, 0x30, 0xe9, 0x30, 0xea, 0x30, 0xeb, + 0x30, 0xec, 0x30, 0xed, 0x30, 0xee, 0x30, 0xef, + 0x30, 0xf0, 0x30, 0xf1, 0x30, 0xf2, 0x30, 0xf3, + 0x30, 0xf4, 0x30, 0xf5, 0x30, 0xf6, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x03, 0x91, + 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, + 0x03, 0x96, 0x03, 0x97, 0x03, 0x98, 0x03, 0x99, + 0x03, 0x9a, 0x03, 0x9b, 0x03, 0x9c, 0x03, 0x9d, + 0x03, 0x9e, 0x03, 0x9f, 0x03, 0xa0, 0x03, 0xa1, + 0x03, 0xa3, 0x03, 0xa4, 0x03, 0xa5, 0x03, 0xa6, + 0x03, 0xa7, 0x03, 0xa8, 0x03, 0xa9, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x03, 0xb1, + 0x03, 0xb2, 0x03, 0xb3, 0x03, 0xb4, 0x03, 0xb5, + 0x03, 0xb6, 0x03, 0xb7, 0x03, 0xb8, 0x03, 0xb9, + 0x03, 0xba, 0x03, 0xbb, 0x03, 0xbc, 0x03, 0xbd, + 0x03, 0xbe, 0x03, 0xbf, 0x03, 0xc0, 0x03, 0xc1, + 0x03, 0xc3, 0x03, 0xc4, 0x03, 0xc5, 0x03, 0xc6, + 0x03, 0xc7, 0x03, 0xc8, 0x03, 0xc9, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x04, 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, + 0x04, 0x14, 0x04, 0x15, 0x04, 0x01, 0x04, 0x16, + 0x04, 0x17, 0x04, 0x18, 0x04, 0x19, 0x04, 0x1a, + 0x04, 0x1b, 0x04, 0x1c, 0x04, 0x1d, 0x04, 0x1e, + 0x04, 0x1f, 0x04, 0x20, 0x04, 0x21, 0x04, 0x22, + 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, + 0x04, 0x27, 0x04, 0x28, 0x04, 0x29, 0x04, 0x2a, + 0x04, 0x2b, 0x04, 0x2c, 0x04, 0x2d, 0x04, 0x2e, + 0x04, 0x2f, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x04, 0x30, 0x04, 0x31, 0x04, 0x32, 0x04, 0x33, + 0x04, 0x34, 0x04, 0x35, 0x04, 0x51, 0x04, 0x36, + 0x04, 0x37, 0x04, 0x38, 0x04, 0x39, 0x04, 0x3a, + 0x04, 0x3b, 0x04, 0x3c, 0x04, 0x3d, 0x00, 0x20, + 0x04, 0x3e, 0x04, 0x3f, 0x04, 0x40, 0x04, 0x41, + 0x04, 0x42, 0x04, 0x43, 0x04, 0x44, 0x04, 0x45, + 0x04, 0x46, 0x04, 0x47, 0x04, 0x48, 0x04, 0x49, + 0x04, 0x4a, 0x04, 0x4b, 0x04, 0x4c, 0x04, 0x4d, + 0x04, 0x4e, 0x04, 0x4f, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x25, 0x00, + 0x25, 0x02, 0x25, 0x0c, 0x25, 0x10, 0x25, 0x18, + 0x25, 0x14, 0x25, 0x1c, 0x25, 0x2c, 0x25, 0x24, + 0x25, 0x34, 0x25, 0x3c, 0x25, 0x01, 0x25, 0x03, + 0x25, 0x0f, 0x25, 0x13, 0x25, 0x1b, 0x25, 0x17, + 0x25, 0x23, 0x25, 0x33, 0x25, 0x2b, 0x25, 0x3b, + 0x25, 0x4b, 0x25, 0x20, 0x25, 0x2f, 0x25, 0x28, + 0x25, 0x37, 0x25, 0x3f, 0x25, 0x1d, 0x25, 0x30, + 0x25, 0x25, 0x25, 0x38, 0x25, 0x42, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x4e, 0x9c, + 0x55, 0x16, 0x5a, 0x03, 0x96, 0x3f, 0x54, 0xc0, + 0x61, 0x1b, 0x63, 0x28, 0x59, 0xf6, 0x90, 0x22, + 0x84, 0x75, 0x83, 0x1c, 0x7a, 0x50, 0x60, 0xaa, + 0x63, 0xe1, 0x6e, 0x25, 0x65, 0xed, 0x84, 0x66, + 0x82, 0xa6, 0x9b, 0xf5, 0x68, 0x93, 0x57, 0x27, + 0x65, 0xa1, 0x62, 0x71, 0x5b, 0x9b, 0x59, 0xd0, + 0x86, 0x7b, 0x98, 0xf4, 0x7d, 0x62, 0x7d, 0xbe, + 0x9b, 0x8e, 0x62, 0x16, 0x7c, 0x9f, 0x88, 0xb7, + 0x5b, 0x89, 0x5e, 0xb5, 0x63, 0x09, 0x66, 0x97, + 0x68, 0x48, 0x95, 0xc7, 0x97, 0x8d, 0x67, 0x4f, + 0x4e, 0xe5, 0x4f, 0x0a, 0x4f, 0x4d, 0x4f, 0x9d, + 0x50, 0x49, 0x56, 0xf2, 0x59, 0x37, 0x59, 0xd4, + 0x5a, 0x01, 0x5c, 0x09, 0x60, 0xdf, 0x61, 0x0f, + 0x61, 0x70, 0x66, 0x13, 0x69, 0x05, 0x70, 0xba, + 0x75, 0x4f, 0x75, 0x70, 0x79, 0xfb, 0x7d, 0xad, + 0x7d, 0xef, 0x80, 0xc3, 0x84, 0x0e, 0x88, 0x63, + 0x8b, 0x02, 0x90, 0x55, 0x90, 0x7a, 0x53, 0x3b, + 0x4e, 0x95, 0x4e, 0xa5, 0x57, 0xdf, 0x80, 0xb2, + 0x90, 0xc1, 0x78, 0xef, 0x4e, 0x00, 0x58, 0xf1, + 0x6e, 0xa2, 0x90, 0x38, 0x7a, 0x32, 0x83, 0x28, + 0x82, 0x8b, 0x9c, 0x2f, 0x51, 0x41, 0x53, 0x70, + 0x54, 0xbd, 0x54, 0xe1, 0x56, 0xe0, 0x59, 0xfb, + 0x5f, 0x15, 0x98, 0xf2, 0x6d, 0xeb, 0x80, 0xe4, + 0x85, 0x2d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x96, 0x62, 0x96, 0x70, 0x96, 0xa0, 0x97, 0xfb, + 0x54, 0x0b, 0x53, 0xf3, 0x5b, 0x87, 0x70, 0xcf, + 0x7f, 0xbd, 0x8f, 0xc2, 0x96, 0xe8, 0x53, 0x6f, + 0x9d, 0x5c, 0x7a, 0xba, 0x4e, 0x11, 0x78, 0x93, + 0x81, 0xfc, 0x6e, 0x26, 0x56, 0x18, 0x55, 0x04, + 0x6b, 0x1d, 0x85, 0x1a, 0x9c, 0x3b, 0x59, 0xe5, + 0x53, 0xa9, 0x6d, 0x66, 0x74, 0xdc, 0x95, 0x8f, + 0x56, 0x42, 0x4e, 0x91, 0x90, 0x4b, 0x96, 0xf2, + 0x83, 0x4f, 0x99, 0x0c, 0x53, 0xe1, 0x55, 0xb6, + 0x5b, 0x30, 0x5f, 0x71, 0x66, 0x20, 0x66, 0xf3, + 0x68, 0x04, 0x6c, 0x38, 0x6c, 0xf3, 0x6d, 0x29, + 0x74, 0x5b, 0x76, 0xc8, 0x7a, 0x4e, 0x98, 0x34, + 0x82, 0xf1, 0x88, 0x5b, 0x8a, 0x60, 0x92, 0xed, + 0x6d, 0xb2, 0x75, 0xab, 0x76, 0xca, 0x99, 0xc5, + 0x60, 0xa6, 0x8b, 0x01, 0x8d, 0x8a, 0x95, 0xb2, + 0x69, 0x8e, 0x53, 0xad, 0x51, 0x86, 0x00, 0x20, + 0x57, 0x12, 0x58, 0x30, 0x59, 0x44, 0x5b, 0xb4, + 0x5e, 0xf6, 0x60, 0x28, 0x63, 0xa9, 0x63, 0xf4, + 0x6c, 0xbf, 0x6f, 0x14, 0x70, 0x8e, 0x71, 0x14, + 0x71, 0x59, 0x71, 0xd5, 0x73, 0x3f, 0x7e, 0x01, + 0x82, 0x76, 0x82, 0xd1, 0x85, 0x97, 0x90, 0x60, + 0x92, 0x5b, 0x9d, 0x1b, 0x58, 0x69, 0x65, 0xbc, + 0x6c, 0x5a, 0x75, 0x25, 0x51, 0xf9, 0x59, 0x2e, + 0x59, 0x65, 0x5f, 0x80, 0x5f, 0xdc, 0x62, 0xbc, + 0x65, 0xfa, 0x6a, 0x2a, 0x6b, 0x27, 0x6b, 0xb4, + 0x73, 0x8b, 0x7f, 0xc1, 0x89, 0x56, 0x9d, 0x2c, + 0x9d, 0x0e, 0x9e, 0xc4, 0x5c, 0xa1, 0x6c, 0x96, + 0x83, 0x7b, 0x51, 0x04, 0x5c, 0x4b, 0x61, 0xb6, + 0x81, 0xc6, 0x68, 0x76, 0x72, 0x61, 0x4e, 0x59, + 0x4f, 0xfa, 0x53, 0x78, 0x60, 0x69, 0x6e, 0x29, + 0x7a, 0x4f, 0x97, 0xf3, 0x4e, 0x0b, 0x53, 0x16, + 0x4e, 0xee, 0x4f, 0x55, 0x4f, 0x3d, 0x4f, 0xa1, + 0x4f, 0x73, 0x52, 0xa0, 0x53, 0xef, 0x56, 0x09, + 0x59, 0x0f, 0x5a, 0xc1, 0x5b, 0xb6, 0x5b, 0xe1, + 0x79, 0xd1, 0x66, 0x87, 0x67, 0x9c, 0x67, 0xb6, + 0x6b, 0x4c, 0x6c, 0xb3, 0x70, 0x6b, 0x73, 0xc2, + 0x79, 0x8d, 0x79, 0xbe, 0x7a, 0x3c, 0x7b, 0x87, + 0x82, 0xb1, 0x82, 0xdb, 0x83, 0x04, 0x83, 0x77, + 0x83, 0xef, 0x83, 0xd3, 0x87, 0x66, 0x8a, 0xb2, + 0x56, 0x29, 0x8c, 0xa8, 0x8f, 0xe6, 0x90, 0x4e, + 0x97, 0x1e, 0x86, 0x8a, 0x4f, 0xc4, 0x5c, 0xe8, + 0x62, 0x11, 0x72, 0x59, 0x75, 0x3b, 0x81, 0xe5, + 0x82, 0xbd, 0x86, 0xfe, 0x8c, 0xc0, 0x96, 0xc5, + 0x99, 0x13, 0x99, 0xd5, 0x4e, 0xcb, 0x4f, 0x1a, + 0x89, 0xe3, 0x56, 0xde, 0x58, 0x4a, 0x58, 0xca, + 0x5e, 0xfb, 0x5f, 0xeb, 0x60, 0x2a, 0x60, 0x94, + 0x60, 0x62, 0x61, 0xd0, 0x62, 0x12, 0x62, 0xd0, + 0x65, 0x39, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x9b, 0x41, 0x66, 0x66, 0x68, 0xb0, 0x6d, 0x77, + 0x70, 0x70, 0x75, 0x4c, 0x76, 0x86, 0x7d, 0x75, + 0x82, 0xa5, 0x87, 0xf9, 0x95, 0x8b, 0x96, 0x8e, + 0x8c, 0x9d, 0x51, 0xf1, 0x52, 0xbe, 0x59, 0x16, + 0x54, 0xb3, 0x5b, 0xb3, 0x5d, 0x16, 0x61, 0x68, + 0x69, 0x82, 0x6d, 0xaf, 0x78, 0x8d, 0x84, 0xcb, + 0x88, 0x57, 0x8a, 0x72, 0x93, 0xa7, 0x9a, 0xb8, + 0x6d, 0x6c, 0x99, 0xa8, 0x86, 0xd9, 0x57, 0xa3, + 0x67, 0xff, 0x86, 0xce, 0x92, 0x0e, 0x52, 0x83, + 0x56, 0x87, 0x54, 0x04, 0x5e, 0xd3, 0x62, 0xe1, + 0x64, 0xb9, 0x68, 0x3c, 0x68, 0x38, 0x6b, 0xbb, + 0x73, 0x72, 0x78, 0xba, 0x7a, 0x6b, 0x89, 0x9a, + 0x89, 0xd2, 0x8d, 0x6b, 0x8f, 0x03, 0x90, 0xed, + 0x95, 0xa3, 0x96, 0x94, 0x97, 0x69, 0x5b, 0x66, + 0x5c, 0xb3, 0x69, 0x7d, 0x98, 0x4d, 0x98, 0x4e, + 0x63, 0x9b, 0x7b, 0x20, 0x6a, 0x2b, 0x00, 0x20, + 0x6a, 0x7f, 0x68, 0xb6, 0x9c, 0x0d, 0x6f, 0x5f, + 0x52, 0x72, 0x55, 0x9d, 0x60, 0x70, 0x62, 0xec, + 0x6d, 0x3b, 0x6e, 0x07, 0x6e, 0xd1, 0x84, 0x5b, + 0x89, 0x10, 0x8f, 0x44, 0x4e, 0x14, 0x9c, 0x39, + 0x53, 0xf6, 0x69, 0x1b, 0x6a, 0x3a, 0x97, 0x84, + 0x68, 0x2a, 0x51, 0x5c, 0x7a, 0xc3, 0x84, 0xb2, + 0x91, 0xdc, 0x93, 0x8c, 0x56, 0x5b, 0x9d, 0x28, + 0x68, 0x22, 0x83, 0x05, 0x84, 0x31, 0x7c, 0xa5, + 0x52, 0x08, 0x82, 0xc5, 0x74, 0xe6, 0x4e, 0x7e, + 0x4f, 0x83, 0x51, 0xa0, 0x5b, 0xd2, 0x52, 0x0a, + 0x52, 0xd8, 0x52, 0xe7, 0x5d, 0xfb, 0x55, 0x9a, + 0x58, 0x2a, 0x59, 0xe6, 0x5b, 0x8c, 0x5b, 0x98, + 0x5b, 0xdb, 0x5e, 0x72, 0x5e, 0x79, 0x60, 0xa3, + 0x61, 0x1f, 0x61, 0x63, 0x61, 0xbe, 0x63, 0xdb, + 0x65, 0x62, 0x67, 0xd1, 0x68, 0x53, 0x68, 0xfa, + 0x6b, 0x3e, 0x6b, 0x53, 0x6c, 0x57, 0x6f, 0x22, + 0x6f, 0x97, 0x6f, 0x45, 0x74, 0xb0, 0x75, 0x18, + 0x76, 0xe3, 0x77, 0x0b, 0x7a, 0xff, 0x7b, 0xa1, + 0x7c, 0x21, 0x7d, 0xe9, 0x7f, 0x36, 0x7f, 0xf0, + 0x80, 0x9d, 0x82, 0x66, 0x83, 0x9e, 0x89, 0xb3, + 0x8a, 0xcc, 0x8c, 0xab, 0x90, 0x84, 0x94, 0x51, + 0x95, 0x93, 0x95, 0x91, 0x95, 0xa2, 0x96, 0x65, + 0x97, 0xd3, 0x99, 0x28, 0x82, 0x18, 0x4e, 0x38, + 0x54, 0x2b, 0x5c, 0xb8, 0x5d, 0xcc, 0x73, 0xa9, + 0x76, 0x4c, 0x77, 0x3c, 0x5c, 0xa9, 0x7f, 0xeb, + 0x8d, 0x0b, 0x96, 0xc1, 0x98, 0x11, 0x98, 0x54, + 0x98, 0x58, 0x4f, 0x01, 0x4f, 0x0e, 0x53, 0x71, + 0x55, 0x9c, 0x56, 0x68, 0x57, 0xfa, 0x59, 0x47, + 0x5b, 0x09, 0x5b, 0xc4, 0x5c, 0x90, 0x5e, 0x0c, + 0x5e, 0x7e, 0x5f, 0xcc, 0x63, 0xee, 0x67, 0x3a, + 0x65, 0xd7, 0x65, 0xe2, 0x67, 0x1f, 0x68, 0xcb, + 0x68, 0xc4, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x6a, 0x5f, 0x5e, 0x30, 0x6b, 0xc5, 0x6c, 0x17, + 0x6c, 0x7d, 0x75, 0x7f, 0x79, 0x48, 0x5b, 0x63, + 0x7a, 0x00, 0x7d, 0x00, 0x5f, 0xbd, 0x89, 0x8f, + 0x8a, 0x18, 0x8c, 0xb4, 0x8d, 0x77, 0x8e, 0xcc, + 0x8f, 0x1d, 0x98, 0xe2, 0x9a, 0x0e, 0x9b, 0x3c, + 0x4e, 0x80, 0x50, 0x7d, 0x51, 0x00, 0x59, 0x93, + 0x5b, 0x9c, 0x62, 0x2f, 0x62, 0x80, 0x64, 0xec, + 0x6b, 0x3a, 0x72, 0xa0, 0x75, 0x91, 0x79, 0x47, + 0x7f, 0xa9, 0x87, 0xfb, 0x8a, 0xbc, 0x8b, 0x70, + 0x63, 0xac, 0x83, 0xca, 0x97, 0xa0, 0x54, 0x09, + 0x54, 0x03, 0x55, 0xab, 0x68, 0x54, 0x6a, 0x58, + 0x8a, 0x70, 0x78, 0x27, 0x67, 0x75, 0x9e, 0xcd, + 0x53, 0x74, 0x5b, 0xa2, 0x81, 0x1a, 0x86, 0x50, + 0x90, 0x06, 0x4e, 0x18, 0x4e, 0x45, 0x4e, 0xc7, + 0x4f, 0x11, 0x53, 0xca, 0x54, 0x38, 0x5b, 0xae, + 0x5f, 0x13, 0x60, 0x25, 0x65, 0x51, 0x00, 0x20, + 0x67, 0x3d, 0x6c, 0x42, 0x6c, 0x72, 0x6c, 0xe3, + 0x70, 0x78, 0x74, 0x03, 0x7a, 0x76, 0x7a, 0xae, + 0x7b, 0x08, 0x7d, 0x1a, 0x7c, 0xfe, 0x7d, 0x66, + 0x65, 0xe7, 0x72, 0x5b, 0x53, 0xbb, 0x5c, 0x45, + 0x5d, 0xe8, 0x62, 0xd2, 0x62, 0xe0, 0x63, 0x19, + 0x6e, 0x20, 0x86, 0x5a, 0x8a, 0x31, 0x8d, 0xdd, + 0x92, 0xf8, 0x6f, 0x01, 0x79, 0xa6, 0x9b, 0x5a, + 0x4e, 0xa8, 0x4e, 0xab, 0x4e, 0xac, 0x4f, 0x9b, + 0x4f, 0xa0, 0x50, 0xd1, 0x51, 0x47, 0x7a, 0xf6, + 0x51, 0x71, 0x51, 0xf6, 0x53, 0x54, 0x53, 0x21, + 0x53, 0x7f, 0x53, 0xeb, 0x55, 0xac, 0x58, 0x83, + 0x5c, 0xe1, 0x5f, 0x37, 0x5f, 0x4a, 0x60, 0x2f, + 0x60, 0x50, 0x60, 0x6d, 0x63, 0x1f, 0x65, 0x59, + 0x6a, 0x4b, 0x6c, 0xc1, 0x72, 0xc2, 0x72, 0xed, + 0x77, 0xef, 0x80, 0xf8, 0x81, 0x05, 0x82, 0x08, + 0x85, 0x4e, 0x90, 0xf7, 0x93, 0xe1, 0x97, 0xff, + 0x99, 0x57, 0x9a, 0x5a, 0x4e, 0xf0, 0x51, 0xdd, + 0x5c, 0x2d, 0x66, 0x81, 0x69, 0x6d, 0x5c, 0x40, + 0x66, 0xf2, 0x69, 0x75, 0x73, 0x89, 0x68, 0x50, + 0x7c, 0x81, 0x50, 0xc5, 0x52, 0xe4, 0x57, 0x47, + 0x5d, 0xfe, 0x93, 0x26, 0x65, 0xa4, 0x6b, 0x23, + 0x6b, 0x3d, 0x74, 0x34, 0x79, 0x81, 0x79, 0xbd, + 0x7b, 0x4b, 0x7d, 0xca, 0x82, 0xb9, 0x83, 0xcc, + 0x88, 0x7f, 0x89, 0x5f, 0x8b, 0x39, 0x8f, 0xd1, + 0x91, 0xd1, 0x54, 0x1f, 0x92, 0x80, 0x4e, 0x5d, + 0x50, 0x36, 0x53, 0xe5, 0x53, 0x3a, 0x72, 0xd7, + 0x73, 0x96, 0x77, 0xe9, 0x82, 0xe6, 0x8e, 0xaf, + 0x99, 0xc6, 0x99, 0xc8, 0x99, 0xd2, 0x51, 0x77, + 0x61, 0x1a, 0x86, 0x5e, 0x55, 0xb0, 0x7a, 0x7a, + 0x50, 0x76, 0x5b, 0xd3, 0x90, 0x47, 0x96, 0x85, + 0x4e, 0x32, 0x6a, 0xdb, 0x91, 0xe7, 0x5c, 0x51, + 0x5c, 0x48, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x63, 0x98, 0x7a, 0x9f, 0x6c, 0x93, 0x97, 0x74, + 0x8f, 0x61, 0x7a, 0xaa, 0x71, 0x8a, 0x96, 0x88, + 0x7c, 0x82, 0x68, 0x17, 0x7e, 0x70, 0x68, 0x51, + 0x93, 0x6c, 0x52, 0xf2, 0x54, 0x1b, 0x85, 0xab, + 0x8a, 0x13, 0x7f, 0xa4, 0x8e, 0xcd, 0x90, 0xe1, + 0x53, 0x66, 0x88, 0x88, 0x79, 0x41, 0x4f, 0xc2, + 0x50, 0xbe, 0x52, 0x11, 0x51, 0x44, 0x55, 0x53, + 0x57, 0x2d, 0x73, 0xea, 0x57, 0x8b, 0x59, 0x51, + 0x5f, 0x62, 0x5f, 0x84, 0x60, 0x75, 0x61, 0x76, + 0x61, 0x67, 0x61, 0xa9, 0x63, 0xb2, 0x64, 0x3a, + 0x65, 0x6c, 0x66, 0x6f, 0x68, 0x42, 0x6e, 0x13, + 0x75, 0x66, 0x7a, 0x3d, 0x7c, 0xfb, 0x7d, 0x4c, + 0x7d, 0x99, 0x7e, 0x4b, 0x7f, 0x6b, 0x83, 0x0e, + 0x83, 0x4a, 0x86, 0xcd, 0x8a, 0x08, 0x8a, 0x63, + 0x8b, 0x66, 0x8e, 0xfd, 0x98, 0x1a, 0x9d, 0x8f, + 0x82, 0xb8, 0x8f, 0xce, 0x9b, 0xe8, 0x00, 0x20, + 0x52, 0x87, 0x62, 0x1f, 0x64, 0x83, 0x6f, 0xc0, + 0x96, 0x99, 0x68, 0x41, 0x50, 0x91, 0x6b, 0x20, + 0x6c, 0x7a, 0x6f, 0x54, 0x7a, 0x74, 0x7d, 0x50, + 0x88, 0x40, 0x8a, 0x23, 0x67, 0x08, 0x4e, 0xf6, + 0x50, 0x39, 0x50, 0x26, 0x50, 0x65, 0x51, 0x7c, + 0x52, 0x38, 0x52, 0x63, 0x55, 0xa7, 0x57, 0x0f, + 0x58, 0x05, 0x5a, 0xcc, 0x5e, 0xfa, 0x61, 0xb2, + 0x61, 0xf8, 0x62, 0xf3, 0x63, 0x72, 0x69, 0x1c, + 0x6a, 0x29, 0x72, 0x7d, 0x72, 0xac, 0x73, 0x2e, + 0x78, 0x14, 0x78, 0x6f, 0x7d, 0x79, 0x77, 0x0c, + 0x80, 0xa9, 0x89, 0x8b, 0x8b, 0x19, 0x8c, 0xe2, + 0x8e, 0xd2, 0x90, 0x63, 0x93, 0x75, 0x96, 0x7a, + 0x98, 0x55, 0x9a, 0x13, 0x9e, 0x78, 0x51, 0x43, + 0x53, 0x9f, 0x53, 0xb3, 0x5e, 0x7b, 0x5f, 0x26, + 0x6e, 0x1b, 0x6e, 0x90, 0x73, 0x84, 0x73, 0xfe, + 0x7d, 0x43, 0x82, 0x37, 0x8a, 0x00, 0x8a, 0xfa, + 0x96, 0x50, 0x4e, 0x4e, 0x50, 0x0b, 0x53, 0xe4, + 0x54, 0x7c, 0x56, 0xfa, 0x59, 0xd1, 0x5b, 0x64, + 0x5d, 0xf1, 0x5e, 0xab, 0x5f, 0x27, 0x62, 0x38, + 0x65, 0x45, 0x67, 0xaf, 0x6e, 0x56, 0x72, 0xd0, + 0x7c, 0xca, 0x88, 0xb4, 0x80, 0xa1, 0x80, 0xe1, + 0x83, 0xf0, 0x86, 0x4e, 0x8a, 0x87, 0x8d, 0xe8, + 0x92, 0x37, 0x96, 0xc7, 0x98, 0x67, 0x9f, 0x13, + 0x4e, 0x94, 0x4e, 0x92, 0x4f, 0x0d, 0x53, 0x48, + 0x54, 0x49, 0x54, 0x3e, 0x5a, 0x2f, 0x5f, 0x8c, + 0x5f, 0xa1, 0x60, 0x9f, 0x68, 0xa7, 0x6a, 0x8e, + 0x74, 0x5a, 0x78, 0x81, 0x8a, 0x9e, 0x8a, 0xa4, + 0x8b, 0x77, 0x91, 0x90, 0x4e, 0x5e, 0x9b, 0xc9, + 0x4e, 0xa4, 0x4f, 0x7c, 0x4f, 0xaf, 0x50, 0x19, + 0x50, 0x16, 0x51, 0x49, 0x51, 0x6c, 0x52, 0x9f, + 0x52, 0xb9, 0x52, 0xfe, 0x53, 0x9a, 0x53, 0xe3, + 0x54, 0x11, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x54, 0x0e, 0x55, 0x89, 0x57, 0x51, 0x57, 0xa2, + 0x59, 0x7d, 0x5b, 0x54, 0x5b, 0x5d, 0x5b, 0x8f, + 0x5d, 0xe5, 0x5d, 0xe7, 0x5d, 0xf7, 0x5e, 0x78, + 0x5e, 0x83, 0x5e, 0x9a, 0x5e, 0xb7, 0x5f, 0x18, + 0x60, 0x52, 0x61, 0x4c, 0x62, 0x97, 0x62, 0xd8, + 0x63, 0xa7, 0x65, 0x3b, 0x66, 0x02, 0x66, 0x43, + 0x66, 0xf4, 0x67, 0x6d, 0x68, 0x21, 0x68, 0x97, + 0x69, 0xcb, 0x6c, 0x5f, 0x6d, 0x2a, 0x6d, 0x69, + 0x6e, 0x2f, 0x6e, 0x9d, 0x75, 0x32, 0x76, 0x87, + 0x78, 0x6c, 0x7a, 0x3f, 0x7c, 0xe0, 0x7d, 0x05, + 0x7d, 0x18, 0x7d, 0x5e, 0x7d, 0xb1, 0x80, 0x15, + 0x80, 0x03, 0x80, 0xaf, 0x80, 0xb1, 0x81, 0x54, + 0x81, 0x8f, 0x82, 0x2a, 0x83, 0x52, 0x88, 0x4c, + 0x88, 0x61, 0x8b, 0x1b, 0x8c, 0xa2, 0x8c, 0xfc, + 0x90, 0xca, 0x91, 0x75, 0x92, 0x71, 0x78, 0x3f, + 0x92, 0xfc, 0x95, 0xa4, 0x96, 0x4d, 0x00, 0x20, + 0x98, 0x05, 0x99, 0x99, 0x9a, 0xd8, 0x9d, 0x3b, + 0x52, 0x5b, 0x52, 0xab, 0x53, 0xf7, 0x54, 0x08, + 0x58, 0xd5, 0x62, 0xf7, 0x6f, 0xe0, 0x8c, 0x6a, + 0x8f, 0x5f, 0x9e, 0xb9, 0x51, 0x4b, 0x52, 0x3b, + 0x54, 0x4a, 0x56, 0xfd, 0x7a, 0x40, 0x91, 0x77, + 0x9d, 0x60, 0x9e, 0xd2, 0x73, 0x44, 0x6f, 0x09, + 0x81, 0x70, 0x75, 0x11, 0x5f, 0xfd, 0x60, 0xda, + 0x9a, 0xa8, 0x72, 0xdb, 0x8f, 0xbc, 0x6b, 0x64, + 0x98, 0x03, 0x4e, 0xca, 0x56, 0xf0, 0x57, 0x64, + 0x58, 0xbe, 0x5a, 0x5a, 0x60, 0x68, 0x61, 0xc7, + 0x66, 0x0f, 0x66, 0x06, 0x68, 0x39, 0x68, 0xb1, + 0x6d, 0xf7, 0x75, 0xd5, 0x7d, 0x3a, 0x82, 0x6e, + 0x9b, 0x42, 0x4e, 0x9b, 0x4f, 0x50, 0x53, 0xc9, + 0x55, 0x06, 0x5d, 0x6f, 0x5d, 0xe6, 0x5d, 0xee, + 0x67, 0xfb, 0x6c, 0x99, 0x74, 0x73, 0x78, 0x02, + 0x8a, 0x50, 0x93, 0x96, 0x88, 0xdf, 0x57, 0x50, + 0x5e, 0xa7, 0x63, 0x2b, 0x50, 0xb5, 0x50, 0xac, + 0x51, 0x8d, 0x67, 0x00, 0x54, 0xc9, 0x58, 0x5e, + 0x59, 0xbb, 0x5b, 0xb0, 0x5f, 0x69, 0x62, 0x4d, + 0x63, 0xa1, 0x68, 0x3d, 0x6b, 0x73, 0x6e, 0x08, + 0x70, 0x7d, 0x91, 0xc7, 0x72, 0x80, 0x78, 0x15, + 0x78, 0x26, 0x79, 0x6d, 0x65, 0x8e, 0x7d, 0x30, + 0x83, 0xdc, 0x88, 0xc1, 0x8f, 0x09, 0x96, 0x9b, + 0x52, 0x64, 0x57, 0x28, 0x67, 0x50, 0x7f, 0x6a, + 0x8c, 0xa1, 0x51, 0xb4, 0x57, 0x42, 0x96, 0x2a, + 0x58, 0x3a, 0x69, 0x8a, 0x80, 0xb4, 0x54, 0xb2, + 0x5d, 0x0e, 0x57, 0xfc, 0x78, 0x95, 0x9d, 0xfa, + 0x4f, 0x5c, 0x52, 0x4a, 0x54, 0x8b, 0x64, 0x3e, + 0x66, 0x28, 0x67, 0x14, 0x67, 0xf5, 0x7a, 0x84, + 0x7b, 0x56, 0x7d, 0x22, 0x93, 0x2f, 0x68, 0x5c, + 0x9b, 0xad, 0x7b, 0x39, 0x53, 0x19, 0x51, 0x8a, + 0x52, 0x37, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x5b, 0xdf, 0x62, 0xf6, 0x64, 0xae, 0x64, 0xe6, + 0x67, 0x2d, 0x6b, 0xba, 0x85, 0xa9, 0x96, 0xd1, + 0x76, 0x90, 0x9b, 0xd6, 0x63, 0x4c, 0x93, 0x06, + 0x9b, 0xab, 0x76, 0xbf, 0x66, 0x52, 0x4e, 0x09, + 0x50, 0x98, 0x53, 0xc2, 0x5c, 0x71, 0x60, 0xe8, + 0x64, 0x92, 0x65, 0x63, 0x68, 0x5f, 0x71, 0xe6, + 0x73, 0xca, 0x75, 0x23, 0x7b, 0x97, 0x7e, 0x82, + 0x86, 0x95, 0x8b, 0x83, 0x8c, 0xdb, 0x91, 0x78, + 0x99, 0x10, 0x65, 0xac, 0x66, 0xab, 0x6b, 0x8b, + 0x4e, 0xd5, 0x4e, 0xd4, 0x4f, 0x3a, 0x4f, 0x7f, + 0x52, 0x3a, 0x53, 0xf8, 0x53, 0xf2, 0x55, 0xe3, + 0x56, 0xdb, 0x58, 0xeb, 0x59, 0xcb, 0x59, 0xc9, + 0x59, 0xff, 0x5b, 0x50, 0x5c, 0x4d, 0x5e, 0x02, + 0x5e, 0x2b, 0x5f, 0xd7, 0x60, 0x1d, 0x63, 0x07, + 0x65, 0x2f, 0x5b, 0x5c, 0x65, 0xaf, 0x65, 0xbd, + 0x65, 0xe8, 0x67, 0x9d, 0x6b, 0x62, 0x00, 0x20, + 0x6b, 0x7b, 0x6c, 0x0f, 0x73, 0x45, 0x79, 0x49, + 0x79, 0xc1, 0x7c, 0xf8, 0x7d, 0x19, 0x7d, 0x2b, + 0x80, 0xa2, 0x81, 0x02, 0x81, 0xf3, 0x89, 0x96, + 0x8a, 0x5e, 0x8a, 0x69, 0x8a, 0x66, 0x8a, 0x8c, + 0x8a, 0xee, 0x8c, 0xc7, 0x8c, 0xdc, 0x96, 0xcc, + 0x98, 0xfc, 0x6b, 0x6f, 0x4e, 0x8b, 0x4f, 0x3c, + 0x4f, 0x8d, 0x51, 0x50, 0x5b, 0x57, 0x5b, 0xfa, + 0x61, 0x48, 0x63, 0x01, 0x66, 0x42, 0x6b, 0x21, + 0x6e, 0xcb, 0x6c, 0xbb, 0x72, 0x3e, 0x74, 0xbd, + 0x75, 0xd4, 0x78, 0xc1, 0x79, 0x3a, 0x80, 0x0c, + 0x80, 0x33, 0x81, 0xea, 0x84, 0x94, 0x8f, 0x9e, + 0x6c, 0x50, 0x9e, 0x7f, 0x5f, 0x0f, 0x8b, 0x58, + 0x9d, 0x2b, 0x7a, 0xfa, 0x8e, 0xf8, 0x5b, 0x8d, + 0x96, 0xeb, 0x4e, 0x03, 0x53, 0xf1, 0x57, 0xf7, + 0x59, 0x31, 0x5a, 0xc9, 0x5b, 0xa4, 0x60, 0x89, + 0x6e, 0x7f, 0x6f, 0x06, 0x75, 0xbe, 0x8c, 0xea, + 0x5b, 0x9f, 0x85, 0x00, 0x7b, 0xe0, 0x50, 0x72, + 0x67, 0xf4, 0x82, 0x9d, 0x5c, 0x61, 0x85, 0x4a, + 0x7e, 0x1e, 0x82, 0x0e, 0x51, 0x99, 0x5c, 0x04, + 0x63, 0x68, 0x8d, 0x66, 0x65, 0x9c, 0x71, 0x6e, + 0x79, 0x3e, 0x7d, 0x17, 0x80, 0x05, 0x8b, 0x1d, + 0x8e, 0xca, 0x90, 0x6e, 0x86, 0xc7, 0x90, 0xaa, + 0x50, 0x1f, 0x52, 0xfa, 0x5c, 0x3a, 0x67, 0x53, + 0x70, 0x7c, 0x72, 0x35, 0x91, 0x4c, 0x91, 0xc8, + 0x93, 0x2b, 0x82, 0xe5, 0x5b, 0xc2, 0x5f, 0x31, + 0x60, 0xf9, 0x4e, 0x3b, 0x53, 0xd6, 0x5b, 0x88, + 0x62, 0x4b, 0x67, 0x31, 0x6b, 0x8a, 0x72, 0xe9, + 0x73, 0xe0, 0x7a, 0x2e, 0x81, 0x6b, 0x8d, 0xa3, + 0x91, 0x52, 0x99, 0x96, 0x51, 0x12, 0x53, 0xd7, + 0x54, 0x6a, 0x5b, 0xff, 0x63, 0x88, 0x6a, 0x39, + 0x7d, 0xac, 0x97, 0x00, 0x56, 0xda, 0x53, 0xce, + 0x54, 0x68, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x5b, 0x97, 0x5c, 0x31, 0x5d, 0xde, 0x4f, 0xee, + 0x61, 0x01, 0x62, 0xfe, 0x6d, 0x32, 0x79, 0xc0, + 0x79, 0xcb, 0x7d, 0x42, 0x7e, 0x4d, 0x7f, 0xd2, + 0x81, 0xed, 0x82, 0x1f, 0x84, 0x90, 0x88, 0x46, + 0x89, 0x72, 0x8b, 0x90, 0x8e, 0x74, 0x8f, 0x2f, + 0x90, 0x31, 0x91, 0x4b, 0x91, 0x6c, 0x96, 0xc6, + 0x91, 0x9c, 0x4e, 0xc0, 0x4f, 0x4f, 0x51, 0x45, + 0x53, 0x41, 0x5f, 0x93, 0x62, 0x0e, 0x67, 0xd4, + 0x6c, 0x41, 0x6e, 0x0b, 0x73, 0x63, 0x7e, 0x26, + 0x91, 0xcd, 0x92, 0x83, 0x53, 0xd4, 0x59, 0x19, + 0x5b, 0xbf, 0x6d, 0xd1, 0x79, 0x5d, 0x7e, 0x2e, + 0x7c, 0x9b, 0x58, 0x7e, 0x71, 0x9f, 0x51, 0xfa, + 0x88, 0x53, 0x8f, 0xf0, 0x4f, 0xca, 0x5c, 0xfb, + 0x66, 0x25, 0x77, 0xac, 0x7a, 0xe3, 0x82, 0x1c, + 0x99, 0xff, 0x51, 0xc6, 0x5f, 0xaa, 0x65, 0xec, + 0x69, 0x6f, 0x6b, 0x89, 0x6d, 0xf3, 0x00, 0x20, + 0x6e, 0x96, 0x6f, 0x64, 0x76, 0xfe, 0x7d, 0x14, + 0x5d, 0xe1, 0x90, 0x75, 0x91, 0x87, 0x98, 0x06, + 0x51, 0xe6, 0x52, 0x1d, 0x62, 0x40, 0x66, 0x91, + 0x66, 0xd9, 0x6e, 0x1a, 0x5e, 0xb6, 0x7d, 0xd2, + 0x7f, 0x72, 0x66, 0xf8, 0x85, 0xaf, 0x85, 0xf7, + 0x8a, 0xf8, 0x52, 0xa9, 0x53, 0xd9, 0x59, 0x73, + 0x5e, 0x8f, 0x5f, 0x90, 0x60, 0x55, 0x92, 0xe4, + 0x96, 0x64, 0x50, 0xb7, 0x51, 0x1f, 0x52, 0xdd, + 0x53, 0x20, 0x53, 0x47, 0x53, 0xec, 0x54, 0xe8, + 0x55, 0x46, 0x55, 0x31, 0x56, 0x17, 0x59, 0x68, + 0x59, 0xbe, 0x5a, 0x3c, 0x5b, 0xb5, 0x5c, 0x06, + 0x5c, 0x0f, 0x5c, 0x11, 0x5c, 0x1a, 0x5e, 0x84, + 0x5e, 0x8a, 0x5e, 0xe0, 0x5f, 0x70, 0x62, 0x7f, + 0x62, 0x84, 0x62, 0xdb, 0x63, 0x8c, 0x63, 0x77, + 0x66, 0x07, 0x66, 0x0c, 0x66, 0x2d, 0x66, 0x76, + 0x67, 0x7e, 0x68, 0xa2, 0x6a, 0x1f, 0x6a, 0x35, + 0x6c, 0xbc, 0x6d, 0x88, 0x6e, 0x09, 0x6e, 0x58, + 0x71, 0x3c, 0x71, 0x26, 0x71, 0x67, 0x75, 0xc7, + 0x77, 0x01, 0x78, 0x5d, 0x79, 0x01, 0x79, 0x65, + 0x79, 0xf0, 0x7a, 0xe0, 0x7b, 0x11, 0x7c, 0xa7, + 0x7d, 0x39, 0x80, 0x96, 0x83, 0xd6, 0x84, 0x8b, + 0x85, 0x49, 0x88, 0x5d, 0x88, 0xf3, 0x8a, 0x1f, + 0x8a, 0x3c, 0x8a, 0x54, 0x8a, 0x73, 0x8c, 0x61, + 0x8c, 0xde, 0x91, 0xa4, 0x92, 0x66, 0x93, 0x7e, + 0x94, 0x18, 0x96, 0x9c, 0x97, 0x98, 0x4e, 0x0a, + 0x4e, 0x08, 0x4e, 0x1e, 0x4e, 0x57, 0x51, 0x97, + 0x52, 0x70, 0x57, 0xce, 0x58, 0x34, 0x58, 0xcc, + 0x5b, 0x22, 0x5e, 0x38, 0x60, 0xc5, 0x64, 0xfe, + 0x67, 0x61, 0x67, 0x56, 0x6d, 0x44, 0x72, 0xb6, + 0x75, 0x73, 0x7a, 0x63, 0x84, 0xb8, 0x8b, 0x72, + 0x91, 0xb8, 0x93, 0x20, 0x56, 0x31, 0x57, 0xf4, + 0x98, 0xfe, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x62, 0xed, 0x69, 0x0d, 0x6b, 0x96, 0x71, 0xed, + 0x7e, 0x54, 0x80, 0x77, 0x82, 0x72, 0x89, 0xe6, + 0x98, 0xdf, 0x87, 0x55, 0x8f, 0xb1, 0x5c, 0x3b, + 0x4f, 0x38, 0x4f, 0xe1, 0x4f, 0xb5, 0x55, 0x07, + 0x5a, 0x20, 0x5b, 0xdd, 0x5b, 0xe9, 0x5f, 0xc3, + 0x61, 0x4e, 0x63, 0x2f, 0x65, 0xb0, 0x66, 0x4b, + 0x68, 0xee, 0x69, 0x9b, 0x6d, 0x78, 0x6d, 0xf1, + 0x75, 0x33, 0x75, 0xb9, 0x77, 0x1f, 0x79, 0x5e, + 0x79, 0xe6, 0x7d, 0x33, 0x81, 0xe3, 0x82, 0xaf, + 0x85, 0xaa, 0x89, 0xaa, 0x8a, 0x3a, 0x8e, 0xab, + 0x8f, 0x9b, 0x90, 0x32, 0x91, 0xdd, 0x97, 0x07, + 0x4e, 0xba, 0x4e, 0xc1, 0x52, 0x03, 0x58, 0x75, + 0x58, 0xec, 0x5c, 0x0b, 0x75, 0x1a, 0x5c, 0x3d, + 0x81, 0x4e, 0x8a, 0x0a, 0x8f, 0xc5, 0x96, 0x63, + 0x97, 0x6d, 0x7b, 0x25, 0x8a, 0xcf, 0x98, 0x08, + 0x91, 0x62, 0x56, 0xf3, 0x53, 0xa8, 0x00, 0x20, + 0x90, 0x17, 0x54, 0x39, 0x57, 0x82, 0x5e, 0x25, + 0x63, 0xa8, 0x6c, 0x34, 0x70, 0x8a, 0x77, 0x61, + 0x7c, 0x8b, 0x7f, 0xe0, 0x88, 0x70, 0x90, 0x42, + 0x91, 0x54, 0x93, 0x10, 0x93, 0x18, 0x96, 0x8f, + 0x74, 0x5e, 0x9a, 0xc4, 0x5d, 0x07, 0x5d, 0x69, + 0x65, 0x70, 0x67, 0xa2, 0x8d, 0xa8, 0x96, 0xdb, + 0x63, 0x6e, 0x67, 0x49, 0x69, 0x19, 0x83, 0xc5, + 0x98, 0x17, 0x96, 0xc0, 0x88, 0xfe, 0x6f, 0x84, + 0x64, 0x7a, 0x5b, 0xf8, 0x4e, 0x16, 0x70, 0x2c, + 0x75, 0x5d, 0x66, 0x2f, 0x51, 0xc4, 0x52, 0x36, + 0x52, 0xe2, 0x59, 0xd3, 0x5f, 0x81, 0x60, 0x27, + 0x62, 0x10, 0x65, 0x3f, 0x65, 0x74, 0x66, 0x1f, + 0x66, 0x74, 0x68, 0xf2, 0x68, 0x16, 0x6b, 0x63, + 0x6e, 0x05, 0x72, 0x72, 0x75, 0x1f, 0x76, 0xdb, + 0x7c, 0xbe, 0x80, 0x56, 0x58, 0xf0, 0x88, 0xfd, + 0x89, 0x7f, 0x8a, 0xa0, 0x8a, 0x93, 0x8a, 0xcb, + 0x90, 0x1d, 0x91, 0x92, 0x97, 0x52, 0x97, 0x59, + 0x65, 0x89, 0x7a, 0x0e, 0x81, 0x06, 0x96, 0xbb, + 0x5e, 0x2d, 0x60, 0xdc, 0x62, 0x1a, 0x65, 0xa5, + 0x66, 0x14, 0x67, 0x90, 0x77, 0xf3, 0x7a, 0x4d, + 0x7c, 0x4d, 0x7e, 0x3e, 0x81, 0x0a, 0x8c, 0xac, + 0x8d, 0x64, 0x8d, 0xe1, 0x8e, 0x5f, 0x78, 0xa9, + 0x52, 0x07, 0x62, 0xd9, 0x63, 0xa5, 0x64, 0x42, + 0x62, 0x98, 0x8a, 0x2d, 0x7a, 0x83, 0x7b, 0xc0, + 0x8a, 0xac, 0x96, 0xea, 0x7d, 0x76, 0x82, 0x0c, + 0x87, 0x49, 0x4e, 0xd9, 0x51, 0x48, 0x53, 0x43, + 0x53, 0x60, 0x5b, 0xa3, 0x5c, 0x02, 0x5c, 0x16, + 0x5d, 0xdd, 0x62, 0x26, 0x62, 0x47, 0x64, 0xb0, + 0x68, 0x13, 0x68, 0x34, 0x6c, 0xc9, 0x6d, 0x45, + 0x6d, 0x17, 0x67, 0xd3, 0x6f, 0x5c, 0x71, 0x4e, + 0x71, 0x7d, 0x65, 0xcb, 0x7a, 0x7f, 0x7b, 0xad, + 0x7d, 0xda, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x7e, 0x4a, 0x7f, 0xa8, 0x81, 0x7a, 0x82, 0x1b, + 0x82, 0x39, 0x85, 0xa6, 0x8a, 0x6e, 0x8c, 0xce, + 0x8d, 0xf5, 0x90, 0x78, 0x90, 0x77, 0x92, 0xad, + 0x92, 0x91, 0x95, 0x83, 0x9b, 0xae, 0x52, 0x4d, + 0x55, 0x84, 0x6f, 0x38, 0x71, 0x36, 0x51, 0x68, + 0x79, 0x85, 0x7e, 0x55, 0x81, 0xb3, 0x7c, 0xce, + 0x56, 0x4c, 0x58, 0x51, 0x5c, 0xa8, 0x63, 0xaa, + 0x66, 0xfe, 0x66, 0xfd, 0x69, 0x5a, 0x72, 0xd9, + 0x75, 0x8f, 0x75, 0x8e, 0x79, 0x0e, 0x79, 0x56, + 0x79, 0xdf, 0x7c, 0x97, 0x7d, 0x20, 0x7d, 0x44, + 0x86, 0x07, 0x8a, 0x34, 0x96, 0x3b, 0x90, 0x61, + 0x9f, 0x20, 0x50, 0xe7, 0x52, 0x75, 0x53, 0xcc, + 0x53, 0xe2, 0x50, 0x09, 0x55, 0xaa, 0x58, 0xee, + 0x59, 0x4f, 0x72, 0x3d, 0x5b, 0x8b, 0x5c, 0x64, + 0x53, 0x1d, 0x60, 0xe3, 0x60, 0xf3, 0x63, 0x5c, + 0x63, 0x83, 0x63, 0x3f, 0x63, 0xbb, 0x00, 0x20, + 0x64, 0xcd, 0x65, 0xe9, 0x66, 0xf9, 0x5d, 0xe3, + 0x69, 0xcd, 0x69, 0xfd, 0x6f, 0x15, 0x71, 0xe5, + 0x4e, 0x89, 0x75, 0xe9, 0x76, 0xf8, 0x7a, 0x93, + 0x7c, 0xdf, 0x7d, 0xcf, 0x7d, 0x9c, 0x80, 0x61, + 0x83, 0x49, 0x83, 0x58, 0x84, 0x6c, 0x84, 0xbc, + 0x85, 0xfb, 0x88, 0xc5, 0x8d, 0x70, 0x90, 0x01, + 0x90, 0x6d, 0x93, 0x97, 0x97, 0x1c, 0x9a, 0x12, + 0x50, 0xcf, 0x58, 0x97, 0x61, 0x8e, 0x81, 0xd3, + 0x85, 0x35, 0x8d, 0x08, 0x90, 0x20, 0x4f, 0xc3, + 0x50, 0x74, 0x52, 0x47, 0x53, 0x73, 0x60, 0x6f, + 0x63, 0x49, 0x67, 0x5f, 0x6e, 0x2c, 0x8d, 0xb3, + 0x90, 0x1f, 0x4f, 0xd7, 0x5c, 0x5e, 0x8c, 0xca, + 0x65, 0xcf, 0x7d, 0x9a, 0x53, 0x52, 0x88, 0x96, + 0x51, 0x76, 0x63, 0xc3, 0x5b, 0x58, 0x5b, 0x6b, + 0x5c, 0x0a, 0x64, 0x0d, 0x67, 0x51, 0x90, 0x5c, + 0x4e, 0xd6, 0x59, 0x1a, 0x59, 0x2a, 0x6c, 0x70, + 0x8a, 0x51, 0x55, 0x3e, 0x58, 0x15, 0x59, 0xa5, + 0x60, 0xf0, 0x62, 0x53, 0x67, 0xc1, 0x82, 0x35, + 0x69, 0x55, 0x96, 0x40, 0x99, 0xc4, 0x9a, 0x28, + 0x4f, 0x53, 0x58, 0x06, 0x5b, 0xfe, 0x80, 0x10, + 0x5c, 0xb1, 0x5e, 0x2f, 0x5f, 0x85, 0x60, 0x20, + 0x61, 0x4b, 0x62, 0x34, 0x66, 0xff, 0x6c, 0xf0, + 0x6e, 0xde, 0x80, 0xce, 0x81, 0x7f, 0x82, 0xd4, + 0x88, 0x8b, 0x8c, 0xb8, 0x90, 0x00, 0x90, 0x2e, + 0x96, 0x8a, 0x9e, 0xdb, 0x9b, 0xdb, 0x4e, 0xe3, + 0x53, 0xf0, 0x59, 0x27, 0x7b, 0x2c, 0x91, 0x8d, + 0x98, 0x4c, 0x9d, 0xf9, 0x6e, 0xdd, 0x70, 0x27, + 0x53, 0x53, 0x55, 0x44, 0x5b, 0x85, 0x62, 0x58, + 0x62, 0x9e, 0x62, 0xd3, 0x6c, 0xa2, 0x6f, 0xef, + 0x74, 0x22, 0x8a, 0x17, 0x94, 0x38, 0x6f, 0xc1, + 0x8a, 0xfe, 0x83, 0x38, 0x51, 0xe7, 0x86, 0xf8, + 0x53, 0xea, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x53, 0xe9, 0x4f, 0x46, 0x90, 0x54, 0x8f, 0xb0, + 0x59, 0x6a, 0x81, 0x31, 0x5d, 0xfd, 0x7a, 0xea, + 0x8f, 0xbf, 0x68, 0xda, 0x8c, 0x37, 0x72, 0xf8, + 0x9c, 0x48, 0x6a, 0x3d, 0x8a, 0xb0, 0x4e, 0x39, + 0x53, 0x58, 0x56, 0x06, 0x57, 0x66, 0x62, 0xc5, + 0x63, 0xa2, 0x65, 0xe6, 0x6b, 0x4e, 0x6d, 0xe1, + 0x6e, 0x5b, 0x70, 0xad, 0x77, 0xed, 0x7a, 0xef, + 0x7b, 0xaa, 0x7d, 0xbb, 0x80, 0x3d, 0x80, 0xc6, + 0x86, 0xcb, 0x8a, 0x95, 0x93, 0x5b, 0x56, 0xe3, + 0x58, 0xc7, 0x5f, 0x3e, 0x65, 0xad, 0x66, 0x96, + 0x6a, 0x80, 0x6b, 0xb5, 0x75, 0x37, 0x8a, 0xc7, + 0x50, 0x24, 0x77, 0xe5, 0x57, 0x30, 0x5f, 0x1b, + 0x60, 0x65, 0x66, 0x7a, 0x6c, 0x60, 0x75, 0xf4, + 0x7a, 0x1a, 0x7f, 0x6e, 0x81, 0xf4, 0x87, 0x18, + 0x90, 0x45, 0x99, 0xb3, 0x7b, 0xc9, 0x75, 0x5c, + 0x7a, 0xf9, 0x7b, 0x51, 0x84, 0xc4, 0x00, 0x20, + 0x90, 0x10, 0x79, 0xe9, 0x7a, 0x92, 0x83, 0x36, + 0x5a, 0xe1, 0x77, 0x40, 0x4e, 0x2d, 0x4e, 0xf2, + 0x5b, 0x99, 0x5f, 0xe0, 0x62, 0xbd, 0x66, 0x3c, + 0x67, 0xf1, 0x6c, 0xe8, 0x86, 0x6b, 0x88, 0x77, + 0x8a, 0x3b, 0x91, 0x4e, 0x92, 0xf3, 0x99, 0xd0, + 0x6a, 0x17, 0x70, 0x26, 0x73, 0x2a, 0x82, 0xe7, + 0x84, 0x57, 0x8c, 0xaf, 0x4e, 0x01, 0x51, 0x46, + 0x51, 0xcb, 0x55, 0x8b, 0x5b, 0xf5, 0x5e, 0x16, + 0x5e, 0x33, 0x5e, 0x81, 0x5f, 0x14, 0x5f, 0x35, + 0x5f, 0x6b, 0x5f, 0xb4, 0x61, 0xf2, 0x63, 0x11, + 0x66, 0xa2, 0x67, 0x1d, 0x6f, 0x6e, 0x72, 0x52, + 0x75, 0x3a, 0x77, 0x3a, 0x80, 0x74, 0x81, 0x39, + 0x81, 0x78, 0x87, 0x76, 0x8a, 0xbf, 0x8a, 0xdc, + 0x8d, 0x85, 0x8d, 0xf3, 0x92, 0x9a, 0x95, 0x77, + 0x98, 0x02, 0x9c, 0xe5, 0x52, 0xc5, 0x63, 0x57, + 0x76, 0xf4, 0x67, 0x15, 0x6c, 0x88, 0x73, 0xcd, + 0x8c, 0xc3, 0x93, 0xae, 0x96, 0x73, 0x6d, 0x25, + 0x58, 0x9c, 0x69, 0x0e, 0x69, 0xcc, 0x8f, 0xfd, + 0x93, 0x9a, 0x75, 0xdb, 0x90, 0x1a, 0x58, 0x5a, + 0x68, 0x02, 0x63, 0xb4, 0x69, 0xfb, 0x4f, 0x43, + 0x6f, 0x2c, 0x67, 0xd8, 0x8f, 0xbb, 0x85, 0x26, + 0x7d, 0xb4, 0x93, 0x54, 0x69, 0x3f, 0x6f, 0x70, + 0x57, 0x6a, 0x58, 0xf7, 0x5b, 0x2c, 0x7d, 0x2c, + 0x72, 0x2a, 0x54, 0x0a, 0x91, 0xe3, 0x9d, 0xb4, + 0x4e, 0xad, 0x4f, 0x4e, 0x50, 0x5c, 0x50, 0x75, + 0x52, 0x43, 0x8c, 0x9e, 0x54, 0x48, 0x58, 0x24, + 0x5b, 0x9a, 0x5e, 0x1d, 0x5e, 0x95, 0x5e, 0xad, + 0x5e, 0xf7, 0x5f, 0x1f, 0x60, 0x8c, 0x62, 0xb5, + 0x63, 0x3a, 0x63, 0xd0, 0x68, 0xaf, 0x6c, 0x40, + 0x78, 0x87, 0x79, 0x8e, 0x7a, 0x0b, 0x7d, 0xe0, + 0x82, 0x47, 0x8a, 0x02, 0x8a, 0xe6, 0x8e, 0x44, + 0x90, 0x13, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x90, 0xb8, 0x91, 0x2d, 0x91, 0xd8, 0x9f, 0x0e, + 0x6c, 0xe5, 0x64, 0x58, 0x64, 0xe2, 0x65, 0x75, + 0x6e, 0xf4, 0x76, 0x84, 0x7b, 0x1b, 0x90, 0x69, + 0x93, 0xd1, 0x6e, 0xba, 0x54, 0xf2, 0x5f, 0xb9, + 0x64, 0xa4, 0x8f, 0x4d, 0x8f, 0xed, 0x92, 0x44, + 0x51, 0x78, 0x58, 0x6b, 0x59, 0x29, 0x5c, 0x55, + 0x5e, 0x97, 0x6d, 0xfb, 0x7e, 0x8f, 0x75, 0x1c, + 0x8c, 0xbc, 0x8e, 0xe2, 0x98, 0x5b, 0x70, 0xb9, + 0x4f, 0x1d, 0x6b, 0xbf, 0x6f, 0xb1, 0x75, 0x30, + 0x96, 0xfb, 0x51, 0x4e, 0x54, 0x10, 0x58, 0x35, + 0x58, 0x57, 0x59, 0xac, 0x5c, 0x60, 0x5f, 0x92, + 0x65, 0x97, 0x67, 0x5c, 0x6e, 0x21, 0x76, 0x7b, + 0x83, 0xdf, 0x8c, 0xed, 0x90, 0x14, 0x90, 0xfd, + 0x93, 0x4d, 0x78, 0x25, 0x78, 0x3a, 0x52, 0xaa, + 0x5e, 0xa6, 0x57, 0x1f, 0x59, 0x74, 0x60, 0x12, + 0x50, 0x12, 0x51, 0x5a, 0x51, 0xac, 0x00, 0x20, + 0x51, 0xcd, 0x52, 0x00, 0x55, 0x10, 0x58, 0x54, + 0x58, 0x58, 0x59, 0x57, 0x5b, 0x95, 0x5c, 0xf6, + 0x5d, 0x8b, 0x60, 0xbc, 0x62, 0x95, 0x64, 0x2d, + 0x67, 0x71, 0x68, 0x43, 0x68, 0xbc, 0x68, 0xdf, + 0x76, 0xd7, 0x6d, 0xd8, 0x6e, 0x6f, 0x6d, 0x9b, + 0x70, 0x6f, 0x71, 0xc8, 0x5f, 0x53, 0x75, 0xd8, + 0x79, 0x77, 0x7b, 0x49, 0x7b, 0x54, 0x7b, 0x52, + 0x7c, 0xd6, 0x7d, 0x71, 0x52, 0x30, 0x84, 0x63, + 0x85, 0x69, 0x85, 0xe4, 0x8a, 0x0e, 0x8b, 0x04, + 0x8c, 0x46, 0x8e, 0x0f, 0x90, 0x03, 0x90, 0x0f, + 0x94, 0x19, 0x96, 0x76, 0x98, 0x2d, 0x9a, 0x30, + 0x95, 0xd8, 0x50, 0xcd, 0x52, 0xd5, 0x54, 0x0c, + 0x58, 0x02, 0x5c, 0x0e, 0x61, 0xa7, 0x64, 0x9e, + 0x6d, 0x1e, 0x77, 0xb3, 0x7a, 0xe5, 0x80, 0xf4, + 0x84, 0x04, 0x90, 0x53, 0x92, 0x85, 0x5c, 0xe0, + 0x9d, 0x07, 0x53, 0x3f, 0x5f, 0x97, 0x5f, 0xb3, + 0x6d, 0x9c, 0x72, 0x79, 0x77, 0x63, 0x79, 0xbf, + 0x7b, 0xe4, 0x6b, 0xd2, 0x72, 0xec, 0x8a, 0xad, + 0x68, 0x03, 0x6a, 0x61, 0x51, 0xf8, 0x7a, 0x81, + 0x69, 0x34, 0x5c, 0x4a, 0x9c, 0xf6, 0x82, 0xeb, + 0x5b, 0xc5, 0x91, 0x49, 0x70, 0x1e, 0x56, 0x78, + 0x5c, 0x6f, 0x60, 0xc7, 0x65, 0x66, 0x6c, 0x8c, + 0x8c, 0x5a, 0x90, 0x41, 0x98, 0x13, 0x54, 0x51, + 0x66, 0xc7, 0x92, 0x0d, 0x59, 0x48, 0x90, 0xa3, + 0x51, 0x85, 0x4e, 0x4d, 0x51, 0xea, 0x85, 0x99, + 0x8b, 0x0e, 0x70, 0x58, 0x63, 0x7a, 0x93, 0x4b, + 0x69, 0x62, 0x99, 0xb4, 0x7e, 0x04, 0x75, 0x77, + 0x53, 0x57, 0x69, 0x60, 0x8e, 0xdf, 0x96, 0xe3, + 0x6c, 0x5d, 0x4e, 0x8c, 0x5c, 0x3c, 0x5f, 0x10, + 0x8f, 0xe9, 0x53, 0x02, 0x8c, 0xd1, 0x80, 0x89, + 0x86, 0x79, 0x5e, 0xff, 0x65, 0xe5, 0x4e, 0x73, + 0x51, 0x65, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x59, 0x82, 0x5c, 0x3f, 0x97, 0xee, 0x4e, 0xfb, + 0x59, 0x8a, 0x5f, 0xcd, 0x8a, 0x8d, 0x6f, 0xe1, + 0x79, 0xb0, 0x79, 0x62, 0x5b, 0xe7, 0x84, 0x71, + 0x73, 0x2b, 0x71, 0xb1, 0x5e, 0x74, 0x5f, 0xf5, + 0x63, 0x7b, 0x64, 0x9a, 0x71, 0xc3, 0x7c, 0x98, + 0x4e, 0x43, 0x5e, 0xfc, 0x4e, 0x4b, 0x57, 0xdc, + 0x56, 0xa2, 0x60, 0xa9, 0x6f, 0xc3, 0x7d, 0x0d, + 0x80, 0xfd, 0x81, 0x33, 0x81, 0xbf, 0x8f, 0xb2, + 0x89, 0x97, 0x86, 0xa4, 0x5d, 0xf4, 0x62, 0x8a, + 0x64, 0xad, 0x89, 0x87, 0x67, 0x77, 0x6c, 0xe2, + 0x6d, 0x3e, 0x74, 0x36, 0x78, 0x34, 0x5a, 0x46, + 0x7f, 0x75, 0x82, 0xad, 0x99, 0xac, 0x4f, 0xf3, + 0x5e, 0xc3, 0x62, 0xdd, 0x63, 0x92, 0x65, 0x57, + 0x67, 0x6f, 0x76, 0xc3, 0x72, 0x4c, 0x80, 0xcc, + 0x80, 0xba, 0x8f, 0x29, 0x91, 0x4d, 0x50, 0x0d, + 0x57, 0xf9, 0x5a, 0x92, 0x68, 0x85, 0x00, 0x20, + 0x69, 0x73, 0x71, 0x64, 0x72, 0xfd, 0x8c, 0xb7, + 0x58, 0xf2, 0x8c, 0xe0, 0x96, 0x6a, 0x90, 0x19, + 0x87, 0x7f, 0x79, 0xe4, 0x77, 0xe7, 0x84, 0x29, + 0x4f, 0x2f, 0x52, 0x65, 0x53, 0x5a, 0x62, 0xcd, + 0x67, 0xcf, 0x6c, 0xca, 0x76, 0x7d, 0x7b, 0x94, + 0x7c, 0x95, 0x82, 0x36, 0x85, 0x84, 0x8f, 0xeb, + 0x66, 0xdd, 0x6f, 0x20, 0x72, 0x06, 0x7e, 0x1b, + 0x83, 0xab, 0x99, 0xc1, 0x9e, 0xa6, 0x51, 0xfd, + 0x7b, 0xb1, 0x78, 0x72, 0x7b, 0xb8, 0x80, 0x87, + 0x7b, 0x48, 0x6a, 0xe8, 0x5e, 0x61, 0x80, 0x8c, + 0x75, 0x51, 0x75, 0x60, 0x51, 0x6b, 0x92, 0x62, + 0x6e, 0x8c, 0x76, 0x7a, 0x91, 0x97, 0x9a, 0xea, + 0x4f, 0x10, 0x7f, 0x70, 0x62, 0x9c, 0x7b, 0x4f, + 0x95, 0xa5, 0x9c, 0xe9, 0x56, 0x7a, 0x58, 0x59, + 0x86, 0xe4, 0x96, 0xbc, 0x4f, 0x34, 0x52, 0x24, + 0x53, 0x4a, 0x53, 0xcd, 0x53, 0xdb, 0x5e, 0x06, + 0x64, 0x2c, 0x65, 0x91, 0x67, 0x7f, 0x6c, 0x3e, + 0x6c, 0x4e, 0x72, 0x48, 0x72, 0xaf, 0x73, 0xed, + 0x75, 0x54, 0x7e, 0x41, 0x82, 0x2c, 0x85, 0xe9, + 0x8c, 0xa9, 0x7b, 0xc4, 0x91, 0xc6, 0x71, 0x69, + 0x98, 0x12, 0x98, 0xef, 0x63, 0x3d, 0x66, 0x69, + 0x75, 0x6a, 0x76, 0xe4, 0x78, 0xd0, 0x85, 0x43, + 0x86, 0xee, 0x53, 0x2a, 0x53, 0x51, 0x54, 0x26, + 0x59, 0x83, 0x5e, 0x87, 0x5f, 0x7c, 0x60, 0xb2, + 0x62, 0x49, 0x62, 0x79, 0x62, 0xab, 0x65, 0x90, + 0x6b, 0xd4, 0x6c, 0xcc, 0x75, 0xb2, 0x76, 0xae, + 0x78, 0x91, 0x79, 0xd8, 0x7d, 0xcb, 0x7f, 0x77, + 0x80, 0xa5, 0x88, 0xab, 0x8a, 0xb9, 0x8c, 0xbb, + 0x90, 0x7f, 0x97, 0x5e, 0x98, 0xdb, 0x6a, 0x0b, + 0x7c, 0x38, 0x50, 0x99, 0x5c, 0x3e, 0x5f, 0xae, + 0x67, 0x87, 0x6b, 0xd8, 0x74, 0x35, 0x77, 0x09, + 0x7f, 0x8e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x9f, 0x3b, 0x67, 0xca, 0x7a, 0x17, 0x53, 0x39, + 0x75, 0x8b, 0x9a, 0xed, 0x5f, 0x66, 0x81, 0x9d, + 0x83, 0xf1, 0x80, 0x98, 0x5f, 0x3c, 0x5f, 0xc5, + 0x75, 0x62, 0x7b, 0x46, 0x90, 0x3c, 0x68, 0x67, + 0x59, 0xeb, 0x5a, 0x9b, 0x7d, 0x10, 0x76, 0x7e, + 0x8b, 0x2c, 0x4f, 0xf5, 0x5f, 0x6a, 0x6a, 0x19, + 0x6c, 0x37, 0x6f, 0x02, 0x74, 0xe2, 0x79, 0x68, + 0x88, 0x68, 0x8a, 0x55, 0x8c, 0x79, 0x5e, 0xdf, + 0x63, 0xcf, 0x75, 0xc5, 0x79, 0xd2, 0x82, 0xd7, + 0x93, 0x28, 0x92, 0xf2, 0x84, 0x9c, 0x86, 0xed, + 0x9c, 0x2d, 0x54, 0xc1, 0x5f, 0x6c, 0x65, 0x8c, + 0x6d, 0x5c, 0x70, 0x15, 0x8c, 0xa7, 0x8c, 0xd3, + 0x98, 0x3b, 0x65, 0x4f, 0x74, 0xf6, 0x4e, 0x0d, + 0x4e, 0xd8, 0x57, 0xe0, 0x59, 0x2b, 0x5a, 0x66, + 0x5b, 0xcc, 0x51, 0xa8, 0x5e, 0x03, 0x5e, 0x9c, + 0x60, 0x16, 0x62, 0x76, 0x65, 0x77, 0x00, 0x20, + 0x65, 0xa7, 0x66, 0x6e, 0x6d, 0x6e, 0x72, 0x36, + 0x7b, 0x26, 0x81, 0x50, 0x81, 0x9a, 0x82, 0x99, + 0x8b, 0x5c, 0x8c, 0xa0, 0x8c, 0xe6, 0x8d, 0x74, + 0x96, 0x1c, 0x96, 0x44, 0x4f, 0xae, 0x64, 0xab, + 0x6b, 0x66, 0x82, 0x1e, 0x84, 0x61, 0x85, 0x6a, + 0x90, 0xe8, 0x5c, 0x01, 0x69, 0x53, 0x98, 0xa8, + 0x84, 0x7a, 0x85, 0x57, 0x4f, 0x0f, 0x52, 0x6f, + 0x5f, 0xa9, 0x5e, 0x45, 0x67, 0x0d, 0x79, 0x8f, + 0x81, 0x79, 0x89, 0x07, 0x89, 0x86, 0x6d, 0xf5, + 0x5f, 0x17, 0x62, 0x55, 0x6c, 0xb8, 0x4e, 0xcf, + 0x72, 0x69, 0x9b, 0x92, 0x52, 0x06, 0x54, 0x3b, + 0x56, 0x74, 0x58, 0xb3, 0x61, 0xa4, 0x62, 0x6e, + 0x71, 0x1a, 0x59, 0x6e, 0x7c, 0x89, 0x7c, 0xde, + 0x7d, 0x1b, 0x96, 0xf0, 0x65, 0x87, 0x80, 0x5e, + 0x4e, 0x19, 0x4f, 0x75, 0x51, 0x75, 0x58, 0x40, + 0x5e, 0x63, 0x5e, 0x73, 0x5f, 0x0a, 0x67, 0xc4, + 0x4e, 0x26, 0x85, 0x3d, 0x95, 0x89, 0x96, 0x5b, + 0x7c, 0x73, 0x98, 0x01, 0x50, 0xfb, 0x58, 0xc1, + 0x76, 0x56, 0x78, 0xa7, 0x52, 0x25, 0x77, 0xa5, + 0x85, 0x11, 0x7b, 0x86, 0x50, 0x4f, 0x59, 0x09, + 0x72, 0x47, 0x7b, 0xc7, 0x7d, 0xe8, 0x8f, 0xba, + 0x8f, 0xd4, 0x90, 0x4d, 0x4f, 0xbf, 0x52, 0xc9, + 0x5a, 0x29, 0x5f, 0x01, 0x97, 0xad, 0x4f, 0xdd, + 0x82, 0x17, 0x92, 0xea, 0x57, 0x03, 0x63, 0x55, + 0x6b, 0x69, 0x75, 0x2b, 0x88, 0xdc, 0x8f, 0x14, + 0x7a, 0x42, 0x52, 0xdf, 0x58, 0x93, 0x61, 0x55, + 0x62, 0x0a, 0x66, 0xae, 0x6b, 0xcd, 0x7c, 0x3f, + 0x83, 0xe9, 0x50, 0x23, 0x4f, 0xf8, 0x53, 0x05, + 0x54, 0x46, 0x58, 0x31, 0x59, 0x49, 0x5b, 0x9d, + 0x5c, 0xf0, 0x5c, 0xef, 0x5d, 0x29, 0x5e, 0x96, + 0x62, 0xb1, 0x63, 0x67, 0x65, 0x3e, 0x65, 0xb9, + 0x67, 0x0b, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x6c, 0xd5, 0x6c, 0xe1, 0x70, 0xf9, 0x78, 0x32, + 0x7e, 0x2b, 0x80, 0xde, 0x82, 0xb3, 0x84, 0x0c, + 0x84, 0xec, 0x87, 0x02, 0x89, 0x12, 0x8a, 0x2a, + 0x8c, 0x4a, 0x90, 0xa6, 0x92, 0xd2, 0x98, 0xfd, + 0x9c, 0xf3, 0x9d, 0x6c, 0x4e, 0x4f, 0x4e, 0xa1, + 0x50, 0x8d, 0x52, 0x56, 0x57, 0x4a, 0x59, 0xa8, + 0x5e, 0x3d, 0x5f, 0xd8, 0x5f, 0xd9, 0x62, 0x3f, + 0x66, 0xb4, 0x67, 0x1b, 0x67, 0xd0, 0x68, 0xd2, + 0x51, 0x92, 0x7d, 0x21, 0x80, 0xaa, 0x81, 0xa8, + 0x8b, 0x00, 0x8c, 0x8c, 0x8c, 0xbf, 0x92, 0x7e, + 0x96, 0x32, 0x54, 0x20, 0x98, 0x2c, 0x53, 0x17, + 0x50, 0xd5, 0x53, 0x5c, 0x58, 0xa8, 0x64, 0xb2, + 0x67, 0x34, 0x72, 0x67, 0x77, 0x66, 0x7a, 0x46, + 0x91, 0xe6, 0x52, 0xc3, 0x6c, 0xa1, 0x6b, 0x86, + 0x58, 0x00, 0x5e, 0x4c, 0x59, 0x54, 0x67, 0x2c, + 0x7f, 0xfb, 0x51, 0xe1, 0x76, 0xc6, 0x00, 0x20, + 0x64, 0x69, 0x78, 0xe8, 0x9b, 0x54, 0x9e, 0xbb, + 0x57, 0xcb, 0x59, 0xb9, 0x66, 0x27, 0x67, 0x9a, + 0x6b, 0xce, 0x54, 0xe9, 0x69, 0xd9, 0x5e, 0x55, + 0x81, 0x9c, 0x67, 0x95, 0x9b, 0xaa, 0x67, 0xfe, + 0x9c, 0x52, 0x68, 0x5d, 0x4e, 0xa6, 0x4f, 0xe3, + 0x53, 0xc8, 0x62, 0xb9, 0x67, 0x2b, 0x6c, 0xab, + 0x8f, 0xc4, 0x4f, 0xad, 0x7e, 0x6d, 0x9e, 0xbf, + 0x4e, 0x07, 0x61, 0x62, 0x6e, 0x80, 0x6f, 0x2b, + 0x85, 0x13, 0x54, 0x73, 0x67, 0x2a, 0x9b, 0x45, + 0x5d, 0xf3, 0x7b, 0x95, 0x5c, 0xac, 0x5b, 0xc6, + 0x87, 0x1c, 0x6e, 0x4a, 0x84, 0xd1, 0x7a, 0x14, + 0x81, 0x08, 0x59, 0x99, 0x7c, 0x8d, 0x6c, 0x11, + 0x77, 0x20, 0x52, 0xd9, 0x59, 0x22, 0x71, 0x21, + 0x72, 0x5f, 0x77, 0xdb, 0x97, 0x27, 0x9d, 0x61, + 0x69, 0x0b, 0x5a, 0x7f, 0x5a, 0x18, 0x51, 0xa5, + 0x54, 0x0d, 0x54, 0x7d, 0x66, 0x0e, 0x76, 0xdf, + 0x8f, 0xf7, 0x92, 0x98, 0x9c, 0xf4, 0x59, 0xea, + 0x72, 0x5d, 0x6e, 0xc5, 0x51, 0x4d, 0x68, 0xc9, + 0x7d, 0xbf, 0x7d, 0xec, 0x97, 0x62, 0x9e, 0xba, + 0x64, 0x78, 0x6a, 0x21, 0x83, 0x02, 0x59, 0x84, + 0x5b, 0x5f, 0x6b, 0xdb, 0x73, 0x1b, 0x76, 0xf2, + 0x7d, 0xb2, 0x80, 0x17, 0x84, 0x99, 0x51, 0x32, + 0x67, 0x28, 0x9e, 0xd9, 0x76, 0xee, 0x67, 0x62, + 0x52, 0xff, 0x99, 0x05, 0x5c, 0x24, 0x62, 0x3b, + 0x7c, 0x7e, 0x8c, 0xb0, 0x55, 0x4f, 0x60, 0xb6, + 0x7d, 0x0b, 0x95, 0x80, 0x53, 0x01, 0x4e, 0x5f, + 0x51, 0xb6, 0x59, 0x1c, 0x72, 0x3a, 0x80, 0x36, + 0x91, 0xce, 0x5f, 0x25, 0x77, 0xe2, 0x53, 0x84, + 0x5f, 0x79, 0x7d, 0x04, 0x85, 0xac, 0x8a, 0x33, + 0x8e, 0x8d, 0x97, 0x56, 0x67, 0xf3, 0x85, 0xae, + 0x94, 0x53, 0x61, 0x09, 0x61, 0x08, 0x6c, 0xb9, + 0x76, 0x52, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x8a, 0xed, 0x8f, 0x38, 0x55, 0x2f, 0x4f, 0x51, + 0x51, 0x2a, 0x52, 0xc7, 0x53, 0xcb, 0x5b, 0xa5, + 0x5e, 0x7d, 0x60, 0xa0, 0x61, 0x82, 0x63, 0xd6, + 0x67, 0x09, 0x67, 0xda, 0x6e, 0x67, 0x6d, 0x8c, + 0x73, 0x36, 0x73, 0x37, 0x75, 0x31, 0x79, 0x50, + 0x88, 0xd5, 0x8a, 0x98, 0x90, 0x4a, 0x90, 0x91, + 0x90, 0xf5, 0x96, 0xc4, 0x87, 0x8d, 0x59, 0x15, + 0x4e, 0x88, 0x4f, 0x59, 0x4e, 0x0e, 0x8a, 0x89, + 0x8f, 0x3f, 0x98, 0x10, 0x50, 0xad, 0x5e, 0x7c, + 0x59, 0x96, 0x5b, 0xb9, 0x5e, 0xb8, 0x63, 0xda, + 0x63, 0xfa, 0x64, 0xc1, 0x66, 0xdc, 0x69, 0x4a, + 0x69, 0xd8, 0x6d, 0x0b, 0x6e, 0xb6, 0x71, 0x94, + 0x75, 0x28, 0x7a, 0xaf, 0x7f, 0x8a, 0x80, 0x00, + 0x84, 0x49, 0x84, 0xc9, 0x89, 0x81, 0x8b, 0x21, + 0x8e, 0x0a, 0x90, 0x65, 0x96, 0x7d, 0x99, 0x0a, + 0x61, 0x7e, 0x62, 0x91, 0x6b, 0x32, 0x00, 0x20, + 0x6c, 0x83, 0x6d, 0x74, 0x7f, 0xcc, 0x7f, 0xfc, + 0x6d, 0xc0, 0x7f, 0x85, 0x87, 0xba, 0x88, 0xf8, + 0x67, 0x65, 0x83, 0xb1, 0x98, 0x3c, 0x96, 0xf7, + 0x6d, 0x1b, 0x7d, 0x61, 0x84, 0x3d, 0x91, 0x6a, + 0x4e, 0x71, 0x53, 0x75, 0x5d, 0x50, 0x6b, 0x04, + 0x6f, 0xeb, 0x85, 0xcd, 0x86, 0x2d, 0x89, 0xa7, + 0x52, 0x29, 0x54, 0x0f, 0x5c, 0x65, 0x67, 0x4e, + 0x68, 0xa8, 0x74, 0x06, 0x74, 0x83, 0x75, 0xe2, + 0x88, 0xcf, 0x88, 0xe1, 0x91, 0xcc, 0x96, 0xe2, + 0x96, 0x78, 0x5f, 0x8b, 0x73, 0x87, 0x7a, 0xcb, + 0x84, 0x4e, 0x63, 0xa0, 0x75, 0x65, 0x52, 0x89, + 0x6d, 0x41, 0x6e, 0x9c, 0x74, 0x09, 0x75, 0x59, + 0x78, 0x6b, 0x7c, 0x92, 0x96, 0x86, 0x7a, 0xdc, + 0x9f, 0x8d, 0x4f, 0xb6, 0x61, 0x6e, 0x65, 0xc5, + 0x86, 0x5c, 0x4e, 0x86, 0x4e, 0xae, 0x50, 0xda, + 0x4e, 0x21, 0x51, 0xcc, 0x5b, 0xee, 0x65, 0x99, + 0x68, 0x81, 0x6d, 0xbc, 0x73, 0x1f, 0x76, 0x42, + 0x77, 0xad, 0x7a, 0x1c, 0x7c, 0xe7, 0x82, 0x6f, + 0x8a, 0xd2, 0x90, 0x7c, 0x91, 0xcf, 0x96, 0x75, + 0x98, 0x18, 0x52, 0x9b, 0x7d, 0xd1, 0x50, 0x2b, + 0x53, 0x98, 0x67, 0x97, 0x6d, 0xcb, 0x71, 0xd0, + 0x74, 0x33, 0x81, 0xe8, 0x8f, 0x2a, 0x96, 0xa3, + 0x9c, 0x57, 0x9e, 0x9f, 0x74, 0x60, 0x58, 0x41, + 0x6d, 0x99, 0x7d, 0x2f, 0x98, 0x5e, 0x4e, 0xe4, + 0x4f, 0x36, 0x4f, 0x8b, 0x51, 0xb7, 0x52, 0xb1, + 0x5d, 0xba, 0x60, 0x1c, 0x73, 0xb2, 0x79, 0x3c, + 0x82, 0xd3, 0x92, 0x34, 0x96, 0xb7, 0x96, 0xf6, + 0x97, 0x0a, 0x9e, 0x97, 0x9f, 0x62, 0x66, 0xa6, + 0x6b, 0x74, 0x52, 0x17, 0x52, 0xa3, 0x70, 0xc8, + 0x88, 0xc2, 0x5e, 0xc9, 0x60, 0x4b, 0x61, 0x90, + 0x6f, 0x23, 0x71, 0x49, 0x7c, 0x3e, 0x7d, 0xf4, + 0x80, 0x6f, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x84, 0xee, 0x90, 0x23, 0x93, 0x2c, 0x54, 0x42, + 0x9b, 0x6f, 0x6a, 0xd3, 0x70, 0x89, 0x8c, 0xc2, + 0x8d, 0xef, 0x97, 0x32, 0x52, 0xb4, 0x5a, 0x41, + 0x5e, 0xca, 0x5f, 0x04, 0x67, 0x17, 0x69, 0x7c, + 0x69, 0x94, 0x6d, 0x6a, 0x6f, 0x0f, 0x72, 0x62, + 0x72, 0xfc, 0x7b, 0xed, 0x80, 0x01, 0x80, 0x7e, + 0x87, 0x4b, 0x90, 0xce, 0x51, 0x6d, 0x9e, 0x93, + 0x79, 0x84, 0x80, 0x8b, 0x93, 0x32, 0x8a, 0xd6, + 0x50, 0x2d, 0x54, 0x8c, 0x8a, 0x71, 0x6b, 0x6a, + 0x8c, 0xc4, 0x81, 0x07, 0x60, 0xd1, 0x67, 0xa0, + 0x9d, 0xf2, 0x4e, 0x99, 0x4e, 0x98, 0x9c, 0x10, + 0x8a, 0x6b, 0x85, 0xc1, 0x85, 0x68, 0x69, 0x00, + 0x6e, 0x7e, 0x78, 0x97, 0x81, 0x55, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x5f, 0x0c, + 0x4e, 0x10, 0x4e, 0x15, 0x4e, 0x2a, 0x4e, 0x31, + 0x4e, 0x36, 0x4e, 0x3c, 0x4e, 0x3f, 0x4e, 0x42, + 0x4e, 0x56, 0x4e, 0x58, 0x4e, 0x82, 0x4e, 0x85, + 0x8c, 0x6b, 0x4e, 0x8a, 0x82, 0x12, 0x5f, 0x0d, + 0x4e, 0x8e, 0x4e, 0x9e, 0x4e, 0x9f, 0x4e, 0xa0, + 0x4e, 0xa2, 0x4e, 0xb0, 0x4e, 0xb3, 0x4e, 0xb6, + 0x4e, 0xce, 0x4e, 0xcd, 0x4e, 0xc4, 0x4e, 0xc6, + 0x4e, 0xc2, 0x4e, 0xd7, 0x4e, 0xde, 0x4e, 0xed, + 0x4e, 0xdf, 0x4e, 0xf7, 0x4f, 0x09, 0x4f, 0x5a, + 0x4f, 0x30, 0x4f, 0x5b, 0x4f, 0x5d, 0x4f, 0x57, + 0x4f, 0x47, 0x4f, 0x76, 0x4f, 0x88, 0x4f, 0x8f, + 0x4f, 0x98, 0x4f, 0x7b, 0x4f, 0x69, 0x4f, 0x70, + 0x4f, 0x91, 0x4f, 0x6f, 0x4f, 0x86, 0x4f, 0x96, + 0x51, 0x18, 0x4f, 0xd4, 0x4f, 0xdf, 0x4f, 0xce, + 0x4f, 0xd8, 0x4f, 0xdb, 0x4f, 0xd1, 0x4f, 0xda, + 0x4f, 0xd0, 0x4f, 0xe4, 0x4f, 0xe5, 0x50, 0x1a, + 0x50, 0x28, 0x50, 0x14, 0x50, 0x2a, 0x50, 0x25, + 0x50, 0x05, 0x4f, 0x1c, 0x4f, 0xf6, 0x50, 0x21, + 0x50, 0x29, 0x50, 0x2c, 0x4f, 0xfe, 0x4f, 0xef, + 0x50, 0x11, 0x50, 0x06, 0x50, 0x43, 0x50, 0x47, + 0x67, 0x03, 0x50, 0x55, 0x50, 0x50, 0x50, 0x48, + 0x50, 0x5a, 0x50, 0x56, 0x50, 0x6c, 0x50, 0x78, + 0x50, 0x80, 0x50, 0x9a, 0x50, 0x85, 0x50, 0xb4, + 0x50, 0xb2, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x50, 0xc9, 0x50, 0xca, 0x50, 0xb3, 0x50, 0xc2, + 0x50, 0xd6, 0x50, 0xde, 0x50, 0xe5, 0x50, 0xed, + 0x50, 0xe3, 0x50, 0xee, 0x50, 0xf9, 0x50, 0xf5, + 0x51, 0x09, 0x51, 0x01, 0x51, 0x02, 0x51, 0x16, + 0x51, 0x15, 0x51, 0x14, 0x51, 0x1a, 0x51, 0x21, + 0x51, 0x3a, 0x51, 0x37, 0x51, 0x3c, 0x51, 0x3b, + 0x51, 0x3f, 0x51, 0x40, 0x51, 0x52, 0x51, 0x4c, + 0x51, 0x54, 0x51, 0x62, 0x7a, 0xf8, 0x51, 0x69, + 0x51, 0x6a, 0x51, 0x6e, 0x51, 0x80, 0x51, 0x82, + 0x56, 0xd8, 0x51, 0x8c, 0x51, 0x89, 0x51, 0x8f, + 0x51, 0x91, 0x51, 0x93, 0x51, 0x95, 0x51, 0x96, + 0x51, 0xa4, 0x51, 0xa6, 0x51, 0xa2, 0x51, 0xa9, + 0x51, 0xaa, 0x51, 0xab, 0x51, 0xb3, 0x51, 0xb1, + 0x51, 0xb2, 0x51, 0xb0, 0x51, 0xb5, 0x51, 0xbd, + 0x51, 0xc5, 0x51, 0xc9, 0x51, 0xdb, 0x51, 0xe0, + 0x86, 0x55, 0x51, 0xe9, 0x51, 0xed, 0x00, 0x20, + 0x51, 0xf0, 0x51, 0xf5, 0x51, 0xfe, 0x52, 0x04, + 0x52, 0x0b, 0x52, 0x14, 0x52, 0x0e, 0x52, 0x27, + 0x52, 0x2a, 0x52, 0x2e, 0x52, 0x33, 0x52, 0x39, + 0x52, 0x4f, 0x52, 0x44, 0x52, 0x4b, 0x52, 0x4c, + 0x52, 0x5e, 0x52, 0x54, 0x52, 0x6a, 0x52, 0x74, + 0x52, 0x69, 0x52, 0x73, 0x52, 0x7f, 0x52, 0x7d, + 0x52, 0x8d, 0x52, 0x94, 0x52, 0x92, 0x52, 0x71, + 0x52, 0x88, 0x52, 0x91, 0x8f, 0xa8, 0x8f, 0xa7, + 0x52, 0xac, 0x52, 0xad, 0x52, 0xbc, 0x52, 0xb5, + 0x52, 0xc1, 0x52, 0xcd, 0x52, 0xd7, 0x52, 0xde, + 0x52, 0xe3, 0x52, 0xe6, 0x98, 0xed, 0x52, 0xe0, + 0x52, 0xf3, 0x52, 0xf5, 0x52, 0xf8, 0x52, 0xf9, + 0x53, 0x06, 0x53, 0x08, 0x75, 0x38, 0x53, 0x0d, + 0x53, 0x10, 0x53, 0x0f, 0x53, 0x15, 0x53, 0x1a, + 0x53, 0x23, 0x53, 0x2f, 0x53, 0x31, 0x53, 0x33, + 0x53, 0x38, 0x53, 0x40, 0x53, 0x46, 0x53, 0x45, + 0x4e, 0x17, 0x53, 0x49, 0x53, 0x4d, 0x51, 0xd6, + 0x53, 0x5e, 0x53, 0x69, 0x53, 0x6e, 0x59, 0x18, + 0x53, 0x7b, 0x53, 0x77, 0x53, 0x82, 0x53, 0x96, + 0x53, 0xa0, 0x53, 0xa6, 0x53, 0xa5, 0x53, 0xae, + 0x53, 0xb0, 0x53, 0xb6, 0x53, 0xc3, 0x7c, 0x12, + 0x96, 0xd9, 0x53, 0xdf, 0x66, 0xfc, 0x71, 0xee, + 0x53, 0xee, 0x53, 0xe8, 0x53, 0xed, 0x53, 0xfa, + 0x54, 0x01, 0x54, 0x3d, 0x54, 0x40, 0x54, 0x2c, + 0x54, 0x2d, 0x54, 0x3c, 0x54, 0x2e, 0x54, 0x36, + 0x54, 0x29, 0x54, 0x1d, 0x54, 0x4e, 0x54, 0x8f, + 0x54, 0x75, 0x54, 0x8e, 0x54, 0x5f, 0x54, 0x71, + 0x54, 0x77, 0x54, 0x70, 0x54, 0x92, 0x54, 0x7b, + 0x54, 0x80, 0x54, 0x76, 0x54, 0x84, 0x54, 0x90, + 0x54, 0x86, 0x54, 0xc7, 0x54, 0xa2, 0x54, 0xb8, + 0x54, 0xa5, 0x54, 0xac, 0x54, 0xc4, 0x54, 0xc8, + 0x54, 0xa8, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x54, 0xab, 0x54, 0xc2, 0x54, 0xa4, 0x54, 0xbe, + 0x54, 0xbc, 0x54, 0xd8, 0x54, 0xe5, 0x54, 0xe6, + 0x55, 0x0f, 0x55, 0x14, 0x54, 0xfd, 0x54, 0xee, + 0x54, 0xed, 0x54, 0xfa, 0x54, 0xe2, 0x55, 0x39, + 0x55, 0x40, 0x55, 0x63, 0x55, 0x4c, 0x55, 0x2e, + 0x55, 0x5c, 0x55, 0x45, 0x55, 0x56, 0x55, 0x57, + 0x55, 0x38, 0x55, 0x33, 0x55, 0x5d, 0x55, 0x99, + 0x55, 0x80, 0x54, 0xaf, 0x55, 0x8a, 0x55, 0x9f, + 0x55, 0x7b, 0x55, 0x7e, 0x55, 0x98, 0x55, 0x9e, + 0x55, 0xae, 0x55, 0x7c, 0x55, 0x83, 0x55, 0xa9, + 0x55, 0x87, 0x55, 0xa8, 0x55, 0xda, 0x55, 0xc5, + 0x55, 0xdf, 0x55, 0xc4, 0x55, 0xdc, 0x55, 0xe4, + 0x55, 0xd4, 0x56, 0x14, 0x55, 0xf7, 0x56, 0x16, + 0x55, 0xfe, 0x55, 0xfd, 0x56, 0x1b, 0x55, 0xf9, + 0x56, 0x4e, 0x56, 0x50, 0x71, 0xdf, 0x56, 0x34, + 0x56, 0x36, 0x56, 0x32, 0x56, 0x38, 0x00, 0x20, + 0x56, 0x6b, 0x56, 0x64, 0x56, 0x2f, 0x56, 0x6c, + 0x56, 0x6a, 0x56, 0x86, 0x56, 0x80, 0x56, 0x8a, + 0x56, 0xa0, 0x56, 0x94, 0x56, 0x8f, 0x56, 0xa5, + 0x56, 0xae, 0x56, 0xb6, 0x56, 0xb4, 0x56, 0xc2, + 0x56, 0xbc, 0x56, 0xc1, 0x56, 0xc3, 0x56, 0xc0, + 0x56, 0xc8, 0x56, 0xce, 0x56, 0xd1, 0x56, 0xd3, + 0x56, 0xd7, 0x56, 0xee, 0x56, 0xf9, 0x57, 0x00, + 0x56, 0xff, 0x57, 0x04, 0x57, 0x09, 0x57, 0x08, + 0x57, 0x0b, 0x57, 0x0d, 0x57, 0x13, 0x57, 0x18, + 0x57, 0x16, 0x55, 0xc7, 0x57, 0x1c, 0x57, 0x26, + 0x57, 0x37, 0x57, 0x38, 0x57, 0x4e, 0x57, 0x3b, + 0x57, 0x40, 0x57, 0x4f, 0x57, 0x69, 0x57, 0xc0, + 0x57, 0x88, 0x57, 0x61, 0x57, 0x7f, 0x57, 0x89, + 0x57, 0x93, 0x57, 0xa0, 0x57, 0xb3, 0x57, 0xa4, + 0x57, 0xaa, 0x57, 0xb0, 0x57, 0xc3, 0x57, 0xc6, + 0x57, 0xd4, 0x57, 0xd2, 0x57, 0xd3, 0x58, 0x0a, + 0x57, 0xd6, 0x57, 0xe3, 0x58, 0x0b, 0x58, 0x19, + 0x58, 0x1d, 0x58, 0x72, 0x58, 0x21, 0x58, 0x62, + 0x58, 0x4b, 0x58, 0x70, 0x6b, 0xc0, 0x58, 0x52, + 0x58, 0x3d, 0x58, 0x79, 0x58, 0x85, 0x58, 0xb9, + 0x58, 0x9f, 0x58, 0xab, 0x58, 0xba, 0x58, 0xde, + 0x58, 0xbb, 0x58, 0xb8, 0x58, 0xae, 0x58, 0xc5, + 0x58, 0xd3, 0x58, 0xd1, 0x58, 0xd7, 0x58, 0xd9, + 0x58, 0xd8, 0x58, 0xe5, 0x58, 0xdc, 0x58, 0xe4, + 0x58, 0xdf, 0x58, 0xef, 0x58, 0xfa, 0x58, 0xf9, + 0x58, 0xfb, 0x58, 0xfc, 0x58, 0xfd, 0x59, 0x02, + 0x59, 0x0a, 0x59, 0x10, 0x59, 0x1b, 0x68, 0xa6, + 0x59, 0x25, 0x59, 0x2c, 0x59, 0x2d, 0x59, 0x32, + 0x59, 0x38, 0x59, 0x3e, 0x7a, 0xd2, 0x59, 0x55, + 0x59, 0x50, 0x59, 0x4e, 0x59, 0x5a, 0x59, 0x58, + 0x59, 0x62, 0x59, 0x60, 0x59, 0x67, 0x59, 0x6c, + 0x59, 0x69, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x59, 0x78, 0x59, 0x81, 0x59, 0x9d, 0x4f, 0x5e, + 0x4f, 0xab, 0x59, 0xa3, 0x59, 0xb2, 0x59, 0xc6, + 0x59, 0xe8, 0x59, 0xdc, 0x59, 0x8d, 0x59, 0xd9, + 0x59, 0xda, 0x5a, 0x25, 0x5a, 0x1f, 0x5a, 0x11, + 0x5a, 0x1c, 0x5a, 0x09, 0x5a, 0x1a, 0x5a, 0x40, + 0x5a, 0x6c, 0x5a, 0x49, 0x5a, 0x35, 0x5a, 0x36, + 0x5a, 0x62, 0x5a, 0x6a, 0x5a, 0x9a, 0x5a, 0xbc, + 0x5a, 0xbe, 0x5a, 0xcb, 0x5a, 0xc2, 0x5a, 0xbd, + 0x5a, 0xe3, 0x5a, 0xd7, 0x5a, 0xe6, 0x5a, 0xe9, + 0x5a, 0xd6, 0x5a, 0xfa, 0x5a, 0xfb, 0x5b, 0x0c, + 0x5b, 0x0b, 0x5b, 0x16, 0x5b, 0x32, 0x5a, 0xd0, + 0x5b, 0x2a, 0x5b, 0x36, 0x5b, 0x3e, 0x5b, 0x43, + 0x5b, 0x45, 0x5b, 0x40, 0x5b, 0x51, 0x5b, 0x55, + 0x5b, 0x5a, 0x5b, 0x5b, 0x5b, 0x65, 0x5b, 0x69, + 0x5b, 0x70, 0x5b, 0x73, 0x5b, 0x75, 0x5b, 0x78, + 0x65, 0x88, 0x5b, 0x7a, 0x5b, 0x80, 0x00, 0x20, + 0x5b, 0x83, 0x5b, 0xa6, 0x5b, 0xb8, 0x5b, 0xc3, + 0x5b, 0xc7, 0x5b, 0xc9, 0x5b, 0xd4, 0x5b, 0xd0, + 0x5b, 0xe4, 0x5b, 0xe6, 0x5b, 0xe2, 0x5b, 0xde, + 0x5b, 0xe5, 0x5b, 0xeb, 0x5b, 0xf0, 0x5b, 0xf6, + 0x5b, 0xf3, 0x5c, 0x05, 0x5c, 0x07, 0x5c, 0x08, + 0x5c, 0x0d, 0x5c, 0x13, 0x5c, 0x20, 0x5c, 0x22, + 0x5c, 0x28, 0x5c, 0x38, 0x5c, 0x39, 0x5c, 0x41, + 0x5c, 0x46, 0x5c, 0x4e, 0x5c, 0x53, 0x5c, 0x50, + 0x5c, 0x4f, 0x5b, 0x71, 0x5c, 0x6c, 0x5c, 0x6e, + 0x4e, 0x62, 0x5c, 0x76, 0x5c, 0x79, 0x5c, 0x8c, + 0x5c, 0x91, 0x5c, 0x94, 0x59, 0x9b, 0x5c, 0xab, + 0x5c, 0xbb, 0x5c, 0xb6, 0x5c, 0xbc, 0x5c, 0xb7, + 0x5c, 0xc5, 0x5c, 0xbe, 0x5c, 0xc7, 0x5c, 0xd9, + 0x5c, 0xe9, 0x5c, 0xfd, 0x5c, 0xfa, 0x5c, 0xed, + 0x5d, 0x8c, 0x5c, 0xea, 0x5d, 0x0b, 0x5d, 0x15, + 0x5d, 0x17, 0x5d, 0x5c, 0x5d, 0x1f, 0x5d, 0x1b, + 0x5d, 0x11, 0x5d, 0x14, 0x5d, 0x22, 0x5d, 0x1a, + 0x5d, 0x19, 0x5d, 0x18, 0x5d, 0x4c, 0x5d, 0x52, + 0x5d, 0x4e, 0x5d, 0x4b, 0x5d, 0x6c, 0x5d, 0x73, + 0x5d, 0x76, 0x5d, 0x87, 0x5d, 0x84, 0x5d, 0x82, + 0x5d, 0xa2, 0x5d, 0x9d, 0x5d, 0xac, 0x5d, 0xae, + 0x5d, 0xbd, 0x5d, 0x90, 0x5d, 0xb7, 0x5d, 0xbc, + 0x5d, 0xc9, 0x5d, 0xcd, 0x5d, 0xd3, 0x5d, 0xd2, + 0x5d, 0xd6, 0x5d, 0xdb, 0x5d, 0xeb, 0x5d, 0xf2, + 0x5d, 0xf5, 0x5e, 0x0b, 0x5e, 0x1a, 0x5e, 0x19, + 0x5e, 0x11, 0x5e, 0x1b, 0x5e, 0x36, 0x5e, 0x37, + 0x5e, 0x44, 0x5e, 0x43, 0x5e, 0x40, 0x5e, 0x4e, + 0x5e, 0x57, 0x5e, 0x54, 0x5e, 0x5f, 0x5e, 0x62, + 0x5e, 0x64, 0x5e, 0x47, 0x5e, 0x75, 0x5e, 0x76, + 0x5e, 0x7a, 0x9e, 0xbc, 0x5e, 0x7f, 0x5e, 0xa0, + 0x5e, 0xc1, 0x5e, 0xc2, 0x5e, 0xc8, 0x5e, 0xd0, + 0x5e, 0xcf, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x5e, 0xd6, 0x5e, 0xe3, 0x5e, 0xdd, 0x5e, 0xda, + 0x5e, 0xdb, 0x5e, 0xe2, 0x5e, 0xe1, 0x5e, 0xe8, + 0x5e, 0xe9, 0x5e, 0xec, 0x5e, 0xf1, 0x5e, 0xf3, + 0x5e, 0xf0, 0x5e, 0xf4, 0x5e, 0xf8, 0x5e, 0xfe, + 0x5f, 0x03, 0x5f, 0x09, 0x5f, 0x5d, 0x5f, 0x5c, + 0x5f, 0x0b, 0x5f, 0x11, 0x5f, 0x16, 0x5f, 0x29, + 0x5f, 0x2d, 0x5f, 0x38, 0x5f, 0x41, 0x5f, 0x48, + 0x5f, 0x4c, 0x5f, 0x4e, 0x5f, 0x2f, 0x5f, 0x51, + 0x5f, 0x56, 0x5f, 0x57, 0x5f, 0x59, 0x5f, 0x61, + 0x5f, 0x6d, 0x5f, 0x73, 0x5f, 0x77, 0x5f, 0x83, + 0x5f, 0x82, 0x5f, 0x7f, 0x5f, 0x8a, 0x5f, 0x88, + 0x5f, 0x91, 0x5f, 0x87, 0x5f, 0x9e, 0x5f, 0x99, + 0x5f, 0x98, 0x5f, 0xa0, 0x5f, 0xa8, 0x5f, 0xad, + 0x5f, 0xbc, 0x5f, 0xd6, 0x5f, 0xfb, 0x5f, 0xe4, + 0x5f, 0xf8, 0x5f, 0xf1, 0x5f, 0xdd, 0x60, 0xb3, + 0x5f, 0xff, 0x60, 0x21, 0x60, 0x60, 0x00, 0x20, + 0x60, 0x19, 0x60, 0x10, 0x60, 0x29, 0x60, 0x0e, + 0x60, 0x31, 0x60, 0x1b, 0x60, 0x15, 0x60, 0x2b, + 0x60, 0x26, 0x60, 0x0f, 0x60, 0x3a, 0x60, 0x5a, + 0x60, 0x41, 0x60, 0x6a, 0x60, 0x77, 0x60, 0x5f, + 0x60, 0x4a, 0x60, 0x46, 0x60, 0x4d, 0x60, 0x63, + 0x60, 0x43, 0x60, 0x64, 0x60, 0x42, 0x60, 0x6c, + 0x60, 0x6b, 0x60, 0x59, 0x60, 0x81, 0x60, 0x8d, + 0x60, 0xe7, 0x60, 0x83, 0x60, 0x9a, 0x60, 0x84, + 0x60, 0x9b, 0x60, 0x96, 0x60, 0x97, 0x60, 0x92, + 0x60, 0xa7, 0x60, 0x8b, 0x60, 0xe1, 0x60, 0xb8, + 0x60, 0xe0, 0x60, 0xd3, 0x60, 0xb4, 0x5f, 0xf0, + 0x60, 0xbd, 0x60, 0xc6, 0x60, 0xb5, 0x60, 0xd8, + 0x61, 0x4d, 0x61, 0x15, 0x61, 0x06, 0x60, 0xf6, + 0x60, 0xf7, 0x61, 0x00, 0x60, 0xf4, 0x60, 0xfa, + 0x61, 0x03, 0x61, 0x21, 0x60, 0xfb, 0x60, 0xf1, + 0x61, 0x0d, 0x61, 0x0e, 0x61, 0x47, 0x61, 0x3e, + 0x61, 0x28, 0x61, 0x27, 0x61, 0x4a, 0x61, 0x3f, + 0x61, 0x3c, 0x61, 0x2c, 0x61, 0x34, 0x61, 0x3d, + 0x61, 0x42, 0x61, 0x44, 0x61, 0x73, 0x61, 0x77, + 0x61, 0x58, 0x61, 0x59, 0x61, 0x5a, 0x61, 0x6b, + 0x61, 0x74, 0x61, 0x6f, 0x61, 0x65, 0x61, 0x71, + 0x61, 0x5f, 0x61, 0x5d, 0x61, 0x53, 0x61, 0x75, + 0x61, 0x99, 0x61, 0x96, 0x61, 0x87, 0x61, 0xac, + 0x61, 0x94, 0x61, 0x9a, 0x61, 0x8a, 0x61, 0x91, + 0x61, 0xab, 0x61, 0xae, 0x61, 0xcc, 0x61, 0xca, + 0x61, 0xc9, 0x61, 0xf7, 0x61, 0xc8, 0x61, 0xc3, + 0x61, 0xc6, 0x61, 0xba, 0x61, 0xcb, 0x7f, 0x79, + 0x61, 0xcd, 0x61, 0xe6, 0x61, 0xe3, 0x61, 0xf6, + 0x61, 0xfa, 0x61, 0xf4, 0x61, 0xff, 0x61, 0xfd, + 0x61, 0xfc, 0x61, 0xfe, 0x62, 0x00, 0x62, 0x08, + 0x62, 0x09, 0x62, 0x0d, 0x62, 0x0c, 0x62, 0x14, + 0x62, 0x1b, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x62, 0x1e, 0x62, 0x21, 0x62, 0x2a, 0x62, 0x2e, + 0x62, 0x30, 0x62, 0x32, 0x62, 0x33, 0x62, 0x41, + 0x62, 0x4e, 0x62, 0x5e, 0x62, 0x63, 0x62, 0x5b, + 0x62, 0x60, 0x62, 0x68, 0x62, 0x7c, 0x62, 0x82, + 0x62, 0x89, 0x62, 0x7e, 0x62, 0x92, 0x62, 0x93, + 0x62, 0x96, 0x62, 0xd4, 0x62, 0x83, 0x62, 0x94, + 0x62, 0xd7, 0x62, 0xd1, 0x62, 0xbb, 0x62, 0xcf, + 0x62, 0xff, 0x62, 0xc6, 0x64, 0xd4, 0x62, 0xc8, + 0x62, 0xdc, 0x62, 0xcc, 0x62, 0xca, 0x62, 0xc2, + 0x62, 0xc7, 0x62, 0x9b, 0x62, 0xc9, 0x63, 0x0c, + 0x62, 0xee, 0x62, 0xf1, 0x63, 0x27, 0x63, 0x02, + 0x63, 0x08, 0x62, 0xef, 0x62, 0xf5, 0x63, 0x50, + 0x63, 0x3e, 0x63, 0x4d, 0x64, 0x1c, 0x63, 0x4f, + 0x63, 0x96, 0x63, 0x8e, 0x63, 0x80, 0x63, 0xab, + 0x63, 0x76, 0x63, 0xa3, 0x63, 0x8f, 0x63, 0x89, + 0x63, 0x9f, 0x63, 0xb5, 0x63, 0x6b, 0x00, 0x20, + 0x63, 0x69, 0x63, 0xbe, 0x63, 0xe9, 0x63, 0xc0, + 0x63, 0xc6, 0x63, 0xe3, 0x63, 0xc9, 0x63, 0xd2, + 0x63, 0xf6, 0x63, 0xc4, 0x64, 0x16, 0x64, 0x34, + 0x64, 0x06, 0x64, 0x13, 0x64, 0x26, 0x64, 0x36, + 0x65, 0x1d, 0x64, 0x17, 0x64, 0x28, 0x64, 0x0f, + 0x64, 0x67, 0x64, 0x6f, 0x64, 0x76, 0x64, 0x4e, + 0x65, 0x2a, 0x64, 0x95, 0x64, 0x93, 0x64, 0xa5, + 0x64, 0xa9, 0x64, 0x88, 0x64, 0xbc, 0x64, 0xda, + 0x64, 0xd2, 0x64, 0xc5, 0x64, 0xc7, 0x64, 0xbb, + 0x64, 0xd8, 0x64, 0xc2, 0x64, 0xf1, 0x64, 0xe7, + 0x82, 0x09, 0x64, 0xe0, 0x64, 0xe1, 0x62, 0xac, + 0x64, 0xe3, 0x64, 0xef, 0x65, 0x2c, 0x64, 0xf6, + 0x64, 0xf4, 0x64, 0xf2, 0x64, 0xfa, 0x65, 0x00, + 0x64, 0xfd, 0x65, 0x18, 0x65, 0x1c, 0x65, 0x05, + 0x65, 0x24, 0x65, 0x23, 0x65, 0x2b, 0x65, 0x34, + 0x65, 0x35, 0x65, 0x37, 0x65, 0x36, 0x65, 0x38, + 0x75, 0x4b, 0x65, 0x48, 0x65, 0x56, 0x65, 0x55, + 0x65, 0x4d, 0x65, 0x58, 0x65, 0x5e, 0x65, 0x5d, + 0x65, 0x72, 0x65, 0x78, 0x65, 0x82, 0x65, 0x83, + 0x8b, 0x8a, 0x65, 0x9b, 0x65, 0x9f, 0x65, 0xab, + 0x65, 0xb7, 0x65, 0xc3, 0x65, 0xc6, 0x65, 0xc1, + 0x65, 0xc4, 0x65, 0xcc, 0x65, 0xd2, 0x65, 0xdb, + 0x65, 0xd9, 0x65, 0xe0, 0x65, 0xe1, 0x65, 0xf1, + 0x67, 0x72, 0x66, 0x0a, 0x66, 0x03, 0x65, 0xfb, + 0x67, 0x73, 0x66, 0x35, 0x66, 0x36, 0x66, 0x34, + 0x66, 0x1c, 0x66, 0x4f, 0x66, 0x44, 0x66, 0x49, + 0x66, 0x41, 0x66, 0x5e, 0x66, 0x5d, 0x66, 0x64, + 0x66, 0x67, 0x66, 0x68, 0x66, 0x5f, 0x66, 0x62, + 0x66, 0x70, 0x66, 0x83, 0x66, 0x88, 0x66, 0x8e, + 0x66, 0x89, 0x66, 0x84, 0x66, 0x98, 0x66, 0x9d, + 0x66, 0xc1, 0x66, 0xb9, 0x66, 0xc9, 0x66, 0xbe, + 0x66, 0xbc, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x66, 0xc4, 0x66, 0xb8, 0x66, 0xd6, 0x66, 0xda, + 0x66, 0xe0, 0x66, 0x3f, 0x66, 0xe6, 0x66, 0xe9, + 0x66, 0xf0, 0x66, 0xf5, 0x66, 0xf7, 0x67, 0x0f, + 0x67, 0x16, 0x67, 0x1e, 0x67, 0x26, 0x67, 0x27, + 0x97, 0x38, 0x67, 0x2e, 0x67, 0x3f, 0x67, 0x36, + 0x67, 0x41, 0x67, 0x38, 0x67, 0x37, 0x67, 0x46, + 0x67, 0x5e, 0x67, 0x60, 0x67, 0x59, 0x67, 0x63, + 0x67, 0x64, 0x67, 0x89, 0x67, 0x70, 0x67, 0xa9, + 0x67, 0x7c, 0x67, 0x6a, 0x67, 0x8c, 0x67, 0x8b, + 0x67, 0xa6, 0x67, 0xa1, 0x67, 0x85, 0x67, 0xb7, + 0x67, 0xef, 0x67, 0xb4, 0x67, 0xec, 0x67, 0xb3, + 0x67, 0xe9, 0x67, 0xb8, 0x67, 0xe4, 0x67, 0xde, + 0x67, 0xdd, 0x67, 0xe2, 0x67, 0xee, 0x67, 0xb9, + 0x67, 0xce, 0x67, 0xc6, 0x67, 0xe7, 0x6a, 0x9c, + 0x68, 0x1e, 0x68, 0x46, 0x68, 0x29, 0x68, 0x40, + 0x68, 0x4d, 0x68, 0x32, 0x68, 0x4e, 0x00, 0x20, + 0x68, 0xb3, 0x68, 0x2b, 0x68, 0x59, 0x68, 0x63, + 0x68, 0x77, 0x68, 0x7f, 0x68, 0x9f, 0x68, 0x8f, + 0x68, 0xad, 0x68, 0x94, 0x68, 0x9d, 0x68, 0x9b, + 0x68, 0x83, 0x6a, 0xae, 0x68, 0xb9, 0x68, 0x74, + 0x68, 0xb5, 0x68, 0xa0, 0x68, 0xba, 0x69, 0x0f, + 0x68, 0x8d, 0x68, 0x7e, 0x69, 0x01, 0x68, 0xca, + 0x69, 0x08, 0x68, 0xd8, 0x69, 0x22, 0x69, 0x26, + 0x68, 0xe1, 0x69, 0x0c, 0x68, 0xcd, 0x68, 0xd4, + 0x68, 0xe7, 0x68, 0xd5, 0x69, 0x36, 0x69, 0x12, + 0x69, 0x04, 0x68, 0xd7, 0x68, 0xe3, 0x69, 0x25, + 0x68, 0xf9, 0x68, 0xe0, 0x68, 0xef, 0x69, 0x28, + 0x69, 0x2a, 0x69, 0x1a, 0x69, 0x23, 0x69, 0x21, + 0x68, 0xc6, 0x69, 0x79, 0x69, 0x77, 0x69, 0x5c, + 0x69, 0x78, 0x69, 0x6b, 0x69, 0x54, 0x69, 0x7e, + 0x69, 0x6e, 0x69, 0x39, 0x69, 0x74, 0x69, 0x3d, + 0x69, 0x59, 0x69, 0x30, 0x69, 0x61, 0x69, 0x5e, + 0x69, 0x5d, 0x69, 0x81, 0x69, 0x6a, 0x69, 0xb2, + 0x69, 0xae, 0x69, 0xd0, 0x69, 0xbf, 0x69, 0xc1, + 0x69, 0xd3, 0x69, 0xbe, 0x69, 0xce, 0x5b, 0xe8, + 0x69, 0xca, 0x69, 0xdd, 0x69, 0xbb, 0x69, 0xc3, + 0x69, 0xa7, 0x6a, 0x2e, 0x69, 0x91, 0x69, 0xa0, + 0x69, 0x9c, 0x69, 0x95, 0x69, 0xb4, 0x69, 0xde, + 0x69, 0xe8, 0x6a, 0x02, 0x6a, 0x1b, 0x69, 0xff, + 0x6b, 0x0a, 0x69, 0xf9, 0x69, 0xf2, 0x69, 0xe7, + 0x6a, 0x05, 0x69, 0xb1, 0x6a, 0x1e, 0x69, 0xed, + 0x6a, 0x14, 0x69, 0xeb, 0x6a, 0x0a, 0x6a, 0x12, + 0x6a, 0xc1, 0x6a, 0x23, 0x6a, 0x13, 0x6a, 0x44, + 0x6a, 0x0c, 0x6a, 0x72, 0x6a, 0x36, 0x6a, 0x78, + 0x6a, 0x47, 0x6a, 0x62, 0x6a, 0x59, 0x6a, 0x66, + 0x6a, 0x48, 0x6a, 0x38, 0x6a, 0x22, 0x6a, 0x90, + 0x6a, 0x8d, 0x6a, 0xa0, 0x6a, 0x84, 0x6a, 0xa2, + 0x6a, 0xa3, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x6a, 0x97, 0x86, 0x17, 0x6a, 0xbb, 0x6a, 0xc3, + 0x6a, 0xc2, 0x6a, 0xb8, 0x6a, 0xb3, 0x6a, 0xac, + 0x6a, 0xde, 0x6a, 0xd1, 0x6a, 0xdf, 0x6a, 0xaa, + 0x6a, 0xda, 0x6a, 0xea, 0x6a, 0xfb, 0x6b, 0x05, + 0x86, 0x16, 0x6a, 0xfa, 0x6b, 0x12, 0x6b, 0x16, + 0x9b, 0x31, 0x6b, 0x1f, 0x6b, 0x38, 0x6b, 0x37, + 0x76, 0xdc, 0x6b, 0x39, 0x98, 0xee, 0x6b, 0x47, + 0x6b, 0x43, 0x6b, 0x49, 0x6b, 0x50, 0x6b, 0x59, + 0x6b, 0x54, 0x6b, 0x5b, 0x6b, 0x5f, 0x6b, 0x61, + 0x6b, 0x78, 0x6b, 0x79, 0x6b, 0x7f, 0x6b, 0x80, + 0x6b, 0x84, 0x6b, 0x83, 0x6b, 0x8d, 0x6b, 0x98, + 0x6b, 0x95, 0x6b, 0x9e, 0x6b, 0xa4, 0x6b, 0xaa, + 0x6b, 0xab, 0x6b, 0xaf, 0x6b, 0xb2, 0x6b, 0xb1, + 0x6b, 0xb3, 0x6b, 0xb7, 0x6b, 0xbc, 0x6b, 0xc6, + 0x6b, 0xcb, 0x6b, 0xd3, 0x6b, 0xdf, 0x6b, 0xec, + 0x6b, 0xeb, 0x6b, 0xf3, 0x6b, 0xef, 0x00, 0x20, + 0x9e, 0xbe, 0x6c, 0x08, 0x6c, 0x13, 0x6c, 0x14, + 0x6c, 0x1b, 0x6c, 0x24, 0x6c, 0x23, 0x6c, 0x5e, + 0x6c, 0x55, 0x6c, 0x62, 0x6c, 0x6a, 0x6c, 0x82, + 0x6c, 0x8d, 0x6c, 0x9a, 0x6c, 0x81, 0x6c, 0x9b, + 0x6c, 0x7e, 0x6c, 0x68, 0x6c, 0x73, 0x6c, 0x92, + 0x6c, 0x90, 0x6c, 0xc4, 0x6c, 0xf1, 0x6c, 0xd3, + 0x6c, 0xbd, 0x6c, 0xd7, 0x6c, 0xc5, 0x6c, 0xdd, + 0x6c, 0xae, 0x6c, 0xb1, 0x6c, 0xbe, 0x6c, 0xba, + 0x6c, 0xdb, 0x6c, 0xef, 0x6c, 0xd9, 0x6c, 0xea, + 0x6d, 0x1f, 0x88, 0x4d, 0x6d, 0x36, 0x6d, 0x2b, + 0x6d, 0x3d, 0x6d, 0x38, 0x6d, 0x19, 0x6d, 0x35, + 0x6d, 0x33, 0x6d, 0x12, 0x6d, 0x0c, 0x6d, 0x63, + 0x6d, 0x93, 0x6d, 0x64, 0x6d, 0x5a, 0x6d, 0x79, + 0x6d, 0x59, 0x6d, 0x8e, 0x6d, 0x95, 0x6f, 0xe4, + 0x6d, 0x85, 0x6d, 0xf9, 0x6e, 0x15, 0x6e, 0x0a, + 0x6d, 0xb5, 0x6d, 0xc7, 0x6d, 0xe6, 0x6d, 0xb8, + 0x6d, 0xc6, 0x6d, 0xec, 0x6d, 0xde, 0x6d, 0xcc, + 0x6d, 0xe8, 0x6d, 0xd2, 0x6d, 0xc5, 0x6d, 0xfa, + 0x6d, 0xd9, 0x6d, 0xe4, 0x6d, 0xd5, 0x6d, 0xea, + 0x6d, 0xee, 0x6e, 0x2d, 0x6e, 0x6e, 0x6e, 0x2e, + 0x6e, 0x19, 0x6e, 0x72, 0x6e, 0x5f, 0x6e, 0x3e, + 0x6e, 0x23, 0x6e, 0x6b, 0x6e, 0x2b, 0x6e, 0x76, + 0x6e, 0x4d, 0x6e, 0x1f, 0x6e, 0x43, 0x6e, 0x3a, + 0x6e, 0x4e, 0x6e, 0x24, 0x6e, 0xff, 0x6e, 0x1d, + 0x6e, 0x38, 0x6e, 0x82, 0x6e, 0xaa, 0x6e, 0x98, + 0x6e, 0xc9, 0x6e, 0xb7, 0x6e, 0xd3, 0x6e, 0xbd, + 0x6e, 0xaf, 0x6e, 0xc4, 0x6e, 0xb2, 0x6e, 0xd4, + 0x6e, 0xd5, 0x6e, 0x8f, 0x6e, 0xa5, 0x6e, 0xc2, + 0x6e, 0x9f, 0x6f, 0x41, 0x6f, 0x11, 0x70, 0x4c, + 0x6e, 0xec, 0x6e, 0xf8, 0x6e, 0xfe, 0x6f, 0x3f, + 0x6e, 0xf2, 0x6f, 0x31, 0x6e, 0xef, 0x6f, 0x32, + 0x6e, 0xcc, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x6f, 0x3e, 0x6f, 0x13, 0x6e, 0xf7, 0x6f, 0x86, + 0x6f, 0x7a, 0x6f, 0x78, 0x6f, 0x81, 0x6f, 0x80, + 0x6f, 0x6f, 0x6f, 0x5b, 0x6f, 0xf3, 0x6f, 0x6d, + 0x6f, 0x82, 0x6f, 0x7c, 0x6f, 0x58, 0x6f, 0x8e, + 0x6f, 0x91, 0x6f, 0xc2, 0x6f, 0x66, 0x6f, 0xb3, + 0x6f, 0xa3, 0x6f, 0xa1, 0x6f, 0xa4, 0x6f, 0xb9, + 0x6f, 0xc6, 0x6f, 0xaa, 0x6f, 0xdf, 0x6f, 0xd5, + 0x6f, 0xec, 0x6f, 0xd4, 0x6f, 0xd8, 0x6f, 0xf1, + 0x6f, 0xee, 0x6f, 0xdb, 0x70, 0x09, 0x70, 0x0b, + 0x6f, 0xfa, 0x70, 0x11, 0x70, 0x01, 0x70, 0x0f, + 0x6f, 0xfe, 0x70, 0x1b, 0x70, 0x1a, 0x6f, 0x74, + 0x70, 0x1d, 0x70, 0x18, 0x70, 0x1f, 0x70, 0x30, + 0x70, 0x3e, 0x70, 0x32, 0x70, 0x51, 0x70, 0x63, + 0x70, 0x99, 0x70, 0x92, 0x70, 0xaf, 0x70, 0xf1, + 0x70, 0xac, 0x70, 0xb8, 0x70, 0xb3, 0x70, 0xae, + 0x70, 0xdf, 0x70, 0xcb, 0x70, 0xdd, 0x00, 0x20, + 0x70, 0xd9, 0x71, 0x09, 0x70, 0xfd, 0x71, 0x1c, + 0x71, 0x19, 0x71, 0x65, 0x71, 0x55, 0x71, 0x88, + 0x71, 0x66, 0x71, 0x62, 0x71, 0x4c, 0x71, 0x56, + 0x71, 0x6c, 0x71, 0x8f, 0x71, 0xfb, 0x71, 0x84, + 0x71, 0x95, 0x71, 0xa8, 0x71, 0xac, 0x71, 0xd7, + 0x71, 0xb9, 0x71, 0xbe, 0x71, 0xd2, 0x71, 0xc9, + 0x71, 0xd4, 0x71, 0xce, 0x71, 0xe0, 0x71, 0xec, + 0x71, 0xe7, 0x71, 0xf5, 0x71, 0xfc, 0x71, 0xf9, + 0x71, 0xff, 0x72, 0x0d, 0x72, 0x10, 0x72, 0x1b, + 0x72, 0x28, 0x72, 0x2d, 0x72, 0x2c, 0x72, 0x30, + 0x72, 0x32, 0x72, 0x3b, 0x72, 0x3c, 0x72, 0x3f, + 0x72, 0x40, 0x72, 0x46, 0x72, 0x4b, 0x72, 0x58, + 0x72, 0x74, 0x72, 0x7e, 0x72, 0x82, 0x72, 0x81, + 0x72, 0x87, 0x72, 0x92, 0x72, 0x96, 0x72, 0xa2, + 0x72, 0xa7, 0x72, 0xb9, 0x72, 0xb2, 0x72, 0xc3, + 0x72, 0xc6, 0x72, 0xc4, 0x72, 0xce, 0x72, 0xd2, + 0x72, 0xe2, 0x72, 0xe0, 0x72, 0xe1, 0x72, 0xf9, + 0x72, 0xf7, 0x50, 0x0f, 0x73, 0x17, 0x73, 0x0a, + 0x73, 0x1c, 0x73, 0x16, 0x73, 0x1d, 0x73, 0x34, + 0x73, 0x2f, 0x73, 0x29, 0x73, 0x25, 0x73, 0x3e, + 0x73, 0x4e, 0x73, 0x4f, 0x9e, 0xd8, 0x73, 0x57, + 0x73, 0x6a, 0x73, 0x68, 0x73, 0x70, 0x73, 0x78, + 0x73, 0x75, 0x73, 0x7b, 0x73, 0x7a, 0x73, 0xc8, + 0x73, 0xb3, 0x73, 0xce, 0x73, 0xbb, 0x73, 0xc0, + 0x73, 0xe5, 0x73, 0xee, 0x73, 0xde, 0x74, 0xa2, + 0x74, 0x05, 0x74, 0x6f, 0x74, 0x25, 0x73, 0xf8, + 0x74, 0x32, 0x74, 0x3a, 0x74, 0x55, 0x74, 0x3f, + 0x74, 0x5f, 0x74, 0x59, 0x74, 0x41, 0x74, 0x5c, + 0x74, 0x69, 0x74, 0x70, 0x74, 0x63, 0x74, 0x6a, + 0x74, 0x76, 0x74, 0x7e, 0x74, 0x8b, 0x74, 0x9e, + 0x74, 0xa7, 0x74, 0xca, 0x74, 0xcf, 0x74, 0xd4, + 0x73, 0xf1, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x74, 0xe0, 0x74, 0xe3, 0x74, 0xe7, 0x74, 0xe9, + 0x74, 0xee, 0x74, 0xf2, 0x74, 0xf0, 0x74, 0xf1, + 0x74, 0xf8, 0x74, 0xf7, 0x75, 0x04, 0x75, 0x03, + 0x75, 0x05, 0x75, 0x0c, 0x75, 0x0e, 0x75, 0x0d, + 0x75, 0x15, 0x75, 0x13, 0x75, 0x1e, 0x75, 0x26, + 0x75, 0x2c, 0x75, 0x3c, 0x75, 0x44, 0x75, 0x4d, + 0x75, 0x4a, 0x75, 0x49, 0x75, 0x5b, 0x75, 0x46, + 0x75, 0x5a, 0x75, 0x69, 0x75, 0x64, 0x75, 0x67, + 0x75, 0x6b, 0x75, 0x6d, 0x75, 0x78, 0x75, 0x76, + 0x75, 0x86, 0x75, 0x87, 0x75, 0x74, 0x75, 0x8a, + 0x75, 0x89, 0x75, 0x82, 0x75, 0x94, 0x75, 0x9a, + 0x75, 0x9d, 0x75, 0xa5, 0x75, 0xa3, 0x75, 0xc2, + 0x75, 0xb3, 0x75, 0xc3, 0x75, 0xb5, 0x75, 0xbd, + 0x75, 0xb8, 0x75, 0xbc, 0x75, 0xb1, 0x75, 0xcd, + 0x75, 0xca, 0x75, 0xd2, 0x75, 0xd9, 0x75, 0xe3, + 0x75, 0xde, 0x75, 0xfe, 0x75, 0xff, 0x00, 0x20, + 0x75, 0xfc, 0x76, 0x01, 0x75, 0xf0, 0x75, 0xfa, + 0x75, 0xf2, 0x75, 0xf3, 0x76, 0x0b, 0x76, 0x0d, + 0x76, 0x09, 0x76, 0x1f, 0x76, 0x27, 0x76, 0x20, + 0x76, 0x21, 0x76, 0x22, 0x76, 0x24, 0x76, 0x34, + 0x76, 0x30, 0x76, 0x3b, 0x76, 0x47, 0x76, 0x48, + 0x76, 0x46, 0x76, 0x5c, 0x76, 0x58, 0x76, 0x61, + 0x76, 0x62, 0x76, 0x68, 0x76, 0x69, 0x76, 0x6a, + 0x76, 0x67, 0x76, 0x6c, 0x76, 0x70, 0x76, 0x72, + 0x76, 0x76, 0x76, 0x78, 0x76, 0x7c, 0x76, 0x80, + 0x76, 0x83, 0x76, 0x88, 0x76, 0x8b, 0x76, 0x8e, + 0x76, 0x96, 0x76, 0x93, 0x76, 0x99, 0x76, 0x9a, + 0x76, 0xb0, 0x76, 0xb4, 0x76, 0xb8, 0x76, 0xb9, + 0x76, 0xba, 0x76, 0xc2, 0x76, 0xcd, 0x76, 0xd6, + 0x76, 0xd2, 0x76, 0xde, 0x76, 0xe1, 0x76, 0xe5, + 0x76, 0xe7, 0x76, 0xea, 0x86, 0x2f, 0x76, 0xfb, + 0x77, 0x08, 0x77, 0x07, 0x77, 0x04, 0x77, 0x29, + 0x77, 0x24, 0x77, 0x1e, 0x77, 0x25, 0x77, 0x26, + 0x77, 0x1b, 0x77, 0x37, 0x77, 0x38, 0x77, 0x47, + 0x77, 0x5a, 0x77, 0x68, 0x77, 0x6b, 0x77, 0x5b, + 0x77, 0x65, 0x77, 0x7f, 0x77, 0x7e, 0x77, 0x79, + 0x77, 0x8e, 0x77, 0x8b, 0x77, 0x91, 0x77, 0xa0, + 0x77, 0x9e, 0x77, 0xb0, 0x77, 0xb6, 0x77, 0xb9, + 0x77, 0xbf, 0x77, 0xbc, 0x77, 0xbd, 0x77, 0xbb, + 0x77, 0xc7, 0x77, 0xcd, 0x77, 0xd7, 0x77, 0xda, + 0x77, 0xdc, 0x77, 0xe3, 0x77, 0xee, 0x77, 0xfc, + 0x78, 0x0c, 0x78, 0x12, 0x79, 0x26, 0x78, 0x20, + 0x79, 0x2a, 0x78, 0x45, 0x78, 0x8e, 0x78, 0x74, + 0x78, 0x86, 0x78, 0x7c, 0x78, 0x9a, 0x78, 0x8c, + 0x78, 0xa3, 0x78, 0xb5, 0x78, 0xaa, 0x78, 0xaf, + 0x78, 0xd1, 0x78, 0xc6, 0x78, 0xcb, 0x78, 0xd4, + 0x78, 0xbe, 0x78, 0xbc, 0x78, 0xc5, 0x78, 0xca, + 0x78, 0xec, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x78, 0xe7, 0x78, 0xda, 0x78, 0xfd, 0x78, 0xf4, + 0x79, 0x07, 0x79, 0x12, 0x79, 0x11, 0x79, 0x19, + 0x79, 0x2c, 0x79, 0x2b, 0x79, 0x40, 0x79, 0x60, + 0x79, 0x57, 0x79, 0x5f, 0x79, 0x5a, 0x79, 0x55, + 0x79, 0x53, 0x79, 0x7a, 0x79, 0x7f, 0x79, 0x8a, + 0x79, 0x9d, 0x79, 0xa7, 0x9f, 0x4b, 0x79, 0xaa, + 0x79, 0xae, 0x79, 0xb3, 0x79, 0xb9, 0x79, 0xba, + 0x79, 0xc9, 0x79, 0xd5, 0x79, 0xe7, 0x79, 0xec, + 0x79, 0xe1, 0x79, 0xe3, 0x7a, 0x08, 0x7a, 0x0d, + 0x7a, 0x18, 0x7a, 0x19, 0x7a, 0x20, 0x7a, 0x1f, + 0x79, 0x80, 0x7a, 0x31, 0x7a, 0x3b, 0x7a, 0x3e, + 0x7a, 0x37, 0x7a, 0x43, 0x7a, 0x57, 0x7a, 0x49, + 0x7a, 0x61, 0x7a, 0x62, 0x7a, 0x69, 0x9f, 0x9d, + 0x7a, 0x70, 0x7a, 0x79, 0x7a, 0x7d, 0x7a, 0x88, + 0x7a, 0x97, 0x7a, 0x95, 0x7a, 0x98, 0x7a, 0x96, + 0x7a, 0xa9, 0x7a, 0xc8, 0x7a, 0xb0, 0x00, 0x20, + 0x7a, 0xb6, 0x7a, 0xc5, 0x7a, 0xc4, 0x7a, 0xbf, + 0x90, 0x83, 0x7a, 0xc7, 0x7a, 0xca, 0x7a, 0xcd, + 0x7a, 0xcf, 0x7a, 0xd5, 0x7a, 0xd3, 0x7a, 0xd9, + 0x7a, 0xda, 0x7a, 0xdd, 0x7a, 0xe1, 0x7a, 0xe2, + 0x7a, 0xe6, 0x7a, 0xed, 0x7a, 0xf0, 0x7b, 0x02, + 0x7b, 0x0f, 0x7b, 0x0a, 0x7b, 0x06, 0x7b, 0x33, + 0x7b, 0x18, 0x7b, 0x19, 0x7b, 0x1e, 0x7b, 0x35, + 0x7b, 0x28, 0x7b, 0x36, 0x7b, 0x50, 0x7b, 0x7a, + 0x7b, 0x04, 0x7b, 0x4d, 0x7b, 0x0b, 0x7b, 0x4c, + 0x7b, 0x45, 0x7b, 0x75, 0x7b, 0x65, 0x7b, 0x74, + 0x7b, 0x67, 0x7b, 0x70, 0x7b, 0x71, 0x7b, 0x6c, + 0x7b, 0x6e, 0x7b, 0x9d, 0x7b, 0x98, 0x7b, 0x9f, + 0x7b, 0x8d, 0x7b, 0x9c, 0x7b, 0x9a, 0x7b, 0x8b, + 0x7b, 0x92, 0x7b, 0x8f, 0x7b, 0x5d, 0x7b, 0x99, + 0x7b, 0xcb, 0x7b, 0xc1, 0x7b, 0xcc, 0x7b, 0xcf, + 0x7b, 0xb4, 0x7b, 0xc6, 0x7b, 0xdd, 0x7b, 0xe9, + 0x7c, 0x11, 0x7c, 0x14, 0x7b, 0xe6, 0x7b, 0xe5, + 0x7c, 0x60, 0x7c, 0x00, 0x7c, 0x07, 0x7c, 0x13, + 0x7b, 0xf3, 0x7b, 0xf7, 0x7c, 0x17, 0x7c, 0x0d, + 0x7b, 0xf6, 0x7c, 0x23, 0x7c, 0x27, 0x7c, 0x2a, + 0x7c, 0x1f, 0x7c, 0x37, 0x7c, 0x2b, 0x7c, 0x3d, + 0x7c, 0x4c, 0x7c, 0x43, 0x7c, 0x54, 0x7c, 0x4f, + 0x7c, 0x40, 0x7c, 0x50, 0x7c, 0x58, 0x7c, 0x5f, + 0x7c, 0x64, 0x7c, 0x56, 0x7c, 0x65, 0x7c, 0x6c, + 0x7c, 0x75, 0x7c, 0x83, 0x7c, 0x90, 0x7c, 0xa4, + 0x7c, 0xad, 0x7c, 0xa2, 0x7c, 0xab, 0x7c, 0xa1, + 0x7c, 0xa8, 0x7c, 0xb3, 0x7c, 0xb2, 0x7c, 0xb1, + 0x7c, 0xae, 0x7c, 0xb9, 0x7c, 0xbd, 0x7c, 0xc0, + 0x7c, 0xc5, 0x7c, 0xc2, 0x7c, 0xd8, 0x7c, 0xd2, + 0x7c, 0xdc, 0x7c, 0xe2, 0x9b, 0x3b, 0x7c, 0xef, + 0x7c, 0xf2, 0x7c, 0xf4, 0x7c, 0xf6, 0x7c, 0xfa, + 0x7d, 0x06, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x7d, 0x02, 0x7d, 0x1c, 0x7d, 0x15, 0x7d, 0x0a, + 0x7d, 0x45, 0x7d, 0x4b, 0x7d, 0x2e, 0x7d, 0x32, + 0x7d, 0x3f, 0x7d, 0x35, 0x7d, 0x46, 0x7d, 0x73, + 0x7d, 0x56, 0x7d, 0x4e, 0x7d, 0x72, 0x7d, 0x68, + 0x7d, 0x6e, 0x7d, 0x4f, 0x7d, 0x63, 0x7d, 0x93, + 0x7d, 0x89, 0x7d, 0x5b, 0x7d, 0x8f, 0x7d, 0x7d, + 0x7d, 0x9b, 0x7d, 0xba, 0x7d, 0xae, 0x7d, 0xa3, + 0x7d, 0xb5, 0x7d, 0xc7, 0x7d, 0xbd, 0x7d, 0xab, + 0x7e, 0x3d, 0x7d, 0xa2, 0x7d, 0xaf, 0x7d, 0xdc, + 0x7d, 0xb8, 0x7d, 0x9f, 0x7d, 0xb0, 0x7d, 0xd8, + 0x7d, 0xdd, 0x7d, 0xe4, 0x7d, 0xde, 0x7d, 0xfb, + 0x7d, 0xf2, 0x7d, 0xe1, 0x7e, 0x05, 0x7e, 0x0a, + 0x7e, 0x23, 0x7e, 0x21, 0x7e, 0x12, 0x7e, 0x31, + 0x7e, 0x1f, 0x7e, 0x09, 0x7e, 0x0b, 0x7e, 0x22, + 0x7e, 0x46, 0x7e, 0x66, 0x7e, 0x3b, 0x7e, 0x35, + 0x7e, 0x39, 0x7e, 0x43, 0x7e, 0x37, 0x00, 0x20, + 0x7e, 0x32, 0x7e, 0x3a, 0x7e, 0x67, 0x7e, 0x5d, + 0x7e, 0x56, 0x7e, 0x5e, 0x7e, 0x59, 0x7e, 0x5a, + 0x7e, 0x79, 0x7e, 0x6a, 0x7e, 0x69, 0x7e, 0x7c, + 0x7e, 0x7b, 0x7e, 0x83, 0x7d, 0xd5, 0x7e, 0x7d, + 0x8f, 0xae, 0x7e, 0x7f, 0x7e, 0x88, 0x7e, 0x89, + 0x7e, 0x8c, 0x7e, 0x92, 0x7e, 0x90, 0x7e, 0x93, + 0x7e, 0x94, 0x7e, 0x96, 0x7e, 0x8e, 0x7e, 0x9b, + 0x7e, 0x9c, 0x7f, 0x38, 0x7f, 0x3a, 0x7f, 0x45, + 0x7f, 0x4c, 0x7f, 0x4d, 0x7f, 0x4e, 0x7f, 0x50, + 0x7f, 0x51, 0x7f, 0x55, 0x7f, 0x54, 0x7f, 0x58, + 0x7f, 0x5f, 0x7f, 0x60, 0x7f, 0x68, 0x7f, 0x69, + 0x7f, 0x67, 0x7f, 0x78, 0x7f, 0x82, 0x7f, 0x86, + 0x7f, 0x83, 0x7f, 0x88, 0x7f, 0x87, 0x7f, 0x8c, + 0x7f, 0x94, 0x7f, 0x9e, 0x7f, 0x9d, 0x7f, 0x9a, + 0x7f, 0xa3, 0x7f, 0xaf, 0x7f, 0xb2, 0x7f, 0xb9, + 0x7f, 0xae, 0x7f, 0xb6, 0x7f, 0xb8, 0x8b, 0x71, + 0x7f, 0xc5, 0x7f, 0xc6, 0x7f, 0xca, 0x7f, 0xd5, + 0x7f, 0xd4, 0x7f, 0xe1, 0x7f, 0xe6, 0x7f, 0xe9, + 0x7f, 0xf3, 0x7f, 0xf9, 0x98, 0xdc, 0x80, 0x06, + 0x80, 0x04, 0x80, 0x0b, 0x80, 0x12, 0x80, 0x18, + 0x80, 0x19, 0x80, 0x1c, 0x80, 0x21, 0x80, 0x28, + 0x80, 0x3f, 0x80, 0x3b, 0x80, 0x4a, 0x80, 0x46, + 0x80, 0x52, 0x80, 0x58, 0x80, 0x5a, 0x80, 0x5f, + 0x80, 0x62, 0x80, 0x68, 0x80, 0x73, 0x80, 0x72, + 0x80, 0x70, 0x80, 0x76, 0x80, 0x79, 0x80, 0x7d, + 0x80, 0x7f, 0x80, 0x84, 0x80, 0x86, 0x80, 0x85, + 0x80, 0x9b, 0x80, 0x93, 0x80, 0x9a, 0x80, 0xad, + 0x51, 0x90, 0x80, 0xac, 0x80, 0xdb, 0x80, 0xe5, + 0x80, 0xd9, 0x80, 0xdd, 0x80, 0xc4, 0x80, 0xda, + 0x80, 0xd6, 0x81, 0x09, 0x80, 0xef, 0x80, 0xf1, + 0x81, 0x1b, 0x81, 0x29, 0x81, 0x23, 0x81, 0x2f, + 0x81, 0x4b, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x96, 0x8b, 0x81, 0x46, 0x81, 0x3e, 0x81, 0x53, + 0x81, 0x51, 0x80, 0xfc, 0x81, 0x71, 0x81, 0x6e, + 0x81, 0x65, 0x81, 0x66, 0x81, 0x74, 0x81, 0x83, + 0x81, 0x88, 0x81, 0x8a, 0x81, 0x80, 0x81, 0x82, + 0x81, 0xa0, 0x81, 0x95, 0x81, 0xa4, 0x81, 0xa3, + 0x81, 0x5f, 0x81, 0x93, 0x81, 0xa9, 0x81, 0xb0, + 0x81, 0xb5, 0x81, 0xbe, 0x81, 0xb8, 0x81, 0xbd, + 0x81, 0xc0, 0x81, 0xc2, 0x81, 0xba, 0x81, 0xc9, + 0x81, 0xcd, 0x81, 0xd1, 0x81, 0xd9, 0x81, 0xd8, + 0x81, 0xc8, 0x81, 0xda, 0x81, 0xdf, 0x81, 0xe0, + 0x81, 0xe7, 0x81, 0xfa, 0x81, 0xfb, 0x81, 0xfe, + 0x82, 0x01, 0x82, 0x02, 0x82, 0x05, 0x82, 0x07, + 0x82, 0x0a, 0x82, 0x0d, 0x82, 0x10, 0x82, 0x16, + 0x82, 0x29, 0x82, 0x2b, 0x82, 0x38, 0x82, 0x33, + 0x82, 0x40, 0x82, 0x59, 0x82, 0x58, 0x82, 0x5d, + 0x82, 0x5a, 0x82, 0x5f, 0x82, 0x64, 0x00, 0x20, + 0x82, 0x62, 0x82, 0x68, 0x82, 0x6a, 0x82, 0x6b, + 0x82, 0x2e, 0x82, 0x71, 0x82, 0x77, 0x82, 0x78, + 0x82, 0x7e, 0x82, 0x8d, 0x82, 0x92, 0x82, 0xab, + 0x82, 0x9f, 0x82, 0xbb, 0x82, 0xac, 0x82, 0xe1, + 0x82, 0xe3, 0x82, 0xdf, 0x82, 0xd2, 0x82, 0xf4, + 0x82, 0xf3, 0x82, 0xfa, 0x83, 0x93, 0x83, 0x03, + 0x82, 0xfb, 0x82, 0xf9, 0x82, 0xde, 0x83, 0x06, + 0x82, 0xdc, 0x83, 0x09, 0x82, 0xd9, 0x83, 0x35, + 0x83, 0x34, 0x83, 0x16, 0x83, 0x32, 0x83, 0x31, + 0x83, 0x40, 0x83, 0x39, 0x83, 0x50, 0x83, 0x45, + 0x83, 0x2f, 0x83, 0x2b, 0x83, 0x17, 0x83, 0x18, + 0x83, 0x85, 0x83, 0x9a, 0x83, 0xaa, 0x83, 0x9f, + 0x83, 0xa2, 0x83, 0x96, 0x83, 0x23, 0x83, 0x8e, + 0x83, 0x87, 0x83, 0x8a, 0x83, 0x7c, 0x83, 0xb5, + 0x83, 0x73, 0x83, 0x75, 0x83, 0xa0, 0x83, 0x89, + 0x83, 0xa8, 0x83, 0xf4, 0x84, 0x13, 0x83, 0xeb, + 0x83, 0xce, 0x83, 0xfd, 0x84, 0x03, 0x83, 0xd8, + 0x84, 0x0b, 0x83, 0xc1, 0x83, 0xf7, 0x84, 0x07, + 0x83, 0xe0, 0x83, 0xf2, 0x84, 0x0d, 0x84, 0x22, + 0x84, 0x20, 0x83, 0xbd, 0x84, 0x38, 0x85, 0x06, + 0x83, 0xfb, 0x84, 0x6d, 0x84, 0x2a, 0x84, 0x3c, + 0x85, 0x5a, 0x84, 0x84, 0x84, 0x77, 0x84, 0x6b, + 0x84, 0xad, 0x84, 0x6e, 0x84, 0x82, 0x84, 0x69, + 0x84, 0x46, 0x84, 0x2c, 0x84, 0x6f, 0x84, 0x79, + 0x84, 0x35, 0x84, 0xca, 0x84, 0x62, 0x84, 0xb9, + 0x84, 0xbf, 0x84, 0x9f, 0x84, 0xd9, 0x84, 0xcd, + 0x84, 0xbb, 0x84, 0xda, 0x84, 0xd0, 0x84, 0xc1, + 0x84, 0xc6, 0x84, 0xd6, 0x84, 0xa1, 0x85, 0x21, + 0x84, 0xff, 0x84, 0xf4, 0x85, 0x17, 0x85, 0x18, + 0x85, 0x2c, 0x85, 0x1f, 0x85, 0x15, 0x85, 0x14, + 0x84, 0xfc, 0x85, 0x40, 0x85, 0x63, 0x85, 0x58, + 0x85, 0x48, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x85, 0x41, 0x86, 0x02, 0x85, 0x4b, 0x85, 0x55, + 0x85, 0x80, 0x85, 0xa4, 0x85, 0x88, 0x85, 0x91, + 0x85, 0x8a, 0x85, 0xa8, 0x85, 0x6d, 0x85, 0x94, + 0x85, 0x9b, 0x85, 0xea, 0x85, 0x87, 0x85, 0x9c, + 0x85, 0x77, 0x85, 0x7e, 0x85, 0x90, 0x85, 0xc9, + 0x85, 0xba, 0x85, 0xcf, 0x85, 0xb9, 0x85, 0xd0, + 0x85, 0xd5, 0x85, 0xdd, 0x85, 0xe5, 0x85, 0xdc, + 0x85, 0xf9, 0x86, 0x0a, 0x86, 0x13, 0x86, 0x0b, + 0x85, 0xfe, 0x85, 0xfa, 0x86, 0x06, 0x86, 0x22, + 0x86, 0x1a, 0x86, 0x30, 0x86, 0x3f, 0x86, 0x4d, + 0x4e, 0x55, 0x86, 0x54, 0x86, 0x5f, 0x86, 0x67, + 0x86, 0x71, 0x86, 0x93, 0x86, 0xa3, 0x86, 0xa9, + 0x86, 0xaa, 0x86, 0x8b, 0x86, 0x8c, 0x86, 0xb6, + 0x86, 0xaf, 0x86, 0xc4, 0x86, 0xc6, 0x86, 0xb0, + 0x86, 0xc9, 0x88, 0x23, 0x86, 0xab, 0x86, 0xd4, + 0x86, 0xde, 0x86, 0xe9, 0x86, 0xec, 0x00, 0x20, + 0x86, 0xdf, 0x86, 0xdb, 0x86, 0xef, 0x87, 0x12, + 0x87, 0x06, 0x87, 0x08, 0x87, 0x00, 0x87, 0x03, + 0x86, 0xfb, 0x87, 0x11, 0x87, 0x09, 0x87, 0x0d, + 0x86, 0xf9, 0x87, 0x0a, 0x87, 0x34, 0x87, 0x3f, + 0x87, 0x37, 0x87, 0x3b, 0x87, 0x25, 0x87, 0x29, + 0x87, 0x1a, 0x87, 0x60, 0x87, 0x5f, 0x87, 0x78, + 0x87, 0x4c, 0x87, 0x4e, 0x87, 0x74, 0x87, 0x57, + 0x87, 0x68, 0x87, 0x6e, 0x87, 0x59, 0x87, 0x53, + 0x87, 0x63, 0x87, 0x6a, 0x88, 0x05, 0x87, 0xa2, + 0x87, 0x9f, 0x87, 0x82, 0x87, 0xaf, 0x87, 0xcb, + 0x87, 0xbd, 0x87, 0xc0, 0x87, 0xd0, 0x96, 0xd6, + 0x87, 0xab, 0x87, 0xc4, 0x87, 0xb3, 0x87, 0xc7, + 0x87, 0xc6, 0x87, 0xbb, 0x87, 0xef, 0x87, 0xf2, + 0x87, 0xe0, 0x88, 0x0f, 0x88, 0x0d, 0x87, 0xfe, + 0x87, 0xf6, 0x87, 0xf7, 0x88, 0x0e, 0x87, 0xd2, + 0x88, 0x11, 0x88, 0x16, 0x88, 0x15, 0x88, 0x22, + 0x88, 0x21, 0x88, 0x31, 0x88, 0x36, 0x88, 0x39, + 0x88, 0x27, 0x88, 0x3b, 0x88, 0x44, 0x88, 0x42, + 0x88, 0x52, 0x88, 0x59, 0x88, 0x5e, 0x88, 0x62, + 0x88, 0x6b, 0x88, 0x81, 0x88, 0x7e, 0x88, 0x9e, + 0x88, 0x75, 0x88, 0x7d, 0x88, 0xb5, 0x88, 0x72, + 0x88, 0x82, 0x88, 0x97, 0x88, 0x92, 0x88, 0xae, + 0x88, 0x99, 0x88, 0xa2, 0x88, 0x8d, 0x88, 0xa4, + 0x88, 0xb0, 0x88, 0xbf, 0x88, 0xb1, 0x88, 0xc3, + 0x88, 0xc4, 0x88, 0xd4, 0x88, 0xd8, 0x88, 0xd9, + 0x88, 0xdd, 0x88, 0xf9, 0x89, 0x02, 0x88, 0xfc, + 0x88, 0xf4, 0x88, 0xe8, 0x88, 0xf2, 0x89, 0x04, + 0x89, 0x0c, 0x89, 0x0a, 0x89, 0x13, 0x89, 0x43, + 0x89, 0x1e, 0x89, 0x25, 0x89, 0x2a, 0x89, 0x2b, + 0x89, 0x41, 0x89, 0x44, 0x89, 0x3b, 0x89, 0x36, + 0x89, 0x38, 0x89, 0x4c, 0x89, 0x1d, 0x89, 0x60, + 0x89, 0x5e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x89, 0x66, 0x89, 0x64, 0x89, 0x6d, 0x89, 0x6a, + 0x89, 0x6f, 0x89, 0x74, 0x89, 0x77, 0x89, 0x7e, + 0x89, 0x83, 0x89, 0x88, 0x89, 0x8a, 0x89, 0x93, + 0x89, 0x98, 0x89, 0xa1, 0x89, 0xa9, 0x89, 0xa6, + 0x89, 0xac, 0x89, 0xaf, 0x89, 0xb2, 0x89, 0xba, + 0x89, 0xbd, 0x89, 0xbf, 0x89, 0xc0, 0x89, 0xda, + 0x89, 0xdc, 0x89, 0xdd, 0x89, 0xe7, 0x89, 0xf4, + 0x89, 0xf8, 0x8a, 0x03, 0x8a, 0x16, 0x8a, 0x10, + 0x8a, 0x0c, 0x8a, 0x1b, 0x8a, 0x1d, 0x8a, 0x25, + 0x8a, 0x36, 0x8a, 0x41, 0x8a, 0x5b, 0x8a, 0x52, + 0x8a, 0x46, 0x8a, 0x48, 0x8a, 0x7c, 0x8a, 0x6d, + 0x8a, 0x6c, 0x8a, 0x62, 0x8a, 0x85, 0x8a, 0x82, + 0x8a, 0x84, 0x8a, 0xa8, 0x8a, 0xa1, 0x8a, 0x91, + 0x8a, 0xa5, 0x8a, 0xa6, 0x8a, 0x9a, 0x8a, 0xa3, + 0x8a, 0xc4, 0x8a, 0xcd, 0x8a, 0xc2, 0x8a, 0xda, + 0x8a, 0xeb, 0x8a, 0xf3, 0x8a, 0xe7, 0x00, 0x20, + 0x8a, 0xe4, 0x8a, 0xf1, 0x8b, 0x14, 0x8a, 0xe0, + 0x8a, 0xe2, 0x8a, 0xf7, 0x8a, 0xde, 0x8a, 0xdb, + 0x8b, 0x0c, 0x8b, 0x07, 0x8b, 0x1a, 0x8a, 0xe1, + 0x8b, 0x16, 0x8b, 0x10, 0x8b, 0x17, 0x8b, 0x20, + 0x8b, 0x33, 0x97, 0xab, 0x8b, 0x26, 0x8b, 0x2b, + 0x8b, 0x3e, 0x8b, 0x28, 0x8b, 0x41, 0x8b, 0x4c, + 0x8b, 0x4f, 0x8b, 0x4e, 0x8b, 0x49, 0x8b, 0x56, + 0x8b, 0x5b, 0x8b, 0x5a, 0x8b, 0x6b, 0x8b, 0x5f, + 0x8b, 0x6c, 0x8b, 0x6f, 0x8b, 0x74, 0x8b, 0x7d, + 0x8b, 0x80, 0x8b, 0x8c, 0x8b, 0x8e, 0x8b, 0x92, + 0x8b, 0x93, 0x8b, 0x96, 0x8b, 0x99, 0x8b, 0x9a, + 0x8c, 0x3a, 0x8c, 0x41, 0x8c, 0x3f, 0x8c, 0x48, + 0x8c, 0x4c, 0x8c, 0x4e, 0x8c, 0x50, 0x8c, 0x55, + 0x8c, 0x62, 0x8c, 0x6c, 0x8c, 0x78, 0x8c, 0x7a, + 0x8c, 0x82, 0x8c, 0x89, 0x8c, 0x85, 0x8c, 0x8a, + 0x8c, 0x8d, 0x8c, 0x8e, 0x8c, 0x94, 0x8c, 0x7c, + 0x8c, 0x98, 0x62, 0x1d, 0x8c, 0xad, 0x8c, 0xaa, + 0x8c, 0xbd, 0x8c, 0xb2, 0x8c, 0xb3, 0x8c, 0xae, + 0x8c, 0xb6, 0x8c, 0xc8, 0x8c, 0xc1, 0x8c, 0xe4, + 0x8c, 0xe3, 0x8c, 0xda, 0x8c, 0xfd, 0x8c, 0xfa, + 0x8c, 0xfb, 0x8d, 0x04, 0x8d, 0x05, 0x8d, 0x0a, + 0x8d, 0x07, 0x8d, 0x0f, 0x8d, 0x0d, 0x8d, 0x10, + 0x9f, 0x4e, 0x8d, 0x13, 0x8c, 0xcd, 0x8d, 0x14, + 0x8d, 0x16, 0x8d, 0x67, 0x8d, 0x6d, 0x8d, 0x71, + 0x8d, 0x73, 0x8d, 0x81, 0x8d, 0x99, 0x8d, 0xc2, + 0x8d, 0xbe, 0x8d, 0xba, 0x8d, 0xcf, 0x8d, 0xda, + 0x8d, 0xd6, 0x8d, 0xcc, 0x8d, 0xdb, 0x8d, 0xcb, + 0x8d, 0xea, 0x8d, 0xeb, 0x8d, 0xdf, 0x8d, 0xe3, + 0x8d, 0xfc, 0x8e, 0x08, 0x8e, 0x09, 0x8d, 0xff, + 0x8e, 0x1d, 0x8e, 0x1e, 0x8e, 0x10, 0x8e, 0x1f, + 0x8e, 0x42, 0x8e, 0x35, 0x8e, 0x30, 0x8e, 0x34, + 0x8e, 0x4a, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x8e, 0x47, 0x8e, 0x49, 0x8e, 0x4c, 0x8e, 0x50, + 0x8e, 0x48, 0x8e, 0x59, 0x8e, 0x64, 0x8e, 0x60, + 0x8e, 0x2a, 0x8e, 0x63, 0x8e, 0x55, 0x8e, 0x76, + 0x8e, 0x72, 0x8e, 0x7c, 0x8e, 0x81, 0x8e, 0x87, + 0x8e, 0x85, 0x8e, 0x84, 0x8e, 0x8b, 0x8e, 0x8a, + 0x8e, 0x93, 0x8e, 0x91, 0x8e, 0x94, 0x8e, 0x99, + 0x8e, 0xaa, 0x8e, 0xa1, 0x8e, 0xac, 0x8e, 0xb0, + 0x8e, 0xc6, 0x8e, 0xb1, 0x8e, 0xbe, 0x8e, 0xc5, + 0x8e, 0xc8, 0x8e, 0xcb, 0x8e, 0xdb, 0x8e, 0xe3, + 0x8e, 0xfc, 0x8e, 0xfb, 0x8e, 0xeb, 0x8e, 0xfe, + 0x8f, 0x0a, 0x8f, 0x05, 0x8f, 0x15, 0x8f, 0x12, + 0x8f, 0x19, 0x8f, 0x13, 0x8f, 0x1c, 0x8f, 0x1f, + 0x8f, 0x1b, 0x8f, 0x0c, 0x8f, 0x26, 0x8f, 0x33, + 0x8f, 0x3b, 0x8f, 0x39, 0x8f, 0x45, 0x8f, 0x42, + 0x8f, 0x3e, 0x8f, 0x4c, 0x8f, 0x49, 0x8f, 0x46, + 0x8f, 0x4e, 0x8f, 0x57, 0x8f, 0x5c, 0x00, 0x20, + 0x8f, 0x62, 0x8f, 0x63, 0x8f, 0x64, 0x8f, 0x9c, + 0x8f, 0x9f, 0x8f, 0xa3, 0x8f, 0xad, 0x8f, 0xaf, + 0x8f, 0xb7, 0x8f, 0xda, 0x8f, 0xe5, 0x8f, 0xe2, + 0x8f, 0xea, 0x8f, 0xef, 0x90, 0x87, 0x8f, 0xf4, + 0x90, 0x05, 0x8f, 0xf9, 0x8f, 0xfa, 0x90, 0x11, + 0x90, 0x15, 0x90, 0x21, 0x90, 0x0d, 0x90, 0x1e, + 0x90, 0x16, 0x90, 0x0b, 0x90, 0x27, 0x90, 0x36, + 0x90, 0x35, 0x90, 0x39, 0x8f, 0xf8, 0x90, 0x4f, + 0x90, 0x50, 0x90, 0x51, 0x90, 0x52, 0x90, 0x0e, + 0x90, 0x49, 0x90, 0x3e, 0x90, 0x56, 0x90, 0x58, + 0x90, 0x5e, 0x90, 0x68, 0x90, 0x6f, 0x90, 0x76, + 0x96, 0xa8, 0x90, 0x72, 0x90, 0x82, 0x90, 0x7d, + 0x90, 0x81, 0x90, 0x80, 0x90, 0x8a, 0x90, 0x89, + 0x90, 0x8f, 0x90, 0xa8, 0x90, 0xaf, 0x90, 0xb1, + 0x90, 0xb5, 0x90, 0xe2, 0x90, 0xe4, 0x62, 0x48, + 0x90, 0xdb, 0x91, 0x02, 0x91, 0x12, 0x91, 0x19, + 0x91, 0x32, 0x91, 0x30, 0x91, 0x4a, 0x91, 0x56, + 0x91, 0x58, 0x91, 0x63, 0x91, 0x65, 0x91, 0x69, + 0x91, 0x73, 0x91, 0x72, 0x91, 0x8b, 0x91, 0x89, + 0x91, 0x82, 0x91, 0xa2, 0x91, 0xab, 0x91, 0xaf, + 0x91, 0xaa, 0x91, 0xb5, 0x91, 0xb4, 0x91, 0xba, + 0x91, 0xc0, 0x91, 0xc1, 0x91, 0xc9, 0x91, 0xcb, + 0x91, 0xd0, 0x91, 0xd6, 0x91, 0xdf, 0x91, 0xe1, + 0x91, 0xdb, 0x91, 0xfc, 0x91, 0xf5, 0x91, 0xf6, + 0x92, 0x1e, 0x91, 0xff, 0x92, 0x14, 0x92, 0x2c, + 0x92, 0x15, 0x92, 0x11, 0x92, 0x5e, 0x92, 0x57, + 0x92, 0x45, 0x92, 0x49, 0x92, 0x64, 0x92, 0x48, + 0x92, 0x95, 0x92, 0x3f, 0x92, 0x4b, 0x92, 0x50, + 0x92, 0x9c, 0x92, 0x96, 0x92, 0x93, 0x92, 0x9b, + 0x92, 0x5a, 0x92, 0xcf, 0x92, 0xb9, 0x92, 0xb7, + 0x92, 0xe9, 0x93, 0x0f, 0x92, 0xfa, 0x93, 0x44, + 0x93, 0x2e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x93, 0x19, 0x93, 0x22, 0x93, 0x1a, 0x93, 0x23, + 0x93, 0x3a, 0x93, 0x35, 0x93, 0x3b, 0x93, 0x5c, + 0x93, 0x60, 0x93, 0x7c, 0x93, 0x6e, 0x93, 0x56, + 0x93, 0xb0, 0x93, 0xac, 0x93, 0xad, 0x93, 0x94, + 0x93, 0xb9, 0x93, 0xd6, 0x93, 0xd7, 0x93, 0xe8, + 0x93, 0xe5, 0x93, 0xd8, 0x93, 0xc3, 0x93, 0xdd, + 0x93, 0xd0, 0x93, 0xc8, 0x93, 0xe4, 0x94, 0x1a, + 0x94, 0x14, 0x94, 0x13, 0x94, 0x03, 0x94, 0x07, + 0x94, 0x10, 0x94, 0x36, 0x94, 0x2b, 0x94, 0x35, + 0x94, 0x21, 0x94, 0x3a, 0x94, 0x41, 0x94, 0x52, + 0x94, 0x44, 0x94, 0x5b, 0x94, 0x60, 0x94, 0x62, + 0x94, 0x5e, 0x94, 0x6a, 0x92, 0x29, 0x94, 0x70, + 0x94, 0x75, 0x94, 0x77, 0x94, 0x7d, 0x94, 0x5a, + 0x94, 0x7c, 0x94, 0x7e, 0x94, 0x81, 0x94, 0x7f, + 0x95, 0x82, 0x95, 0x87, 0x95, 0x8a, 0x95, 0x94, + 0x95, 0x96, 0x95, 0x98, 0x95, 0x99, 0x00, 0x20, + 0x95, 0xa0, 0x95, 0xa8, 0x95, 0xa7, 0x95, 0xad, + 0x95, 0xbc, 0x95, 0xbb, 0x95, 0xb9, 0x95, 0xbe, + 0x95, 0xca, 0x6f, 0xf6, 0x95, 0xc3, 0x95, 0xcd, + 0x95, 0xcc, 0x95, 0xd5, 0x95, 0xd4, 0x95, 0xd6, + 0x95, 0xdc, 0x95, 0xe1, 0x95, 0xe5, 0x95, 0xe2, + 0x96, 0x21, 0x96, 0x28, 0x96, 0x2e, 0x96, 0x2f, + 0x96, 0x42, 0x96, 0x4c, 0x96, 0x4f, 0x96, 0x4b, + 0x96, 0x77, 0x96, 0x5c, 0x96, 0x5e, 0x96, 0x5d, + 0x96, 0x5f, 0x96, 0x66, 0x96, 0x72, 0x96, 0x6c, + 0x96, 0x8d, 0x96, 0x98, 0x96, 0x95, 0x96, 0x97, + 0x96, 0xaa, 0x96, 0xa7, 0x96, 0xb1, 0x96, 0xb2, + 0x96, 0xb0, 0x96, 0xb4, 0x96, 0xb6, 0x96, 0xb8, + 0x96, 0xb9, 0x96, 0xce, 0x96, 0xcb, 0x96, 0xc9, + 0x96, 0xcd, 0x89, 0x4d, 0x96, 0xdc, 0x97, 0x0d, + 0x96, 0xd5, 0x96, 0xf9, 0x97, 0x04, 0x97, 0x06, + 0x97, 0x08, 0x97, 0x13, 0x97, 0x0e, 0x97, 0x11, + 0x97, 0x0f, 0x97, 0x16, 0x97, 0x19, 0x97, 0x24, + 0x97, 0x2a, 0x97, 0x30, 0x97, 0x39, 0x97, 0x3d, + 0x97, 0x3e, 0x97, 0x44, 0x97, 0x46, 0x97, 0x48, + 0x97, 0x42, 0x97, 0x49, 0x97, 0x5c, 0x97, 0x60, + 0x97, 0x64, 0x97, 0x66, 0x97, 0x68, 0x52, 0xd2, + 0x97, 0x6b, 0x97, 0x71, 0x97, 0x79, 0x97, 0x85, + 0x97, 0x7c, 0x97, 0x81, 0x97, 0x7a, 0x97, 0x86, + 0x97, 0x8b, 0x97, 0x8f, 0x97, 0x90, 0x97, 0x9c, + 0x97, 0xa8, 0x97, 0xa6, 0x97, 0xa3, 0x97, 0xb3, + 0x97, 0xb4, 0x97, 0xc3, 0x97, 0xc6, 0x97, 0xc8, + 0x97, 0xcb, 0x97, 0xdc, 0x97, 0xed, 0x9f, 0x4f, + 0x97, 0xf2, 0x7a, 0xdf, 0x97, 0xf6, 0x97, 0xf5, + 0x98, 0x0f, 0x98, 0x0c, 0x98, 0x38, 0x98, 0x24, + 0x98, 0x21, 0x98, 0x37, 0x98, 0x3d, 0x98, 0x46, + 0x98, 0x4f, 0x98, 0x4b, 0x98, 0x6b, 0x98, 0x6f, + 0x98, 0x70, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x98, 0x71, 0x98, 0x74, 0x98, 0x73, 0x98, 0xaa, + 0x98, 0xaf, 0x98, 0xb1, 0x98, 0xb6, 0x98, 0xc4, + 0x98, 0xc3, 0x98, 0xc6, 0x98, 0xe9, 0x98, 0xeb, + 0x99, 0x03, 0x99, 0x09, 0x99, 0x12, 0x99, 0x14, + 0x99, 0x18, 0x99, 0x21, 0x99, 0x1d, 0x99, 0x1e, + 0x99, 0x24, 0x99, 0x20, 0x99, 0x2c, 0x99, 0x2e, + 0x99, 0x3d, 0x99, 0x3e, 0x99, 0x42, 0x99, 0x49, + 0x99, 0x45, 0x99, 0x50, 0x99, 0x4b, 0x99, 0x51, + 0x99, 0x52, 0x99, 0x4c, 0x99, 0x55, 0x99, 0x97, + 0x99, 0x98, 0x99, 0xa5, 0x99, 0xad, 0x99, 0xae, + 0x99, 0xbc, 0x99, 0xdf, 0x99, 0xdb, 0x99, 0xdd, + 0x99, 0xd8, 0x99, 0xd1, 0x99, 0xed, 0x99, 0xee, + 0x99, 0xf1, 0x99, 0xf2, 0x99, 0xfb, 0x99, 0xf8, + 0x9a, 0x01, 0x9a, 0x0f, 0x9a, 0x05, 0x99, 0xe2, + 0x9a, 0x19, 0x9a, 0x2b, 0x9a, 0x37, 0x9a, 0x45, + 0x9a, 0x42, 0x9a, 0x40, 0x9a, 0x43, 0x00, 0x20, + 0x9a, 0x3e, 0x9a, 0x55, 0x9a, 0x4d, 0x9a, 0x5b, + 0x9a, 0x57, 0x9a, 0x5f, 0x9a, 0x62, 0x9a, 0x65, + 0x9a, 0x64, 0x9a, 0x69, 0x9a, 0x6b, 0x9a, 0x6a, + 0x9a, 0xad, 0x9a, 0xb0, 0x9a, 0xbc, 0x9a, 0xc0, + 0x9a, 0xcf, 0x9a, 0xd1, 0x9a, 0xd3, 0x9a, 0xd4, + 0x9a, 0xde, 0x9a, 0xdf, 0x9a, 0xe2, 0x9a, 0xe3, + 0x9a, 0xe6, 0x9a, 0xef, 0x9a, 0xeb, 0x9a, 0xee, + 0x9a, 0xf4, 0x9a, 0xf1, 0x9a, 0xf7, 0x9a, 0xfb, + 0x9b, 0x06, 0x9b, 0x18, 0x9b, 0x1a, 0x9b, 0x1f, + 0x9b, 0x22, 0x9b, 0x23, 0x9b, 0x25, 0x9b, 0x27, + 0x9b, 0x28, 0x9b, 0x29, 0x9b, 0x2a, 0x9b, 0x2e, + 0x9b, 0x2f, 0x9b, 0x32, 0x9b, 0x44, 0x9b, 0x43, + 0x9b, 0x4f, 0x9b, 0x4d, 0x9b, 0x4e, 0x9b, 0x51, + 0x9b, 0x58, 0x9b, 0x74, 0x9b, 0x93, 0x9b, 0x83, + 0x9b, 0x91, 0x9b, 0x96, 0x9b, 0x97, 0x9b, 0x9f, + 0x9b, 0xa0, 0x9b, 0xa8, 0x9b, 0xb4, 0x9b, 0xc0, + 0x9b, 0xca, 0x9b, 0xb9, 0x9b, 0xc6, 0x9b, 0xcf, + 0x9b, 0xd1, 0x9b, 0xd2, 0x9b, 0xe3, 0x9b, 0xe2, + 0x9b, 0xe4, 0x9b, 0xd4, 0x9b, 0xe1, 0x9c, 0x3a, + 0x9b, 0xf2, 0x9b, 0xf1, 0x9b, 0xf0, 0x9c, 0x15, + 0x9c, 0x14, 0x9c, 0x09, 0x9c, 0x13, 0x9c, 0x0c, + 0x9c, 0x06, 0x9c, 0x08, 0x9c, 0x12, 0x9c, 0x0a, + 0x9c, 0x04, 0x9c, 0x2e, 0x9c, 0x1b, 0x9c, 0x25, + 0x9c, 0x24, 0x9c, 0x21, 0x9c, 0x30, 0x9c, 0x47, + 0x9c, 0x32, 0x9c, 0x46, 0x9c, 0x3e, 0x9c, 0x5a, + 0x9c, 0x60, 0x9c, 0x67, 0x9c, 0x76, 0x9c, 0x78, + 0x9c, 0xe7, 0x9c, 0xec, 0x9c, 0xf0, 0x9d, 0x09, + 0x9d, 0x08, 0x9c, 0xeb, 0x9d, 0x03, 0x9d, 0x06, + 0x9d, 0x2a, 0x9d, 0x26, 0x9d, 0xaf, 0x9d, 0x23, + 0x9d, 0x1f, 0x9d, 0x44, 0x9d, 0x15, 0x9d, 0x12, + 0x9d, 0x41, 0x9d, 0x3f, 0x9d, 0x3e, 0x9d, 0x46, + 0x9d, 0x48, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x9d, 0x5d, 0x9d, 0x5e, 0x9d, 0x64, 0x9d, 0x51, + 0x9d, 0x50, 0x9d, 0x59, 0x9d, 0x72, 0x9d, 0x89, + 0x9d, 0x87, 0x9d, 0xab, 0x9d, 0x6f, 0x9d, 0x7a, + 0x9d, 0x9a, 0x9d, 0xa4, 0x9d, 0xa9, 0x9d, 0xb2, + 0x9d, 0xc4, 0x9d, 0xc1, 0x9d, 0xbb, 0x9d, 0xb8, + 0x9d, 0xba, 0x9d, 0xc6, 0x9d, 0xcf, 0x9d, 0xc2, + 0x9d, 0xd9, 0x9d, 0xd3, 0x9d, 0xf8, 0x9d, 0xe6, + 0x9d, 0xed, 0x9d, 0xef, 0x9d, 0xfd, 0x9e, 0x1a, + 0x9e, 0x1b, 0x9e, 0x1e, 0x9e, 0x75, 0x9e, 0x79, + 0x9e, 0x7d, 0x9e, 0x81, 0x9e, 0x88, 0x9e, 0x8b, + 0x9e, 0x8c, 0x9e, 0x92, 0x9e, 0x95, 0x9e, 0x91, + 0x9e, 0x9d, 0x9e, 0xa5, 0x9e, 0xa9, 0x9e, 0xb8, + 0x9e, 0xaa, 0x9e, 0xad, 0x97, 0x61, 0x9e, 0xcc, + 0x9e, 0xce, 0x9e, 0xcf, 0x9e, 0xd0, 0x9e, 0xd4, + 0x9e, 0xdc, 0x9e, 0xde, 0x9e, 0xdd, 0x9e, 0xe0, + 0x9e, 0xe5, 0x9e, 0xe8, 0x9e, 0xef, 0x00, 0x20, + 0x9e, 0xf4, 0x9e, 0xf6, 0x9e, 0xf7, 0x9e, 0xf9, + 0x9e, 0xfb, 0x9e, 0xfc, 0x9e, 0xfd, 0x9f, 0x07, + 0x9f, 0x08, 0x76, 0xb7, 0x9f, 0x15, 0x9f, 0x21, + 0x9f, 0x2c, 0x9f, 0x3e, 0x9f, 0x4a, 0x9f, 0x52, + 0x9f, 0x54, 0x9f, 0x63, 0x9f, 0x5f, 0x9f, 0x60, + 0x9f, 0x61, 0x9f, 0x66, 0x9f, 0x67, 0x9f, 0x6c, + 0x9f, 0x6a, 0x9f, 0x77, 0x9f, 0x72, 0x9f, 0x76, + 0x9f, 0x95, 0x9f, 0x9c, 0x9f, 0xa0, 0x58, 0x2f, + 0x69, 0xc7, 0x90, 0x59, 0x74, 0x64, 0x51, 0xdc, + 0x71, 0x99, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + +}; diff --git a/include/util.h b/include/util.h index 65d4add..290e335 100644 --- a/include/util.h +++ b/include/util.h @@ -17,6 +17,13 @@ int unmmap_file(u8 *data, u64 size); int calculate_hmac_hash(const u8 *data, u64 size, const u8 *key, u32 key_length, u8 output[20]); int calculate_file_hmac_hash(const char *file_path, const u8 *key, u32 key_length, u8 output[20]); +void append_le_uint16(uint8_t *buf, uint16_t val); +void append_le_uint32(uint8_t *buf, uint32_t val); +void append_le_uint64(uint8_t *buf, uint64_t val); +uint16_t read_le_uint16(const uint8_t *buf); +uint32_t read_le_uint32(const uint8_t *buf); +uint64_t read_le_uint64(const uint8_t *buf); + u64 align_to_pow2(u64 offset, u64 alignment); void notify_popup(const char *p_Uri, const char *p_Format, ...); diff --git a/source/common.c b/source/common.c index c939c97..b239b2f 100644 --- a/source/common.c +++ b/source/common.c @@ -214,24 +214,3 @@ int clean_directory(const char* inputdir) return SUCCESS; } -/* -//---------------------------------------- -//POWER UTILS -//---------------------------------------- - -int sys_shutdown() -{ - unlink_secure("/dev_hdd0/tmp/turnoff"); - - lv2syscall4(379,0x1100,0,0,0); - return_to_user_prog(int); -} - -int sys_reboot() -{ - unlink_secure("/dev_hdd0/tmp/turnoff"); - - lv2syscall4(379,0x1200,0,0,0); - return_to_user_prog(int); -} -*/ \ No newline at end of file diff --git a/source/draw.c b/source/draw.c index aabe01a..47d9ad7 100644 --- a/source/draw.c +++ b/source/draw.c @@ -52,6 +52,25 @@ int LoadMenuTexture(const char* path, int idx) return 1; } +void LoadVmcTexture(int width, int height, uint8_t* icon) +{ + if (menu_textures[icon_png_file_index].texture) + SDL_DestroyTexture(menu_textures[icon_png_file_index].texture); + + menu_textures[icon_png_file_index].width = width; + menu_textures[icon_png_file_index].height = height; + menu_textures[icon_png_file_index].size = width * height * 4; + menu_textures[icon_png_file_index].buffer = NULL; + + SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(icon, width, height, 32, 4 * width, + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + + menu_textures[icon_png_file_index].texture = SDL_CreateTextureFromSurface(renderer, surface); + + SDL_FreeSurface(surface); + free(icon); +} + // draw one background color in virtual 2D coordinates void DrawBackground2D(u32 rgba) { diff --git a/source/exec_cmd.c b/source/exec_cmd.c index f206fab..ce274c8 100644 --- a/source/exec_cmd.c +++ b/source/exec_cmd.c @@ -13,6 +13,7 @@ #include "common.h" #include "util.h" #include "sfo.h" +#include "mcio.h" static char host_buf[256]; @@ -41,7 +42,7 @@ static void downloadSave(const save_entry_t* entry, const char* file, int dst) { char path[256]; - _set_dest_path(path, dst, PS4_SAVES_PATH_USB); + _set_dest_path(path, dst, (entry->flags & SAVE_FLAG_PS4) ? PS4_SAVES_PATH_USB : PS2_SAVES_PATH_USB); if (mkdirs(path) != SUCCESS) { show_message("Error! Export folder is not available:\n%s", path); @@ -739,21 +740,146 @@ static void copyAllSavesUSB(const save_entry_t* save, const char* dst_path, int show_message("All Saves copied to:\n%s", dst_path); } -void exportFolder(const char* src_path, const char* exp_path, const char* msg) +static void exportAllSavesVMC(const save_entry_t* save, int dev, int all) { - if (mkdirs(exp_path) != SUCCESS) + char outPath[256]; + int done = 0, err_count = 0; + list_node_t *node; + save_entry_t *item; + uint64_t progress = 0; + list_t *list = ((void**)save->dir_name)[0]; + + init_progress_bar("Exporting all VMC saves..."); + _set_dest_path(outPath, dev, PS1_IMP_PATH_USB); + mkdirs(outPath); + + LOG("Exporting all saves from '%s' to %s...", save->path, outPath); + for (node = list_head(list); (item = list_get(node)); node = list_next(node)) { - show_message("Error! Export folder is not available:\n%s", exp_path); - return; + update_progress_bar(progress++, list_count(list), item->name); + if (!all && !(item->flags & SAVE_FLAG_SELECTED)) + continue; + +// if (item->type == FILE_TYPE_PS1) +// (saveSingleSave(outPath, save->dir_name[0], PS1SAVE_PSV) ? done++ : err_count++); + + if (item->type == FILE_TYPE_PS2) + (vmc_export_psv(item->dir_name, outPath) ? done++ : err_count++); + } + + end_progress_bar(); + + show_message("%d/%d Saves exported to\n%s", done, done+err_count, outPath); +} + +static void export_vmc2save(const save_entry_t* save, int type, int dst_id) +{ + int ret = 0; + char outPath[256]; + struct tm t; + + _set_dest_path(outPath, dst_id, (type == FILE_TYPE_PSV) ? PSV_SAVES_PATH_USB : PS2_IMP_PATH_USB); + mkdirs(outPath); + if (type != FILE_TYPE_PSV) + { + // build file path + gmtime_r(&(time_t){time(NULL)}, &t); + sprintf(strrchr(outPath, '/'), "/%s_%d-%02d-%02d_%02d%02d%02d.psu", save->title_id, + t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); } - init_loading_screen(msg); + switch (type) + { + case FILE_TYPE_PSV: + ret = vmc_export_psv(save->dir_name, outPath); + break; + + case FILE_TYPE_PSU: + ret = vmc_export_psu(save->dir_name, outPath); + break; + + default: + break; + } - LOG("Copying <%s> to %s...", src_path, exp_path); - copy_directory(src_path, src_path, exp_path); + if (ret) + show_message("Save successfully exported to:\n%s", outPath); + else + show_message("Error exporting save:\n%s", save->path); +} + +static void import_save2vmc(const char* src, int type) +{ + int ret = 0; + + init_loading_screen("Importing PS2 save..."); + switch (type) + { + case FILE_TYPE_PSV: + ret = vmc_import_psv(src); + break; + + case FILE_TYPE_PSU: + ret = vmc_import_psu(src); + break; + + case FILE_TYPE_XPS: + ret = ps2_xps2psv(src, APOLLO_LOCAL_CACHE "TEMP.PSV") && vmc_import_psv(APOLLO_LOCAL_CACHE "TEMP.PSV"); + break; + case FILE_TYPE_CBS: + ret = ps2_cbs2psv(src, APOLLO_LOCAL_CACHE "TEMP.PSV") && vmc_import_psv(APOLLO_LOCAL_CACHE "TEMP.PSV"); + break; + + case FILE_TYPE_MAX: + ret = ps2_max2psv(src, APOLLO_LOCAL_CACHE "TEMP.PSV") && vmc_import_psv(APOLLO_LOCAL_CACHE "TEMP.PSV"); + break; + + default: + break; + } stop_loading_screen(); - show_message("Files successfully copied to:\n%s", exp_path); + + if (ret) + show_message("Successfully imported to VMC:\n%s", src); + else + show_message("Error importing save:\n%s", src); +} + +static void deleteVmcSave(const save_entry_t* save) +{ + if (!show_dialog(DIALOG_TYPE_YESNO, "Do you want to delete %s?", save->dir_name)) + return; + + if ((save->flags & SAVE_FLAG_PS1) ? /*formatSave(save->dir_name[0])*/0 : vmc_delete_save(save->dir_name)) + show_message("Save successfully deleted:\n%s", save->dir_name); + else + show_message("Error! Couldn't delete save:\n%s", save->dir_name); +} + +static void exportVM2raw(const char* vm2_file, int dst, int ecc) +{ + int ret; + char dstfile[256]; + char dst_path[256]; + + _set_dest_path(dst_path, dst, VMC_PS2_PATH_USB); + if (mkdirs(dst_path) != SUCCESS) + { + show_message("Error! Export folder is not available:\n%s", dst_path); + return; + } + + snprintf(dstfile, sizeof(dstfile), "%s%s.%s", dst_path, vm2_file, ecc ? "VM2" : "VMC"); + + init_loading_screen("Exporting PS2 memory card..."); + ret = mcio_vmcExportImage(dstfile, ecc); + stop_loading_screen(); + + if (ret == sceMcResSucceed) + show_message("File successfully saved to:\n%s", dstfile); + else + show_message("Error! Failed to export PS2 memory card"); } static void rebuildAppDB(const char* path) @@ -1144,9 +1270,7 @@ void execCodeCommand(code_entry_t* code, const char* codecmd) break; case CMD_DOWNLOAD_USB: - if (selected_entry->flags & SAVE_FLAG_PS4) - downloadSave(selected_entry, code->file, codecmd[1]); - + downloadSave(selected_entry, code->file, codecmd[1]); code->activated = 0; break; @@ -1296,6 +1420,35 @@ void execCodeCommand(code_entry_t* code, const char* codecmd) code->activated = 0; break; + case CMD_EXP_SAVES_VMC: + case CMD_EXP_ALL_SAVES_VMC: + exportAllSavesVMC(selected_entry, codecmd[1], codecmd[0] == CMD_EXP_ALL_SAVES_VMC); + code->activated = 0; + break; + + case CMD_EXP_VMC2SAVE: + export_vmc2save(selected_entry, code->options[0].id, codecmd[1]); + code->activated = 0; + break; + + case CMD_IMP_VMC2SAVE: + import_save2vmc(code->file, codecmd[1]); + selected_entry->flags |= SAVE_FLAG_UPDATED; + code->activated = 0; + break; + + case CMD_DELETE_VMCSAVE: + deleteVmcSave(selected_entry); + selected_entry->flags |= SAVE_FLAG_UPDATED; + code->activated = 0; + break; + + case CMD_EXP_PS2_VM2: + case CMD_EXP_VM2_RAW: + exportVM2raw(code->file, codecmd[1], codecmd[0] == CMD_EXP_PS2_VM2); + code->activated = 0; + break; + default: break; } diff --git a/source/lzari.c b/source/lzari.c new file mode 100644 index 0000000..6574c21 --- /dev/null +++ b/source/lzari.c @@ -0,0 +1,494 @@ + +// modified by Luigi Auriemma for memory2memory decompression and removing encoding +// Modified by Wesley Castro to restore encoding +/************************************************************** + LZARI.C -- A Data Compression Program + (tab = 4 spaces) +*************************************************************** + 4/7/1989 Haruhiko Okumura + Use, distribute, and modify this program freely. + Please send me your improved versions. + PC-VAN SCIENCE + NIFTY-Serve PAF01022 + CompuServe 74050,1022 +**************************************************************/ +#include "lzari.h" +#include +#include +#include +#include + +/********** Bit I/O **********/ + +static unsigned char *infile = NULL; +static unsigned char *infilel = NULL; +static unsigned char *outfile = NULL; +static unsigned char *outfilel = NULL; +static unsigned long int textsize = 0, codesize = 0; + +static int xgetc(void *skip) +{ + if (infile >= infilel) + return -1; + + return *infile++; +} + +static int xputc(int chr, void *skip) +{ + if (outfile >= outfilel) + return -1; + + *outfile++ = chr; + return chr; +} + +static unsigned int buffer = 0, mask = 128; +static void PutBit(int bit) /* Output one bit (bit = 0,1) */ +{ + if (bit) buffer |= mask; + if ((mask >>= 1) == 0) { + if (xputc(buffer, outfile) == -1) + return; + buffer = 0; mask = 128; codesize++; + } +} + +static void FlushBitBuffer(void) /* Send remaining bits */ +{ + int i; + + for (i = 0; i < 7; i++) PutBit(0); +} + +static unsigned int buffer2 = 0, mask2 = 0; +static int GetBit(void) /* Get one bit (0 or 1) */ +{ + if ((mask2 >>= 1) == 0) { + buffer2 = xgetc(infile); mask2 = 128; + } + return ((buffer2 & mask2) != 0); +} + +/********** LZSS with multiple binary trees **********/ + +#define N 4096 /* size of ring buffer */ +#define F 60 /* upper limit for match_length */ +#define THRESHOLD 2 /* encode string into position and length + if match_length is greater than this */ +#define NIL N /* index for root of binary search trees */ + +unsigned char text_buf[N + F - 1]; /* ring buffer of size N, + with extra F-1 bytes to facilitate string comparison */ +int match_position, match_length, /* of longest match. These are + set by the InsertNode() procedure. */ + lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children & + parents -- These constitute binary search trees. */ + +static void InitTree(void) /* Initialize trees */ +{ + int i; + + /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and + left children of node i. These nodes need not be initialized. + Also, dad[i] is the parent of node i. These are initialized to + NIL (= N), which stands for 'not used.' + For i = 0 to 255, rson[N + i + 1] is the root of the tree + for strings that begin with character i. These are initialized + to NIL. Note there are 256 trees. */ + + for (i = N + 1; i <= N + 256; i++) rson[i] = NIL; /* root */ + for (i = 0; i < N; i++) dad[i] = NIL; /* node */ +} + +static void InsertNode(int r) + /* Inserts string of length F, text_buf[r..r+F-1], into one of the + trees (text_buf[r]'th tree) and returns the longest-match position + and length via the global variables match_position and match_length. + If match_length = F, then removes the old node in favor of the new + one, because the old one will be deleted sooner. + Note r plays double role, as tree node and position in buffer. */ +{ + int i, p, cmp, temp; + unsigned char *key; + + cmp = 1; key = &text_buf[r]; p = N + 1 + key[0]; + rson[r] = lson[r] = NIL; match_length = 0; + for ( ; ; ) { + if (cmp >= 0) { + if (rson[p] != NIL) p = rson[p]; + else { rson[p] = r; dad[r] = p; return; } + } else { + if (lson[p] != NIL) p = lson[p]; + else { lson[p] = r; dad[r] = p; return; } + } + for (i = 1; i < F; i++) + if ((cmp = key[i] - text_buf[p + i]) != 0) break; + if (i > THRESHOLD) { + if (i > match_length) { + match_position = (r - p) & (N - 1); + if ((match_length = i) >= F) break; + } else if (i == match_length) { + if ((temp = (r - p) & (N - 1)) < match_position) + match_position = temp; + } + } + } + dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p]; + dad[lson[p]] = r; dad[rson[p]] = r; + if (rson[dad[p]] == p) rson[dad[p]] = r; + else lson[dad[p]] = r; + dad[p] = NIL; /* remove p */ +} + +static void DeleteNode(int p) /* Delete node p from tree */ +{ + int q; + + if (dad[p] == NIL) return; /* not in tree */ + if (rson[p] == NIL) q = lson[p]; + else if (lson[p] == NIL) q = rson[p]; + else { + q = lson[p]; + if (rson[q] != NIL) { + do { q = rson[q]; } while (rson[q] != NIL); + rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q]; + lson[q] = lson[p]; dad[lson[p]] = q; + } + rson[q] = rson[p]; dad[rson[p]] = q; + } + dad[q] = dad[p]; + if (rson[dad[p]] == p) rson[dad[p]] = q; + else lson[dad[p]] = q; + dad[p] = NIL; +} + +/********** Arithmetic Compression **********/ + +/* If you are not familiar with arithmetic compression, you should read + I. E. Witten, R. M. Neal, and J. G. Cleary, + Communications of the ACM, Vol. 30, pp. 520-540 (1987), + from which much have been borrowed. */ + +#define M 15 + +/* Q1 (= 2 to the M) must be sufficiently large, but not so + large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */ + +#define Q1 (1UL << M) +#define Q2 (2 * Q1) +#define Q3 (3 * Q1) +#define Q4 (4 * Q1) +#define MAX_CUM (Q1 - 1) + +#define N_CHAR (256 - THRESHOLD + F) + /* character code = 0, 1, ..., N_CHAR - 1 */ + +unsigned long int low = 0, high = Q4, value = 0; +int shifts = 0; /* counts for magnifying low and high around Q2 */ +int char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1]; +unsigned int + sym_freq[N_CHAR + 1], /* frequency for symbols */ + sym_cum[N_CHAR + 1], /* cumulative freq for symbols */ + position_cum[N + 1]; /* cumulative freq for positions */ + +static void StartModel(void) /* Initialize model */ +{ + int ch, sym, i; + + sym_cum[N_CHAR] = 0; + for (sym = N_CHAR; sym >= 1; sym--) { + ch = sym - 1; + char_to_sym[ch] = sym; sym_to_char[sym] = ch; + sym_freq[sym] = 1; + sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym]; + } + sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */ + position_cum[N] = 0; + for (i = N; i >= 1; i--) + position_cum[i - 1] = position_cum[i] + 10000 / (i + 200); + /* empirical distribution function (quite tentative) */ + /* Please devise a better mechanism! */ +} + +static void UpdateModel(int sym) +{ + int i, c, ch_i, ch_sym; + + if (sym_cum[0] >= MAX_CUM) { + c = 0; + for (i = N_CHAR; i > 0; i--) { + sym_cum[i] = c; + c += (sym_freq[i] = (sym_freq[i] + 1) >> 1); + } + sym_cum[0] = c; + } + for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ; + if (i < sym) { + ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym]; + sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i; + char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i; + } + sym_freq[i]++; + while (--i >= 0) sym_cum[i]++; +} + +static void Output(int bit) /* Output 1 bit, followed by its complements */ +{ + PutBit(bit); + for ( ; shifts > 0; shifts--) PutBit(! bit); +} + +static void EncodeChar(int ch) +{ + int sym; + unsigned long int range; + + sym = char_to_sym[ch]; + range = high - low; + high = low + (range * sym_cum[sym - 1]) / sym_cum[0]; + low += (range * sym_cum[sym ]) / sym_cum[0]; + for ( ; ; ) { + if (high <= Q2) Output(0); + else if (low >= Q2) { + Output(1); low -= Q2; high -= Q2; + } else if (low >= Q1 && high <= Q3) { + shifts++; low -= Q1; high -= Q1; + } else break; + low += low; high += high; + } + UpdateModel(sym); +} + +static void EncodePosition(int position) +{ + unsigned long int range; + + range = high - low; + high = low + (range * position_cum[position ]) / position_cum[0]; + low += (range * position_cum[position + 1]) / position_cum[0]; + for ( ; ; ) { + if (high <= Q2) Output(0); + else if (low >= Q2) { + Output(1); low -= Q2; high -= Q2; + } else if (low >= Q1 && high <= Q3) { + shifts++; low -= Q1; high -= Q1; + } else break; + low += low; high += high; + } +} + +static void EncodeEnd(void) +{ + shifts++; + if (low < Q1) Output(0); else Output(1); + FlushBitBuffer(); /* flush bits remaining in buffer */ +} + +static int BinarySearchSym(unsigned int x) + /* 1 if x >= sym_cum[1], + N_CHAR if sym_cum[N_CHAR] > x, + i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */ +{ + int i, j, k; + + i = 1; j = N_CHAR; + while (i < j) { + k = (i + j) / 2; + if (sym_cum[k] > x) i = k + 1; else j = k; + } + return i; +} + +static int BinarySearchPos(unsigned int x) + /* 0 if x >= position_cum[1], + N - 1 if position_cum[N] > x, + i such that position_cum[i] > x >= position_cum[i + 1] otherwise */ +{ + int i, j, k; + + i = 1; j = N; + while (i < j) { + k = (i + j) / 2; + if (position_cum[k] > x) i = k + 1; else j = k; + } + return i - 1; +} + +static void StartDecode(void) +{ + int i; + + for (i = 0; i < M + 2; i++) + value = 2 * value + GetBit(); +} + +static int DecodeChar(void) +{ + int sym, ch; + unsigned long int range; + + range = high - low; + sym = BinarySearchSym((unsigned int) + (((value - low + 1) * sym_cum[0] - 1) / range)); + high = low + (range * sym_cum[sym - 1]) / sym_cum[0]; + low += (range * sym_cum[sym ]) / sym_cum[0]; + for ( ; ; ) { + if (low >= Q2) { + value -= Q2; low -= Q2; high -= Q2; + } else if (low >= Q1 && high <= Q3) { + value -= Q1; low -= Q1; high -= Q1; + } else if (high > Q2) break; + low += low; high += high; + value = 2 * value + GetBit(); + } + ch = sym_to_char[sym]; + UpdateModel(sym); + return ch; +} + +static int DecodePosition(void) +{ + int position; + unsigned long int range; + + range = high - low; + position = BinarySearchPos((unsigned int) + (((value - low + 1) * position_cum[0] - 1) / range)); + high = low + (range * position_cum[position ]) / position_cum[0]; + low += (range * position_cum[position + 1]) / position_cum[0]; + for ( ; ; ) { + if (low >= Q2) { + value -= Q2; low -= Q2; high -= Q2; + } else if (low >= Q1 && high <= Q3) { + value -= Q1; low -= Q1; high -= Q1; + } else if (high > Q2) break; + low += low; high += high; + value = 2 * value + GetBit(); + } + return position; +} + +/********** Encode and Decode **********/ + +int lzari(unsigned char *in, int insz, unsigned char *out, int outsz) +{ + int i, c, len, r, s, last_match_length; + + if(!in || !out) + return -1; + + // Reset compressor state + low = 0; + high = Q4; + value = 0; + codesize = 0; + match_position = 0; + buffer = 0; + buffer2 = 0; + mask = 128; + mask2 = 0; + + infile = in; + infilel = in + insz; + outfile = out; + outfilel = out + outsz; + textsize = insz; + + xputc((textsize >> 0) & 0xFF, 0); + xputc((textsize >> 8) & 0xFF, 0); + xputc((textsize >> 16) & 0xFF, 0); + xputc((textsize >> 24) & 0xFF, 0); + + codesize += sizeof textsize; + if (textsize == 0) return -1; + textsize = 0; + StartModel(); InitTree(); + s = 0; r = N - F; + for (i = s; i < r; i++) text_buf[i] = ' '; + for (len = 0; len < F && (c = xgetc(infile)) != -1; len++) + text_buf[r + len] = c; + textsize = len; + for (i = 1; i <= F; i++) InsertNode(r - i); + InsertNode(r); + do { + if (match_length > len) match_length = len; + if (match_length <= THRESHOLD) { + match_length = 1; EncodeChar(text_buf[r]); + } else { + EncodeChar(255 - THRESHOLD + match_length); + EncodePosition(match_position - 1); + } + last_match_length = match_length; + for (i = 0; i < last_match_length && + (c = xgetc(infile)) != -1; i++) { + DeleteNode(s); text_buf[s] = c; + if (s < F - 1) text_buf[s + N] = c; + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + InsertNode(r); + } + while (i++ < last_match_length) { + DeleteNode(s); + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + if (--len) InsertNode(r); + } + } while (len > 0); + EncodeEnd(); + + return outfile - out; +} + +int unlzari(unsigned char *in, int insz, unsigned char *out, int outsz) +{ + int i, j, k, r, c; + unsigned long int count; + + if(!in || !out) + return -1; + + // Reset decompressor state + low = 0; + high = Q4; + value = 0; + codesize = 0; + match_position = 0; + buffer = 0; + buffer2 = 0; + mask = 128; + mask2 = 0; + + infile = in; + infilel = in + insz; + outfile = out; + outfilel = out + outsz; + + textsize = (xgetc(infile)); + textsize |= (xgetc(infile) << 8); + textsize |= (xgetc(infile) << 16); + textsize |= (xgetc(infile) << 24); + if (textsize == 0) + return 0; + + StartDecode(); StartModel(); + for (i = 0; i < N - F; i++) text_buf[i] = ' '; + r = N - F; + for (count = 0; count < textsize; ) { + if (infile >= infilel) break; + c = DecodeChar(); + if (c < 256) { + xputc(c, outfile); text_buf[r++] = c; + r &= (N - 1); count++; + } else { + i = (r - DecodePosition() - 1) & (N - 1); + j = c - 255 + THRESHOLD; + for (k = 0; k < j; k++) { + c = text_buf[(i + k) & (N - 1)]; + xputc(c, outfile); text_buf[r++] = c; + r &= (N - 1); count++; + } + } + } + return outfile - out; +} diff --git a/source/main.c b/source/main.c index 0f2e0c6..4b9300b 100644 --- a/source/main.c +++ b/source/main.c @@ -47,6 +47,7 @@ void update_usb_path(char *p); void update_hdd_path(char *p); void update_trophy_path(char *p); void update_db_path(char *p); +void update_vmc_path(char *p); app_config_t apollo_config = { .app_name = "APOLLO", @@ -136,6 +137,19 @@ save_list_t user_backup = { .UpdatePath = NULL, }; +/* +* PS2 VMC list +*/ +save_list_t vmc2_saves = { + .icon_id = cat_usb_png_index, + .title = "PS2 Virtual Memory Card", + .list = NULL, + .path = "", + .ReadList = &ReadVmc2List, + .ReadCodes = &ReadVmc2Codes, + .UpdatePath = &update_vmc_path, +}; + static const char* get_button_prompts(int menu_id) { const char* prompt = NULL; @@ -145,11 +159,13 @@ static const char* get_button_prompts(int menu_id) case MENU_TROPHIES: case MENU_USB_SAVES: case MENU_HDD_SAVES: + case MENU_ONLINE_DB: + case MENU_PS1VMC_SAVES: + case MENU_PS2VMC_SAVES: prompt = "\x10 Select \x13 Back \x12 Details \x11 Refresh"; break; case MENU_USER_BACKUP: - case MENU_ONLINE_DB: prompt = "\x10 Select \x13 Back \x11 Refresh"; break; @@ -294,7 +310,7 @@ static int LoadTextures_Menu(void) load_menu_texture(logo_text, png); load_menu_texture(tag_lock, png); load_menu_texture(tag_own, png); - load_menu_texture(tag_pce, png); + load_menu_texture(tag_vmc, png); load_menu_texture(tag_ps1, png); load_menu_texture(tag_ps2, png); load_menu_texture(tag_ps3, png); @@ -375,25 +391,32 @@ void update_usb_path(char* path) { if (apollo_config.usb_dev < MAX_USB_DEVICES) { - sprintf(path, USB_PATH "PS4/", apollo_config.usb_dev); + sprintf(path, USB_PATH, apollo_config.usb_dev); return; } if (apollo_config.usb_dev == MAX_USB_DEVICES) { - sprintf(path, FAKE_USB_PATH "PS4/"); + sprintf(path, FAKE_USB_PATH); return; } for (int i = 0; i < MAX_USB_DEVICES; i++) { - sprintf(path, USB_PATH "PS4/", i); + sprintf(path, USB_PATH ".apollo", i); + + FILE *fp = fopen(path, "w"); + if (!fp) + continue; + + fclose(fp); + remove(path); + *strrchr(path, '.') = 0; - if (dir_exists(path) == SUCCESS) - return; + return; } - sprintf(path, FAKE_USB_PATH "PS4/"); + sprintf(path, FAKE_USB_PATH); if (dir_exists(path) == SUCCESS) return; @@ -415,16 +438,24 @@ void update_db_path(char* path) strcpy(path, apollo_config.save_db); } +void update_vmc_path(char* path) +{ + if (file_exists(path) == SUCCESS) + return; + + path[0] = 0; +} + static void registerSpecialChars(void) { // Register save tags RegisterSpecialCharacter(CHAR_TAG_PS1, 2, 1.5, &menu_textures[tag_ps1_png_index]); - RegisterSpecialCharacter(CHAR_TAG_PS2, 2, 1.5, &menu_textures[tag_ps2_png_index]); + RegisterSpecialCharacter(CHAR_TAG_PS2, 0, 1.5, &menu_textures[tag_ps2_png_index]); RegisterSpecialCharacter(CHAR_TAG_PS3, 2, 1.5, &menu_textures[tag_ps3_png_index]); RegisterSpecialCharacter(CHAR_TAG_PS4, 2, 1.5, &menu_textures[tag_ps4_png_index]); RegisterSpecialCharacter(CHAR_TAG_PSP, 2, 1.5, &menu_textures[tag_psp_png_index]); RegisterSpecialCharacter(CHAR_TAG_PSV, 2, 1.5, &menu_textures[tag_psv_png_index]); - RegisterSpecialCharacter(CHAR_TAG_PCE, 2, 1.5, &menu_textures[tag_pce_png_index]); + RegisterSpecialCharacter(CHAR_TAG_VMC, 2, 1.0, &menu_textures[tag_vmc_png_index]); RegisterSpecialCharacter(CHAR_TAG_LOCKED, 0, 1.3, &menu_textures[tag_lock_png_index]); RegisterSpecialCharacter(CHAR_TAG_OWNER, 0, 1.3, &menu_textures[tag_own_png_index]); RegisterSpecialCharacter(CHAR_TAG_WARNING, 0, 1.3, &menu_textures[tag_warning_png_index]); diff --git a/source/mcio.c b/source/mcio.c new file mode 100644 index 0000000..906f63c --- /dev/null +++ b/source/mcio.c @@ -0,0 +1,3606 @@ +/* + * PS2VMC Tool - PS2 Virtual Memory Card Tool by Bucanero + * + * based on + * ps3mca-tool - PlayStation 3 Memory Card Adaptor Software + * Copyright (C) 2011 - jimmikaelkael + * Copyright (C) 2011 - "someone who wants to stay anonymous" + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mcio.h" +#include "util.h" +#include "ps2mc.h" +#include "common.h" + +#include +#include + +/* Card Flags */ +#define CF_USE_ECC 0x01 +#define CF_BAD_BLOCK 0x08 +#define CF_ERASE_ZEROES 0x10 + +#define MCIO_CLUSTERSIZE 1024 +#define MCIO_CLUSTERFATENTRIES 256 + +/* Memory Card device types */ +#define sceMcTypeNoCard 0 +#define sceMcTypePS1 1 +#define sceMcTypePS2 2 +#define sceMcTypePDA 3 + +static const uint8_t ECC_Table[256] = { + 0x00, 0x87, 0x96, 0x11, 0xa5, 0x22, 0x33, 0xb4,0xb4, 0x33, 0x22, 0xa5, 0x11, 0x96, 0x87, 0x00, + 0xc3, 0x44, 0x55, 0xd2, 0x66, 0xe1, 0xf0, 0x77,0x77, 0xf0, 0xe1, 0x66, 0xd2, 0x55, 0x44, 0xc3, + 0xd2, 0x55, 0x44, 0xc3, 0x77, 0xf0, 0xe1, 0x66,0x66, 0xe1, 0xf0, 0x77, 0xc3, 0x44, 0x55, 0xd2, + 0x11, 0x96, 0x87, 0x00, 0xb4, 0x33, 0x22, 0xa5,0xa5, 0x22, 0x33, 0xb4, 0x00, 0x87, 0x96, 0x11, + 0xe1, 0x66, 0x77, 0xf0, 0x44, 0xc3, 0xd2, 0x55,0x55, 0xd2, 0xc3, 0x44, 0xf0, 0x77, 0x66, 0xe1, + 0x22, 0xa5, 0xb4, 0x33, 0x87, 0x00, 0x11, 0x96,0x96, 0x11, 0x00, 0x87, 0x33, 0xb4, 0xa5, 0x22, + 0x33, 0xb4, 0xa5, 0x22, 0x96, 0x11, 0x00, 0x87,0x87, 0x00, 0x11, 0x96, 0x22, 0xa5, 0xb4, 0x33, + 0xf0, 0x77, 0x66, 0xe1, 0x55, 0xd2, 0xc3, 0x44,0x44, 0xc3, 0xd2, 0x55, 0xe1, 0x66, 0x77, 0xf0, + 0xf0, 0x77, 0x66, 0xe1, 0x55, 0xd2, 0xc3, 0x44,0x44, 0xc3, 0xd2, 0x55, 0xe1, 0x66, 0x77, 0xf0, + 0x33, 0xb4, 0xa5, 0x22, 0x96, 0x11, 0x00, 0x87,0x87, 0x00, 0x11, 0x96, 0x22, 0xa5, 0xb4, 0x33, + 0x22, 0xa5, 0xb4, 0x33, 0x87, 0x00, 0x11, 0x96,0x96, 0x11, 0x00, 0x87, 0x33, 0xb4, 0xa5, 0x22, + 0xe1, 0x66, 0x77, 0xf0, 0x44, 0xc3, 0xd2, 0x55,0x55, 0xd2, 0xc3, 0x44, 0xf0, 0x77, 0x66, 0xe1, + 0x11, 0x96, 0x87, 0x00, 0xb4, 0x33, 0x22, 0xa5,0xa5, 0x22, 0x33, 0xb4, 0x00, 0x87, 0x96, 0x11, + 0xd2, 0x55, 0x44, 0xc3, 0x77, 0xf0, 0xe1, 0x66,0x66, 0xe1, 0xf0, 0x77, 0xc3, 0x44, 0x55, 0xd2, + 0xc3, 0x44, 0x55, 0xd2, 0x66, 0xe1, 0xf0, 0x77,0x77, 0xf0, 0xe1, 0x66, 0xd2, 0x55, 0x44, 0xc3, + 0x00, 0x87, 0x96, 0x11, 0xa5, 0x22, 0x33, 0xb4,0xb4, 0x33, 0x22, 0xa5, 0x11, 0x96, 0x87, 0x00 +}; + +static const char SUPERBLOCK_MAGIC[] = "Sony PS2 Memory Card Format "; +static const char SUPERBLOCK_VERSION[] = "1.2.0.0\0\0\0\0"; + +static char vmcpath[256] = ""; +static uint8_t *vmc_data = NULL; +static size_t vmc_size = 0; + +struct MCDevInfo { /* size = 384 */ + uint8_t magic[28]; /* Superblock magic, on PS2 MC : "Sony PS2 Memory Card Format " */ + uint8_t version[12]; /* Version number of the format used, 1.2 indicates full support for bad_block_list */ + uint16_t pagesize; /* size in bytes of a memory card page */ + uint16_t pages_per_cluster; /* number of pages in a cluster */ + uint16_t blocksize; /* number of pages in an erase block */ + uint16_t unused; /* unused */ + uint32_t clusters_per_card; /* total size in clusters of the memory card */ + uint32_t alloc_offset; /* Cluster offset of the first allocatable cluster. Cluster values in the FAT and directory entries */ + /* are relative to this. This is the cluster immediately after the FAT */ + uint32_t alloc_end; /* The cluster after the highest allocatable cluster. Relative to alloc_offset. Not used */ + uint32_t rootdir_cluster; /* First cluster of the root directory. Relative to alloc_offset. Must be zero */ + uint32_t backup_block1; /* Erase block used as a backup area during programming. Normally the the last block on the card, */ + /* it may have a different value if that block was found to be bad */ + uint32_t backup_block2; /* This block should be erased to all ones. Normally the the second last block on the card */ + uint8_t unused2[8]; + uint32_t ifc_list[32]; /* List of indirect FAT clusters. On a standard 8M card there's only one indirect FAT cluster */ + uint32_t bad_block_list[32]; /* List of erase blocks that have errors and shouldn't be used */ + uint8_t cardtype; /* Memory card type. Must be 2, indicating that this is a PS2 memory card */ + uint8_t cardflags; /* Physical characteristics of the memory card */ + uint16_t unused3; + uint32_t cluster_size; + uint32_t FATentries_per_cluster; + uint32_t clusters_per_block; + uint32_t cardform; + uint32_t rootdir_cluster2; + uint32_t unknown1; + uint32_t unknown2; + uint32_t max_allocatable_clusters; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; +} __attribute__((packed)); + +static struct MCDevInfo mcio_devinfo; + +struct MCCacheEntry { + int32_t cluster; + uint8_t *cl_data; + uint8_t wr_flag; + uint8_t rd_flag; +} __attribute__((packed)); + +struct MCCacheDir { + int32_t cluster; + int32_t fsindex; + int32_t maxent; + uint32_t unused; +} __attribute__((packed)); + +struct MCFatCluster { + int32_t entry[MCIO_CLUSTERFATENTRIES]; +} __attribute__((packed)); + +#define MAX_CACHEENTRY 36 +static uint8_t mcio_cachebuf[MAX_CACHEENTRY * MCIO_CLUSTERSIZE]; +static struct MCCacheEntry mcio_entrycache[MAX_CACHEENTRY]; +static struct MCCacheEntry *mcio_mccache[MAX_CACHEENTRY]; + +static struct MCCacheEntry *pmcio_entrycache; +static struct MCCacheEntry **pmcio_mccache; + +struct MCFatCache { + int32_t entry[(MCIO_CLUSTERFATENTRIES * 2)+1]; +} __attribute__((packed)); + +static struct MCFatCache mcio_fatcache; + +#define MAX_CACHEDIRENTRY 3 +static struct MCFsEntry mcio_dircache[MAX_CACHEDIRENTRY]; + + +static uint8_t mcio_pagebuf[1056]; +static uint8_t *mcio_pagedata[32]; +static uint8_t mcio_eccdata[512]; /* size for 32 ecc */ + +static int32_t mcio_badblock = 0; +static int32_t mcio_replacementcluster[16]; + + +struct MCFHandle { /* size = 48 */ + uint8_t status; + uint8_t wrflag; + uint8_t rdflag; + uint8_t unknown1; + uint8_t drdflag; + uint8_t unknown2; + uint16_t unknown3; + uint32_t position; + uint32_t filesize; + uint32_t freeclink; + uint32_t clink; + uint32_t clust_offset; + uint32_t cluster; + uint32_t fsindex; + uint32_t parent_cluster; + uint32_t parent_fsindex; +}; + +#define MAX_FDHANDLES 3 +struct MCFHandle mcio_fdhandles[MAX_FDHANDLES]; + +static int Card_FileClose(int fd); + + +static void long_multiply(uint32_t v1, uint32_t v2, uint32_t *HI, uint32_t *LO) +{ + uint32_t a, b, c, d; + uint32_t x, y; + + a = (v1 >> 16) & 0xffff; + b = v1 & 0xffff; + c = (v2 >> 16) & 0xffff; + d = v2 & 0xffff; + + *LO = b * d; + x = a * d + c * b; + y = ((*LO >> 16) & 0xffff) + x; + + *LO = (*LO & 0xffff) | ((y & 0xffff) << 16); + *HI = (y >> 16) & 0xffff; + + *HI += a * c; +} + +static void Card_DataChecksum(uint8_t *pagebuf, uint8_t *ecc) +{ + uint8_t *p, *p_ecc; + int32_t i, a2, a3, v, t0; + const uint8_t *mcio_xortable = ECC_Table; + + p = pagebuf; + a2 = 0; + a3 = 0; + t0 = 0; + + for (i=0; i<128; i++) { + v = mcio_xortable[*p++]; + a2 ^= v; + if (v & 0x80) { + a3 ^= ~i; + t0 ^= i; + } + } + + p_ecc = ecc; + p_ecc[0] = ~a2 & 0x77; + p_ecc[1] = ~a3 & 0x7F; + p_ecc[2] = ~t0 & 0x7F; +} + +static int Card_CorrectData(uint8_t *pagebuf, uint8_t *ecc) +{ + int32_t xor0, xor1, xor2, xor3, xor4; + uint8_t eccbuf[12]; + + Card_DataChecksum(pagebuf, eccbuf); + + xor0 = ecc[0] ^ eccbuf[0]; + xor1 = ecc[1] ^ eccbuf[1]; + xor2 = ecc[2] ^ eccbuf[2]; + + xor3 = xor1 ^ xor2; + xor4 = (xor0 & 0xf) ^ (xor0 >> 4); + + if (!xor0 && !xor1 && !xor2) + return 0; + + if ((xor3 == 0x7f) && (xor4 == 0x7)) { + ecc[xor2] ^= 1 << (xor0 >> 4); + return -1; + } + + xor0 = 0; + for (xor2=7; xor2>=0; xor2--) { + if ((xor3 & 1)) + xor0++; + xor3 = xor3 >> 1; + } + + for (xor2=3; xor2>=0; xor2--) { + if ((xor4 & 1)) + xor0++; + xor4 = xor4 >> 1; + } + + if (xor0 == 1) + return -2; + + return -3; +} + +static int mcio_chrpos(char *str, char chr) +{ + char *p; + + p = str; + for (p = str; *p != 0; p++) { + if (*p == (chr & 0xff)) + break; + } + + if (*p != (chr & 0xff)) + return -1; + + return p - str; +} + +static void mcio_getmcrtime(struct sceMcStDateTime *mc_time) +{ + time_t rawtime; + struct tm *ptm; + + time(&rawtime); + ptm = gmtime(&rawtime); + + mc_time->Resv2 = 0; + mc_time->Sec = ptm->tm_sec; + mc_time->Min = ptm->tm_min; + mc_time->Hour = ptm->tm_hour; + mc_time->Day = ptm->tm_mday; + mc_time->Month = ptm->tm_mon + 1; + append_le_uint16((uint8_t *)&mc_time->Year, ptm->tm_year + 1900); +} + +static void mcio_copy_dirent(struct io_dirent *dirent, const struct MCFsEntry *fse) +{ + memset((void *)dirent, 0, sizeof(struct io_dirent)); + strncpy(dirent->name, fse->name, 32); + dirent->name[32] = 0; + + dirent->stat.mode = read_le_uint16((uint8_t *)&fse->mode); + dirent->stat.attr = read_le_uint32((uint8_t *)&fse->attr); + dirent->stat.size = read_le_uint32((uint8_t *)&fse->length); + + memcpy(&dirent->stat.ctime, &fse->created, sizeof(struct sceMcStDateTime)); + memcpy(&dirent->stat.mtime, &fse->modified, sizeof(struct sceMcStDateTime)); +} + +static void mcio_copy_mcentry(struct MCFsEntry *fse, const struct io_dirent *dirent) +{ + append_le_uint16((uint8_t *)&fse->mode, dirent->stat.mode); + append_le_uint32((uint8_t *)&fse->attr, dirent->stat.attr); + + memcpy(&fse->created, &dirent->stat.ctime, sizeof(struct sceMcStDateTime)); + memcpy(&fse->modified, &dirent->stat.mtime, sizeof(struct sceMcStDateTime)); +} + +static int Card_GetSpecs(uint16_t *pagesize, uint16_t *blocksize, int32_t *cardsize, uint8_t *flags) +{ + if (memcmp(SUPERBLOCK_MAGIC, vmc_data, 28) != 0) + return sceMcResFailDetect2; + + struct MCDevInfo *mcdi = (struct MCDevInfo *)vmc_data; + + // check for non-ECC images + *flags = mcdi->cardflags & ((vmc_size % 0x800000 == 0) ? ~CF_USE_ECC : 0xFF); + append_le_uint16((uint8_t*)pagesize, read_le_uint16((uint8_t*)&mcdi->pagesize)); + append_le_uint16((uint8_t*)blocksize, read_le_uint16((uint8_t*)&mcdi->blocksize)); + *cardsize = read_le_uint32((uint8_t*)&mcdi->clusters_per_card) * read_le_uint16((uint8_t*)&mcdi->pages_per_cluster); + + return sceMcResSucceed; +} + +static int Card_EraseBlock(int32_t block, uint8_t **pagebuf, uint8_t *eccbuf) +{ + int32_t size, ecc_offset, page; + uint8_t *p_ecc; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + int ecc = (mcdi->cardflags & CF_USE_ECC) ? 1 : 0; + int val = (mcdi->cardflags & CF_ERASE_ZEROES) ? 0x00 : 0xFF; + int sparesize = pagesize >> 5; + + page = block * blocksize; + + for (int i = 0; i < blocksize; i++, page++) { + memset(&vmc_data[page * (pagesize + ecc*sparesize)], val, pagesize); + + if (mcdi->cardflags & CF_USE_ECC) + { + uint8_t* tmp_ecc = calloc(1, sparesize); + p_ecc = tmp_ecc; + size = 0; + + while (size < pagesize) { + Card_DataChecksum(&vmc_data[page * (pagesize + ecc*sparesize)] + size, p_ecc); + size += 128; + p_ecc += 3; + } + + memcpy(&vmc_data[page * (pagesize + ecc*sparesize) + pagesize], tmp_ecc, sparesize); + free(tmp_ecc); + } + } + + if (pagebuf && eccbuf) { /* This part leave the first ecc byte of each block page in eccbuf */ + memset(eccbuf, 0, 32); + + page = 0; + + while (page < blocksize) { + ecc_offset = page * pagesize; + if (ecc_offset < 0) + ecc_offset += 0x1f; + ecc_offset = ecc_offset >> 5; + p_ecc = (uint8_t *)(eccbuf + ecc_offset); + size = 0; + while (size < pagesize) { + if (*pagebuf) + Card_DataChecksum((uint8_t *)(*pagebuf + size), p_ecc); + size += 128; + p_ecc += 3; + } + pagebuf++; + page++; + } + } + + return sceMcResSucceed; +} + +static int Card_WritePageData(int32_t page, uint8_t *pagebuf, uint8_t *eccbuf) +{ + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + int ecc = (mcdi->cardflags & CF_USE_ECC) ? 1 : 0; + int sparesize = pagesize >> 5; + + memcpy(&vmc_data[page * (pagesize + ecc*sparesize)], pagebuf, pagesize); + + if (mcdi->cardflags & CF_USE_ECC) + memcpy(&vmc_data[page * (pagesize + ecc*sparesize) + pagesize], eccbuf, sparesize); + + return sceMcResSucceed; +} + +static int Card_ReadPageData(int32_t page, uint8_t *pagebuf, uint8_t *eccbuf) +{ + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + int ecc = (mcdi->cardflags & CF_USE_ECC) ? 1 : 0; + int sparesize = pagesize >> 5; + + memcpy(pagebuf, &vmc_data[page * (pagesize + ecc*sparesize)], pagesize); + + if (mcdi->cardflags & CF_USE_ECC) + memcpy(eccbuf, &vmc_data[page * (pagesize + ecc*sparesize) + pagesize], sparesize); + + return sceMcResSucceed; +} + +static int Card_SetDeviceSpecs(void) +{ + int32_t cardsize; + uint16_t blocksize, pages_per_cluster; + struct MCDevInfo *mcdi = &mcio_devinfo; + void *ps = (void *)&mcdi->pagesize; + void *bs = (void *)&mcdi->blocksize; + + if (Card_GetSpecs(ps, bs, &cardsize, &mcdi->cardflags) != sceMcResSucceed) + return sceMcResFullDevice; + + append_le_uint16((uint8_t *)&mcdi->pages_per_cluster, MCIO_CLUSTERSIZE / read_le_uint16((uint8_t *)&mcdi->pagesize)); + append_le_uint32((uint8_t *)&mcdi->cluster_size, (uint32_t)MCIO_CLUSTERSIZE); + append_le_uint32((uint8_t *)&mcdi->unknown1, 0); + append_le_uint32((uint8_t *)&mcdi->unknown2, 0); + append_le_uint16((uint8_t *)&mcdi->unused, UINT16_C(0xff00)); + append_le_uint32((uint8_t *)&mcdi->FATentries_per_cluster, (uint32_t)MCIO_CLUSTERFATENTRIES); + append_le_uint32((uint8_t *)&mcdi->unknown5, -1); + append_le_uint32((uint8_t *)&mcdi->rootdir_cluster2, read_le_uint32((uint8_t *)&mcdi->rootdir_cluster)); + blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + pages_per_cluster = read_le_uint16((uint8_t *)&mcdi->pages_per_cluster); + append_le_uint32((uint8_t *)&mcdi->clusters_per_block, blocksize / pages_per_cluster); + append_le_uint32((uint8_t *)&mcdi->clusters_per_card, (cardsize / blocksize) * (blocksize / pages_per_cluster)); + + return sceMcResSucceed; +} + +static int Card_ReadPage(int32_t page, uint8_t *pagebuf) +{ + int r, index, ecres, retries, count, erase_byte; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + uint8_t eccbuf[32]; + uint8_t *pdata, *peccb; + + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + count = pagesize >> 7; + erase_byte = (mcdi->cardflags & CF_ERASE_ZEROES) ? 0x00 : 0xFF; + + retries = 0; + ecres = sceMcResSucceed; + do { + if (Card_ReadPageData(page, pagebuf, eccbuf) == sceMcResSucceed) { + if (mcdi->cardflags & CF_USE_ECC) { /* checking ECC from spare data block */ + /* check for erased page (last byte of spare data set to 0xFF or 0x0) */ + int32_t sparesize = pagesize >> 5; + if (eccbuf[sparesize - 1] == erase_byte) + break; + + index = 0; + peccb = (uint8_t *)eccbuf; + pdata = (uint8_t *)pagebuf; + + while (index++ < count) { + r = Card_CorrectData(pdata, peccb); + if (r < ecres) + ecres = r; + + peccb += 3; + pdata += 128; + } ; + + if (ecres == sceMcResSucceed) + break; + + if ((retries == 4) && (!(ecres < -2))) + break; + } + else break; + } + } while (++retries < 5); + + if (retries < 5) + return sceMcResSucceed; + + return (ecres != sceMcResSucceed) ? sceMcResNoFormat : sceMcResChangedCard; +} + +static void Card_InitCache(void) +{ + int i, j; + uint8_t *p; + + j = MAX_CACHEENTRY - 1; + p = (uint8_t *)mcio_cachebuf; + + for (i = 0; i < MAX_CACHEENTRY; i++) { + mcio_entrycache[i].cl_data = (uint8_t *)p; + mcio_mccache[i] = (struct MCCacheEntry *)&mcio_entrycache[j - i]; + mcio_entrycache[i].cluster = -1; + p += MCIO_CLUSTERSIZE; + } + + pmcio_entrycache = (struct MCCacheEntry *)mcio_entrycache; + pmcio_mccache = (struct MCCacheEntry **)mcio_mccache; + + append_le_uint32((uint8_t *)&mcio_devinfo.unknown3, -1); + append_le_uint32((uint8_t *)&mcio_devinfo.unknown4, -1); + append_le_uint32((uint8_t *)&mcio_devinfo.unknown5, -1); + + memset((void *)&mcio_fatcache, -1, sizeof(mcio_fatcache)); + + append_le_uint32((uint8_t *)&mcio_fatcache.entry[0], 0); +} + +static int Card_ClearCache(void) +{ + int i, j; + struct MCCacheEntry **pmce = (struct MCCacheEntry **)pmcio_mccache; + struct MCCacheEntry *mce, *mce_save; + + for (i = MAX_CACHEENTRY - 1; i >= 0; i--) { + mce = (struct MCCacheEntry *)pmce[i]; + if (mce->cluster >= 0) { + mce->wr_flag = 0; + mce->cluster = -1; + } + } + + for (i = 0; i < (MAX_CACHEENTRY - 1); i++) { + mce = mce_save = (struct MCCacheEntry *)pmce[i]; + if (mce->cluster < 0) { + for (j = i+1; j < MAX_CACHEENTRY; j++) { + mce = (struct MCCacheEntry *)pmce[j]; + if (mce->cluster >= 0) + break; + } + if (j == MAX_CACHEENTRY) + break; + + pmce[i] = (struct MCCacheEntry *)pmce[j]; + pmce[j] = (struct MCCacheEntry *)mce_save; + } + } + + memset((void *)&mcio_fatcache, -1, sizeof(mcio_fatcache)); + + append_le_uint32((uint8_t *)&mcio_fatcache.entry[0], 0); + + return sceMcResSucceed; +} + +static struct MCCacheEntry *Card_GetCacheEntry(int32_t cluster) +{ + int i; + struct MCCacheEntry *mce = (struct MCCacheEntry *)pmcio_entrycache; + + for (i = 0; i < MAX_CACHEENTRY; i++) { + if (mce->cluster == cluster) + return mce; + mce++; + } + + return NULL; +} + +static void Card_FreeCluster(int32_t cluster) /* release cluster from entrycache */ +{ + int i; + struct MCCacheEntry *mce = (struct MCCacheEntry *)pmcio_entrycache; + + for (i = 0; i < MAX_CACHEENTRY; i++) { + if (mce->cluster == cluster) { + mce->cluster = -1; + mce->wr_flag = 0; + } + mce++; + } +} + +static void Card_AddCacheEntry(struct MCCacheEntry *mce) +{ + int i; + struct MCCacheEntry **pmce = (struct MCCacheEntry **)pmcio_mccache; + + for (i = MAX_CACHEENTRY-1; i >= 0; i--) { + if (pmce[i] == mce) + break; + } + + for ( ; i != 0; i--) { + pmce[i] = pmce[i-1]; + } + + pmce[0] = (struct MCCacheEntry *)mce; +} + +static int Card_ReplaceBackupBlock(int32_t block) +{ + int i; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + if (mcio_badblock > 0) + return sceMcResFailReplace; + + for (i = 0; i < 16; i++) { + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->bad_block_list[i]) == -1) + break; + } + + uint32_t max_allocatable_clusters = read_le_uint32((uint8_t *)&mcdi->max_allocatable_clusters); + + if (i < 16) { + uint32_t alloc_offset = read_le_uint32((uint8_t *)&mcdi->alloc_offset); + uint32_t alloc_end = read_le_uint32((uint8_t *)&mcdi->alloc_end); + if ((alloc_end - max_allocatable_clusters) < 8) + return sceMcResFullDevice; + + append_le_uint32((uint8_t *)&mcdi->alloc_end, alloc_end - 8); + append_le_uint32((uint8_t *)&mcdi->bad_block_list[i], block); + mcio_badblock = -1; + + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + + return (alloc_offset + read_le_uint32((uint8_t *)&mcdi->alloc_end)) / clusters_per_block; + } + + return sceMcResFullDevice; +} + +static int Card_FillBackupBlock1(int32_t block, uint8_t **pagedata, uint8_t *eccdata) +{ + int r, i; + int32_t sparesize, page_offset; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + uint8_t *p_ecc; + + int16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + sparesize = pagesize >> 5; + + uint32_t backup_block1 = read_le_uint32((uint8_t *)&mcdi->backup_block1); + uint32_t backup_block2 = read_le_uint32((uint8_t *)&mcdi->backup_block2); + uint32_t alloc_offset = read_le_uint32((uint8_t *)&mcdi->alloc_offset); + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + + if ((mcio_badblock != 0) && (mcio_badblock != block)) + return sceMcResFailReplace; + + if ((int32_t)(alloc_offset / clusters_per_block) == block) /* this refuse to take care of a bad rootdir cluster */ + return sceMcResFailReplace; + + r = Card_EraseBlock(backup_block2, NULL, NULL); + if (r != sceMcResSucceed) + return r; + + r = Card_EraseBlock(backup_block1, NULL, NULL); + if (r != sceMcResSucceed) + return r; + + for (i = 0; i < 16; i++) { + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->bad_block_list[i]) == -1) + break; + } + + if (i >= 16) + return sceMcResFailReplace; + + page_offset = backup_block1 * blocksize; + p_ecc = (uint8_t *)eccdata; + + for (i = 0; i < blocksize; i++) { + r = Card_WritePageData(page_offset + i, pagedata[i], p_ecc); + if (r != sceMcResSucceed) + return r; + p_ecc += sparesize; + } + + mcio_badblock = block; + + i = 15; + do { + mcio_replacementcluster[i] = 0; + } while (--i >= 0); + + return sceMcResSucceed; +} + +static int Card_FlushCacheEntry(struct MCCacheEntry *mce) +{ + int r, i, j, ecc_count; + int temp1, temp2, offset, pageindex; + int32_t clusters_per_block, blocksize, cardtype, pagesize, sparesize, flag, cluster, block; + struct MCCacheEntry *pmce[16]; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mcee; + uint8_t mcio_backupbuf[16384]; + uint8_t eccbuf[32]; + uint8_t *p_page, *p_ecc; + + if (mce->wr_flag == 0) + return sceMcResSucceed; + + pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + int16_t pages_per_cluster = (int16_t)read_le_uint16((uint8_t *)&mcdi->pages_per_cluster); + cardtype = mcdi->cardtype; + + if (cardtype == 0) { + mce->wr_flag = 0; + return sceMcResSucceed; + } + + uint32_t backup_block1 = read_le_uint32((uint8_t *)&mcdi->backup_block1); + uint32_t backup_block2 = read_le_uint32((uint8_t *)&mcdi->backup_block2); + + clusters_per_block = (int32_t)read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + block = mce->cluster / clusters_per_block; + blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + sparesize = pagesize >> 5; + flag = 0; + + memset((void *)pmce, 0, sizeof(pmce)); + + i = 0; + if (MAX_CACHEENTRY > 0) { + mcee = (struct MCCacheEntry *)pmcio_entrycache; + do { + if (mcee->wr_flag == mce->wr_flag) { + temp1 = mcee->cluster / clusters_per_block; + temp2 = mcee->cluster % clusters_per_block; + + if (temp1 == block) { + pmce[temp2] = (struct MCCacheEntry *)mcee; + if (mcee->rd_flag == 0) + flag = 1; + } + } + mcee++; + } while (++i < MAX_CACHEENTRY); + } + + if (clusters_per_block > 0) { + i = 0; + pageindex = 0; + cluster = block * clusters_per_block; + + do { + if (pmce[i] != 0) { + j = 0; + offset = 0; + for (j = 0; j < pages_per_cluster; j++) { + mcio_pagedata[pageindex + j] = (uint8_t *)(pmce[i]->cl_data + offset); + offset += pagesize; + } + } + else { + j = 0; + do { + offset = (pageindex + j) * pagesize; + mcio_pagedata[pageindex + j] = (uint8_t *)(mcio_backupbuf + offset); + + r = Card_ReadPage(((cluster + i) * pages_per_cluster) + j, mcio_backupbuf + offset); + if (r != sceMcResSucceed) + return -51; + } while (++j < pages_per_cluster); + } + + pageindex += pages_per_cluster; + } while (++i < clusters_per_block); + } + +lbl1: + if ((flag != 0) && (mcio_badblock <= 0)) { + r = Card_EraseBlock(backup_block1, (uint8_t **)mcio_pagedata, mcio_eccdata); + if (r == sceMcResFailReplace) { +lbl2: + r = Card_ReplaceBackupBlock(backup_block1); + append_le_uint32((uint8_t *)&mcdi->backup_block1, r); + backup_block1 = r; + goto lbl1; + } + if (r != sceMcResSucceed) + return -52; + + append_le_uint32((uint8_t *)&mcio_pagebuf, block | 0x80000000); + p_page = (uint8_t *)mcio_pagebuf; + p_ecc = (uint8_t *)eccbuf; + + i = 0; + do { + if (pagesize < 0) + ecc_count = (pagesize + 0x7f) >> 7; + else + ecc_count = pagesize >> 7; + + if (i >= ecc_count) + break; + + Card_DataChecksum(p_page, p_ecc); + + p_ecc += 3; + p_page += 128; + i++; + } while (1); + + r = Card_WritePageData(backup_block2 * blocksize, mcio_pagebuf, eccbuf); + if (r == sceMcResFailReplace) + goto lbl3; + if (r != sceMcResSucceed) + return -53; + + if (r < blocksize) { + i = 0; + p_ecc = (void *)mcio_eccdata; + + do { + r = Card_WritePageData((backup_block1 * blocksize) + i, mcio_pagedata[i], p_ecc); + if (r == sceMcResFailReplace) + goto lbl2; + if (r != sceMcResSucceed) + return -54; + p_ecc += sparesize; + } while (++i < blocksize); + } + + r = Card_WritePageData((backup_block2 * blocksize) + 1, mcio_pagebuf, eccbuf); + if (r == sceMcResFailReplace) + goto lbl3; + if (r != sceMcResSucceed) + return -55; + } + + r = Card_EraseBlock(block, (uint8_t **)mcio_pagedata, mcio_eccdata); + if (r == sceMcResFailReplace) { + r = Card_FillBackupBlock1(block, (uint8_t **)mcio_pagedata, mcio_eccdata); + for (i = 0; i < clusters_per_block; i++) { + if (pmce[i] != 0) + pmce[i]->wr_flag = 0; + } + if (r == sceMcResFailReplace) + return r; + return -58; + } + if (r != sceMcResSucceed) + return -57; + + if (blocksize > 0) { + i = 0; + p_ecc = (uint8_t *)mcio_eccdata; + + do { + if (pmce[i / pages_per_cluster] == 0) { + r = Card_WritePageData((block * blocksize) + i, mcio_pagedata[i], p_ecc); + if (r == sceMcResFailReplace) { + r = Card_FillBackupBlock1(block, (uint8_t **)mcio_pagedata, mcio_eccdata); + for (i = 0; i < clusters_per_block; i++) { + if (pmce[i] != 0) + pmce[i]->wr_flag = 0; + } + if (r == sceMcResFailReplace) + return r; + return -58; + } + if (r != sceMcResSucceed) + return -57; + } + p_ecc += sparesize; + } while (++i < blocksize); + } + + if (blocksize > 0) { + i = 0; + p_ecc = (uint8_t *)mcio_eccdata; + + do { + if (pmce[i / pages_per_cluster] != 0) { + r = Card_WritePageData((block * blocksize) + i, mcio_pagedata[i], p_ecc); + if (r == sceMcResFailReplace) { + r = Card_FillBackupBlock1(block, (uint8_t **)mcio_pagedata, mcio_eccdata); + for (i = 0; i < clusters_per_block; i++) { + if (pmce[i] != 0) + pmce[i]->wr_flag = 0; + } + if (r == sceMcResFailReplace) + return r; + return -58; + } + if (r != sceMcResSucceed) + return -57; + } + p_ecc += sparesize; + } while (++i < blocksize); + } + + if (clusters_per_block > 0) { + i = 0; + do { + if (pmce[i] != 0) + pmce[i]->wr_flag = 0; + } while (++i < clusters_per_block); + } + + if ((flag != 0) && (mcio_badblock <= 0)) { + r = Card_EraseBlock(backup_block2, NULL, NULL); + if (r == sceMcResFailReplace) { + goto lbl3; + } + if (r != sceMcResSucceed) + return -58; + } + goto lbl_exit; + +lbl3: + r = Card_ReplaceBackupBlock(backup_block2); + append_le_uint32((uint8_t *)&mcdi->backup_block2, r); + backup_block2 = r; + + goto lbl1; + +lbl_exit: + return sceMcResSucceed; +} + +static int Card_FlushMCCache(void) +{ + int i, r; + struct MCCacheEntry **pmce = (struct MCCacheEntry **)pmcio_mccache; + struct MCCacheEntry *mce; + + i = MAX_CACHEENTRY - 1; + + if (i >= 0) { + do { + mce = (struct MCCacheEntry *)pmce[i]; + if (mce->wr_flag != 0) { + r = Card_FlushCacheEntry((struct MCCacheEntry *)mce); + if (r != sceMcResSucceed) + return r; + } + i--; + } while (i >= 0); + } + + return sceMcResSucceed; +} + +static int Card_ReadCluster(int32_t cluster, struct MCCacheEntry **pmce) +{ + int r, i; + int32_t block, block_offset; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce; + + if (mcio_badblock > 0) { + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + uint32_t backup_block1 = read_le_uint32((uint8_t *)&mcdi->backup_block1); + + block = cluster / clusters_per_block; + block_offset = cluster % clusters_per_block; + + if (block == mcio_badblock) { + cluster = (backup_block1 * clusters_per_block) + block_offset; + } + else { + if (mcio_badblock > 0) { + for (i = 0; i < (int32_t)clusters_per_block; i++) { + if ((mcio_replacementcluster[i] != 0) && (mcio_replacementcluster[i] == cluster)) { + block_offset = i % clusters_per_block; + cluster = (backup_block1 * clusters_per_block) + block_offset; + } + } + } + } + } + + mce = Card_GetCacheEntry(cluster); + if (mce == NULL) { + mce = pmcio_mccache[MAX_CACHEENTRY - 1]; + + if (mce->wr_flag != 0) { + r = Card_FlushCacheEntry((struct MCCacheEntry *)mce); + if (r != sceMcResSucceed) + return r; + } + + mce->cluster = cluster; + mce->rd_flag = 0; + + uint16_t pages_per_cluster = read_le_uint16((uint8_t *)&mcdi->pages_per_cluster); + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + + for (i = 0; i < pages_per_cluster; i++) { + r = Card_ReadPage((cluster * pages_per_cluster) + i, (uint8_t *)(mce->cl_data + (i * pagesize))); + if (r != sceMcResSucceed) + return sceMcResFailReadCluster; + } + } + + Card_AddCacheEntry(mce); + *pmce = (struct MCCacheEntry *)mce; + + return sceMcResSucceed; +} + +static int Card_WriteCluster(int32_t cluster, int32_t flag) +{ + int r, i, j; + int32_t page, block; + uint32_t erase_value; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + + block = cluster / clusters_per_block; + + for (i = 0; i < 16; i++) { /* check only 16 bad blocks ? */ + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->bad_block_list[i]) < 0) + break; + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->bad_block_list[i]) == block) + return 0; + } + + if (flag) { + for (i = 1; i < blocksize; i++) + mcio_pagedata[i] = NULL; + + mcio_pagedata[0] = mcio_pagebuf; + + page = block * blocksize; + + if (mcdi->cardflags & CF_ERASE_ZEROES) + erase_value = 0xffffffff; + else + erase_value = 0x00000000; + + memset(mcio_pagebuf, erase_value, pagesize); + + r = Card_EraseBlock(block, (uint8_t **)mcio_pagedata, (uint8_t *)mcio_eccdata); + if (r == sceMcResFailReplace) + return 0; + if (r != sceMcResSucceed) + return sceMcResChangedCard; + + for (i = 1; i < blocksize; i++) { + r = Card_WritePageData(page + i, mcio_pagebuf, mcio_eccdata); + if (r == sceMcResFailReplace) + return 0; + if (r != sceMcResSucceed) + return sceMcResNoFormat; + } + + for (i = 1; i < blocksize; i++) { + r = Card_ReadPage(page + i, mcio_pagebuf); + if (r == sceMcResNoFormat) + return 0; + if (r != sceMcResSucceed) + return sceMcResFullDevice; + + for (j = 0; j < (pagesize >> 2); j++) { + if (*((uint32_t *)&mcio_pagebuf + j) != erase_value) + return sceMcResSucceed; + } + } + + r = Card_EraseBlock(block, NULL, NULL); + if (r != sceMcResSucceed) + return sceMcResChangedCard; + + r = Card_WritePageData(page, mcio_pagebuf, mcio_eccdata); + if (r == sceMcResFailReplace) + return 0; + if (r != sceMcResSucceed) + return sceMcResNoFormat; + + r = Card_ReadPage(page, mcio_pagebuf); + if (r == sceMcResNoFormat) + return 0; + if (r != sceMcResSucceed) + return sceMcResFullDevice; + + for (j = 0; j < (pagesize >> 2); j++) { + if (*((uint32_t *)&mcio_pagebuf + j) != erase_value) + return 0; + } + + r = Card_EraseBlock(block, NULL, NULL); + if (r == sceMcResFailReplace) + return 0; + if (r != sceMcResSucceed) + return sceMcResFullDevice; + + erase_value = ~erase_value; + + for (i = 0; i < blocksize; i++) { + r = Card_ReadPage(page + i, mcio_pagebuf); + if (r != sceMcResSucceed) + return sceMcResDeniedPermit; + + for (j = 0; j < (pagesize >> 2); j++) { + if (*((uint32_t *)&mcio_pagebuf + j) != erase_value) + return 0; + } + } + } + + return 1; +} + +static int Card_FindFree(int reserve) +{ + int r; + int32_t rfree, indirect_index, ifc_index, fat_offset, indirect_offset, fat_index, block; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce1, *mce2; + + int32_t unknown2 = (int32_t)read_le_uint32((uint8_t *)&mcdi->unknown2); + int32_t FATentries_per_cluster = (int32_t)read_le_uint32((uint8_t *)&mcdi->FATentries_per_cluster); + rfree = 0; + + int32_t max_allocatable_clusters = (int32_t)read_le_uint32((uint8_t *)&mcdi->max_allocatable_clusters); + + for (fat_index = unknown2; fat_index < max_allocatable_clusters; fat_index++) { + + indirect_index = fat_index / FATentries_per_cluster; + fat_offset = fat_index % FATentries_per_cluster; + + if ((fat_offset == 0) || (fat_index == unknown2)) { + + ifc_index = indirect_index / FATentries_per_cluster; + int32_t ifc = (int32_t)read_le_uint32((uint8_t *)&mcdi->ifc_list[ifc_index]); + r = Card_ReadCluster(ifc, &mce1); + if (r != sceMcResSucceed) + return r; + + indirect_offset = indirect_index % FATentries_per_cluster; + struct MCFatCluster *fc = (struct MCFatCluster *)mce1->cl_data; + r = Card_ReadCluster(read_le_uint32((uint8_t *)&fc->entry[indirect_offset]), &mce2); + if (r != sceMcResSucceed) + return r; + } + + struct MCFatCluster *fc = (struct MCFatCluster *)mce2->cl_data; + + if ((int32_t)read_le_uint32((uint8_t *)&fc->entry[fat_offset]) >= 0) { + int32_t alloc_offset = (int32_t)read_le_uint32((uint8_t *)&mcdi->alloc_offset); + int32_t clusters_per_block = (int32_t)read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + block = (alloc_offset + fat_offset) / clusters_per_block; + if (block != mcio_badblock) { + if (reserve) { + append_le_uint32((uint8_t *)&fc->entry[fat_offset], 0xffffffff); + mce2->wr_flag = 1; + append_le_uint32((uint8_t *)&mcdi->unknown2, fat_index); + return fat_index; + } + rfree++; + } + } + } + + if (reserve) + return sceMcResFullDevice; + + return (rfree) ? rfree : sceMcResFullDevice; +} + +static int Card_SetFatEntry(int32_t fat_index, int32_t fat_entry) +{ + int r; + int32_t ifc_index, indirect_index, indirect_offset, fat_offset; + struct MCCacheEntry *mce; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + int32_t FATentries_per_cluster = (int32_t)read_le_uint32((uint8_t *)&mcdi->FATentries_per_cluster); + + indirect_index = fat_index / FATentries_per_cluster; + fat_offset = fat_index % FATentries_per_cluster; + + ifc_index = indirect_index / FATentries_per_cluster; + indirect_offset = indirect_index % FATentries_per_cluster; + + int32_t ifc = (int32_t)read_le_uint32((uint8_t *)&mcdi->ifc_list[ifc_index]); + + r = Card_ReadCluster(ifc, &mce); + if (r != sceMcResSucceed) + return r; + + struct MCFatCluster *fc = (struct MCFatCluster *)mce->cl_data; + + r = Card_ReadCluster(read_le_uint32((uint8_t *)&fc->entry[indirect_offset]), &mce); + if (r != sceMcResSucceed) + return r; + + fc = (struct MCFatCluster *)mce->cl_data; + + append_le_uint32((uint8_t *)&fc->entry[fat_offset], fat_entry); + mce->wr_flag = 1; + + return sceMcResSucceed; +} + +static int Card_GetFatEntry(int32_t fat_index, int32_t *fat_entry) +{ + int r, ifc_index, indirect_index, indirect_offset, fat_offset; + struct MCCacheEntry *mce; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + int32_t FATentries_per_cluster = (int32_t)read_le_uint32((uint8_t *)&mcdi->FATentries_per_cluster); + + indirect_index = fat_index / FATentries_per_cluster; + fat_offset = fat_index % FATentries_per_cluster; + + ifc_index = indirect_index / FATentries_per_cluster; + indirect_offset = indirect_index % FATentries_per_cluster; + + int32_t ifc = (int32_t)read_le_uint32((uint8_t *)&mcdi->ifc_list[ifc_index]); + + r = Card_ReadCluster(ifc, &mce); + if (r != sceMcResSucceed) + return r; + + struct MCFatCluster *fc = (struct MCFatCluster *)mce->cl_data; + + r = Card_ReadCluster(read_le_uint32((uint8_t *)&fc->entry[indirect_offset]), &mce); + if (r != sceMcResSucceed) + return r; + + fc = (struct MCFatCluster *)mce->cl_data; + + *fat_entry = read_le_uint32((uint8_t *)&fc->entry[fat_offset]); + + return sceMcResSucceed; +} + +static int Card_FatRSeek(int fd) +{ + int r; + int32_t entries_to_read, fat_index; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + int32_t fat_entry; + + int32_t cluster_size = (int32_t)read_le_uint32((uint8_t *)&mcdi->cluster_size); + entries_to_read = fh->position / cluster_size; + + if (entries_to_read < (int32_t)fh->clust_offset) + fat_index = fh->freeclink; + else { + fat_index = fh->clink; + entries_to_read -= fh->clust_offset; + } + + int32_t alloc_offset = (int32_t)read_le_uint32((uint8_t *)&mcdi->alloc_offset); + + if (entries_to_read == 0) { + if (fat_index >= 0) + return fat_index + alloc_offset; + + return sceMcResFullDevice; + } + + do { + r = Card_GetFatEntry(fat_index, &fat_entry); + if (r != sceMcResSucceed) + return r; + + fat_index = fat_entry; + + if (fat_index >= -1) + return sceMcResFullDevice; + + entries_to_read--; + + fat_index &= 0x7fffffff; + fh->clink = fat_index; + fh->clust_offset = (fh->position / cluster_size) - entries_to_read; + + } while (entries_to_read > 0); + + return fat_index + alloc_offset; +} + +static int Card_FatWSeek(int fd) /* modify FAT to hold new content for a file */ +{ + int r; + int32_t entries_to_write, fat_index, fat_entry; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce; + + int32_t cluster_size = (int32_t)read_le_uint32((uint8_t *)&mcdi->cluster_size); + entries_to_write = fh->position / cluster_size; + + if ((fh->clust_offset == 0) || (entries_to_write < (int32_t)fh->clust_offset)) { + fat_index = fh->freeclink; + + if (fat_index < 0) { + fat_index = Card_FindFree(1); + + if (fat_index < 0) + return sceMcResFullDevice; + + mce = (struct MCCacheEntry *)*pmcio_mccache; + fh->freeclink = fat_index; + + r = Card_FileClose(fd); + if (r != sceMcResSucceed) + return r; + + Card_AddCacheEntry(mce); + Card_FlushMCCache(); + } + } + else { + fat_index = fh->clink; + entries_to_write -= fh->clust_offset; + } + + if (entries_to_write != 0) { + do { + r = Card_GetFatEntry(fat_index, &fat_entry); + if (r != sceMcResSucceed) + return r; + + if (fat_entry >= (int32_t)0xffffffff) { + r = Card_FindFree(1); + if (r < 0) + return r; + fat_entry = r; + fat_entry |= 0x80000000; + + mce = (struct MCCacheEntry *)*pmcio_mccache; + + r = Card_SetFatEntry(fat_index, fat_entry); + if (r != sceMcResSucceed) + return r; + + Card_AddCacheEntry(mce); + } + + entries_to_write--; + fat_index = fat_entry & 0x7fffffff; + } while (entries_to_write > 0); + } + + fh->clink = fat_index; + fh->clust_offset = fh->position / cluster_size; + + return sceMcResSucceed; +} + +static int Card_ReadDirEntry(int32_t cluster, int32_t fsindex, struct MCFsEntry **pfse) +{ + int r, i; + int32_t maxent, index, clust; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCFatCache *fci = (struct MCFatCache *)&mcio_fatcache; + struct MCCacheEntry *mce; + + uint32_t cluster_size = (int32_t)read_le_uint32((uint8_t *)&mcdi->cluster_size); + + maxent = 1026 / (cluster_size >> 9); + index = fsindex / (cluster_size >> 9); + + clust = cluster; + i = 0; + if ((cluster == 0) && (index != 0)) { + if (index < maxent) { + i = index; + if ((read_le_uint32((uint8_t *)&fci->entry[index])) >= 0 ) + clust = read_le_uint32((uint8_t *)&fci->entry[index]); + } + i = 0; + if (index > 0) { + do { + if (i >= maxent) + break; + if (read_le_uint32((uint8_t *)&fci->entry[i]) < 0) + break; + clust = read_le_uint32((uint8_t *)&fci->entry[i]); + } while (++i < index); + } + i--; + } + + if (i < index) { + do { + r = Card_GetFatEntry(clust, &clust); + if (r != sceMcResSucceed) + return r; + + if (clust == (int32_t)0xffffffff) + return sceMcResNoEntry; + clust &= 0x7fffffff; + + i++; + if (cluster == 0) { + if (i < maxent) + append_le_uint32((uint8_t *)&fci->entry[i], clust); + } + } while (i < index); + } + + uint32_t alloc_offset = read_le_uint32((uint8_t *)&mcdi->alloc_offset); + + r = Card_ReadCluster(alloc_offset + clust, &mce); + if (r != sceMcResSucceed) + return r; + + *pfse = (struct MCFsEntry *)(mce->cl_data + ((fsindex % (cluster_size >> 9)) << 9)); + + return sceMcResSucceed; +} + +static int Card_CreateDirEntry(int32_t parent_cluster, int32_t num_entries, int32_t cluster, struct sceMcStDateTime *ctime) +{ + int r; + struct MCCacheEntry *mce; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCFsEntry *mfe, *mfe_next, *pfse; + + uint32_t alloc_offset = read_le_uint32((uint8_t *)&mcdi->alloc_offset); + + r = Card_ReadCluster(alloc_offset + cluster, &mce); + if (r != sceMcResSucceed) + return r; + + memset(mce->cl_data, 0, MCIO_CLUSTERSIZE); + + mfe = (struct MCFsEntry *)mce->cl_data; + mfe_next = (struct MCFsEntry *)(mce->cl_data + sizeof(struct MCFsEntry)); + + append_le_uint16((uint8_t *)&mfe->mode, sceMcFileAttrReadable | sceMcFileAttrWriteable | sceMcFileAttrExecutable \ + | sceMcFileAttrSubdir | sceMcFile0400 | sceMcFileAttrExists); /* 0x8427 */ + + if (ctime == NULL) + mcio_getmcrtime(&mfe->created); + else + append_le_uint64((uint8_t *)&mfe->created, read_le_uint64((uint8_t *)ctime)); + + append_le_uint64((uint8_t *)&mfe->modified, read_le_uint64((uint8_t *)&mfe->created)); + + append_le_uint32((uint8_t *)&mfe->length, 0); + append_le_uint32((uint8_t *)&mfe->dir_entry, num_entries); + append_le_uint32((uint8_t *)&mfe->cluster, parent_cluster); + strcpy(mfe->name, "."); + + if ((parent_cluster == 0) && (num_entries == 0)) { + /* entry is root directory */ + append_le_uint64((uint8_t *)&mfe_next->created, read_le_uint64((uint8_t *)&mfe->created)); + append_le_uint32((uint8_t *)&mfe->length, 2); + mfe++; + + append_le_uint16((uint8_t *)&mfe->mode, sceMcFileAttrWriteable | sceMcFileAttrExecutable | sceMcFileAttrSubdir \ + | sceMcFile0400 | sceMcFileAttrExists | sceMcFileAttrHidden); /* 0xa426 */ + + append_le_uint32((uint8_t *)&mfe->dir_entry, 0); + append_le_uint32((uint8_t *)&mfe->cluster, 0); + } + else { + /* entry is normal "." / ".." */ + Card_ReadDirEntry(parent_cluster, 0, &pfse); + + append_le_uint64((uint8_t *)&mfe_next->created, read_le_uint64((uint8_t *)&pfse->created)); + mfe++; + + append_le_uint16((uint8_t *)&mfe->mode, sceMcFileAttrReadable | sceMcFileAttrWriteable | sceMcFileAttrExecutable \ + | sceMcFileAttrSubdir | sceMcFile0400 | sceMcFileAttrExists); /* 0x8427 */ + + append_le_uint32((uint8_t *)&mfe->dir_entry, read_le_uint32((uint8_t *)&pfse->dir_entry)); + append_le_uint32((uint8_t *)&mfe->cluster, read_le_uint32((uint8_t *)&pfse->cluster)); + } + + append_le_uint64((uint8_t *)&mfe->modified, read_le_uint64((uint8_t *)&mfe->created)); + append_le_uint32((uint8_t *)&mfe->length, 0); + strcpy(mfe->name, ".."); + + mce->wr_flag = 1; + + return sceMcResSucceed; +} + +static int Card_GetDirInfo(struct MCFsEntry *pfse, char *filename, struct MCCacheDir *pcd, int32_t unknown_flag) +{ + int i, r; + int32_t ret, len, pos; + struct MCFsEntry *fse; + + pos = mcio_chrpos(filename, '/'); + if (pos < 0) + pos = strlen(filename); + + ret = 0; + if ((pos == 2) && (!strncmp(filename, "..", 2))) { + + r = Card_ReadDirEntry((int32_t)read_le_uint32((uint8_t *)&pfse->cluster), 0, &fse); + if (r != sceMcResSucceed) + return r; + + r = Card_ReadDirEntry(fse->cluster, 0, &fse); + if (r != sceMcResSucceed) + return r; + + int32_t cluster = (int32_t)read_le_uint32((uint8_t *)&fse->cluster); + int32_t dir_entry = (int32_t)read_le_uint32((uint8_t *)&fse->dir_entry); + + if (pcd) { + pcd->cluster = cluster; + pcd->fsindex = dir_entry; + } + + r = Card_ReadDirEntry(cluster, dir_entry, &fse); + if (r != sceMcResSucceed) + return r; + + memcpy((void *)pfse, (void *)fse, sizeof(struct MCFsEntry)); + + uint16_t mode = read_le_uint16((uint8_t *)&fse->mode); + + if ((mode & sceMcFileAttrHidden) != 0) { + ret = 1; + } + + if ((pcd == NULL) || (pcd->maxent < 0)) + return sceMcResSucceed; + } + else { + if ((pos == 1) && (!strncmp(filename, ".", 1))) { + + r = Card_ReadDirEntry((int32_t)read_le_uint32((uint8_t *)&pfse->cluster), 0, &fse); + if (r != sceMcResSucceed) + return r; + + int32_t cluster = (int32_t)read_le_uint32((uint8_t *)&fse->cluster); + int32_t dir_entry = (int32_t)read_le_uint32((uint8_t *)&fse->dir_entry); + + if (pcd) { + pcd->cluster = cluster; + pcd->fsindex = dir_entry; + } + + uint16_t mode = read_le_uint16((uint8_t *)&fse->mode); + + ret = 1; + if ((mode & sceMcFileAttrHidden) != 0) { + if ((pcd == NULL) || (pcd->maxent < 0)) + return sceMcResSucceed; + } + else { + if ((pcd == NULL) || (pcd->maxent < 0)) + return sceMcResSucceed; + } + } + } + + uint32_t length = read_le_uint32((uint8_t *)&pfse->length); + + if ((pcd) && (pcd->maxent >= 0)) + pcd->maxent = length; + + if (length > 0) { + + i = 0; + do { + r = Card_ReadDirEntry((int32_t)read_le_uint32((uint8_t *)&pfse->cluster), i, &fse); + if (r != sceMcResSucceed) + return r; + + uint16_t mode = read_le_uint16((uint8_t *)&fse->mode); + if (((mode & sceMcFileAttrExists) == 0) && (pcd) && (i < pcd->maxent)) + pcd->maxent = i; + + if (unknown_flag) { + if ((mode & sceMcFileAttrExists) == 0) + continue; + } + else { + if ((mode & sceMcFileAttrExists) != 0) + continue; + } + + if (ret != 0) + continue; + + if ((pos >= 11) && (!strncmp(&filename[10], &fse->name[10], pos-10))) { + len = pos; + if (strlen(fse->name) >= (uint32_t)pos) + len = strlen(fse->name); + + if (!strncmp(filename, fse->name, len)) + goto continue_check; + } + + if (strlen(fse->name) >= (uint32_t)pos) + len = strlen(fse->name); + else + len = pos; + + if (strncmp(filename, fse->name, len)) + continue; + +continue_check: + ret = 1; + + if (pcd == NULL) + break; + + pcd->fsindex = i; + pcd->cluster = (int32_t)read_le_uint32((uint8_t *)&pfse->cluster); + + if (pcd->maxent < 0) + break; + + } while (++i < (int32_t)read_le_uint32((uint8_t *)&pfse->length)); + } + + if (ret == 2) + return 2; + + return ((ret < 1) ? 1 : 0); +} + +static int Card_SetDirEntryState(int32_t cluster, int32_t fsindex, int32_t flags) +{ + int r, i; + int32_t fat_index, fat_entry; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCFsEntry *fse; + + r = Card_ReadDirEntry(cluster, fsindex, &fse); + if (r != sceMcResSucceed) + return r; + + if (fse->name[0] == '.') { + if ((fse->name[1] == 0) || (fse->name[1] == '.')) + return sceMcResNoEntry; + } + + i = 0; + do { + if (mcio_fdhandles[i].status == 0) + continue; + + if ((int32_t)mcio_fdhandles[i].cluster != cluster) + continue; + + if ((int32_t)mcio_fdhandles[i].fsindex == fsindex) + return sceMcResDeniedPermit; + + } while (++i < MAX_FDHANDLES); + + uint16_t mode = read_le_uint16((uint8_t *)&fse->mode); + + if (flags == 0) + append_le_uint16((uint8_t *)&fse->mode, mode & (sceMcFileAttrExists - 1)); + else + append_le_uint16((uint8_t *)&fse->mode, mode | sceMcFileAttrExists); + + struct MCCacheEntry *mce = (struct MCCacheEntry *)*pmcio_mccache; + mce->wr_flag = -1; + + fat_index = read_le_uint32((uint8_t *)&fse->cluster); + + if (fat_index >= 0) { + if (fat_index < (int32_t)read_le_uint32((uint8_t *)&mcdi->unknown2)) + append_le_uint32((uint8_t *)&mcdi->unknown2, fat_index); + append_le_uint32((uint8_t *)&mcdi->unknown5, -1); + + do { + r = Card_GetFatEntry(fat_index, &fat_entry); + if (r != sceMcResSucceed) + return r; + + if (flags == 0) { + fat_entry &= 0x7fffffff; + if (fat_index < (int32_t)read_le_uint32((uint8_t *)&mcdi->unknown2)) + append_le_uint32((uint8_t *)&mcdi->unknown2, fat_entry); + } + else + fat_entry |= 0x80000000; + + r = Card_SetFatEntry(fat_index, fat_entry); + if (r != sceMcResSucceed) + return r; + + fat_index = fat_entry & 0x7fffffff; + + } while (fat_index != 0x7fffffff); + } + + return sceMcResSucceed; +} + +static int Card_CacheDirEntry(const char *filename, struct MCCacheDir *pcacheDir, struct MCFsEntry **pfse, int unknown_flag) +{ + int r; + int32_t fsindex, cluster, fmode; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCFsEntry *fse; + struct MCCacheDir cacheDir; + char *p; + + if (pcacheDir == NULL) { + pcacheDir = &cacheDir; + pcacheDir->maxent = -1; + } + + p = (char *)filename; + if (*p == '/') { + p++; + cluster = 0; + fsindex = 0; + } + else { + cluster = read_le_uint32((uint8_t *)&mcdi->rootdir_cluster2); + fsindex = read_le_uint32((uint8_t *)&mcdi->unknown1); + } + + r = Card_ReadDirEntry(cluster, fsindex, &fse); + if (r != sceMcResSucceed) + return r; + + if (*p == 0) { + uint16_t mode = read_le_uint16((uint8_t *)&fse->mode); + if (!(mode & sceMcFileAttrExists)) + return 2; + + if (pcacheDir == NULL) { + *pfse = (struct MCFsEntry *)fse; + return sceMcResSucceed; + } + + memcpy((void *)&mcio_dircache[0], (void *)fse, sizeof(struct MCFsEntry)); + + r = Card_GetDirInfo((struct MCFsEntry *)&mcio_dircache[0], ".", pcacheDir, unknown_flag); + + Card_ReadDirEntry(pcacheDir->cluster, pcacheDir->fsindex, pfse); + + if (r > 0) + return 2; + + return r; + + } else { + + do { + fmode = sceMcFileAttrReadable | sceMcFileAttrExecutable; + uint16_t mode = read_le_uint16((uint8_t *)&fse->mode); + if ((mode & fmode) != fmode) + return sceMcResDeniedPermit; + + memcpy((void *)&mcio_dircache[0], (void *)fse, sizeof(struct MCFsEntry)); + + r = Card_GetDirInfo((struct MCFsEntry *)&mcio_dircache[0], p, pcacheDir, unknown_flag); + + if (r > 0) { + if (mcio_chrpos(p, '/') >= 0) + return 2; + + pcacheDir->cluster = cluster; + pcacheDir->fsindex = fsindex; + + return 1; + } + + r = mcio_chrpos(p, '/'); + if ((r >= 0) && (p[r + 1] != 0)) { + p += mcio_chrpos(p, '/') + 1; + cluster = pcacheDir->cluster; + fsindex = pcacheDir->fsindex; + + Card_ReadDirEntry(cluster, fsindex, &fse); + } + else { + Card_ReadDirEntry(pcacheDir->cluster, pcacheDir->fsindex, pfse); + + return sceMcResSucceed; + } + } while (*p != 0); + } + return sceMcResSucceed; +} + +static int Card_GetDirEntryCluster(int32_t cluster, int32_t fsindex) +{ + int r, i; + int32_t maxent, index, clust; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCFatCache *fci = (struct MCFatCache *)&mcio_fatcache; + + uint32_t cluster_size = (int32_t)read_le_uint32((uint8_t *)&mcdi->cluster_size); + + maxent = 1026 / (cluster_size >> 9); + index = fsindex / (cluster_size >> 9); + + clust = cluster; + i = 0; + if ((cluster == 0) && (index != 0)) { + if (index < maxent) { + i = index; + if ((read_le_uint32((uint8_t *)&fci->entry[index])) >= 0 ) + clust = read_le_uint32((uint8_t *)&fci->entry[index]); + } + i = 0; + if (index > 0) { + do { + if (i >= maxent) + break; + if (read_le_uint32((uint8_t *)&fci->entry[i]) < 0) + break; + clust = read_le_uint32((uint8_t *)&fci->entry[i]); + } while (++i < index); + } + i--; + } + + if (i < index) { + do { + r = Card_GetFatEntry(clust, &clust); + if (r != sceMcResSucceed) + return r; + + if (clust == (int32_t)0xffffffff) + return sceMcResNoEntry; + clust &= 0x7fffffff; + + i++; + if (cluster == 0) { + if (i < maxent) + append_le_uint32((uint8_t *)&fci->entry[i], clust); + } + } while (i < index); + } + + uint32_t alloc_offset = read_le_uint32((uint8_t *)&mcdi->alloc_offset); + + return clust + alloc_offset; +} + +static int Card_CheckBackupBlocks(void) +{ + int r1, r2, r; + int32_t value1, value2, eccsize; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce; + int32_t *pagebuf = (int32_t *)&mcio_pagebuf; + + uint32_t backup_block1 = read_le_uint32((uint8_t *)&mcdi->backup_block1); + uint32_t backup_block2 = read_le_uint32((uint8_t *)&mcdi->backup_block2); + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + uint16_t pages_per_cluster = read_le_uint16((uint8_t *)&mcdi->pages_per_cluster); + + /* First check backup block2 to see if it's in erased state */ + r1 = Card_ReadPage(backup_block2 * blocksize, mcio_pagebuf); + + value1 = *pagebuf; + if (((mcdi->cardflags & CF_ERASE_ZEROES) != 0) && (value1 == 0)) + value1 = -1; + if (value1 != -1) + value1 = value1 & 0x7fffffff; + + r2 = Card_ReadPage((backup_block2 * blocksize) + 1, mcio_pagebuf); + + value2 = *pagebuf; + if (((mcdi->cardflags & CF_ERASE_ZEROES) != 0) && (value2 == 0)) + value2 = -1; + if (value2 != -1) + value2 = value2 & 0x7fffffff; + + if ((value1 != -1) && (value2 == -1)) + goto check_done; + if ((r1 < 0) || (r2 < 0)) + goto check_done; + + if ((value1 == -1) && (value1 == value2)) + return sceMcResSucceed; + + /* backup block2 is not erased, so programming is assumed to have not been completed + * reads content of backup block1 + */ + for (r1 = 0; r1 < (int32_t) clusters_per_block; r1++) { + + Card_ReadCluster((backup_block1 * clusters_per_block) + r1, &mce); + mce->rd_flag = 1; + + for (r2 = 0; r2 < pages_per_cluster; r2++) { + mcio_pagedata[(r1 * ((pages_per_cluster << 16) >> 16)) + r2] = \ + (void *)(mce->cl_data + (r2 * pagesize)); + } + } + + /* Erase the block where data must be written */ + r = Card_EraseBlock(value1, (uint8_t **)mcio_pagedata, (void *)mcio_eccdata); + if (r != sceMcResSucceed) + return r; + + /* Write the block */ + for (r1 = 0; r1 < blocksize; r1++) { + + eccsize = pagesize; + if (eccsize < 0) + eccsize += 0x1f; + eccsize = eccsize >> 5; + + r = Card_WritePageData((value1 * ((blocksize << 16) >> 16)) + r1, \ + mcio_pagedata[r1], (uint8_t *)(mcio_eccdata + (eccsize * r1))); + + if (r != sceMcResSucceed) + return r; + } + + for (r1 = 0; r1 < (int32_t)clusters_per_block; r1++) + Card_FreeCluster((backup_block1 * clusters_per_block) + r1); + +check_done: + /* Finally erase backup block2 */ + return Card_EraseBlock(backup_block2, NULL, NULL); +} + +static int Card_SetDeviceInfo(void) +{ + int32_t r, allocatable_clusters_per_card, iscluster_valid, current_allocatable_cluster, cluster_cnt; + struct MCDevInfo *mcdi = &mcio_devinfo; + struct MCFsEntry *pfse; + + memset((void *)mcdi, 0, sizeof(struct MCDevInfo)); + + r = Card_SetDeviceSpecs(); + if (r != sceMcResSucceed) + return sceMcResFailSetDeviceSpecs; + + r = Card_ReadPage(0, mcio_pagebuf); + if (r == sceMcResNoFormat) + return sceMcResNoFormat; /* should rebuild a valid superblock here */ + if (r != sceMcResSucceed) + return sceMcResFailIO; + + if (strncmp(SUPERBLOCK_MAGIC, (char *)mcio_pagebuf, 28) != 0) + return sceMcResNoFormat; + + if (((mcio_pagebuf[28] - 48) == 1) && ((mcio_pagebuf[30] - 48) == 0)) /* check ver major & minor */ + return sceMcResNoFormat; + + uint8_t *p = (uint8_t *)mcdi; + for (r=0; r<336; r++) + p[r] = mcio_pagebuf[r]; + + mcdi->cardtype = sceMcTypePS2; /* <-- */ + + r = Card_CheckBackupBlocks(); + if (r != sceMcResSucceed) + return sceMcResFailCheckBackupBlocks; + + r = Card_ReadDirEntry(0, 0, &pfse); + if (r != sceMcResSucceed) + return sceMcResNoFormat; + + if (strcmp(pfse->name, ".") != 0) + return sceMcResNoFormat; + + if (Card_ReadDirEntry(0, 1, &pfse) != sceMcResSucceed) + return -45; + + if (strcmp(pfse->name, "..") != 0) + return sceMcResNoFormat; + + append_le_uint32((uint8_t *)&mcdi->cardform, 1); + + uint32_t clusters_per_block, alloc_offset, alloc_end, backup_block2; + clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + alloc_offset = read_le_uint32((uint8_t *)&mcdi->alloc_offset); + alloc_end = read_le_uint32((uint8_t *)&mcdi->alloc_end); + backup_block2 = read_le_uint32((uint8_t *)&mcdi->backup_block2); + + if (((mcio_pagebuf[28] - 48) == 1) && ((mcio_pagebuf[30] - 48) == 1)) { /* check ver major & minor */ + if ((clusters_per_block * backup_block2) == alloc_end) + append_le_uint32((uint8_t *)&mcdi->alloc_end, (clusters_per_block * backup_block2) - alloc_offset); + } + + uint32_t hi, lo, temp, clusters_per_card; + + clusters_per_card = read_le_uint32((uint8_t *)&mcdi->clusters_per_card); + + long_multiply(clusters_per_card, 0x10624dd3, &hi, &lo); + temp = (hi >> 6) - (clusters_per_card >> 31); + allocatable_clusters_per_card = (((((temp << 5) - temp) << 2) + temp) << 3) + 1; + iscluster_valid = 0; + cluster_cnt = 0; + current_allocatable_cluster = alloc_offset; + + while (cluster_cnt < allocatable_clusters_per_card) { + if (current_allocatable_cluster >= (int32_t)clusters_per_card) + break; + + if (((current_allocatable_cluster % clusters_per_block) == 0) \ + || (alloc_offset == (uint32_t)current_allocatable_cluster)) { + iscluster_valid = 1; + for (r=0; r<16; r++) { + if ((current_allocatable_cluster / clusters_per_block) == read_le_uint32((uint8_t *)&mcdi->bad_block_list[r])) + iscluster_valid = 0; + } + } + if (iscluster_valid == 1) + cluster_cnt++; + current_allocatable_cluster++; + } + + append_le_uint32((uint8_t *)&mcdi->max_allocatable_clusters, current_allocatable_cluster - alloc_offset); + + return sceMcResSucceed; +} + +static int Card_ReportBadBlocks(void) +{ + int r, i; + int32_t block, bad_blocks, page, erase_byte, err_cnt, err_limit; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + uint8_t *p; + + memset((void *)mcdi->bad_block_list, -1, 128); + + if ((mcdi->cardflags & CF_BAD_BLOCK) == 0) + return sceMcResSucceed; + + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + uint32_t clusters_per_card = read_le_uint32((uint8_t *)&mcdi->clusters_per_card); + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + + err_limit = (((pagesize << 16) >> 16) + ((pagesize << 16) >> 31)) >> 1; + + erase_byte = 0x00; + if ((mcdi->cardflags & CF_ERASE_ZEROES) != 0) + erase_byte = 0xff; + + for (block = 0, bad_blocks = 0; (block < (int32_t)(clusters_per_card / clusters_per_block)) && (bad_blocks < 16); block++) { + + err_cnt = 0; + for (page = 0; page < 2; page++) { + r = Card_ReadPage((block * blocksize) + page, mcio_pagebuf); + if (r == sceMcResNoFormat) { + append_le_uint32((uint8_t *)&mcdi->bad_block_list[bad_blocks], block); + bad_blocks++; + break; + } + if (r != sceMcResSucceed) + return r; + + if ((mcdi->cardflags & CF_USE_ECC) == 0) { + p = (uint8_t *)&mcio_pagebuf; + for (i = 0; i < pagesize; i++) { + /* check if the content of page is clean */ + if (*p++ != erase_byte) + err_cnt++; + + if (err_cnt >= err_limit) { + append_le_uint32((uint8_t *)&mcdi->bad_block_list[bad_blocks], block); + bad_blocks++; + break; + } + } + } + } + } + + return sceMcResSucceed; +} + +static int Card_Unformat(void) +{ + int r, i, j, z, l; + int32_t page, blocks_on_card, erase_byte, err_cnt; + uint32_t erase_value; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + uint32_t clusters_per_card = read_le_uint32((uint8_t *)&mcdi->clusters_per_card); + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + + blocks_on_card = clusters_per_card / clusters_per_block; + + if (mcdi->cardflags & CF_ERASE_ZEROES) + erase_value = 0xffffffff; + else + erase_value = 0x00000000; + + memset(mcio_pagebuf, erase_value, pagesize); + memset(mcio_eccdata, erase_value, 128); + + erase_byte = erase_value & 0xff; + + for (i = 1; i < blocks_on_card; i++) { + page = i * blocksize; + if (read_le_uint32((uint8_t *)&mcdi->cardform) > 0) { + j = 0; + for (j = 0; j < 16; j++) { + if (read_le_uint32((uint8_t *)&mcdi->bad_block_list[j]) <= 0) { + j = 16; + goto lbl1; + } + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->bad_block_list[j]) == i) + goto lbl1; + } + } + else { + err_cnt = 0; + j = -1; + for (z = 0; z < blocksize; z++) { + r = Card_ReadPage(page + z, mcio_pagebuf); + if (r == sceMcResNoFormat) { + j = -2; + break; + } + if (r != sceMcResSucceed) + return -42; + + if ((mcdi->cardflags & CF_USE_ECC) == 0) { + for (l = 0; l < pagesize; l++) { + if (mcio_pagebuf[l] != erase_byte) + err_cnt++; + if (err_cnt >= (int32_t)(clusters_per_block << 6)) { + j = 16; + break; + } + } + if (j != -1) + break; + } + } + } + + if (((mcdi->cardflags & CF_USE_ECC) != 0) && (j == -1)) + j = 16; +lbl1: + if (j == 16) { + r = Card_EraseBlock(i, NULL, NULL); + if (r != sceMcResSucceed) + return -43; + } + else { + memset(mcio_pagebuf, erase_value, pagesize); + for (z = 0; z < blocksize; z++) { + r = Card_WritePageData(page + z, mcio_pagebuf, mcio_eccdata); + if (r != sceMcResSucceed) + return -44; + } + } + } + + r = Card_EraseBlock(0, NULL, NULL); + if (r != sceMcResSucceed) + return -45; + + return sceMcResSucceed; +} + +static int Card_Format(void) +{ + int r; + uint32_t i; + int32_t size, ifc_index, indirect_offset, allocatable_clusters_per_card; + int32_t ifc_length, fat_length, fat_entry, alloc_offset; + int j = 0, z = 0; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce; + + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->cardform) == sceMcResNoFormat) { + for (i = 0; i < 32; i++) + append_le_uint32((uint8_t *)&mcdi->bad_block_list[i], -1); + append_le_uint32((uint8_t *)&mcdi->rootdir_cluster, 0); + append_le_uint32((uint8_t *)&mcdi->rootdir_cluster2, 0); + goto lbl1; + } + + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->cardform) > 0) { + if (((mcdi->version[0] - 48) >= 2) || ((mcdi->version[2] - 48) >= 2)) + goto lbl1; + } + + r = Card_ReportBadBlocks(); + if ((r != sceMcResSucceed) && (r != sceMcResNoFormat)) + return sceMcResChangedCard; + +lbl1: + /* set superblock magic & version */ + memset((void *)&mcdi->magic, 0, sizeof (mcdi->magic) + sizeof (mcdi->version)); + memcpy((uint8_t *)mcdi->magic, SUPERBLOCK_MAGIC, sizeof (mcdi->magic)); + memcpy((uint8_t *)mcdi->version, SUPERBLOCK_VERSION, sizeof (mcdi->version)); + + uint16_t blocksize = read_le_uint16((uint8_t *)&mcdi->blocksize); + uint32_t cluster_size = read_le_uint32((uint8_t *)&mcdi->cluster_size); + uint32_t clusters_per_card = read_le_uint32((uint8_t *)&mcdi->clusters_per_card); + uint32_t FATentries_per_cluster = read_le_uint32((uint8_t *)&mcdi->FATentries_per_cluster); + + size = blocksize; + append_le_uint32((uint8_t *)&mcdi->cardform, -1); + + if (blocksize <= 0) + size = 8; + + /* clear first 8 clusters */ + for (i = 0; i < (uint32_t)size; i++) { + r = Card_WriteCluster(i, 1); + if (r == 0) + return sceMcResNoFormat; + + if (r != 1) + return -40; + } + + fat_length = (((clusters_per_card << 2) - 1) / cluster_size) + 1; /* get length of fat in clusters */ + ifc_length = (((fat_length << 2) - 1) / cluster_size) + 1; /* get number of needed ifc clusters */ + + if (!(ifc_length <= 32)) { + ifc_length = 32; + fat_length = FATentries_per_cluster << 5; + } + + /* clear ifc clusters */ + for(j = 0; j < ifc_length; j++) { + if (i >= clusters_per_card) + return sceMcResNoFormat; + + for ( ; i < clusters_per_card; i++) { + if (Card_WriteCluster(i, 1) != 0) + break; + } + + if (i >= clusters_per_card) + return sceMcResNoFormat; + + append_le_uint32((uint8_t *)&mcdi->ifc_list[j], i); + i++; + } + + /* read ifc clusters to mc cache and clear fat clusters */ + if (fat_length > 0) { + j = 0; + + do { + ifc_index = j / FATentries_per_cluster; + indirect_offset = j % FATentries_per_cluster; + + if (indirect_offset == 0) { + if (Card_ReadCluster(read_le_uint32((uint8_t *)&mcdi->ifc_list[ifc_index]), &mce) != sceMcResSucceed) + return -42; + mce->wr_flag = 1; + } + + if (i >= clusters_per_card) + return sceMcResNoFormat; + + do { + r = Card_WriteCluster(i, 1); + if (r == 1) + break; + + if (r < 0) + return -43; + + i++; + } while (i < clusters_per_card); + + if (i >= clusters_per_card) + return sceMcResNoFormat; + + j++; + struct MCFatCluster *fc = (struct MCFatCluster *)mce->cl_data; + append_le_uint32((uint8_t *)&fc->entry[indirect_offset], i); + i++; + + } while (j < fat_length); + } + alloc_offset = i; + + append_le_uint32((uint8_t *)&mcdi->backup_block1, 0); + append_le_uint32((uint8_t *)&mcdi->backup_block2, 0); + + uint32_t clusters_per_block = read_le_uint32((uint8_t *)&mcdi->clusters_per_block); + + /* clear backup blocks */ + for (i = (clusters_per_card / clusters_per_block) - 1; i > 0; i--) { + + r = Card_WriteCluster(clusters_per_block * i, 1); + if (r < 0) + return -44; + + if ((r != 0) && (read_le_uint32((uint8_t *)&mcdi->backup_block1) == 0)) + append_le_uint32((uint8_t *)&mcdi->backup_block1, i); + else if ((r != 0) && (read_le_uint32((uint8_t *)&mcdi->backup_block2) == 0)) { + append_le_uint32((uint8_t *)&mcdi->backup_block2, i); + break; + } + } + + /* set backup block2 to erased state */ + if (Card_EraseBlock(read_le_uint32((uint8_t *)&mcdi->backup_block2), NULL, NULL) != sceMcResSucceed) + return -45; + + uint32_t hi, lo, temp; + + long_multiply(clusters_per_card, 0x10624dd3, &hi, &lo); + temp = (hi >> 6) - (clusters_per_card >> 31); + allocatable_clusters_per_card = (((((temp << 5) - temp) << 2) + temp) << 3) + 1; + j = alloc_offset; + + /* checking for bad allocated clusters and building FAT */ + if (j < (int32_t)(i * clusters_per_block)) { + z = 0; + do { /* quick check for bad clusters */ + r = Card_WriteCluster(j, 0); + if (r == 1) { + if (z == 0) { + append_le_uint32((uint8_t *)&mcdi->alloc_offset, j); + append_le_uint32((uint8_t *)&mcdi->rootdir_cluster, 0); + fat_entry = 0xffffffff; /* marking rootdir end */ + } + else + fat_entry = 0x7fffffff; /* marking free cluster */ + z++; + if (z == allocatable_clusters_per_card) + append_le_uint32((uint8_t *)&mcdi->max_allocatable_clusters, (j - mcdi->alloc_offset) + 1); + } + else { + if (r != 0) + return -45; + fat_entry = 0xfffffffd; /* marking bad cluster */ + } + + if (Card_SetFatEntry(j - read_le_uint32((uint8_t *)&mcdi->alloc_offset), fat_entry) != sceMcResSucceed) + return -46; + + j++; + } while (j < (int32_t)(i * clusters_per_block)); + } + + append_le_uint32((uint8_t *)&mcdi->alloc_end, (i * clusters_per_block) - read_le_uint32((uint8_t *)&mcdi->alloc_offset)); + + if (read_le_uint32((uint8_t *)&mcdi->max_allocatable_clusters) == 0) + append_le_uint32((uint8_t *)&mcdi->max_allocatable_clusters, i * clusters_per_block); + + if (z < (int32_t)clusters_per_block) + return sceMcResNoFormat; + + /* read superblock to mc cache */ + for (i = 0; i < sizeof(struct MCDevInfo); i += MCIO_CLUSTERSIZE) { + if (i < 0) + size = i + (MCIO_CLUSTERSIZE - 1); + else + size = i; + + if (Card_ReadCluster(size >> 10, &mce) != sceMcResSucceed) + return -48; + + size = MCIO_CLUSTERSIZE; + mce->wr_flag = 1; + + if ((sizeof(struct MCDevInfo) - i) <= 1024) + size = sizeof(struct MCDevInfo) - i; + + memcpy((void *)mce->cl_data, (void *)(mcdi + i), size); + } + + append_le_uint32((uint8_t *)&mcdi->unknown1, 0); + append_le_uint32((uint8_t *)&mcdi->unknown2, 0); + append_le_uint32((uint8_t *)&mcdi->unknown5, -1); + append_le_uint32((uint8_t *)&mcdi->rootdir_cluster2, mcdi->rootdir_cluster); + + /* Create root dir */ + if (Card_CreateDirEntry(0, 0, 0, NULL) != sceMcResSucceed) + return -49; + + /* finally flush cache to memcard */ + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + + append_le_uint32((uint8_t *)&mcdi->cardform, 1); + + return sceMcResSucceed; +} + +static int Card_Delete(const char *filename, int flags) +{ + int r, i; + struct MCCacheDir cacheDir; + struct MCFsEntry *fse1, *fse2; + + r = Card_CacheDirEntry(filename, &cacheDir, &fse1, ((uint32_t)(flags < 1)) ? 1 : 0); + if (r > 0) + return sceMcResNoEntry; + if (r < 0) + return r; + + uint16_t mode = read_le_uint16((uint8_t *)&fse1->mode); + if (!flags) { + if (!(mode & sceMcFileAttrExists)) + return sceMcResNoEntry; + } + else { + if (mode & sceMcFileAttrExists) + return sceMcResNoEntry; + } + + int32_t cluster = (int32_t)read_le_uint32((uint8_t *)&fse1->cluster); + int32_t dir_entry = (int32_t)read_le_uint32((uint8_t *)&fse1->dir_entry); + int32_t length = (int32_t)read_le_uint32((uint8_t *)&fse1->length); + + if (!cluster && !dir_entry) + return sceMcResNoEntry; + + i = 2; + if ((!flags) && (mode & sceMcFileAttrSubdir) && (i < length)) { + do { + r = Card_ReadDirEntry(cluster, i, &fse2); + if (r != sceMcResSucceed) + return r; + + if (read_le_uint16((uint8_t *)&fse2->mode) & sceMcFileAttrExists) + return sceMcResNotEmpty; + + } while (++i < length); + } + + r = Card_SetDirEntryState(cacheDir.cluster, cacheDir.fsindex, flags); + if (r != sceMcResSucceed) + return r; + + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + + return sceMcResSucceed; +} + +static int Card_Probe(void) +{ + int r; + struct MCDevInfo *mcdi; + + r = Card_SetDeviceInfo(); + if (r == sceMcResSucceed) + return sceMcResSucceed; + + if (r != sceMcResNoFormat) + return sceMcResFailDetect2; + + mcdi = &mcio_devinfo; + append_le_uint32((uint8_t *)&mcdi->cardform, r); + + return r; +} + +static void Card_InvFileHandles(void) +{ + int i; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[0]; + + for (i=0; istatus = 0; + fh++; + } +} + +static int Card_FileOpen(const char *filename, int flags) +{ + int i, r; + int32_t fd, fsindex, fsoffset, fat_index, rdflag, wrflag, pos, mcfree; + struct MCFHandle *fh, *fh2; + struct MCCacheDir cacheDir; + struct MCFsEntry *fse1, *fse2; + struct MCCacheEntry *mce; + char *p; + int32_t fat_entry; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + if ((flags & sceMcFileCreateFile) != 0) + flags |= sceMcFileAttrWriteable; + + if (filename[0] == 0) + return sceMcResNoEntry; + + fd = 0; + do { + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + if (fh->status == 0) + break; + } while (++fd < MAX_FDHANDLES); + + if (fd == MAX_FDHANDLES) + return sceMcResUpLimitHandle; + + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + + memset((void *)fh, 0, sizeof(struct MCFHandle)); + + if ((flags & (sceMcFileCreateFile | sceMcFileCreateDir)) == 0) + cacheDir.maxent = -1; + else + cacheDir.maxent = 0; + + fse1 = NULL; + r = Card_CacheDirEntry(filename, &cacheDir, &fse1, 1); + if (r < 0) + return r; + + if (fse1) { + memcpy((void *)&mcio_dircache[1], (void *)fse1, sizeof(struct MCFsEntry)); + + uint16_t mode = read_le_uint16((uint8_t *)&fse1->mode); + if ((flags == 0) && ((mode & sceMcFileAttrExists) == 0)) + r = 1; + } + + if (r == 2) + return sceMcResNoEntry; + + if (r == 3) + return sceMcResDeniedPermit; + + if ((r == 0) && ((flags & sceMcFileCreateDir) != 0)) + return sceMcResNoEntry; + + if ((r == 1) && ((flags & (sceMcFileCreateFile | sceMcFileCreateDir)) == 0)) + return sceMcResNoEntry; + + rdflag = flags & sceMcFileAttrReadable; + wrflag = flags & sceMcFileAttrWriteable; + fh->freeclink = -1; + fh->clink = -1; + fh->clust_offset = 0; + fh->filesize = 0; + fh->position = 0; + fh->unknown2 = 0; + fh->rdflag = rdflag; + fh->wrflag = wrflag; + fh->unknown1 = 0; + fh->cluster = cacheDir.cluster; + fh->fsindex = cacheDir.fsindex; + + if (r == 0) { + uint16_t dircache_mode = read_le_uint16((uint8_t *)&mcio_dircache[1].mode); + + if ((wrflag != 0) && ((dircache_mode & sceMcFileAttrWriteable) == 0)) + return sceMcResDeniedPermit; + + r = Card_ReadDirEntry(cacheDir.cluster, 0, &fse2); + if (r != sceMcResSucceed) + return r; + + fh->parent_cluster = read_le_uint32((uint8_t *)&fse2->cluster); + fh->parent_fsindex = read_le_uint32((uint8_t *)&fse2->dir_entry); + + if ((dircache_mode & sceMcFileAttrSubdir) != 0) { + if ((dircache_mode & sceMcFileAttrReadable) == 0) + return sceMcResDeniedPermit; + + if ((flags & sceMcFileAttrSubdir) == 0) + return sceMcResNotFile; + + fh->freeclink = read_le_uint32((uint8_t *)&mcio_dircache[1].cluster); + fh->rdflag = 0; + fh->wrflag = 0; + fh->unknown1 = 0; + fh->drdflag = 1; + fh->status = 1; + fh->filesize = read_le_uint32((uint8_t *)&mcio_dircache[1].length); + fh->clink = fh->freeclink; + + return fd; + } + + if ((flags & sceMcFileAttrWriteable) != 0) { + i = 0; + do { + fh2 = (struct MCFHandle *)&mcio_fdhandles[i]; + + if ((fh2->status == 0) \ + || (fh2->cluster != (uint32_t) cacheDir.cluster) || (fh2->fsindex != (uint32_t) cacheDir.fsindex)) + continue; + + if (fh2->wrflag != 0) + return sceMcResDeniedPermit; + + } while (++i < MAX_FDHANDLES); + } + + if ((flags & sceMcFileCreateFile) != 0) { + r = Card_SetDirEntryState(cacheDir.cluster, cacheDir.fsindex, 0); + Card_FlushMCCache(); + + if (r != sceMcResSucceed) + return r; + + if (cacheDir.fsindex < cacheDir.maxent) + cacheDir.maxent = cacheDir.fsindex; + } + else { + fh->freeclink = read_le_uint32((uint8_t *)&mcio_dircache[1].cluster); + fh->filesize = read_le_uint32((uint8_t *)&mcio_dircache[1].length); + fh->clink = fh->freeclink; + + if (fh->rdflag != 0) + fh->rdflag = (*((uint8_t *)&mcio_dircache[1].mode)) & sceMcFileAttrReadable; + else + fh->rdflag = 0; + + if (fh->wrflag != 0) + fh->wrflag = (dircache_mode >> 1) & sceMcFileAttrReadable; + else + fh->wrflag = 0; + + fh->status = 1; + + return fd; + } + } + else { + fh->parent_cluster = cacheDir.cluster; + fh->parent_fsindex = cacheDir.fsindex; + } + + r = Card_ReadDirEntry(fh->parent_cluster, fh->parent_fsindex, &fse1); + if (r != sceMcResSucceed) + return r; + + memcpy((void *)&mcio_dircache[2], (void *)fse1, sizeof(struct MCFsEntry)); + uint32_t dircache_length = read_le_uint32((uint8_t *)&mcio_dircache[2].length); + uint32_t dircache_cluster = read_le_uint32((uint8_t *)&mcio_dircache[2].cluster); + + i = -1; + if (dircache_length == (uint32_t) cacheDir.maxent) { + + int32_t cluster_size = (int32_t)read_le_uint32((uint8_t *)&mcdi->cluster_size); + + fsindex = dircache_length / (cluster_size >> 9); + fsoffset = dircache_length % (cluster_size >> 9); + + if (fsoffset == 0) { + fat_index = dircache_cluster; + i = fsindex; + + if ((dircache_cluster == 0) && (i >= 2)) { + if (read_le_uint32((uint8_t *)&mcio_fatcache.entry[i-1]) >= 0) { + fat_index = read_le_uint32((uint8_t *)&mcio_fatcache.entry[i-1]); + i = 1; + } + } + i--; + + if (i != -1) { + + do { + r = Card_GetFatEntry(fat_index, &fat_entry); + if (r != sceMcResSucceed) + return r; + + if (fat_entry >= -1) { + r = Card_FindFree(1); + if (r < 0) + return r; + + fat_entry = r; + mce = *pmcio_mccache; + + fat_entry |= 0x80000000; + + r = Card_SetFatEntry(fat_index, fat_entry); + if (r != sceMcResSucceed) + return r; + + Card_AddCacheEntry(mce); + } + i--; + fat_index = fat_entry & 0x7fffffff; + + } while (i != -1); + } + } + + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + + i = -1; + + dircache_length++; + append_le_uint32((uint8_t *)&mcio_dircache[2].length, dircache_length); + } + + do { + p = (char *)(filename + i + 1); + pos = i + 1; + r = mcio_chrpos(p, '/'); + if (r < 0) + break; + i = pos + r; + } while (1); + + p = (char *)(filename + pos); + + mcfree = 0; + + if ((flags & sceMcFileCreateDir) != 0) { + r = Card_FindFree(1); + if (r < 0) + return r; + mcfree = r; + } + + mce = *pmcio_mccache; + + mcio_getmcrtime(&mcio_dircache[2].modified); + + r = Card_ReadDirEntry(dircache_cluster, cacheDir.maxent, &fse2); + if (r != sceMcResSucceed) + return r; + + memset((void *)fse2, 0, sizeof(struct MCFsEntry)); + + strncpy((void *)fse2->name, p, 32); + + uint64_t modified = read_le_uint64((uint8_t *)&mcio_dircache[2].modified); + append_le_uint64((uint8_t *)&fse2->created, modified); + append_le_uint64((uint8_t *)&fse2->modified, modified); + + struct MCCacheEntry *mce_1st = (struct MCCacheEntry *)*pmcio_mccache; + mce_1st->wr_flag = -1; + + Card_AddCacheEntry(mce); + + if ((flags & sceMcFileCreateDir) != 0) { + + uint16_t fmode = ((flags & sceMcFileAttrHidden) | sceMcFileAttrReadable | sceMcFileAttrWriteable \ + | sceMcFileAttrExecutable | sceMcFileAttrSubdir | sceMcFile0400 | sceMcFileAttrExists) /* 0x8427 */ + | (flags & (sceMcFileAttrPS1 | sceMcFileAttrPDAExec)); + + append_le_uint16((uint8_t *)&fse2->mode, fmode); + append_le_uint32((uint8_t *)&fse2->cluster, mcfree); + append_le_uint32((uint8_t *)&fse2->length, 2); + + r = Card_CreateDirEntry(dircache_cluster, cacheDir.maxent, mcfree, (struct sceMcStDateTime *)&fse2->created); + if (r != sceMcResSucceed) + return -46; + + r = Card_ReadDirEntry(fh->parent_cluster, fh->parent_fsindex, &fse1); + if (r != sceMcResSucceed) + return r; + + memcpy((void *)fse1, (void *)&mcio_dircache[2], sizeof(struct MCFsEntry)); + + mce_1st = (struct MCCacheEntry *)*pmcio_mccache; + mce_1st->wr_flag = -1; + + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + + return sceMcResSucceed; + } + else { + uint16_t fmode = ((flags & sceMcFileAttrHidden) | sceMcFileAttrReadable | sceMcFileAttrWriteable \ + | sceMcFileAttrExecutable | sceMcFileAttrFile | sceMcFile0400 | sceMcFileAttrExists) /* 0x8417 */ + | (flags & (sceMcFileAttrPS1 | sceMcFileAttrPDAExec)); + + append_le_uint16((uint8_t *)&fse2->mode, fmode); + append_le_uint32((uint8_t *)&fse2->cluster, -1); + fh->cluster = dircache_cluster; + fh->status = 1; + fh->fsindex = cacheDir.maxent; + + r = Card_ReadDirEntry(fh->parent_cluster, fh->parent_fsindex, &fse1); + if (r != sceMcResSucceed) + return r; + + memcpy((void *)fse1, (void *)&mcio_dircache[2], sizeof(struct MCFsEntry)); + + mce_1st = (struct MCCacheEntry *)*pmcio_mccache; + mce_1st->wr_flag = -1; + + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + } + + return fd; +} + +static int Card_FileClose(int fd) +{ + int r; + uint16_t fmode; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + struct MCFsEntry *fse1, *fse2; + struct sceMcStDateTime mcio_fsmodtime; + + r = Card_ReadDirEntry(fh->cluster, fh->fsindex, &fse1); + if (r != sceMcResSucceed) + return r; + + uint16_t mode = read_le_uint16((uint8_t *)&fse1->mode); + if (fh->unknown2 == 0) + fmode = mode | sceMcFileAttrClosed; + else + fmode = mode & 0xff7f; + append_le_uint16((uint8_t *)&fse1->mode, fmode); + + mcio_getmcrtime(&fse1->modified); + + append_le_uint32((uint8_t *)&fse1->cluster, fh->freeclink); + append_le_uint32((uint8_t *)&fse1->length, fh->filesize); + + struct MCCacheEntry *mce = (struct MCCacheEntry *)*pmcio_mccache; + mce->wr_flag = -1; + + append_le_uint64((uint8_t *)&mcio_fsmodtime, read_le_uint64((uint8_t *)&fse1->modified)); + + r = Card_ReadDirEntry(fh->parent_cluster, fh->parent_fsindex, &fse2); + if (r != sceMcResSucceed) + return r; + + append_le_uint64((uint8_t *)&fse2->modified, read_le_uint64((uint8_t *)&mcio_fsmodtime)); + + mce = (struct MCCacheEntry *)*pmcio_mccache; + mce->wr_flag = -1; + + return sceMcResSucceed; +} + +static int Card_FileRead(int fd, void *buffer, int nbyte) +{ + int r; + int32_t temp, rpos, size, offset; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce; + + if (fh->position < fh->filesize) { + + temp = fh->filesize - fh->position; + if (nbyte > temp) + nbyte = temp; + + rpos = 0; + if (nbyte > 0) { + + do { + int32_t cluster_size = (int32_t)read_le_uint32((uint8_t *)&mcdi->cluster_size); + offset = fh->position % cluster_size; /* file pointer offset % cluster size */ + temp = cluster_size - offset; + if (temp < nbyte) + size = temp; + else + size = nbyte; + + r = Card_FatRSeek(fd); + + if (r <= 0) + return r; + + r = Card_ReadCluster(r, &mce); + if (r != sceMcResSucceed) + return r; + + uint8_t *p = (uint8_t *)buffer; + memcpy(&p[rpos], &mce->cl_data[offset], size); + + rpos += size; + mce->rd_flag = 1; + nbyte -= size; + fh->position += size; + + } while (nbyte); + } + return rpos; + } + + return 0; +} + +static int Card_FileWrite(int fd, void *buffer, int nbyte) +{ + int r, r2; + int32_t wpos, size, offset; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + struct MCCacheEntry *mce; + + if (nbyte) { + if (fh->unknown2 == 0) { + fh->unknown2 = 1; + + r = Card_FileClose(fd); + if (r != sceMcResSucceed) + return r; + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + } + } + + wpos = 0; + if (nbyte) { + do { + r = Card_FatRSeek(fd); + if (r == sceMcResFullDevice) { + + r2 = Card_FatWSeek(fd); + if (r2 == r) + return sceMcResFullDevice; + + if (r2 != sceMcResSucceed) + return r2; + + r = Card_FatRSeek(fd); + } + else { + if (r < 0) + return r; + } + + r = Card_ReadCluster(r, &mce); + if (r != sceMcResSucceed) + return r; + + mce->rd_flag = 1; + + uint32_t cluster_size = read_le_uint32((uint8_t *)&mcdi->cluster_size); + + offset = fh->position % cluster_size; /* file pointer offset % cluster size */ + r2 = cluster_size - offset; + if (r2 < nbyte) + size = r2; + else + size = nbyte; + + memcpy((void *)(mce->cl_data + offset), (void *)((uint8_t *)buffer + wpos), size); + + mce->wr_flag = 1; + + r = fh->position + size; + fh->position += size; + + if (r < (int32_t)fh->filesize) + r = fh->filesize; + + fh->filesize = r; + + nbyte -= size; + wpos += size; + + } while (nbyte); + } + + r = Card_FileClose(fd); + if (r != sceMcResSucceed) + return r; + + return wpos; +} + + +int mcio_vmcInit(const char* vmc) +{ + int r; + + mcio_vmcFinish(); + + if (read_buffer(vmc, &vmc_data, &vmc_size) < 0) + return sceMcResFailIO; + + strncpy(vmcpath, vmc, sizeof(vmcpath)); + Card_InitCache(); + + r = mcio_mcDetect(); + if (r == sceMcResChangedCard) + return sceMcResSucceed; + + return r; +} + +void mcio_vmcFinish(void) +{ + if (vmc_data) + { + write_buffer(vmcpath, vmc_data, vmc_size); + free(vmc_data); + } + + vmcpath[0] = 0; + vmc_data = NULL; +} + +int mcio_mcDetect(void) +{ + int r=0; + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + + if ((mcdi->cardtype == sceMcTypeNoCard) || (mcdi->cardtype == sceMcTypePS2)) { + r = Card_Probe(); + if (!(r < -9)) { + mcdi->cardtype = sceMcTypePS2; + return r; + } + } + + mcdi->cardtype = 0; + append_le_uint32((uint8_t *)&mcdi->cardform, 0); + Card_InvFileHandles(); + Card_ClearCache(); + + return r; +} + +int mcio_mcOpen(const char *filename, int flag) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->cardform) == sceMcResNoFormat) + return sceMcResNoFormat; + + r = Card_FileOpen(filename, flag); + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + return r; +} + +int mcio_mcClose(int fd) +{ + int r; + struct MCFHandle *fh; + + if (!(fd < MAX_FDHANDLES)) + return sceMcResDeniedPermit; + + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + if (!fh->status) + return sceMcResDeniedPermit; + + fh->status = 0; + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_FlushMCCache(); + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + if (r != sceMcResSucceed) + return r; + + if (fh->unknown2 != 0) { + fh->unknown2 = 0; + r = Card_FileClose(fd); + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + if (r != sceMcResSucceed) + return r; + } + + r = Card_FlushMCCache(); + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + return r; +} + +int mcio_mcRead(int fd, void *buf, int length) +{ + int r; + struct MCFHandle *fh; + + if (!(fd < MAX_FDHANDLES)) + return sceMcResDeniedPermit; + + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + if (!fh->status) + return sceMcResDeniedPermit; + + if (!fh->rdflag) + return sceMcResDeniedPermit; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_FileRead(fd, buf, length); + if (r < 0) { + fh->status = 0; + } + + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + return r; +} + +int mcio_mcWrite(int fd, void *buf, int length) +{ + int r; + struct MCFHandle *fh; + + if (!(fd < MAX_FDHANDLES)) + return sceMcResDeniedPermit; + + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + if (!fh->status) + return sceMcResDeniedPermit; + + if (!fh->wrflag) + return sceMcResDeniedPermit; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_FileWrite(fd, buf, length); + if (r < 0) + fh->status = 0; + + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + return r; +} + +int mcio_mcSeek(int fd, int offset, int origin) +{ + int r; + struct MCFHandle *fh; + + if (!(fd < MAX_FDHANDLES)) + return sceMcResDeniedPermit; + + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + if (!fh->status) + return sceMcResDeniedPermit; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + switch (origin) { + default: + case SEEK_CUR: + r = fh->position + offset; + break; + case SEEK_SET: + r = offset; + break; + case SEEK_END: + r = fh->filesize + offset; + break; + } + + return fh->position = (r < 0) ? 0 : r; +} + +int mcio_mcStat(const char *filename, struct io_dirent *dirent) +{ + int r, fd; + struct MCFsEntry *pfse; + + fd = mcio_mcOpen(filename, sceMcFileAttrSubdir | sceMcFileAttrReadable); + if (fd < 0) + return fd; + + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + + r = Card_ReadDirEntry(fh->cluster, fh->fsindex, &pfse); + if (r < 0) { + mcio_mcClose(fd); + return r; + } + + mcio_copy_dirent(dirent, pfse); + r = mcio_mcClose(fd); + + return r; +} + +int mcio_mcSetStat(const char *filename, const struct io_dirent *dirent) +{ + int r, fd; + struct MCFsEntry *pfse, *pfse2; + struct MCCacheEntry *pmce; + + fd = mcio_mcOpen(filename, sceMcFileAttrSubdir | sceMcFileAttrReadable); + if (fd < 0) + return fd; + + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + + int32_t cluster = Card_GetDirEntryCluster(fh->cluster, fh->fsindex); + r = Card_ReadDirEntry(fh->cluster, fh->fsindex, &pfse2); + if (r < 0) { + mcio_mcClose(fd); + return r; + } + mcio_mcClose(fd); + + r = Card_ReadCluster(cluster, &pmce); + if (r < 0) + return r; + + pfse = (struct MCFsEntry *)pmce->cl_data; + if (pfse->cluster != pfse2->cluster) + pfse++; + if (pfse->cluster != pfse2->cluster) + return r; + + mcio_copy_mcentry(pfse, dirent); + pmce->wr_flag = 1; + + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + + return r; +} + +int mcio_mcCreateCrossLinkedFile(const char *real_filepath, const char *dummy_filepath) +{ + int r, fd; + struct MCFsEntry *pfse; + struct MCCacheEntry *pmce; + + fd = mcio_mcOpen(real_filepath, sceMcFileAttrFile | sceMcFileAttrReadable); + if (fd < 0) + return fd; + + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + if (fh->drdflag) { + mcio_mcClose(fd); + return sceMcResNotFile; + } + + r = Card_ReadDirEntry(fh->cluster, fh->fsindex, &pfse); + if (r < 0) { + mcio_mcClose(fd); + return r; + } + + int32_t real_file_cluster = read_le_uint32((uint8_t *)&pfse->cluster); + int32_t real_file_length = read_le_uint32((uint8_t *)&pfse->length); + + mcio_mcClose(fd); + + fd = mcio_mcOpen(dummy_filepath, sceMcFileAttrWriteable | sceMcFileCreateFile | sceMcFileAttrFile); + if (fd < 0) + return fd; + + fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + + r = Card_ReadDirEntry(fh->cluster, fh->fsindex, &pfse); + if (r < 0) { + mcio_mcClose(fd); + return r; + } + + char dummy_filename[33]; + strncpy(dummy_filename, pfse->name, 32); + + int32_t cluster = Card_GetDirEntryCluster(fh->cluster, fh->fsindex); + if (r < 0) { + mcio_mcClose(fd); + return r; + } + + mcio_mcClose(fd); + + r = Card_ReadCluster(cluster, &pmce); + if (r < 0) + return r; + + struct MCFsEntry *fse = (struct MCFsEntry *)pmce->cl_data; + if (strcmp(dummy_filename, fse->name)) + fse++; + if (strcmp(dummy_filename, fse->name)) + return r; + + append_le_uint32((uint8_t *)&fse->cluster, real_file_cluster); + append_le_uint32((uint8_t *)&fse->length, real_file_length); + + pmce->wr_flag = 1; + + r = Card_FlushMCCache(); + if (r != sceMcResSucceed) + return r; + + return r; +} + +int mcio_mcDopen(const char *dirname) +{ + int r; + + r = mcio_mcOpen(dirname, sceMcFileAttrSubdir); + if (r >= 0) { + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[r]; + if (!fh->drdflag) { + mcio_mcClose(r); + return sceMcResNotDir; + } + } + + return r; +} + +int mcio_mcDclose(int fd) +{ + int r; + + r = mcio_mcClose(fd); + + return r; +} + +int mcio_mcDread(int fd, struct io_dirent *dirent) +{ + int r; + struct MCFHandle *fh = (struct MCFHandle *)&mcio_fdhandles[fd]; + struct MCFsEntry *fse; + uint16_t mode; + + if (fh->position >= fh->filesize) + return 0; + + do { + r = Card_ReadDirEntry(fh->freeclink, fh->position, &fse); + if (r != sceMcResSucceed) + return r; + + mode = read_le_uint16((uint8_t *)&fse->mode); + if (mode & sceMcFileAttrExists) + break; + + fh->position++; + } while (fh->position < fh->filesize); + + if (fh->position >= fh->filesize) + return 0; + + fh->position++; + memset((void *)dirent, 0, sizeof(struct io_dirent)); + strncpy(dirent->name, fse->name, 32); + dirent->name[32] = 0; + + if (mode & sceMcFileAttrReadable) + dirent->stat.mode |= sceMcFileAttrReadable; + if (mode & sceMcFileAttrWriteable) + dirent->stat.mode |= sceMcFileAttrWriteable; + if (mode & sceMcFileAttrExecutable) + dirent->stat.mode |= sceMcFileAttrExecutable; + if (mode & sceMcFileAttrPS1) + dirent->stat.mode |= sceMcFileAttrPS1; + if (mode & sceMcFileAttrPDAExec) + dirent->stat.mode |= sceMcFileAttrPDAExec; + if (mode & sceMcFileAttrDupProhibit) + dirent->stat.mode |= sceMcFileAttrDupProhibit; + if (mode & sceMcFileAttrSubdir) + dirent->stat.mode |= sceMcFileAttrSubdir; + else + dirent->stat.mode |= sceMcFileAttrFile; + + dirent->stat.attr = read_le_uint32((uint8_t *)&fse->attr); + dirent->stat.size = read_le_uint32((uint8_t *)&fse->length); + + dirent->stat.ctime.Resv2 = fse->created.Resv2; + dirent->stat.ctime.Sec = fse->created.Sec; + dirent->stat.ctime.Min = fse->created.Min; + dirent->stat.ctime.Hour = fse->created.Hour; + dirent->stat.ctime.Day = fse->created.Day; + dirent->stat.ctime.Month = fse->created.Month; + dirent->stat.ctime.Year = read_le_uint16((uint8_t *)&fse->created.Year); + + dirent->stat.mtime.Resv2 = fse->modified.Resv2; + dirent->stat.mtime.Sec = fse->modified.Sec; + dirent->stat.mtime.Min = fse->modified.Min; + dirent->stat.mtime.Hour = fse->modified.Hour; + dirent->stat.mtime.Day = fse->modified.Day; + dirent->stat.mtime.Month = fse->modified.Month; + dirent->stat.mtime.Year = read_le_uint16((uint8_t *)&fse->modified.Year); + + return 1; +} + +int mcio_mcMkDir(const char *dirname) +{ + return mcio_mcOpen(dirname, 0x40); +} + +int mcio_mcGetInfo(int *pagesize, int *blocksize, int *cardsize, int *cardflags) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + uint8_t _cardflags; + uint16_t _pagesize, _blocksize; + int32_t _cardsize; + if (Card_GetSpecs(&_pagesize, &_blocksize, &_cardsize, &_cardflags) != sceMcResSucceed) + return r; + + _pagesize = read_le_uint16((uint8_t *)&_pagesize); + *pagesize = (int)_pagesize; + *blocksize = (int)read_le_uint16((uint8_t *)&_blocksize); + *cardsize = (int)_cardsize * _pagesize; + *cardflags = (int)_cardflags; + + return 0; +} + +int mcio_mcGetAvailableSpace(int *cardfree) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + if ((int32_t)read_le_uint32((uint8_t *)&mcdi->cardform) == sceMcResNoFormat) + return sceMcResNoFormat; + + r = Card_FindFree(0); + if (r == sceMcResFullDevice) + *cardfree = 0; + else if (r < 0) + return r; + + *cardfree = r * MCIO_CLUSTERSIZE; + + return 0; +} + +int mcio_mcReadPage(int pagenum, void *buf, void *ecc) +{ + int r; + + r = Card_ReadPage((int32_t)pagenum, (uint8_t *)buf); + + if (ecc) + { + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + uint8_t* p_ecc = ecc; + + memset(ecc, 0, pagesize >> 5); + for (int i = 0; i < pagesize; i += 128, p_ecc += 3) + Card_DataChecksum(buf + i, p_ecc); + } + + return r; +} + +int mcio_mcUnformat(void) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_Unformat(); + if (r != sceMcResSucceed) + return r; + + return 0; +} + +int mcio_mcFormat(void) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_Format(); + if (r != sceMcResSucceed) + return r; + + return 0; +} + +int mcio_mcRemove(const char *filename) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_Delete(filename, 0); + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + return r; +} + +int mcio_mcRmDir(const char *dirname) +{ + int r; + + r = mcio_mcDetect(); + if (r != sceMcResSucceed) + return r; + + r = Card_Delete(dirname, 0); + if (r < -9) { + Card_InvFileHandles(); + Card_ClearCache(); + } + + return r; +} + +int mcio_vmcExportImage(const char *output, int add_ecc) +{ + int r; + int pagesize, blocksize, cardsize, cardflags; + + r = mcio_mcGetInfo(&pagesize, &blocksize, &cardsize, &cardflags); + if (r < 0) + return -1; + + FILE *fh = fopen(output, "wb"); + if (fh == NULL) + return -2; + + void *ecc = malloc(pagesize >> 5); + void *buf = malloc(pagesize); + if (buf == NULL || ecc == NULL) { + fclose(fh); + return -3; + } + + for (int i = 0; i < (cardsize / pagesize); i++) { + mcio_mcReadPage(i, buf, ecc); + r = fwrite(buf, 1, pagesize, fh); + if (r != pagesize) { + free(buf); + fclose(fh); + return -4; + } + + if (!add_ecc) + continue; + + r = fwrite(ecc, 1, pagesize >> 5, fh); + if (r != pagesize >> 5) { + free(buf); + fclose(fh); + return -4; + } + } + + fclose(fh); + free(buf); + free(ecc); + + return sceMcResSucceed; +} diff --git a/source/menu_cheats.c b/source/menu_cheats.c index 8bb7657..e0f2233 100644 --- a/source/menu_cheats.c +++ b/source/menu_cheats.c @@ -106,9 +106,6 @@ void Draw_CheatsMenu_Options_Ani_Exit(void) DrawTexture(&menu_textures[edit_shadow_png_index], left - (menu_textures[edit_shadow_png_index].width * 1) + 1, 0, 0, menu_textures[edit_shadow_png_index].width, SCREEN_HEIGHT, icon_a); DrawHeader(cat_cheats_png_index, left, selected_centry->name, "Options", APP_FONT_TITLE_COLOR | icon_a, 0xffffffff, 1); - //DrawOptions(selected_centry->options[option_index], game_a, 18, menu_old_sel[7]); - //DrawScrollBar2(menu_old_sel[7], selected_centry->options[option_index].size, 18, 700, game_a); - SDL_RenderPresent(renderer); if (left == SCREEN_WIDTH) @@ -355,11 +352,11 @@ void DrawGameList(int selIndex, list_t * games, u8 alpha) tmp[0] = ' '; if (item->flags & SAVE_FLAG_PS2) tmp[0] = CHAR_TAG_PS2; - if (item->flags & SAVE_FLAG_PSP) tmp[0] = CHAR_TAG_PSP; + if (item->flags & SAVE_FLAG_PS1) tmp[0] = CHAR_TAG_PS1; if (item->flags & SAVE_FLAG_PS4) tmp[0] = CHAR_TAG_PS4; tmp[1] = (item->flags & SAVE_FLAG_OWNER) ? CHAR_TAG_OWNER : ' '; tmp[2] = (item->flags & SAVE_FLAG_LOCKED) ? CHAR_TAG_LOCKED : ' '; - if (item->flags & SAVE_FLAG_PSV) tmp[1] = CHAR_TAG_PSV; + if (item->type == FILE_TYPE_VMC) tmp[1] = CHAR_TAG_VMC; DrawString(SCREEN_WIDTH - (MENU_ICON_OFF * 3), game_y, tmp); skip_draw: diff --git a/source/menu_main.c b/source/menu_main.c index 96eaa6f..bf5effa 100644 --- a/source/menu_main.c +++ b/source/menu_main.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "orbisPad.h" #include "saves.h" @@ -8,12 +10,14 @@ #include "libfont.h" #include "ttf_render.h" #include "common.h" +#include "mcio.h" extern save_list_t hdd_saves; extern save_list_t usb_saves; extern save_list_t trophies; extern save_list_t online_saves; extern save_list_t user_backup; +extern save_list_t vmc2_saves; extern int close_app; @@ -67,6 +71,8 @@ static int ReloadUserSaves(save_list_t* save_list) list_bubbleSort(save_list->list, &sortSaveList_Compare); else if (apollo_config.doSort == SORT_BY_TITLE_ID) list_bubbleSort(save_list->list, &sortSaveList_Compare_TitleID); + else if (apollo_config.doSort == SORT_BY_TYPE) + list_bubbleSort(save_list->list, &sortSaveList_Compare_Type); stop_loading_screen(); @@ -91,13 +97,13 @@ static code_entry_t* LoadRawPatch(void) return centry; } -static code_entry_t* LoadSaveDetails(void) +static code_entry_t* LoadSaveDetails(const save_entry_t* save) { code_entry_t* centry = calloc(1, sizeof(code_entry_t)); - centry->name = strdup(selected_entry->title_id); + centry->name = strdup(save->title_id); - if (!get_save_details(selected_entry, ¢ry->codes)) - asprintf(¢ry->codes, "Error getting details (%s)", selected_entry->name); + if (!get_save_details(save, ¢ry->codes)) + asprintf(¢ry->codes, "Error getting details (%s)", save->name); LOG("%s", centry->codes); return (centry); @@ -107,6 +113,24 @@ static void SetMenu(int id) { switch (menu_id) //Leaving menu { + case MENU_PS2VMC_SAVES: + if (id == MENU_MAIN_SCREEN) + { + init_loading_screen("Saving PS2 Memory Card..."); + UnloadGameList(vmc2_saves.list); + vmc2_saves.list = NULL; + mcio_vmcFinish(); + + if(strncmp(APOLLO_SANDBOX_PATH, vmc2_saves.path, 16) == 0) + { + *strrchr(vmc2_saves.path, '/') = 0; + orbis_SaveUmount(strrchr(vmc2_saves.path, '/')); + } + + stop_loading_screen(); + } + break; + case MENU_MAIN_SCREEN: //Main Menu case MENU_TROPHIES: case MENU_USB_SAVES: //USB Saves Menu @@ -118,7 +142,14 @@ static void SetMenu(int id) case MENU_SETTINGS: //Options Menu case MENU_CREDITS: //About Menu + break; + case MENU_PATCHES: //Cheat Selection Menu + if (selected_entry->flags & SAVE_FLAG_UPDATED && id == MENU_PS2VMC_SAVES) + { + selected_entry->flags ^= SAVE_FLAG_UPDATED; + ReloadUserSaves(&vmc2_saves); + } break; case MENU_SAVE_DETAILS: @@ -178,6 +209,14 @@ static void SetMenu(int id) Draw_UserCheatsMenu_Ani(&online_saves); break; + case MENU_PS2VMC_SAVES: //Trophies Menu + if (!vmc2_saves.list && !ReloadUserSaves(&vmc2_saves)) + return; + + if (apollo_config.doAni) + Draw_UserCheatsMenu_Ani(&vmc2_saves); + break; + case MENU_CREDITS: //About Menu if (apollo_config.doAni) Draw_AboutMenu_Ani(); @@ -198,10 +237,12 @@ static void SetMenu(int id) case MENU_PATCHES: //Cheat Selection Menu //if entering from game list, don't keep index, otherwise keep - if (menu_id == MENU_USB_SAVES || menu_id == MENU_HDD_SAVES || menu_id == MENU_ONLINE_DB || menu_id == MENU_TROPHIES) + if (menu_id == MENU_USB_SAVES || menu_id == MENU_HDD_SAVES || menu_id == MENU_ONLINE_DB || + menu_id == MENU_TROPHIES || menu_id == MENU_PS2VMC_SAVES) menu_old_sel[MENU_PATCHES] = 0; char iconfile[256]; + menu_textures[icon_png_file_index].size = 0; snprintf(iconfile, sizeof(iconfile), "%s" "sce_sys/icon0.png", selected_entry->path); if (selected_entry->flags & SAVE_FLAG_ONLINE) @@ -209,15 +250,16 @@ static void SetMenu(int id) snprintf(iconfile, sizeof(iconfile), APOLLO_LOCAL_CACHE "%s.PNG", selected_entry->title_id); if (file_exists(iconfile) != SUCCESS) - http_download(selected_entry->path, "icon0.png", iconfile, 0); + http_download(selected_entry->path, "icon0.png", iconfile, 1); } + else if (selected_entry->flags & SAVE_FLAG_VMC && selected_entry->type == FILE_TYPE_PS2) + LoadVmcTexture(128, 128, getIconPS2(selected_entry->dir_name, strrchr(selected_entry->path, '\n')+1)); + else if (selected_entry->flags & SAVE_FLAG_HDD) snprintf(iconfile, sizeof(iconfile), PS4_SAVES_PATH_HDD "%s/%s_icon0.png", apollo_config.user_id, selected_entry->title_id, selected_entry->dir_name); if (file_exists(iconfile) == SUCCESS) LoadMenuTexture(iconfile, icon_png_file_index); - else - menu_textures[icon_png_file_index].size = 0; if (apollo_config.doAni && menu_id != MENU_PATCH_VIEW && menu_id != MENU_CODE_OPTIONS) Draw_CheatsMenu_Selection_Ani(); @@ -321,6 +363,36 @@ static void doSaveMenu(save_list_t * save_list) { selected_entry = list_get_item(save_list->list, menu_sel); + if (selected_entry->type == FILE_TYPE_VMC && selected_entry->flags & SAVE_FLAG_VMC) + { + char tmp_path[256]; + + strncpy(tmp_path, selected_entry->path, sizeof(tmp_path)); + + if (selected_entry->flags & SAVE_FLAG_HDD) + { + char mount[32]; + + if (!orbis_SaveMount(selected_entry, ORBIS_SAVE_DATA_MOUNT_MODE_RDWR, mount)) + return; + + snprintf(tmp_path, sizeof(tmp_path), APOLLO_SANDBOX_PATH "%s", mount, selected_entry->path); + } + + if (selected_entry->flags & SAVE_FLAG_PS1) + { +// strncpy(vmc1_saves.path, selected_entry->path, sizeof(vmc1_saves.path)); + SetMenu(MENU_PS1VMC_SAVES); + } + else + { + strncpy(vmc2_saves.path, tmp_path, sizeof(vmc2_saves.path)); + SetMenu(MENU_PS2VMC_SAVES); + } + + return; + } + if (!selected_entry->codes && !save_list->ReadCodes(selected_entry)) { show_message("No data found in folder:\n%s", selected_entry->path); @@ -339,7 +411,7 @@ static void doSaveMenu(save_list_t * save_list) selected_entry = list_get_item(save_list->list, menu_sel); if (selected_entry->type != FILE_TYPE_MENU) { - selected_centry = LoadSaveDetails(); + selected_centry = LoadSaveDetails(selected_entry); SetMenu(MENU_SAVE_DETAILS); return; } @@ -715,7 +787,7 @@ static void doPatchMenu(void) if (selected_centry->codes[0] == CMD_VIEW_DETAILS) { selected_centry->activated = 0; - selected_centry = LoadSaveDetails(); + selected_centry = LoadSaveDetails(selected_entry); SetMenu(MENU_SAVE_DETAILS); return; } @@ -792,5 +864,9 @@ void drawScene(void) case MENU_HEX_EDITOR: //Hex Editor Menu doHexEditor(); break; + + case MENU_PS2VMC_SAVES: //PS2 VMC Menu + doSaveMenu(&vmc2_saves); + break; } } diff --git a/source/menu_options.c b/source/menu_options.c index f558c58..755053c 100644 --- a/source/menu_options.c +++ b/source/menu_options.c @@ -58,7 +58,7 @@ static void _draw_OptionsMenu(u8 alpha) } } -void Draw_OptionsMenu_Ani() +void Draw_OptionsMenu_Ani(void) { int ani = 0; for (ani = 0; ani < MENU_ANI_MAX; ani++) @@ -82,7 +82,7 @@ void Draw_OptionsMenu_Ani() } } -void Draw_OptionsMenu() +void Draw_OptionsMenu(void) { DrawHeader(cat_opt_png_index, 0, "Settings", NULL, APP_FONT_TITLE_COLOR | 0xFF, 0xffffffff, 0); _draw_OptionsMenu(0xFF); diff --git a/source/orbis_jbc.c b/source/orbis_jbc.c index 611d18c..7193677 100644 --- a/source/orbis_jbc.c +++ b/source/orbis_jbc.c @@ -321,7 +321,7 @@ static void write_SceShellCore(int pid, uint64_t start, const orbis_patch_t* pat } // hack to disable unpatching on exit in case unmount failed (to avoid KP) -void disable_unpatch() +void disable_unpatch(void) { shellcore_backup = NULL; } diff --git a/source/ps2icon.c b/source/ps2icon.c new file mode 100644 index 0000000..22ea83d --- /dev/null +++ b/source/ps2icon.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +#include "ps2icon.h" +#include "mcio.h" + + +static uint32_t TIM2RGBA(const uint8_t *buf) +{ + uint8_t RGBA[4]; + uint16_t lRGB = (int16_t) (buf[1] << 8) | buf[0]; + + RGBA[3] = 8 * (lRGB & 0x1F); + RGBA[2] = 8 * ((lRGB >> 5) & 0x1F); + RGBA[1] = 8 * (lRGB >> 10); + RGBA[0] = 0xFF; + + return *((uint32_t *) &RGBA); +} + +static void* ps2IconTexture(const uint8_t* iData) +{ + int i; + uint16_t j; + Icon_Header header; + Animation_Header anim_header; + Frame_Data animation; + uint32_t *lTexturePtr, *lRGBA; + + lTexturePtr = (uint32_t *) calloc(128 * 128, sizeof(uint32_t)); + + //read header: + memcpy(&header, iData, sizeof(Icon_Header)); + iData += sizeof(Icon_Header); + + //n_vertices has to be divisible by three, that's for sure: + if(header.file_id != 0x010000 || header.n_vertices % 3 != 0) + return lTexturePtr; + + //read icon data from file: https://ghulbus-inc.de/projects/ps2iconsys/ + ///Vertex data + // each vertex consists of animation_shapes tuples for vertex coordinates, + // followed by one vertex coordinate tuple for normal coordinates + // followed by one texture data tuple for texture coordinates and color + for(i=0; i 0) + iData += sizeof(Frame_Key) * animation.n_keys; + } + + lRGBA = lTexturePtr; + + if (header.texture_type <= 7) + { // Uncompressed texture + for (i = 0; i < (128 * 128); i++) + { + *lRGBA = TIM2RGBA(iData); + lRGBA++; + iData += 2; + } + } + else + { //Compressed texture + iData += 4; + do + { + j = (int16_t) (iData[1] << 8) | iData[0]; + if (0xFF00 == (j & 0xFF00)) + { + for (j = (0x0000 - j) & 0xFFFF; j > 0; j--) + { + iData += 2; + *lRGBA = TIM2RGBA(iData); + lRGBA++; + } + } + else + { + iData += 2; + for (; j > 0; j--) + { + *lRGBA = TIM2RGBA(iData); + lRGBA++; + } + } + iData += 2; + } while ((lRGBA - lTexturePtr) < 0x4000); + } + + return (lTexturePtr); +} + +//Get icon data as bytes +uint8_t* getIconPS2(const char* folder, const char* iconfile) +{ + int fd; + uint8_t *buf, *out; + char filePath[256]; + struct io_dirent st; + + snprintf(filePath, sizeof(filePath), "%s/%s", folder, iconfile); + mcio_mcStat(filePath, &st); + + fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile); + if (fd < 0) + return calloc(128 * 128, sizeof(uint32_t)); + + buf = malloc(st.stat.size); + mcio_mcRead(fd, buf, st.stat.size); + mcio_mcClose(fd); + + out = ps2IconTexture(buf); + free(buf); + + return out; +} diff --git a/source/psv_ps2.c b/source/psv_ps2.c new file mode 100644 index 0000000..4849fbf --- /dev/null +++ b/source/psv_ps2.c @@ -0,0 +1,593 @@ +/* +* original .MAX, .CBS, .PSU file decoding from Cheat Device PS2 by root670 +* https://github.com/root670/CheatDevicePS2 +*/ + +#include +#include +#include + +#include "util.h" +#include "lzari.h" +#include "ps2mc.h" + +#define MAX_HEADER_MAGIC "Ps2PowerSave" +#define CBS_HEADER_MAGIC "CFU\0" +#define XPS_HEADER_MAGIC "SharkPortSave\0\0\0" + +#define xps_mode_swap(M) ((M & 0x00FF) << 8) + ((M & 0xFF00) >> 8) + +// This is the initial permutation state ("S") for the RC4 stream cipher +// algorithm used to encrypt and decrypt Codebreaker saves. +// Source: https://github.com/ps2dev/mymc/blob/master/ps2save.py#L36 +const uint8_t cbsKey[256] = { + 0x5f, 0x1f, 0x85, 0x6f, 0x31, 0xaa, 0x3b, 0x18, + 0x21, 0xb9, 0xce, 0x1c, 0x07, 0x4c, 0x9c, 0xb4, + 0x81, 0xb8, 0xef, 0x98, 0x59, 0xae, 0xf9, 0x26, + 0xe3, 0x80, 0xa3, 0x29, 0x2d, 0x73, 0x51, 0x62, + 0x7c, 0x64, 0x46, 0xf4, 0x34, 0x1a, 0xf6, 0xe1, + 0xba, 0x3a, 0x0d, 0x82, 0x79, 0x0a, 0x5c, 0x16, + 0x71, 0x49, 0x8e, 0xac, 0x8c, 0x9f, 0x35, 0x19, + 0x45, 0x94, 0x3f, 0x56, 0x0c, 0x91, 0x00, 0x0b, + 0xd7, 0xb0, 0xdd, 0x39, 0x66, 0xa1, 0x76, 0x52, + 0x13, 0x57, 0xf3, 0xbb, 0x4e, 0xe5, 0xdc, 0xf0, + 0x65, 0x84, 0xb2, 0xd6, 0xdf, 0x15, 0x3c, 0x63, + 0x1d, 0x89, 0x14, 0xbd, 0xd2, 0x36, 0xfe, 0xb1, + 0xca, 0x8b, 0xa4, 0xc6, 0x9e, 0x67, 0x47, 0x37, + 0x42, 0x6d, 0x6a, 0x03, 0x92, 0x70, 0x05, 0x7d, + 0x96, 0x2f, 0x40, 0x90, 0xc4, 0xf1, 0x3e, 0x3d, + 0x01, 0xf7, 0x68, 0x1e, 0xc3, 0xfc, 0x72, 0xb5, + 0x54, 0xcf, 0xe7, 0x41, 0xe4, 0x4d, 0x83, 0x55, + 0x12, 0x22, 0x09, 0x78, 0xfa, 0xde, 0xa7, 0x06, + 0x08, 0x23, 0xbf, 0x0f, 0xcc, 0xc1, 0x97, 0x61, + 0xc5, 0x4a, 0xe6, 0xa0, 0x11, 0xc2, 0xea, 0x74, + 0x02, 0x87, 0xd5, 0xd1, 0x9d, 0xb7, 0x7e, 0x38, + 0x60, 0x53, 0x95, 0x8d, 0x25, 0x77, 0x10, 0x5e, + 0x9b, 0x7f, 0xd8, 0x6e, 0xda, 0xa2, 0x2e, 0x20, + 0x4f, 0xcd, 0x8f, 0xcb, 0xbe, 0x5a, 0xe0, 0xed, + 0x2c, 0x9a, 0xd4, 0xe2, 0xaf, 0xd0, 0xa9, 0xe8, + 0xad, 0x7a, 0xbc, 0xa8, 0xf2, 0xee, 0xeb, 0xf5, + 0xa6, 0x99, 0x28, 0x24, 0x6c, 0x2b, 0x75, 0x5d, + 0xf8, 0xd3, 0x86, 0x17, 0xfb, 0xc0, 0x7b, 0xb3, + 0x58, 0xdb, 0xc7, 0x4b, 0xff, 0x04, 0x50, 0xe9, + 0x88, 0x69, 0xc9, 0x2a, 0xab, 0xfd, 0x5b, 0x1b, + 0x8a, 0xd9, 0xec, 0x27, 0x44, 0x0e, 0x33, 0xc8, + 0x6b, 0x93, 0x32, 0x48, 0xb6, 0x30, 0x43, 0xa5 +}; + +void write_psv_header(FILE *fp, uint32_t type); + +static void printMAXHeader(const maxHeader_t *header) +{ + if(!header) + return; + + LOG("Magic : %.*s", (int)sizeof(header->magic), header->magic); + LOG("CRC : %08X", (header->crc)); + LOG("dirName : %.*s", (int)sizeof(header->dirName), header->dirName); + LOG("iconSysName : %.*s", (int)sizeof(header->iconSysName), header->iconSysName); + LOG("compressedSize : %u", (header->compressedSize)); + LOG("numFiles : %u", (header->numFiles)); + LOG("decompressedSize : %u", (header->decompressedSize)); +} + +static int roundUp(int i, int j) +{ + return (i + j - 1) / j * j; +} + +static int isMAXFile(const char *path) +{ + if(!path) + return 0; + + FILE *f = fopen(path, "rb"); + if(!f) + return 0; + + // Verify file size + fseek(f, 0, SEEK_END); + int len = ftell(f); + fseek(f, 0, SEEK_SET); + if(len < sizeof(maxHeader_t)) + { + fclose(f); + return 0; + } + + // Verify header + maxHeader_t header; + fread(&header, 1, sizeof(maxHeader_t), f); + fclose(f); + + printMAXHeader(&header); + + return (header.compressedSize > 0) && + (header.decompressedSize > 0) && + (header.numFiles > 0) && + strncmp(header.magic, MAX_HEADER_MAGIC, sizeof(header.magic)) == 0 && + strlen(header.dirName) > 0 && + strlen(header.iconSysName) > 0; +} + +static void setMcDateTime(sceMcStDateTime* mc, struct tm *ftm) +{ + mc->Resv2 = 0; + mc->Sec = ftm->tm_sec; + mc->Min = ftm->tm_min; + mc->Hour = ftm->tm_hour; + mc->Day = ftm->tm_mday; + mc->Month = ftm->tm_mon + 1; + mc->Year = (ftm->tm_year + 1900); +} + +static void set_ps2header_values(ps2_header_t *ps2h, const ps2_FileInfo_t *ps2fi, const ps2_IconSys_t *ps2sys) +{ + if (strcmp(ps2fi->filename, ps2sys->IconName) == 0) + { + ps2h->icon1Size = ps2fi->filesize; + ps2h->icon1Pos = ps2fi->positionInFile; + } + + if (strcmp(ps2fi->filename, ps2sys->copyIconName) == 0) + { + ps2h->icon2Size = ps2fi->filesize; + ps2h->icon2Pos = ps2fi->positionInFile; + } + + if (strcmp(ps2fi->filename, ps2sys->deleteIconName) == 0) + { + ps2h->icon3Size = ps2fi->filesize; + ps2h->icon3Pos = ps2fi->positionInFile; + } + + if(strcmp(ps2fi->filename, "icon.sys") == 0) + { + ps2h->sysSize = ps2fi->filesize; + ps2h->sysPos = ps2fi->positionInFile; + } +} + +int ps2_max2psv(const char *save, const char* psv_path) +{ + if (!isMAXFile(save)) + return 0; + + FILE *f = fopen(save, "rb"); + if(!f) + return 0; + + struct stat st; + sceMcStDateTime fctime, fmtime; + + fstat(fileno(f), &st); + setMcDateTime(&fctime, gmtime(&st.st_ctime)); + setMcDateTime(&fmtime, gmtime(&st.st_mtime)); + + maxHeader_t header; + fread(&header, 1, sizeof(maxHeader_t), f); + + FILE* psv = fopen(psv_path, "wb"); + if (!psv) + return 0; + + // Get compressed file entries + u8 *compressed = malloc(header.compressedSize); + + fseek(f, sizeof(maxHeader_t) - 4, SEEK_SET); // Seek to beginning of LZARI stream. + u32 ret = fread(compressed, 1, header.compressedSize, f); + if(ret != header.compressedSize) + { + LOG("Compressed size: actual=%d, expected=%d\n", ret, header.compressedSize); + free(compressed); + return 0; + } + + fclose(f); + u8 *decompressed = malloc(header.decompressedSize); + + ret = unlzari(compressed, header.compressedSize, decompressed, header.decompressedSize); + // As with other save formats, decompressedSize isn't acccurate. + if(ret == 0) + { + LOG("Decompression failed.\n"); + free(decompressed); + free(compressed); + return 0; + } + + free(compressed); + + int i; + u32 offset = 0; + u32 dataPos = 0; + maxEntry_t *entry; + + ps2_header_t ps2h; + ps2_IconSys_t *ps2sys = NULL; + ps2_MainDirInfo_t ps2md; + + memset(&ps2h, 0, sizeof(ps2_header_t)); + memset(&ps2md, 0, sizeof(ps2_MainDirInfo_t)); + + ps2h.numberOfFiles = (header.numFiles); + + ps2md.attribute = 0x00008427; + ps2md.numberOfFilesInDir = (header.numFiles+2); + memcpy(&ps2md.created, &fctime, sizeof(sceMcStDateTime)); + memcpy(&ps2md.modified, &fmtime, sizeof(sceMcStDateTime)); + memcpy(ps2md.filename, header.dirName, sizeof(ps2md.filename)); + + write_psv_header(psv, 2); + + LOG("\nSave contents:\n"); + + // Find the icon.sys (need to know the icons names) + for(i = 0, offset = 0; i < header.numFiles; i++) + { + entry = (maxEntry_t*) &decompressed[offset]; + offset += sizeof(maxEntry_t); + + if(strcmp(entry->name, "icon.sys") == 0) + ps2sys = (ps2_IconSys_t*) &decompressed[offset]; + + offset = roundUp(offset + entry->length + 8, 16) - 8; + ps2h.displaySize += entry->length; + + LOG(" %8d bytes : %s", entry->length, entry->name); + } + + LOG(" %8d Total bytes", ps2h.displaySize); + + if (!ps2sys) + return 0; + + // Calculate the start offset for the file's data + dataPos = sizeof(psv_header_t) + sizeof(ps2_header_t) + sizeof(ps2_MainDirInfo_t) + sizeof(ps2_FileInfo_t)*header.numFiles; + + ps2_FileInfo_t *ps2fi = malloc(sizeof(ps2_FileInfo_t)*header.numFiles); + + // Build the PS2 FileInfo entries + for(i = 0, offset = 0; i < header.numFiles; i++) + { + entry = (maxEntry_t*) &decompressed[offset]; + offset += sizeof(maxEntry_t); + + ps2fi[i].attribute = 0x00008497; + ps2fi[i].positionInFile = (dataPos); + ps2fi[i].filesize = (entry->length); + memcpy(&ps2fi[i].created, &fctime, sizeof(sceMcStDateTime)); + memcpy(&ps2fi[i].modified, &fmtime, sizeof(sceMcStDateTime)); + memcpy(ps2fi[i].filename, entry->name, sizeof(ps2fi[i].filename)); + + dataPos += entry->length; + + set_ps2header_values(&ps2h, &ps2fi[i], ps2sys); + + offset = roundUp(offset + entry->length + 8, 16) - 8; + } + + fwrite(&ps2h, sizeof(ps2_header_t), 1, psv); + fwrite(&ps2md, sizeof(ps2_MainDirInfo_t), 1, psv); + fwrite(ps2fi, sizeof(ps2_FileInfo_t), header.numFiles, psv); + + free(ps2fi); + + // Write the file's data + for(i = 0, offset = 0; i < header.numFiles; i++) + { + entry = (maxEntry_t*) &decompressed[offset]; + offset += sizeof(maxEntry_t); + + fwrite(&decompressed[offset], 1, entry->length, psv); + + offset = roundUp(offset + entry->length + 8, 16) - 8; + } + + fclose(psv); + free(decompressed); + + return 1; +} + +static void cbsCrypt(uint8_t *buf, size_t bufLen) +{ + arc4_context ctx; + + memset(&ctx, 0, sizeof(arc4_context)); + memcpy(ctx.m, cbsKey, sizeof(cbsKey)); + arc4_crypt(&ctx, bufLen, buf, buf); +} + +static int isCBSFile(const char *path) +{ + if(!path) + return 0; + + FILE *f = fopen(path, "rb"); + if(!f) + return 0; + + // Verify file size + fseek(f, 0, SEEK_END); + int len = ftell(f); + fseek(f, 0, SEEK_SET); + if(len < sizeof(cbsHeader_t)) + { + fclose(f); + return 0; + } + + // Verify header magic + char magic[4]; + fread(magic, 1, 4, f); + fclose(f); + + if(memcmp(magic, CBS_HEADER_MAGIC, 4) != 0) + return 0; + + return 1; +} + +int ps2_cbs2psv(const char *save, const char *psv_path) +{ + FILE *dstFile; + u8 *cbsData; + u8 *compressed; + u8 *decompressed; + cbsHeader_t *header; + cbsEntry_t *entryHeader; + unsigned long decompressedSize; + size_t cbsLen; + int i, numFiles = 0; + u32 dataPos = 0, offset = 0; + + if(!isCBSFile(save)) + return 0; + + if(read_buffer(save, &cbsData, &cbsLen) < 0) + return 0; + + header = (cbsHeader_t *)cbsData; + dstFile = fopen(psv_path, "wb"); + + if (!dstFile) + return 0; + + // Get data for file entries + compressed = cbsData + sizeof(cbsHeader_t); + // Some tools create .CBS saves with an incorrect compressed size in the header. + // It can't be trusted! + cbsCrypt(compressed, cbsLen - sizeof(cbsHeader_t)); + decompressedSize = header->decompressedSize; + decompressed = malloc(decompressedSize); + int z_ret = uncompress(decompressed, &decompressedSize, compressed, cbsLen - sizeof(cbsHeader_t)); + + if(z_ret != Z_OK) + { + // Compression failed. + LOG("Decompression failed! (Z_ERR = %d)", z_ret); + free(cbsData); + free(decompressed); + return 0; + } + + ps2_header_t ps2h; + ps2_IconSys_t *ps2sys = NULL; + ps2_MainDirInfo_t ps2md; + + memset(&ps2h, 0, sizeof(ps2_header_t)); + memset(&ps2md, 0, sizeof(ps2_MainDirInfo_t)); + + ps2md.attribute = header->mode; + memcpy(&ps2md.created, &header->created, sizeof(sceMcStDateTime)); + memcpy(&ps2md.modified, &header->modified, sizeof(sceMcStDateTime)); + memcpy(ps2md.filename, header->name, sizeof(ps2md.filename)); + + write_psv_header(dstFile, 2); + + LOG("Save contents:\n"); + + // Find the icon.sys (need to know the icons names) + while(offset < (decompressedSize - sizeof(cbsEntry_t))) + { + numFiles++; + + entryHeader = (cbsEntry_t*) &decompressed[offset]; + offset += sizeof(cbsEntry_t); + + if(strcmp(entryHeader->name, "icon.sys") == 0) + ps2sys = (ps2_IconSys_t*) &decompressed[offset]; + + ps2h.displaySize += entryHeader->length; + offset += entryHeader->length; + + LOG(" %8d bytes : %s", entryHeader->length, entryHeader->name); + } + + LOG(" %8d Total bytes", ps2h.displaySize); + ps2h.displaySize = (ps2h.displaySize); + ps2h.numberOfFiles = (numFiles); + ps2md.numberOfFilesInDir = (numFiles+2); + + if (!ps2sys) + return 0; + + // Calculate the start offset for the file's data + dataPos = sizeof(psv_header_t) + sizeof(ps2_header_t) + sizeof(ps2_MainDirInfo_t) + sizeof(ps2_FileInfo_t)*numFiles; + + ps2_FileInfo_t *ps2fi = malloc(sizeof(ps2_FileInfo_t)*numFiles); + + // Build the PS2 FileInfo entries + for(i = 0, offset = 0; i < numFiles; i++) + { + entryHeader = (cbsEntry_t*) &decompressed[offset]; + offset += sizeof(cbsEntry_t); + + ps2fi[i].attribute = entryHeader->mode; + ps2fi[i].positionInFile = (dataPos); + ps2fi[i].filesize = entryHeader->length; + memcpy(&ps2fi[i].created, &entryHeader->created, sizeof(sceMcStDateTime)); + memcpy(&ps2fi[i].modified, &entryHeader->modified, sizeof(sceMcStDateTime)); + memcpy(ps2fi[i].filename, entryHeader->name, sizeof(ps2fi[i].filename)); + + dataPos += entryHeader->length; + + set_ps2header_values(&ps2h, &ps2fi[i], ps2sys); + + offset += entryHeader->length; + } + + fwrite(&ps2h, sizeof(ps2_header_t), 1, dstFile); + fwrite(&ps2md, sizeof(ps2_MainDirInfo_t), 1, dstFile); + fwrite(ps2fi, sizeof(ps2_FileInfo_t), numFiles, dstFile); + + free(ps2fi); + + // Write the file's data + for(i = 0, offset = 0; i < numFiles; i++) + { + entryHeader = (cbsEntry_t*) &decompressed[offset]; + offset += sizeof(cbsEntry_t); + + fwrite(&decompressed[offset], 1, entryHeader->length, dstFile); + + offset += entryHeader->length; + } + + fclose(dstFile); + free(decompressed); + free(cbsData); + + return 1; +} + +int ps2_xps2psv(const char *save, const char *psv_path) +{ + u32 len, dataPos = 0; + FILE *xpsFile, *psvFile; + int numFiles, i; + char tmp[100]; + u8 *data; + xpsEntry_t entry; + + xpsFile = fopen(save, "rb"); + if(!xpsFile) + return 0; + + fread(&tmp, 1, 0x15, xpsFile); + + if (memcmp(&tmp[4], XPS_HEADER_MAGIC, 16) != 0) + { + fclose(xpsFile); + return 0; + } + + // Skip the variable size header + fread(&len, 1, sizeof(uint32_t), xpsFile); + fread(&tmp, 1, len, xpsFile); + fread(&len, 1, sizeof(uint32_t), xpsFile); + fread(&tmp, 1, len, xpsFile); + fread(&len, 1, sizeof(uint32_t), xpsFile); + fread(&len, 1, sizeof(uint32_t), xpsFile); + + // Read main directory entry + fread(&entry, 1, sizeof(xpsEntry_t), xpsFile); + numFiles = entry.length - 2; + + // Keep the file position (start of file entries) + len = ftell(xpsFile); + + psvFile = fopen(psv_path, "wb"); + if(!psvFile) + { + fclose(xpsFile); + return 0; + } + + ps2_header_t ps2h; + ps2_IconSys_t ps2sys; + ps2_MainDirInfo_t ps2md; + + memset(&ps2h, 0, sizeof(ps2_header_t)); + memset(&ps2md, 0, sizeof(ps2_MainDirInfo_t)); + + ps2h.numberOfFiles = numFiles; + + ps2md.attribute = xps_mode_swap(entry.mode); + ps2md.numberOfFilesInDir = entry.length; + memcpy(&ps2md.created, &entry.created, sizeof(sceMcStDateTime)); + memcpy(&ps2md.modified, &entry.modified, sizeof(sceMcStDateTime)); + memcpy(ps2md.filename, entry.name, sizeof(ps2md.filename)); + + write_psv_header(psvFile, 2); + + // Find the icon.sys (need to know the icons names) + for(i = 0; i < numFiles; i++) + { + fread(&entry, 1, sizeof(xpsEntry_t), xpsFile); + + if(strcmp(entry.name, "icon.sys") == 0) + fread(&ps2sys, 1, sizeof(ps2_IconSys_t), xpsFile); + else + fseek(xpsFile, entry.length, SEEK_CUR); + + ps2h.displaySize += entry.length; + + LOG(" %8d bytes : %s", entry.length, entry.name); + } + + LOG(" %8d Total bytes", ps2h.displaySize); + + // Rewind + fseek(xpsFile, len, SEEK_SET); + + // Calculate the start offset for the file's data + dataPos = sizeof(psv_header_t) + sizeof(ps2_header_t) + sizeof(ps2_MainDirInfo_t) + sizeof(ps2_FileInfo_t)*numFiles; + + ps2_FileInfo_t *ps2fi = malloc(sizeof(ps2_FileInfo_t)*numFiles); + + // Build the PS2 FileInfo entries + for(i = 0; i < numFiles; i++) + { + fread(&entry, 1, sizeof(xpsEntry_t), xpsFile); + + ps2fi[i].attribute = xps_mode_swap(entry.mode); + ps2fi[i].positionInFile = dataPos; + ps2fi[i].filesize = entry.length; + memcpy(&ps2fi[i].created, &entry.created, sizeof(sceMcStDateTime)); + memcpy(&ps2fi[i].modified, &entry.modified, sizeof(sceMcStDateTime)); + memcpy(ps2fi[i].filename, entry.name, sizeof(ps2fi[i].filename)); + + dataPos += entry.length; + fseek(xpsFile, entry.length, SEEK_CUR); + + set_ps2header_values(&ps2h, &ps2fi[i], &ps2sys); + } + + fwrite(&ps2h, sizeof(ps2_header_t), 1, psvFile); + fwrite(&ps2md, sizeof(ps2_MainDirInfo_t), 1, psvFile); + fwrite(ps2fi, sizeof(ps2_FileInfo_t), numFiles, psvFile); + + free(ps2fi); + + // Rewind + fseek(xpsFile, len, SEEK_SET); + + // Copy each file entry + for(i = 0; i < numFiles; i++) + { + fread(&entry, 1, sizeof(xpsEntry_t), xpsFile); + + data = malloc(entry.length); + fread(data, 1, entry.length, xpsFile); + fwrite(data, 1, entry.length, psvFile); + + free(data); + } + + fclose(psvFile); + fclose(xpsFile); + + return 1; +} diff --git a/source/psv_resign.c b/source/psv_resign.c new file mode 100644 index 0000000..41669a3 --- /dev/null +++ b/source/psv_resign.c @@ -0,0 +1,796 @@ +/* +* ps3-psvresigner by @dots_tb - Resigns non-console specific PS3 PSV savefiles. +* PSV files embed PS1 and PS2 save data. This does not inject! +* With help from the CBPS (https://discord.gg/2nDCbxJ) , especially: +* @AnalogMan151, @teakhanirons, Silica, @notzecoxao, @nyaaasen +*/ + +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "ps2mc.h" +#include "mcio.h" +#include "shiftjis.h" + +#define PSV_TYPE_PS1 0x01 +#define PSV_TYPE_PS2 0x02 +#define PSV_SEED_OFFSET 0x08 +#define PSV_HASH_OFFSET 0x1C +#define PSV_TYPE_OFFSET 0x3C +#define VMP_SEED_OFFSET 0x0C +#define VMP_HASH_OFFSET 0x20 +#define VMP_MAGIC 0x00504D56 +#define VMP_SIZE 0x20080 + +static const char SJIS_REPLACEMENT_TABLE[] = + " ,.,..:;?!\"*'`*^" + "-_????????*---/\\" + "~||--''\"\"()()[]{" + "}<><>[][][]+-+X?" + "-==<><>????*'\"CY" + "$c&%#&*@S*******" + "*******T><^_'='"; + +static const uint8_t psv_ps2key[0x10] = { + 0xFA, 0x72, 0xCE, 0xEF, 0x59, 0xB4, 0xD2, 0x98, 0x9F, 0x11, 0x19, 0x13, 0x28, 0x7F, 0x51, 0xC7 +}; + +static const uint8_t psv_ps1key[0x10] = { + 0xAB, 0x5A, 0xBC, 0x9F, 0xC1, 0xF4, 0x9D, 0xE6, 0xA0, 0x51, 0xDB, 0xAE, 0xFA, 0x51, 0x88, 0x59 +}; + +static const uint8_t psv_iv[0x10] = { + 0xB3, 0x0F, 0xFE, 0xED, 0xB7, 0xDC, 0x5E, 0xB7, 0x13, 0x3D, 0xA6, 0x0D, 0x1B, 0x6B, 0x2C, 0xDC +}; + + +static void XorWithByte(uint8_t* buf, uint8_t byte, int length) +{ + for (int i = 0; i < length; ++i) { + buf[i] ^= byte; + } +} + +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) +{ + uint8_t i; + for (i = 0; i < 16; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } +} + +static void generateHash(const uint8_t *input, uint8_t *dest, size_t sz, uint8_t type) +{ + aes_context aes_ctx; + sha1_context sha1_ctx; + uint8_t iv[0x10]; + uint8_t salt[0x40]; + uint8_t work_buf[0x14]; + const uint8_t *salt_seed = input + PSV_SEED_OFFSET; + + memset(salt , 0, sizeof(salt)); + memset(&aes_ctx, 0, sizeof(aes_context)); + + LOG("Type detected: %d", type); + if(type == PSV_TYPE_PS1) + { //PS1 + LOG("PS1 Save File"); + //idk why the normal cbc doesn't work. + memcpy(work_buf, salt_seed, 0x10); + + aes_setkey_dec(&aes_ctx, psv_ps1key, 128); + aes_crypt_ecb(&aes_ctx, AES_DECRYPT, work_buf, salt); + aes_setkey_enc(&aes_ctx, psv_ps1key, 128); + aes_crypt_ecb(&aes_ctx, AES_ENCRYPT, work_buf, salt + 0x10); + + XorWithIv(salt, psv_iv); + + memset(work_buf, 0xFF, sizeof(work_buf)); + memcpy(work_buf, salt_seed + 0x10, 0x4); + + XorWithIv(salt + 0x10, work_buf); + } + else if(type == PSV_TYPE_PS2) + { //PS2 + LOG("PS2 Save File"); + uint8_t laid_paid[16] = { + 0x10, 0x70, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x10, 0x70, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x01 }; + + memcpy(salt, salt_seed, 0x14); + memcpy(iv, psv_iv, sizeof(iv)); + XorWithIv(laid_paid, psv_ps2key); + + aes_setkey_dec(&aes_ctx, laid_paid, 128); + aes_crypt_cbc(&aes_ctx, AES_DECRYPT, sizeof(salt), iv, salt, salt); + } + else + { + LOG("Error: Unknown type"); + return; + } + + memset(salt + 0x14, 0, sizeof(salt) - 0x14); + memset(dest, 0, 0x14); + + XorWithByte(salt, 0x36, sizeof(salt)); + + memset(&sha1_ctx, 0, sizeof(sha1_context)); + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, salt, sizeof(salt)); + sha1_update(&sha1_ctx, input, sz); + sha1_finish(&sha1_ctx, work_buf); + + XorWithByte(salt, 0x6A, sizeof(salt)); + + memset(&sha1_ctx, 0, sizeof(sha1_context)); + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, salt, sizeof(salt)); + sha1_update(&sha1_ctx, work_buf, 0x14); + sha1_finish(&sha1_ctx, dest); +} + +int psv_resign(const char *src_psv) +{ + size_t sz; + uint8_t *input; + + LOG("=====ps3-psvresigner by @dots_tb====="); +// LOG("\nWith CBPS help especially: @AnalogMan151, @teakhanirons, Silica, @nyaaasen, and @notzecoxao\n"); +// LOG("Resigns non-console specific PS3 PSV savefiles. PSV files embed PS1 and PS2 save data. This does not inject!\n\n"); + + if (read_buffer(src_psv, &input, &sz) < 0) { + LOG("Failed to open input file"); + return 0; + } + + LOG("File Size: %ld bytes", sz); + + if (memcmp(input, PSV_MAGIC, 4) != 0) { + LOG("Not a PSV file"); + free(input); + return 0; + } + + generateHash(input, input + PSV_HASH_OFFSET, sz, input[PSV_TYPE_OFFSET]); + + LOG("New signature: "); + dump_data(input + PSV_HASH_OFFSET, 0x14); + + if (write_buffer(src_psv, input, sz) < 0) { + LOG("Failed to open output file"); + free(input); + return 0; + } + + free(input); + LOG("PSV resigned successfully: %s\n", src_psv); + + return 1; +} +/* +int vmp_resign(const char *src_vmp) +{ + size_t sz; + uint8_t *input; + + LOG("=====Vita MCR2VMP by @dots_tb====="); + + if (read_buffer(src_vmp, &input, &sz) < 0) { + LOG("Failed to open input file"); + return 0; + } + + if (sz != VMP_SIZE || *(uint32_t*)input != VMP_MAGIC) { + LOG("Not a VMP file"); + free(input); + return 0; + } + + generateHash(input, input + VMP_SEED_OFFSET, input + VMP_HASH_OFFSET, sz, 1); + + LOG("New signature:"); + dump_data(input+VMP_HASH_OFFSET, 20); + + if (write_buffer(src_vmp, input, sz) < 0) { + LOG("Failed to open output file"); + free(input); + return 0; + } + + free(input); + LOG("VMP resigned successfully: %s", src_vmp); + + return 1; +} +*/ +void get_psv_filename(char* psvName, const char* path, const char* dirName) +{ + char tmpName[13]; + const char *ch = &dirName[12]; + + memcpy(tmpName, dirName, 12); + tmpName[12] = 0; + + strcpy(psvName, path); + strcat(psvName, tmpName); + while (*ch) + { + snprintf(tmpName, sizeof(tmpName), "%02X", *ch++); + strcat(psvName, tmpName); + } + strcat(psvName, ".PSV"); +} + +void write_psv_header(FILE *fp, uint32_t type) +{ + psv_header_t ph; + + memset(&ph, 0, sizeof(psv_header_t)); + ph.headerSize = (type == PSV_TYPE_PS1) ? 0x14 : 0x2C; + ph.saveType = type; + memcpy(&ph.magic, PSV_MAGIC, sizeof(ph.magic)); + memcpy(&ph.salt, PSV_SALT, sizeof(ph.salt)); + + fwrite(&ph, sizeof(psv_header_t), 1, fp); +} + +//Convert Shift-JIS characters to ASCII equivalent +static void sjis2ascii(char* bData) +{ + uint16_t ch; + int i, j = 0; + int len = strlen(bData); + + for (i = 0; i < len; i += 2) + { + ch = (bData[i]<<8) | bData[i+1]; + + // 'A' .. 'Z' + // '0' .. '9' + if ((ch >= 0x8260 && ch <= 0x8279) || (ch >= 0x824F && ch <= 0x8258)) + { + bData[j++] = (ch & 0xFF) - 0x1F; + continue; + } + + // 'a' .. 'z' + if (ch >= 0x8281 && ch <= 0x829A) + { + bData[j++] = (ch & 0xFF) - 0x20; + continue; + } + + if (ch >= 0x8140 && ch <= 0x81AC) + { + bData[j++] = SJIS_REPLACEMENT_TABLE[(ch & 0xFF) - 0x40]; + continue; + } + + if (ch == 0x0000) + { + //End of the string + bData[j] = 0; + return; + } + + // Character not found + bData[j++] = bData[i]; + bData[j++] = bData[i+1]; + } + + bData[j] = 0; + return; +} + +// PSV files (PS1/PS2) savegame titles are stored in Shift-JIS +char* sjis2utf8(char* input) +{ + // Simplify the input and decode standard ASCII characters + sjis2ascii(input); + + int len = strlen(input); + char* output = malloc(3 * len); //ShiftJis won't give 4byte UTF8, so max. 3 byte per input char are needed + size_t indexInput = 0, indexOutput = 0; + + while(indexInput < len) + { + char arraySection = ((uint8_t)input[indexInput]) >> 4; + + size_t arrayOffset; + if(arraySection == 0x8) arrayOffset = 0x100; //these are two-byte shiftjis + else if(arraySection == 0x9) arrayOffset = 0x1100; + else if(arraySection == 0xE) arrayOffset = 0x2100; + else arrayOffset = 0; //this is one byte shiftjis + + //determining real array offset + if(arrayOffset) + { + arrayOffset += (((uint8_t)input[indexInput]) & 0xf) << 8; + indexInput++; + if(indexInput >= len) break; + } + arrayOffset += (uint8_t)input[indexInput++]; + arrayOffset <<= 1; + + //unicode number is... + uint16_t unicodeValue = (shiftJIS_convTable[arrayOffset] << 8) | shiftJIS_convTable[arrayOffset + 1]; + + //converting to UTF8 + if(unicodeValue < 0x80) + { + output[indexOutput++] = unicodeValue; + } + else if(unicodeValue < 0x800) + { + output[indexOutput++] = 0xC0 | (unicodeValue >> 6); + output[indexOutput++] = 0x80 | (unicodeValue & 0x3f); + } + else + { + output[indexOutput++] = 0xE0 | (unicodeValue >> 12); + output[indexOutput++] = 0x80 | ((unicodeValue & 0xfff) >> 6); + output[indexOutput++] = 0x80 | (unicodeValue & 0x3f); + } + } + + //remove the unnecessary bytes + output[indexOutput] = 0; + return output; +} + +int vmc_import_psv(const char *input) +{ + int fd, r; + uint8_t *p; + size_t filesize; + char filepath[256]; + struct io_dirent entry; + ps2_MainDirInfo_t *ps2md; + ps2_FileInfo_t *ps2fi; + + if (read_buffer(input, &p, &filesize) < 0) + return 0; + + if (memcmp(PSV_MAGIC, p, 4) != 0 || p[PSV_TYPE_OFFSET] != PSV_TYPE_PS2) { + LOG("Not a PS2 .PSV file"); + free(p); + return 0; + } + + ps2md = (ps2_MainDirInfo_t *)&p[0x68]; + ps2fi = (ps2_FileInfo_t *)&ps2md[1]; + + LOG("Writing data to: '/%s'...", ps2md->filename); + + r = mcio_mcMkDir(ps2md->filename); + if (r < 0) + LOG("Error: can't create directory '%s'... (%d)", ps2md->filename, r); + else + mcio_mcClose(r); + + for (int total = (read_le_uint32((uint8_t*)&ps2md->numberOfFilesInDir) - 2), i = 0; i < total; i++, ps2fi++) + { + filesize = read_le_uint32((uint8_t*)&ps2fi->filesize); + + snprintf(filepath, sizeof(filepath), "%s/%s", ps2md->filename, ps2fi->filename); + LOG("Adding %-48s | %8d bytes", filepath, filesize); + + fd = mcio_mcOpen(filepath, sceMcFileCreateFile | sceMcFileAttrWriteable | sceMcFileAttrFile); + if (fd < 0) { + free(p); + return 0; + } + + r = mcio_mcWrite(fd, &p[read_le_uint32((uint8_t*)&ps2fi->positionInFile)], filesize); + mcio_mcClose(fd); + if (r != filesize) { + free(p); + return 0; + } + + mcio_mcStat(filepath, &entry); + memcpy(&entry.stat.ctime, &ps2fi->created, sizeof(struct sceMcStDateTime)); + memcpy(&entry.stat.mtime, &ps2fi->modified, sizeof(struct sceMcStDateTime)); + entry.stat.mode = read_le_uint32((uint8_t*)&ps2fi->attribute); + mcio_mcSetStat(filepath, &entry); + } + + mcio_mcStat(ps2md->filename, &entry); + memcpy(&entry.stat.ctime, &ps2md->created, sizeof(struct sceMcStDateTime)); + memcpy(&entry.stat.mtime, &ps2md->modified, sizeof(struct sceMcStDateTime)); + entry.stat.mode = read_le_uint32((uint8_t*)&ps2md->attribute); + mcio_mcSetStat(ps2md->filename, &entry); + + free(p); + LOG("Save succesfully imported: %s", input); + + return 1; +} + +int vmc_import_psu(const char *input) +{ + int fd, r; + char filepath[256]; + struct io_dirent entry; + McFsEntry psu_entry, file_entry; + + FILE *fh = fopen(input, "rb"); + if (fh == NULL) + return 0; + + fseek(fh, 0, SEEK_END); + r = ftell(fh); + + if (!r || r % 512) { + LOG("Not a .PSU file"); + fclose(fh); + return 0; + } + + LOG("Reading file: '%s'...", input); + fseek(fh, 0, SEEK_SET); + + r = fread(&psu_entry, sizeof(McFsEntry), 1, fh); + if (!r) { + fclose(fh); + return 0; + } + + // Skip "." and ".." + fseek(fh, sizeof(McFsEntry)*2, SEEK_CUR); + + LOG("Writing data to: '/%s'...", psu_entry.name); + + r = mcio_mcMkDir(psu_entry.name); + if (r < 0) + LOG("Error: can't create directory '%s'... (%d)", psu_entry.name, r); + else + mcio_mcClose(r); + + for (int total = (psu_entry.length - 2), i = 0; i < total; i++) + { + fread(&file_entry, 1, sizeof(McFsEntry), fh); + + snprintf(filepath, sizeof(filepath), "%s/%s", psu_entry.name, file_entry.name); + LOG("Adding %-48s | %8d bytes", filepath, file_entry.length); + + fd = mcio_mcOpen(filepath, sceMcFileCreateFile | sceMcFileAttrWriteable | sceMcFileAttrFile); + if (fd < 0) + return 0; + + uint8_t *p = malloc(file_entry.length); + if (!p) + { + mcio_mcClose(fd); + return 0; + } + + fread(p, 1, file_entry.length, fh); + r = mcio_mcWrite(fd, p, file_entry.length); + mcio_mcClose(fd); + free(p); + + if (r != (int)file_entry.length) + return 0; + + mcio_mcStat(filepath, &entry); + memcpy(&entry.stat.ctime, &file_entry.created, sizeof(struct sceMcStDateTime)); + memcpy(&entry.stat.mtime, &file_entry.modified, sizeof(struct sceMcStDateTime)); + entry.stat.mode = file_entry.mode; + mcio_mcSetStat(filepath, &entry); + + r = 1024 - (file_entry.length % 1024); + if(r < 1024) + fseek(fh, r, SEEK_CUR); + } + + mcio_mcStat(psu_entry.name, &entry); + memcpy(&entry.stat.ctime, &psu_entry.created, sizeof(struct sceMcStDateTime)); + memcpy(&entry.stat.mtime, &psu_entry.modified, sizeof(struct sceMcStDateTime)); + entry.stat.mode = psu_entry.mode; + mcio_mcSetStat(psu_entry.name, &entry); + + return 1; +} + +int vmc_export_psv(const char* save, const char* out_path) +{ + FILE *psvFile; + ps2_header_t ps2h; + ps2_FileInfo_t *ps2fi; + ps2_MainDirInfo_t ps2md; + ps2_IconSys_t iconsys; + uint32_t dataPos, i; + char filePath[256]; + uint8_t *data; + int r, dd, fd; + struct io_dirent dirent; + + snprintf(filePath, sizeof(filePath), "%s/icon.sys", save); + fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile); + if (fd < 0) + { + LOG("Error! '%s' not found", filePath); + return 0; + } + + r = mcio_mcRead(fd, &iconsys, sizeof(ps2_IconSys_t)); + mcio_mcClose(fd); + + if (r != sizeof(ps2_IconSys_t)) + return 0; + + get_psv_filename(filePath, out_path, save); + + LOG("Export %s -> %s ...", save, filePath); + psvFile = fopen(filePath, "wb"); + if(!psvFile) + return 0; + + write_psv_header(psvFile, PSV_TYPE_PS2); + + memset(&ps2h, 0, sizeof(ps2_header_t)); + memset(&ps2md, 0, sizeof(ps2_MainDirInfo_t)); + + // Read main directory entry + mcio_mcStat(save, &dirent); + + // PSV root directory values + ps2h.numberOfFiles = dirent.stat.size - 2; + ps2md.attribute = dirent.stat.mode; + ps2md.numberOfFilesInDir = dirent.stat.size; + memcpy(&ps2md.created, &dirent.stat.ctime, sizeof(sceMcStDateTime)); + memcpy(&ps2md.modified, &dirent.stat.mtime, sizeof(sceMcStDateTime)); + memcpy(ps2md.filename, dirent.name, sizeof(ps2md.filename)); + + dd = mcio_mcDopen(save); + if (dd < 0) + { + fclose(psvFile); + return 0; + } + + // Calculate the start offset for the file's data + dataPos = sizeof(psv_header_t) + sizeof(ps2_header_t) + sizeof(ps2_MainDirInfo_t) + sizeof(ps2_FileInfo_t)*ps2h.numberOfFiles; + ps2fi = malloc(sizeof(ps2_FileInfo_t)*ps2h.numberOfFiles); + + // Build the PS2 FileInfo entries + i = 0; + do { + r = mcio_mcDread(dd, &dirent); + if (r && (strcmp(dirent.name, ".")) && (strcmp(dirent.name, ".."))) + { + snprintf(filePath, sizeof(filePath), "%s/%s", save, dirent.name); + mcio_mcStat(filePath, &dirent); + + ps2fi[i].attribute = dirent.stat.mode; + ps2fi[i].positionInFile = dataPos; + ps2fi[i].filesize = dirent.stat.size; + memcpy(&ps2fi[i].created, &dirent.stat.ctime, sizeof(sceMcStDateTime)); + memcpy(&ps2fi[i].modified, &dirent.stat.mtime, sizeof(sceMcStDateTime)); + memcpy(ps2fi[i].filename, dirent.name, sizeof(ps2fi[i].filename)); + + dataPos += dirent.stat.size; + ps2h.displaySize += dirent.stat.size; + + if (strcmp(ps2fi[i].filename, iconsys.IconName) == 0) + { + ps2h.icon1Size = ps2fi[i].filesize; + ps2h.icon1Pos = ps2fi[i].positionInFile; + } + + if (strcmp(ps2fi[i].filename, iconsys.copyIconName) == 0) + { + ps2h.icon2Size = ps2fi[i].filesize; + ps2h.icon2Pos = ps2fi[i].positionInFile; + } + + if (strcmp(ps2fi[i].filename, iconsys.deleteIconName) == 0) + { + ps2h.icon3Size = ps2fi[i].filesize; + ps2h.icon3Pos = ps2fi[i].positionInFile; + } + + if(strcmp(ps2fi[i].filename, "icon.sys") == 0) + { + ps2h.sysSize = ps2fi[i].filesize; + ps2h.sysPos = ps2fi[i].positionInFile; + } + i++; + } + } while (r); + + mcio_mcDclose(dd); + + LOG("%d Files: %8d Total bytes", i, ps2h.displaySize); + + fwrite(&ps2h, sizeof(ps2_header_t), 1, psvFile); + fwrite(&ps2md, sizeof(ps2_MainDirInfo_t), 1, psvFile); + fwrite(ps2fi, sizeof(ps2_FileInfo_t), ps2h.numberOfFiles, psvFile); + free(ps2fi); + + // Write the file's data + dd = mcio_mcDopen(save); + + i = 0; + do { + r = mcio_mcDread(dd, &dirent); + if (r && (strcmp(dirent.name, ".")) && (strcmp(dirent.name, ".."))) + { + snprintf(filePath, sizeof(filePath), "%s/%s", save, dirent.name); + LOG("(%d/%d) Add '%s'", ++i, ps2h.numberOfFiles, filePath); + + fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile); + if (fd < 0) + { + i = 0; + break; + } + + data = malloc(dirent.stat.size); + if (!data) + { + i = 0; + break; + } + + r = mcio_mcRead(fd, data, dirent.stat.size); + mcio_mcClose(fd); + + if (r != (int)dirent.stat.size) + { + i = 0; + free(data); + break; + } + + fwrite(data, 1, dirent.stat.size, psvFile); + free(data); + } + } while (r); + + mcio_mcDclose(dd); + + fclose(psvFile); + get_psv_filename(filePath, out_path, save); + psv_resign(filePath); + + return (i > 0); +} + +int vmc_export_psu(const char* path, const char* output) +{ + int r, fd, dd; + uint32_t total, i = 0; + struct io_dirent dirent; + McFsEntry entry; + char filepath[256]; + + LOG("Exporting '%s' to %s...", path, output); + + dd = mcio_mcDopen(path); + if (dd < 0) + return 0; + + FILE *fh = fopen(output, "wb"); + if (fh == NULL) { + mcio_mcDclose(dd); + return 0; + } + + // Read main directory entry + mcio_mcStat(path, &dirent); + + memset(&entry, 0, sizeof(McFsEntry)); + memcpy(&entry.created, &dirent.stat.ctime, sizeof(sceMcStDateTime)); + memcpy(&entry.modified, &dirent.stat.mtime, sizeof(sceMcStDateTime)); + memcpy(entry.name, dirent.name, sizeof(entry.name)); + entry.mode = dirent.stat.mode; + entry.length = dirent.stat.size; + fwrite(&entry, sizeof(McFsEntry), 1, fh); + total = dirent.stat.size - 2; + + // "." + memset(entry.name, 0, sizeof(entry.name)); + strncpy(entry.name, ".", sizeof(entry.name)); + entry.length = 0; + fwrite(&entry, sizeof(McFsEntry), 1, fh); + + // ".." + strncpy(entry.name, "..", sizeof(entry.name)); + fwrite(&entry, sizeof(McFsEntry), 1, fh); + + do { + r = mcio_mcDread(dd, &dirent); + if (r && (strcmp(dirent.name, ".")) && (strcmp(dirent.name, ".."))) + { + snprintf(filepath, sizeof(filepath), "%s/%s", path, dirent.name); + LOG("Adding (%d/%d) %-40s | %8d bytes", ++i, total, filepath, dirent.stat.size); + + mcio_mcStat(filepath, &dirent); + + memset(&entry, 0, sizeof(McFsEntry)); + memcpy(&entry.created, &dirent.stat.ctime, sizeof(sceMcStDateTime)); + memcpy(&entry.modified, &dirent.stat.mtime, sizeof(sceMcStDateTime)); + memcpy(entry.name, dirent.name, sizeof(entry.name)); + entry.mode = dirent.stat.mode; + entry.length = dirent.stat.size; + fwrite(&entry, sizeof(McFsEntry), 1, fh); + + fd = mcio_mcOpen(filepath, sceMcFileAttrReadable | sceMcFileAttrFile); + if (fd < 0) { + i = 0; + break; + } + + uint8_t *p = malloc(dirent.stat.size); + if (p == NULL) { + i = 0; + break; + } + + r = mcio_mcRead(fd, p, dirent.stat.size); + mcio_mcClose(fd); + + if (r != (int)dirent.stat.size) { + free(p); + i = 0; + break; + } + + r = fwrite(p, 1, dirent.stat.size, fh); + if (r != (int)dirent.stat.size) { + fclose(fh); + free(p); + i = 0; + break; + } + free(p); + + entry.length = 1024 - (dirent.stat.size % 1024); + while(--entry.length < 1023) + fputc(0xFF, fh); + } + } while (r); + + mcio_mcDclose(dd); + fclose(fh); + + LOG("Save succesfully exported to %s.", output); + + return (i > 0); +} + +int vmc_delete_save(const char* path) +{ + int r, dd; + struct io_dirent dirent; + char filepath[256]; + + LOG("Deleting '%s'...", path); + + dd = mcio_mcDopen(path); + if (dd < 0) + return 0; + + do { + r = mcio_mcDread(dd, &dirent); + if (r && (strcmp(dirent.name, ".")) && (strcmp(dirent.name, ".."))) + { + snprintf(filepath, sizeof(filepath), "%s/%s", path, dirent.name); + LOG("Deleting '%s'", filepath); + mcio_mcRemove(filepath); + } + } while (r); + + mcio_mcDclose(dd); + r = mcio_mcRmDir(path); + + return (r == sceMcResSucceed); +} diff --git a/source/saves.c b/source/saves.c index 94644fa..26308da 100644 --- a/source/saves.c +++ b/source/saves.c @@ -13,12 +13,15 @@ #include "sfo.h" #include "settings.h" #include "util.h" +#include "ps2mc.h" +#include "mcio.h" #define UTF8_CHAR_STAR "\xE2\x98\x85" #define CHAR_ICON_NET "\x09" #define CHAR_ICON_ZIP "\x0C" -#define CHAR_ICON_COPY "\x0B" +#define CHAR_ICON_VMC "\x0B" +#define CHAR_ICON_COPY "\x0E" #define CHAR_ICON_SIGN "\x06" #define CHAR_ICON_USER "\x07" #define CHAR_ICON_LOCK "\x08" @@ -973,6 +976,128 @@ int ReadTrophies(save_entry_t * game) return list_count(game->codes); } +static void add_vmc2_import_saves(list_t* list, const char* path, const char* folder) +{ + code_entry_t * cmd; + DIR *d; + struct dirent *dir; + char psvPath[256]; + int type; + + snprintf(psvPath, sizeof(psvPath), "%s%s", path, folder); + d = opendir(psvPath); + + if (!d) + return; + + while ((dir = readdir(d)) != NULL) + { + if (dir->d_type != DT_REG) + continue; + + // check for PS2 PSV saves + if (endsWith(dir->d_name, ".PSV")) + { + snprintf(psvPath, sizeof(psvPath), "%s%s%s", path, folder, dir->d_name); + if (read_file(psvPath, (uint8_t*) psvPath, 0x40) < 0 || psvPath[0x3C] != 0x02) + continue; + +// toff = 0x80; + type = FILE_TYPE_PSV; + } + else if (endsWith(dir->d_name, ".PSU")) + { +// toff = 0x40; + type = FILE_TYPE_PSU; + } + else if (endsWith(dir->d_name, ".CBS")) + type = FILE_TYPE_CBS; + + else if (endsWith(dir->d_name, ".XPS")) + type = FILE_TYPE_XPS; + + else if (endsWith(dir->d_name, ".MAX")) + type = FILE_TYPE_MAX; + else continue; + + snprintf(psvPath, sizeof(psvPath), "%s%s%s", path, folder, dir->d_name); + LOG("Reading %s...", psvPath); + +/* + FILE *fp = fopen(psvPath, "rb"); + if (!fp) { + LOG("Unable to open '%s'", psvPath); + continue; + } + fseek(fp, toff, SEEK_SET); + fread(data, 1, sizeof(data), fp); + fclose(fp); +*/ + + cmd = _createCmdCode(PATCH_COMMAND, psvPath, CMD_IMP_VMC2SAVE); + cmd->file = strdup(psvPath); + cmd->codes[1] = type; + sprintf(cmd->name, "%s %s", CHAR_ICON_COPY, dir->d_name); + list_append(list, cmd); + + LOG("[%s] F(%X) name '%s'", cmd->file, cmd->flags, cmd->name+2); + } + + closedir(d); +} + +int ReadVmc2Codes(save_entry_t * save) +{ + code_entry_t * cmd; + + save->codes = list_alloc(); + + if (save->type == FILE_TYPE_MENU) + { + add_vmc2_import_saves(save->codes, save->path, PS2_IMP_PATH_USB); + add_vmc2_import_saves(save->codes, save->path, PSV_SAVES_PATH_USB); + if (!list_count(save->codes)) + { + list_free(save->codes); + save->codes = NULL; + return 0; + } + + list_bubbleSort(save->codes, &sortCodeList_Compare); + + return list_count(save->codes); + } + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_USER " View Save Details", CMD_VIEW_DETAILS); + list_append(save->codes, cmd); + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_WARN " Delete Save Game", CMD_DELETE_VMCSAVE); + list_append(save->codes, cmd); + + cmd = _createCmdCode(PATCH_NULL, "----- " UTF8_CHAR_STAR " Save Game Backup " UTF8_CHAR_STAR " -----", CMD_CODE_NULL); + list_append(save->codes, cmd); + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export save game to .PSU format", CMD_CODE_NULL); + cmd->options_count = 1; + cmd->options = _createOptions(3, "Export .PSU save to USB", CMD_EXP_VMC2SAVE); + asprintf(&cmd->options->name[2], "Export .PSU save to HDD"); + asprintf(&cmd->options->value[2], "%c%c", CMD_EXP_VMC2SAVE, STORAGE_HDD); + cmd->options[0].id = FILE_TYPE_PSU; + list_append(save->codes, cmd); + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export save game to .PSV format", CMD_CODE_NULL); + cmd->options_count = 1; + cmd->options = _createOptions(3, "Export .PSV save to USB", CMD_EXP_VMC2SAVE); + asprintf(&cmd->options->name[2], "Export .PSV save to HDD"); + asprintf(&cmd->options->value[2], "%c%c", CMD_EXP_VMC2SAVE, STORAGE_HDD); + cmd->options[0].id = FILE_TYPE_PSV; + list_append(save->codes, cmd); + + LOG("Loaded %ld codes", list_count(save->codes)); + + return list_count(save->codes); +} + /* * Function: ReadOnlineSaves() * File: saves.c @@ -995,16 +1120,18 @@ int ReadOnlineSaves(save_entry_t * game) stat(path, &stats); // re-download if file is +1 day old if ((stats.st_mtime + ONLINE_CACHE_TIMEOUT) < time(NULL)) - http_download(game->path, "saves.txt", path, 0); + http_download(game->path, "saves.txt", path, 1); } else { - if (!http_download(game->path, "saves.txt", path, 0)) + if (!http_download(game->path, "saves.txt", path, 1)) return -1; } long fsize; char *data = readTextFile(path, &fsize); + if (!data) + return 0; char *ptr = data; char *end = data + fsize; @@ -1045,8 +1172,15 @@ int ReadOnlineSaves(save_entry_t * game) ptr++; } } + free(data); + + if (!list_count(game->codes)) + { + list_free(game->codes); + game->codes = NULL; + return 0; + } - if (data) free(data); LOG("Loaded %d saves", list_count(game->codes)); return (list_count(game->codes)); @@ -1336,7 +1470,22 @@ int sortSaveList_Compare_TitleID(const void* a, const void* b) if (!tb) return (1); - return strcasecmp(ta, tb); + int ret = strcasecmp(ta, tb); + + return (ret ? ret : sortSaveList_Compare(a, b)); +} + +int sortSaveList_Compare_Type(const void* a, const void* b) +{ + int ta = ((save_entry_t*) a)->type; + int tb = ((save_entry_t*) b)->type; + + if (ta == tb) + return sortSaveList_Compare(a, b); + else if (ta < tb) + return -1; + else + return 1; } static void read_usb_encrypted_saves(const char* userPath, list_t *list, uint64_t account) @@ -1524,6 +1673,88 @@ static void read_hdd_savegames(const char* userPath, list_t *list, sqlite3 *appd sqlite3_close(db); } +static void read_vmc2_files(const char* userPath, const save_entry_t* parent, list_t *list) +{ + DIR *d; + struct dirent *dir; + save_entry_t *item; + char psvPath[256]; + uint64_t size; + + d = opendir(userPath); + if (!d) + return; + + while ((dir = readdir(d)) != NULL) + { + if (dir->d_type != DT_REG || !(endsWith(dir->d_name, ".VMC") || endsWith(dir->d_name, ".VM2") || + endsWith(dir->d_name, ".BIN") || endsWith(dir->d_name, ".PS2")|| endsWith(dir->d_name, ".CARD"))) + continue; + + snprintf(psvPath, sizeof(psvPath), "%s%s", userPath, dir->d_name); + get_file_size(psvPath, &size); + + LOG("Adding %s...", psvPath); + if (size % 0x840000 != 0 && size % 0x800000 != 0) + continue; + + item = _createSaveEntry(SAVE_FLAG_PS2 | SAVE_FLAG_VMC, dir->d_name); + item->type = FILE_TYPE_VMC; + + if (parent) + { + item->flags |= (parent->flags & SAVE_FLAG_HDD); + item->path = strdup((parent->flags & SAVE_FLAG_HDD) ? dir->d_name : psvPath); + item->dir_name = strdup((parent->flags & SAVE_FLAG_HDD) ? parent->dir_name : userPath); + item->title_id = strdup(parent->title_id); + item->blocks = parent->blocks; + + free(item->name); + asprintf(&item->name, "%s - %s", parent->name, dir->d_name); + } + else + { + item->title_id = strdup("VMC"); + item->path = strdup(psvPath); + item->dir_name = strdup(userPath); + } + + LOG("[%s] F(%X) name '%s'", item->title_id, item->flags, item->name); + list_append(list, item); + } + + closedir(d); +} + +static void read_inner_vmc2_files(list_t *list) +{ + char mount[32]; + char save_path[256]; + list_node_t *node; + save_entry_t *item; + + for (node = list_head(list); (item = list_get(node)); node = list_next(node)) + { + if (item->type != FILE_TYPE_PS4 || (item->flags & SAVE_FLAG_LOCKED) || (strncmp("CUSA", item->title_id, 4) == 0)) + continue; + + if (item->flags & SAVE_FLAG_HDD) + { + if (!orbis_SaveMount(item, ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY, mount)) + continue; + + snprintf(save_path, sizeof(save_path), APOLLO_SANDBOX_PATH, mount); + } + else + snprintf(save_path, sizeof(save_path), "%s", item->path); + + read_vmc2_files(save_path, item, list); + + if (item->flags & SAVE_FLAG_HDD) + orbis_SaveUmount(mount); + } +} + /* * Function: ReadUserList() * File: saves.c @@ -1538,12 +1769,7 @@ list_t * ReadUsbList(const char* userPath) save_entry_t *item; code_entry_t *cmd; list_t *list; - char pathEnc[64], pathDec[64]; - - snprintf(pathDec, sizeof(pathDec), "%sAPOLLO/", userPath); - snprintf(pathEnc, sizeof(pathEnc), "%sSAVEDATA/", userPath); - if (dir_exists(pathDec) != SUCCESS && dir_exists(pathEnc) != SUCCESS) - return NULL; + char path[64]; list = list_alloc(); @@ -1574,8 +1800,15 @@ list_t * ReadUsbList(const char* userPath) list_append(item->codes, cmd); list_append(list, item); - read_usb_savegames(pathDec, list); - read_usb_encrypted_savegames(pathEnc, list); + snprintf(path, sizeof(path), "%sPS4/APOLLO/", userPath); + read_usb_savegames(path, list); + read_inner_vmc2_files(list); + + snprintf(path, sizeof(path), "%sPS4/SAVEDATA/", userPath); + read_usb_encrypted_savegames(path, list); + + snprintf(path, sizeof(path), "%s%s", userPath, VMC_PS2_PATH_USB); + read_vmc2_files(path, NULL, list); return list; } @@ -1621,6 +1854,8 @@ list_t * ReadUserList(const char* userPath) read_hdd_savegames(userPath, list, appdb); sqlite3_close(appdb); + read_inner_vmc2_files(list); + return list; } @@ -1656,6 +1891,8 @@ static void _ReadOnlineListEx(const char* urlPath, uint16_t flag, list_t *list) long fsize; char *data = readTextFile(path, &fsize); + if (!data) + return; char *ptr = data; char *end = data + fsize; @@ -1691,7 +1928,7 @@ static void _ReadOnlineListEx(const char* urlPath, uint16_t flag, list_t *list) } } - if (data) free(data); + free(data); } list_t * ReadOnlineList(const char* urlPath) @@ -1703,11 +1940,11 @@ list_t * ReadOnlineList(const char* urlPath) snprintf(url, sizeof(url), "%s" "PS4/", urlPath); _ReadOnlineListEx(url, SAVE_FLAG_PS4, list); -/* // PS2 save-games (Zip PSV) snprintf(url, sizeof(url), "%s" "PS2/", urlPath); _ReadOnlineListEx(url, SAVE_FLAG_PS2, list); +/* // PS1 save-games (Zip PSV) //snprintf(url, sizeof(url), "%s" "PS1/", urlPath); //_ReadOnlineListEx(url, SAVE_FLAG_PS1, list); @@ -1722,6 +1959,134 @@ list_t * ReadOnlineList(const char* urlPath) return list; } +list_t * ReadVmc2List(const char* userPath) +{ + char filePath[256]; + save_entry_t *item; + code_entry_t *cmd; + list_t *list; + ps2_IconSys_t iconsys; + int r, dd, fd; + + r = mcio_vmcInit(userPath); + if (r < 0) + { + LOG("Error: no PS2 Memory Card detected! (%d)", r); + return NULL; + } + + list = list_alloc(); + + item = _createSaveEntry(SAVE_FLAG_PS2, CHAR_ICON_VMC " Memory Card Management"); + item->type = FILE_TYPE_MENU; + item->path = strdup(userPath); + item->title_id = strdup("VMC"); + item->codes = list_alloc(); + //bulk management hack + item->dir_name = malloc(sizeof(void**)); + ((void**)item->dir_name)[0] = list; + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export selected Saves to USB", CMD_CODE_NULL); + cmd->options_count = 1; + cmd->options = _createOptions(2, "Copy selected Saves to USB", CMD_EXP_SAVES_VMC); + list_append(item->codes, cmd); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export all Saves to USB", CMD_CODE_NULL); + cmd->options_count = 1; + cmd->options = _createOptions(2, "Copy all Saves to USB", CMD_EXP_ALL_SAVES_VMC); + list_append(item->codes, cmd); + list_append(list, item); + + cmd = _createCmdCode(PATCH_NULL, "----- " UTF8_CHAR_STAR " Virtual Memory Card " UTF8_CHAR_STAR " -----", CMD_CODE_NULL); + list_append(item->codes, cmd); + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export Memory Card to .VM2 format", CMD_CODE_NULL); + cmd->file = strdup(strrchr(userPath, '/')+1); + cmd->options_count = 1; + cmd->options = _createOptions(3, "Save .VM2 Memory Card to USB", CMD_EXP_PS2_VM2); + asprintf(&cmd->options->name[2], "Save .VM2 Memory Card to HDD"); + asprintf(&cmd->options->value[2], "%c%c", CMD_EXP_PS2_VM2, STORAGE_HDD); + list_append(item->codes, cmd); + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export Memory Card to .VMC format (No ECC)", CMD_CODE_NULL); + cmd->file = strdup(strrchr(userPath, '/')+1); + cmd->options_count = 1; + cmd->options = _createOptions(3, "Save .VMC Memory Card to USB", CMD_EXP_VM2_RAW); + asprintf(&cmd->options->name[2], "Save .VMC Memory Card to HDD"); + asprintf(&cmd->options->value[2], "%c%c", CMD_EXP_VM2_RAW, STORAGE_HDD); + list_append(item->codes, cmd); + + item = _createSaveEntry(SAVE_FLAG_PS2, CHAR_ICON_COPY " Import Saves to Virtual Card"); + item->path = strdup(FAKE_USB_PATH); + item->title_id = strdup("HDD"); + item->type = FILE_TYPE_MENU; + list_append(list, item); + + for (int i = 0; i <= MAX_USB_DEVICES; i++) + { + snprintf(filePath, sizeof(filePath), USB_PATH PS2_IMP_PATH_USB, i); + if (i && dir_exists(filePath) != SUCCESS) + continue; + + item = _createSaveEntry(SAVE_FLAG_PS2, CHAR_ICON_COPY " Import Saves to Virtual Card"); + asprintf(&item->path, USB_PATH, i); + asprintf(&item->title_id, "USB %d", i); + item->type = FILE_TYPE_MENU; + list_append(list, item); + } + + dd = mcio_mcDopen("/"); + if (dd < 0) + { + LOG("mcio Dopen Error %d", dd); + return list; + } + + struct io_dirent dirent; + + do { + r = mcio_mcDread(dd, &dirent); + if ((r) && (strcmp(dirent.name, ".")) && (strcmp(dirent.name, ".."))) + { + snprintf(filePath, sizeof(filePath), "%s/icon.sys", dirent.name); + LOG("Reading %s...", filePath); + + fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile); + if (fd < 0) { + LOG("Unable to read from '%s'", filePath); + continue; + } + + r = mcio_mcRead(fd, &iconsys, sizeof(ps2_IconSys_t)); + mcio_mcClose(fd); + + if (r != sizeof(ps2_IconSys_t)) + continue; + + if (iconsys.secondLineOffset) + { + memmove(&iconsys.title[iconsys.secondLineOffset+2], &iconsys.title[iconsys.secondLineOffset], sizeof(iconsys.title) - iconsys.secondLineOffset); + iconsys.title[iconsys.secondLineOffset] = 0x81; + iconsys.title[iconsys.secondLineOffset+1] = 0x50; + } + + char* title = sjis2utf8(iconsys.title); + item = _createSaveEntry(SAVE_FLAG_PS2 | SAVE_FLAG_VMC, title); + item->type = FILE_TYPE_PS2; + item->dir_name = strdup(dirent.name); + asprintf(&item->title_id, "%.10s", dirent.name+2); + asprintf(&item->path, "%s\n%s/\n%s", userPath, dirent.name, iconsys.copyIconName); + free(title); + + LOG("[%s] F(%X) name '%s'", item->title_id, item->flags, item->name); + list_append(list, item); + } + } while (r); + + mcio_mcDclose(dd); + + return list; +} + list_t * ReadTrophyList(const char* userPath) { save_entry_t *item; @@ -1781,6 +2146,43 @@ int get_save_details(const save_entry_t* save, char **details) sqlite3 *db; sqlite3_stmt *res; + if(save->type == FILE_TYPE_PS2) + { + asprintf(details, "%s\n\n----- PS2 Save -----\n" + "Game: %s\n" + "Title ID: %s\n" + "Folder: %s\n" + "Icon: %s\n", + save->path, + save->name, + save->title_id, + save->dir_name, + strrchr(save->path, '\n')+1); + return 1; + } + + if(save->type == FILE_TYPE_VMC) + { + char *tmp = strrchr(save->path, '/'); + asprintf(details, "%s\n\n----- Virtual Memory Card -----\n" + "File: %s\n" + "Folder: %s\n", + save->path, + (tmp ? tmp+1 : save->path), + save->dir_name); + return 1; + } + + if (save->flags & SAVE_FLAG_ONLINE) + { + asprintf(details, "%s\n----- Online Database -----\n" + "Game: %s\n" + "Title ID: %s\n", + save->path, + save->name, + save->title_id); + return 1; + } if (!(save->flags & SAVE_FLAG_PS4)) { diff --git a/source/settings.c b/source/settings.c index 72bad25..c59d5d1 100644 --- a/source/settings.c +++ b/source/settings.c @@ -14,7 +14,7 @@ #define ORBIS_USER_SERVICE_USER_ID_INVALID -1 -static char * sort_opt[] = {"Disabled", "by Name", "by Title ID", NULL}; +static char * sort_opt[] = {"Disabled", "by Name", "by Title ID", "by Type", NULL}; static char * usb_src[] = {"USB 0", "USB 1", "USB 2", "USB 3", "USB 4", "USB 5", "USB 6", "USB 7", "Fake USB", "Auto-detect", NULL}; static void usb_callback(int sel); diff --git a/source/sfo.c b/source/sfo.c index 07f745b..87edcb8 100644 --- a/source/sfo.c +++ b/source/sfo.c @@ -436,6 +436,7 @@ int patch_sfo(const char *in_file_path, sfo_patch_t* patches) { sfo = sfo_alloc(); if (sfo_read(sfo, in_file_path) < 0) { + sfo_free(sfo); LOG("Unable to read from '%s'", in_file_path); return -1; } @@ -464,12 +465,14 @@ int build_sfo(const char *in_file_path, const char *out_file_path, const char *t sfo1 = sfo_alloc(); if (sfo_read(sfo1, in_file_path) < 0) { + sfo_free(sfo1); LOG("Unable to read from '%s'", in_file_path); return -1; } sfo2 = sfo_alloc(); if (sfo_read(sfo2, tpl_file_path) < 0) { + sfo_free(sfo2); LOG("Unable to read from '%s'", tpl_file_path); return -1; } @@ -499,6 +502,7 @@ int patch_sfo_trophy(const char *in_file_path, const char* account) { sfo = sfo_alloc(); if (sfo_read(sfo, in_file_path) < 0) { + sfo_free(sfo); LOG("Unable to read from '%s'", in_file_path); return -1; } diff --git a/source/util.c b/source/util.c index c78aaf2..a95896f 100644 --- a/source/util.c +++ b/source/util.c @@ -158,3 +158,82 @@ int calculate_file_hmac_hash(const char *file_path, const u8 *key, u32 key_lengt u64 align_to_pow2(u64 offset, u64 alignment) { return (offset + alignment - 1) & ~(alignment - 1); } + +/* + * append_le_uint16: append an unsigned 16 bits Little Endian + * value to a buffer + */ +void append_le_uint16(uint8_t *buf, uint16_t val) +{ + buf[0] = (uint8_t)val; + buf[1] = (uint8_t)(val >> 8); +} + +/* + * append_le_uint32: append an unsigned 32 bits Little Endian + * value to a buffer + */ +void append_le_uint32(uint8_t *buf, uint32_t val) +{ + buf[0] = (uint8_t)val; + buf[1] = (uint8_t)(val >> 8); + buf[2] = (uint8_t)(val >> 16); + buf[3] = (uint8_t)(val >> 24); +} + +/* + * append_le_uint64: append an unsigned 64 bits Little Endian + * value to a buffer + */ +void append_le_uint64(uint8_t *buf, uint64_t val) +{ + int i; + for (i = 7; i >= 0; i--, val >>= 8) { + buf[i] = (uint8_t)val; + } +} + +/* + * read_le_uint16: read an unsigned 16 bits Little Endian + * value from a buffer + */ +uint16_t read_le_uint16(const uint8_t *buf) +{ + register uint16_t val; + + val = buf[0]; + val |= (buf[1] << 8); + + return val; +} + +/* + * read_le_uint32: read an unsigned 32 bits Little Endian + * value from a buffer + */ +uint32_t read_le_uint32(const uint8_t *buf) +{ + register uint32_t val; + + val = buf[0]; + val |= (buf[1] << 8); + val |= (buf[2] << 16); + val |= (buf[3] << 24); + + return val; +} + +/* + * read_le_uint64: read an unsigned 64 bits Little Endian + * value from a buffer + */ +uint64_t read_le_uint64(const uint8_t *buf) +{ + uint64_t val = 0; + int i; + for (i = 0; i < 8; i++) { + val = (val << 8) | buf[i]; + } + + return val; +}