[
  {
    "path": ".github/workflows/build.yml",
    "content": "name: CMake\n\non:\n  push:\n    branches: [ master ]\n    paths: [ \".github/workflows/build.yml\", CMakeLists.txt, 'src/**', 'd2mapapi/**', 'tools/**', 'inih/**' ]\n  pull_request:\n    branches: [ master ]\n    paths: [ \".github/workflows/build.yml\", CMakeLists.txt, 'src/**', 'd2mapapi/**', 'tools/**', 'inih/**' ]\n\nenv:\n  BUILD_TYPE: Release\n\njobs:\n  build:\n    runs-on: windows-latest\n\n    strategy:\n      matrix:\n        compiler: [\"msys2_mingw\", \"msvc2022\"]\n\n    steps:\n      - name: Install MSYS2/MinGW\n        if: matrix.compiler == 'msys2_mingw'\n        uses: msys2/setup-msys2@v2\n        with:\n          location: D:\\\n          update: true\n          install: >-\n            mingw-w64-x86_64-binutils\n            mingw-w64-i686-binutils\n            mingw-w64-x86_64-gcc\n            mingw-w64-i686-gcc\n            mingw-w64-x86_64-make\n            mingw-w64-i686-make\n\n      - name: Checkout Repository\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n\n      - name: CMake Configure and Build\n        shell: cmd\n        working-directory: ${{github.workspace}}\n        run: build_${{matrix.compiler}}.bat D:\\msys64\n\n      - uses: actions/upload-artifact@v2\n        with:\n          name: D2RMH-snapshot-${{matrix.compiler}}\n          path: |\n            ${{github.workspace}}/build/${{matrix.compiler}}/dist/D2RMH-snapshot.zip\n          retention-days: 7"
  },
  {
    "path": ".gitignore",
    "content": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n*.ilk\n*.pdb\n\n# Executables\n*.exe\n*.out\n*.app\n\n# additional exclusions\n*.tlog\n*.log\n.vs\nDebug\nRelease\n*.user\n\n# Jetbrains generated files\n/.idea/\n/cmake-*/\n\n# Build directory(ies)\n**/build/\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\nproject(D2RMH C CXX)\n\nif(MSVC)\n    set(CMAKE_CXX_STANDARD 20)\nelse()\n    set(CMAKE_CXX_STANDARD 17)\nendif()\n\nlist(APPEND CMAKE_MODULE_PATH \"${PROJECT_SOURCE_DIR}/cmake\")\ninclude(CustomCompilerOptions)\nfix_compile_flags()\nfix_release_flags()\nadd_static_runtime_option()\n\nadd_subdirectory(deps)\nadd_subdirectory(d2mapapi)\nadd_subdirectory(src)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021-2022 Soar Qin, and contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "**README in other languages: [中文说明](contrib/zhCN/README.md)**\n\n# D2RMH\nDiablo II Resurrected map revealing tool.\n\n# Disclaimer\n**D2RMH is only reading process memory from D2R, without injects, hooks or memory writes,  \nbut I do not guarentee that it is totally ban-free, use at your own risk.**\n\n# What's New\nCheck [ChangeLog](doc/ChangeLog.md)\n\n# Prerequisite\n* Diablo II 1.11, 1.11b, 1.12, 1.13c or 1.13d is required. You can get a minimal subset of v1.13c files [HERE](https://archive.org/details/diablo-ii-1.13c-minimal.-7z)\n\n# Usage\n0. Virus/Malware detection WARNING:\n   * If you are using Windows Defender, disable it or add D2RMH to whitelist to avoid misreporting of malware.\n   * D2RMH can pass most Anti-Virus software detections, but not all of them, you can compile it your self if worry about it, check `How to build` section below\n1. Download from `Releases` section, or any snapshot packs from `Actions` section(You need to log-in to GitHub). \n2. Edit D2RMH.ini, set `d2_path` to path of your Diablo II folder,\n   or just put extracted `D2RMH.exe` and all `.ini` files to D2 v1.13c folder.\n3. Run D2RMH.exe, enjoy!\n\n# Screenshots\n![Screenshot 1](screenshots/screenshot_0.png)\n![Screenshot 2](screenshots/screenshot_1.png)\n![Screenshot 3](screenshots/screenshot_2.png)\n\n# Plugin system\n* Plugins are `.lua` scripts loaded from `plugins` folder\n* Read [document](doc/Plugin.md) if you want to write your own plugin\n\n# TODO\nCheck [TODO](doc/TODO.md)\n\n# How to build\n## Quick instruction\n* Install [cmake](https://www.cmake.org/) and add `cmake\\bin` to your `PATH` environment variable so that you can type `cmake` in command line to call it directly\n* Run `build_msvc2019.bat`, `build_msvc2022.bat`, `build_msys2_clang.bat` or `build_msys2_mingw.bat` to build.  \n  Note: You should have certain compilers intalled. For msys2 builds, install required packages as instructions below.\n## Detailed instruction without .bat scripts \n### MinGW GCC\n* Install MSYS2(https://www.msys2.org), type `pacman -Syu --noconfirm && pacman -S --noconfirm --needed make git mingw-w64-i686-toolchain mingw-w64-i686-cmake mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-cmake` in MSYS2 command line to install required components\n* Build D2RMH(64bit):\n  * Open new Shell using ucrt64.exe\n  * Clone D2RMH source by type `git clone https://github.com/soarqin/D2RMH`\n  * Type `cd D2RMH && cmake -Bbuild -G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON`\n  * Then `make -Cbuild D2RMH` to get the compiled binary in `build/bin` folder\n* Build d2mapapi-piped(32bit):\n  * Open new Shell using mingw32.exe\n  * Change current directory to D2RMH source\n  * Type `cmake -Bbuild_d2mapapi -G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON d2mapapi`\n  * Then `make -Cbuild_d2mapapi d2mapapi-piped` to get the compiled binary in `build_d2mapapi/bin` folder\n### MSYS2 Clang\n* Mostly same as MinGW GCC, with following changes:\n  * `mingw-w64-i686-toolchain`->`mingw-w64-clang-i686-toolchain`\n  * `mingw-w64-i686-cmake`->`mingw-w64-clang-i686-cmake`\n  * `mingw-w64-ucrt-x86_64-toolchain`->`mingw-w64-clang-x86_64-toolchain`\n  * `mingw-w64-ucrt-x86_64-cmake`->`mingw-w64-clang-x86_64-cmake`\n  * `ucrt64.exe`->`clang64.exe`\n  * `mingw32.exe`->`clang32.exe`\n### Microsoft Visual Studio 2019/2022\n* Install Visual Studio 2019 or 2022 Community Edition(or Pro/Ent if you have)\n* Unpack downloaded source code file, or you can use git to Clone D2RMH source by type: `git clone https://github.com/soarqin/D2RMH`. Note: Using git requires [Git for windows](https://git-scm.com/download/win) installed\n* Build D2RMH(64bit):\n  * (Visual Studio 2019) Type `cmake -Bbuild -G \"Visual Studio 16 2019\" -A x64 -DUSE_STATIC_CRT=ON`  \n    (Visual Studio 2022) Type `cmake -Bbuild -G \"Visual Studio 17 2022\" -A x64 -DUSE_STATIC_CRT=ON`\n  * Now you can either:\n    * Type `cmake --build build --config Release --target D2RMH`\n    * Open generated `build\\D2RMH.sln` and build `D2RMH` target\n  * Compiled binaries are located in `build\\bin` folder\n* Build d2mapapi-piped(32bit):\n  * (Visual Studio 2019) Type `cmake -Bbuild_d2mapapi -G \"Visual Studio 16 2019\" -A Win32 -DUSE_STATIC_CRT=ON d2mapapi`  \n    (Visual Studio 2022) Type `cmake -Bbuild_d2mapapi -G \"Visual Studio 17 2022\" -A Win32 -DUSE_STATIC_CRT=ON d2mapapi`\n  * Now you can either:\n    * Type `cmake --build build_d2mapapi --config Release --target d2mapapi_piped`\n    * Open generated `build_d2mapapi\\d2mapapi.sln` and build `d2mapapi_piped` target\n  * Compiled binaries are located in `build_d2mapapi\\bin` folder\n\n# Credits\n* [d2mapapi_mod](https://github.com/soarqin/d2mapapi_mod) modified from [d2mapapi](https://github.com/jcageman/d2mapapi).\n* Idea and memory offsets from [MapAssist](https://github.com/misterokaygo/MapAssist).\n* [Handmade Math](https://github.com/HandmadeMath/Handmade-Math) for matrix calculations.\n* [glad](https://glad.dav1d.de) for loading OpenGL(Core)/WGL functions.\n* [inih](https://github.com/benhoyt/inih) for reading INI files.\n* [JSON for Modern C++](https://github.com/nlohmann/json) for processing JSON files.\n* [CascLib](https://github.com/ladislav-zezula/CascLib) for reading Casc Storage from Diablo II Resurrected.\n* [stb](https://github.com/nothings/stb), stb_truetype and stb_rect_pack are used.\n"
  },
  {
    "path": "bin/D2RMH.ini",
    "content": "[main]\n; path to your Diablo II LOD.\n; if not found in this path, D2RMH will fallback to read installation path from registry.\nd2_path = .\n; font settings, you can:\n; 1. use TTF inside D2R Casc Storage, supported fonts:\n;    All languages (especially koKR, ruRU, zhCN):\n;      blizzardglobal-v5_81.ttf(default)\n;    zhTW:\n;      blizzardglobaltcunicode.ttf(default), arfangxinshuh7c95b5_eb_t.ttf\n;    jaJP:\n;      bljap_v8_3.ttf(default), ik4ll3.ttf, tbgdb_0pp.ttf\n;    enUS, deDE, plPL and other latin languages:\n;      formal436bt.ttf(default), exocetblizzardot-medium.otf, irisl.ttf, kodia.ttf, philosopher-bolditalic.ttf\n;    leave empty to use default font\n; 2. use external TTF(with .ttf or .ttc extension), or TBL/DC6 from D2/D2R\n;    a) for TTF font, just put full path in `font_file_path`\n;    b) for TBL/DC6 font, you should put 3 files: base.dc6, base.tbl, base.pal(you can get it from data\\global\\palette\\fechar\\pal.dat and rename it),\n;       and put the full path of any of the file in `font_file_path`, you can also append original font size separated by `|` if it does not match `msg_font_size`.\n;       for example: font_file_path = font24.dc6|24\nfont_file_path =\nfont_size = 14\n; font size for message list\nmsg_font_size = 24\n; can be: enUS,deDE,esES,frFR,itIT,koKR,plPL,esMX,jaJP,ptBR,ruRU,zhTW,zhCN\n; leave empty to use D2R language settings\nlanguage =\n\n[ui]\n; Positive value will limit FPS to certain value, negative value will change OpenGL context swap interval:\n;   0=No limit and Disable VSync\n;  -1=Enable VSync(aka equal to video adapter fps),\n;  -2=VSync with 2 frames per swap(aka video adapter fps/2), etc.\n; Note: D2's logic is running at 25 frames per second, so this value is set to 25 by default\nfps = 25\n; 0-show map layer when in-game map is off\n; 1-show map layer when in-game map is on\n; 2-show map layer always\nshow = 0\n; set this to 0 if you don't wanna map drawn on bottom game bar\ndraw_on_game_bar = 1\n; hide map layer when certain panels are opened, 0x1FF=all panels\n;  0x01-inventory panel\n;  0x02-character panel\n;  0x04-skill-tree panel\n;  0x08-system menu\n;  0x10-quest panel\n;  0x20-party panel\n;  0x40-mercenary panel\n;  0x80-waypoint panel\n; 0x100-skill selection popup\npanel_mask = 0x1FF\n; style for guide line\n;  0-draw a short line with dot ahead to target (d2hackmap style)\n;  1-draw a full line to target\n;  2-draw walk-path to target in lines(more CPU usage)\nline_style = 0\n; 0-top left\n; 1-top right\n; 2-center\n; Note: check `map_area` entry for more info when you set position to 0 or 1\nposition = 2\n; restricted map_area ratio relative to D2R window(width,height)\n; each value should be between 0.0 and 1.0, while 0.0 means\n; adaptive size, aka suite current map size.\n; you can set only one value so that width/height will both use it.\n; the map will be drawn in the center of this area if map_centered=0\nmap_area = 0.0\n; map scaling, can be 1.0-4.0\n; cut when map_area is not set to adaptive size, or map size is larger than\n; D2R game window\nscale = 2.0\n; 0-static map\n; 1-keep player in map center\nmap_centered = 1\n; Alpha channel(aka opacity) for whole layer (0-255)\n;  0 is completely transparent, 255 is not tranparent at all\n; this is stacked with other color settings, for exampe:\n;   while color = 128,128,128,128(alpha channel is 128), alpha = 160,\n;   the drawn color alpha channel is: 128*160/255=80\nalpha = 255\n; bounds(in piexls) for neighbour maps\n; can be set to negative to indicate recursive depth,\n;   e.g. -1 for show only nearby level maps\n;        -2 for show maps around nearby maps also\n; set to 0 to disable neighbour maps show\n; note: this costs CPU/VRAM a bit if is set to a large value, or nearby maps\n;       are large while set to negative(=2048 costs ~64MB VRAM at max),\n;       disable it if you get performance impact\nneighbour_map_bounds = -1\n; walkable area color (R,G,B) 0-255 for each channel, 0,0,0,0 = transparent\nwalkable_color = 20,20,20,50\n; map edge color, set 0,0,0,0 to hide edge\nedge_color = 128,128,128,240\n; text color\ntext_color = 255,255,255,180\n; colors for player pointer (inner/outer)\nplayer_inner_color = 255,128,128,80\nplayer_outer_color = 51,255,255,180\nnon_party_player_inner_color = 255,128,128,80\nnon_party_player_outer_color = 255,20,20,180\n; color for guide lines\nline_color = 204,204,204,144\n; colors for waypoints/portals/chests/quests/wells\nwaypoint_color = 153,153,255,200\nportal_color = 255,255,102,160\nchest_color = 255,102,102,160\nquest_color = 102,102,255,160\nshrine_color = 255,51,178,160\nwell_color = 51,51,255,160\n; colors for monsters/unique monsters(including champions)/npcs\nmonster_color = 255,0,0,128\nunique_monster_color = 192,166,130,204\nnpc_color = 160,160,160,160\n; color for doors\ndoor_color = 80,255,80,180\n; message list background color\nmsg_bg_color = 1,1,1,128\n; message position (x,y,align)\n; range of x and is [0.0,1.0], align can be 0(left), 1(centered), 2(right)\nmsg_position = 0.95,0.25,2\n; show a text panel (updated every second), leave empty to disable\n; usable patterns:\n;   {newline}/{n} start a newline here\n;   {duration}    current game duration, shown as hh:mm:ss\n;   {time}        current system time in 24h clock format: hh:mm:ss\n;   {timea}       current system time in locale's 12h clock format\n;   {difficulty}  current difficulty name\n;   {act}         current act name ('ACT I' to 'ACT V')\n;   {mapname}     current map name\n;   {gamename}    current game name\n;   {gamepass}    current game password\n;   {region}      region code of the server which current game creates on\n;   {season}      current battle.net season string\ntext_panel_pattern =\n;text_panel_pattern = {duration}\n;text_panel_pattern = {difficulty}{n}{act}-{mapname}{n}{time}{n}{duration}\n;text_panel_pattern = {gamename}{n}{gamepass}{n}{region} {season}{n}{difficulty}{n}{act}-{mapname}{n}{time}{n}{duration}\n\n; text panel position, same as `msg_position`\ntext_panel_position = 0.93,0.015,2\n\n; show player names\nshow_player_names = 1\n; show npc's name\nshow_npc_names = 1\n; show in-memory nearby objects(currently only shrines)\nshow_objects = 1\n; minimal size of objects in pixels (except doors)\nobject_size_minimal = 6\n; show in-memory nearby items on ground, check D2RMH_item.ini for filter settings\nshow_items = 1\n; show in-memory nearby monsters\n;  0 - not shown\n;  1 - only NPCs/super-uniques/bosses/champions are shown\n;  2 - common monsters and minions are also shown\nshow_monsters = 2\n; show monster's name, monsters must be shown in `show_monsters`\n;  0 - not shown\n;  1 - only NPCs/super-uniques/bosses/champions are shown\n;  2 - common monsters and minions are also shown\nshow_monster_names = 1\n; show monster's enchant including aura, check [enchants] section below, monsters must be shown in `show_monsters`\n;  0 - not shown\n;  1 - only NPCs/super-uniques/bosses/champions are shown\n;  2 - common monsters and minions are also shown\nshow_monster_enchants = 1\n; show monster's resist(immunity), check [enchants] section below, monsters must be shown in `show_monsters`\n;  0 - not shown\n;  1 - only NPCs/super-uniques/bosses/champions are shown\n;  2 - common monsters and minions are also shown\nshow_monster_immunities = 2\n\n[enchants]\n; strings can be tagged with color, in form '{n}', while n is taken from d2hackmap:\n;  0-text color 1-red 2-green 3-blue 4-gold 5-gray 6-black 7-gold2\n;  8-orange 9-yellow 10-green2 11-purple 12-green3 13~15-white\n; if no color is set, white is selected by default.\nextra_strong = S\nextra_fast = F\ncursed = {2}C\nmagic_resistant = M\nfire_enchanted = {1}FE\nligntning_enchanted = {9}LE\ncold_enchanted = {3}CE\nmana_burn = {3}MB\nteleportation = T\nspectral_hit = H\nstone_skin = {4}SS\nmultiple_shots = {12}MS\nfanatic = {11}F\nberserker = {4}B\n; auras\nmight_aura = {4}A\nholyFire_aura = {1}A\nblessedAim_aura = A\nholyFreeze_aura = {3}A\nholyShock_aura = {9}A\nconviction_aura = {11}A\nfanaticism_aura = {5}A\n; immnuties\nphysical_immunity = {4}i\nmagic_immunity = {8}i\nfire_immunity = {1}i\nlightning_immunity = {9}i\ncold_immunity = {3}i\npoison_immunity = {2}i\n\n[sound]\n; sound files used by various functions\n; support WAVE files, filename with without '.wav' ext will be treated as system event sounds.\n; commonly used system event sounds:\n;   SystemAsterisk, SystemDefault, SystemExclamation, SystemHand\n; you can also check registry 'HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default' for more\n; event sounds.\nsound[1] = SystemDefault\nsound[2] = SystemAsterisk\n; sound[3] = Beep.wav\n"
  },
  {
    "path": "bin/D2RMH_gamedata.ini",
    "content": "[guides]\n; \"string\" = Map Name\n; \"+number\" = Object with certain ID\n; \"-number\" = Npc(Monster) with certain ID\n;Act1:\nguide[Blood Moor][Den of Evil]                              =1\nguide[Cold Plains][Burial Grounds]                          =1\nguide[Stony Field][+61]                                     =1\nguide[Underground Passage Level 1][Dark Wood]               =1\nguide[Dark Wood][+30]                                       =1\nguide[Black Marsh][Forgotten Tower]                         =1\nguide[Tower Cellar Level 1][Tower Cellar Level 2]           =1\nguide[Tower Cellar Level 2][Tower Cellar Level 3]           =1\nguide[Tower Cellar Level 3][Tower Cellar Level 4]           =1\nguide[Tower Cellar Level 4][Tower Cellar Level 5]           =1\nguide[Tamoe Highland][Pit Level 1]                          =1\nguide[Pit Level 1][Pit Level 2]                             =1\nguide[Barracks][+108]                                       =1\nguide[Jail Level 1][Jail Level 2]                           =1\nguide[Jail Level 2][Jail Level 3]                           =1\nguide[Jail Level 3][Inner Cloister]                         =1\nguide[Cathedral][Catacombs Level 1]                         =1\nguide[Catacombs Level 1][Catacombs Level 2]                 =1\nguide[Catacombs Level 2][Catacombs Level 3]                 =1\nguide[Catacombs Level 3][Catacombs Level 4]                 =1\n;Act2:\nguide[47][48]                                               =1\nguide[48][49]                                               =1\nguide[Dry Hills][Halls of the Dead Level 1]                 =1\nguide[Halls of the Dead Level 1][Halls of the Dead Level 2] =1\nguide[Halls of the Dead Level 2][Halls of the Dead Level 3] =1\nguide[Far Oasis][Maggot Lair Level 1]                       =1\nguide[Maggot Lair Level 1][Maggot Lair Level 2]             =1\nguide[Maggot Lair Level 2][Maggot Lair Level 3]             =1\nguide[Valley of Snakes][Claw Viper Temple Level 1]          =1\nguide[Claw Viper Temple Level 1][Claw Viper Temple Level 2] =1\nguide[Lost City][Ancient Tunnels]                           =1\nguide[Harem Level 1][Harem Level 2]                         =1\nguide[Harem Level 2][Palace Cellar Level 1]                 =1\nguide[Palace Cellar Level 1][Palace Cellar Level 2]         =1\nguide[Palace Cellar Level 2][Palace Cellar Level 3]         =1\nguide[Arcane Sanctuary][+357]                               =1\nguide[66][+152]                                             =1\nguide[67][+152]                                             =1\nguide[68][+152]                                             =1\nguide[69][+152]                                             =1\nguide[70][+152]                                             =1\nguide[71][+152]                                             =1\nguide[72][+152]                                             =1\n;Act3:\nguide[Spider Forest][Spider Cavern]                         =1\nguide[Flayer Jungle][+252]                                  =1\n;guide[Flayer Jungle][Flayer Dungeon Level 1]               =1   Flayer Dungeon is nearby Gidbinn, no need to tip it\nguide[Flayer Dungeon Level 1][Flayer Dungeon Level 2]       =1\nguide[Flayer Dungeon Level 2][Flayer Dungeon Level 3]       =1\nguide[Kurast Bazaar][Ruined Temple]                         =1\nguide[92][93]                                               =1\nguide[Travincal][Durance of Hate Level 1]                   =1\nguide[Durance of Hate Level 1][Durance of Hate Level 2]     =1\nguide[Durance of Hate Level 2][Durance of Hate Level 3]     =1\n;Act4:\nguide[Outer Steppes][Plains of Despair]                     =1\nguide[Plains of Despair][-256]                              =1\nguide[City of the Damned][River of Flame]                   =1\nguide[River of Flame][+376]                                 =1\n;Act5:\nguide[Arreat Plateau][Crystalline Passage]                  =1\nguide[Crystalline Passage][Frozen River]                    =1\nguide[Frozen River][+460]                                   =1\nguide[Glacial Trail][Frozen Tundra]                         =1\nguide[Nihlathak's Temple][Halls of Anguish]                 =1\nguide[Halls of Anguish][Halls of Pain]                      =1\nguide[Halls of Pain][Halls of Vaught]                       =1\nguide[Halls of Vaught][+462]                                =1\nguide[Frozen Tundra][The Ancients' Way]                     =1\nguide[The Ancients' Way][Arreat Summit]                     =1\nguide[Worldstone Keep Level 1][Worldstone Keep Level 2]     =1\nguide[Worldstone Keep Level 2][Worldstone Keep Level 3]     =1\nguide[Worldstone Keep Level 3][Throne of Destruction]       =1\n\n[useful_object_op]\n2=Shrine\n10=Quest                 ;Gibbet of Cairn\n12=Quest                 ;Tree of Inifuss\n15=Portal                ;Player's Portal, or Permanent Portal by shrines\n21=Quest                 ;Malus\n22=Well,well\n23=Waypoint\n24=Quest                 ;Tainted Sun Altar\n25=Quest                 ;Where you place the Horadric staff\n28=Quest                 ;Lam Esen's Tome\n31=Quest                 ;Gidbinn\n34=Portal                ;Arcane Sanctuary portal\n39=Chest,box             ;Horadric Cube Chest\n40=Chest,tr1             ;Horadric Scroll Chest\n41=Chest,Staff of Kings  ;Staff Of Kings Chest\n42=Quest                 ;Horazon's Journal\n43=Portal                ;Portal to Duriel's Lair\n46=Portal                ;Hellgate\n49=Quest                 ;Hellforge\n57=Chest,qhr             ;Khalim's Heart\n58=Chest,qey             ;Khalim's Eye\n59=Chest,qbr             ;Khalim's Brain\n69=Chest                 ;Evil Urn\n\n[useful_objects]\n61=Quest,StoneAlpha  ;Cairn Stones\n397=Chest            ;Sparky Chest\n460=Quest,Drehya     ;Anya\n462=Quest,Nihlathak  ;Nihlathak\n473=Quest            ;Caged Barbarian\n580=Chest,chest      ;Unique Chest\n\n[useful_npcs]\n256=Quest  ;Izual\n"
  },
  {
    "path": "bin/D2RMH_item.ini",
    "content": "[items]\n; format:\n;  <ID or Code>[+quality][*sockets][#ethereal]=style[,color,[sound]]\n;  ID or Code: check `ID` and `code` in doc/ItemDesc.md\n;  quality: 0-low 1-normal 2-superior 3-magic 4-set 5-rare 6-unique 7-crafted\n;  ethereal: 0 or 1\n;  all other fields can be single value or range/list\n;    you can use `642` or `r33` for Zod Rune\n;            use `640,642` or `r31,r33` for both Jah and Zod Rune\n;            use `640-642` or `r31-r33` for Jah, Cham and Zod Rune\n;       mix them `634,636-638,640-642` or `r24,r26-r29,r31-r33`\n;  style: 0-don't show  1-show on minimap  2-show on a separate message list  3-show both\n;  color: 0-default 1-red 2-green 3-blue 4-gold 5-gray 6-black 7-gold2\n;         8-orange 9-yellow 10-green2 11-purple 12-green3 13~15-white\n;         use quality color by default if set to 0 or absent:\n;            low/normal=15, superior=5, magic=3, set=2, rare=9, unique=4, crafted=8\n;  sound: index for sound playing on drop, check `[sound]` section in D2RMH.ini. 0 for mute, as default.\n; full example: `crs+2,3*0,4,6=1,0,1` shows \"Normal/Superior 0/4/6 Sockets Crystal Sword\" on minimap\n;               with default color and play sound[1] in `[sound]` section in D2RMH.ini.\n\n; Items for Charsi's imbue\n; Dimensional Shard\n300+1,2*0#0 = 0\n; Diadem\n421+1,2*0#0 = 0\n\n; Items for crafting\n; Vampirefang Belt\n461+3 = 0\n; Gloves\n334-338,380-384,450-454+3 = 0\n; Monarch Shield\n447+3#0 = 0\n; Circlet, Coronet, Tiara, Diadem\n418-421+3#0 = 0\n; Amulet, Ring\n520,522+3 = 0\n; Elite Light Armors\n429-432,436,443+3#0 = 0\n; Assa Claws\n182-188,189-195+3 = 0\n; Sorc Orbs\n276-280,286-290,296-300+3 = 0\n; Ancient Armor\n326+3#0 = 0\n; Embossed Plate\n370+3#0 = 0\n; Ornate Plate\n372+3#0 = 0\n; Elite Medium Armors\n433,435,437,439,440,442+3#0 = 0\n; Battle Boots, Mirrored Boots\n388,458+3 = 0\n; Druid Helmets\n; Alpha Helm, Griffon Headdress, Hunter's Guise, Sacred Feathers, Totemic Mask, Blood Spirit, Sun Spirit, Earth Spirit, Sky Spirit, Dream Spirit\n468-472,488-492+3#0 = 0\n; Bar Helmets\n403-407,473-477,493-497+3#0 = 0\n\n; Potential good rare items\n; Short Sword, Falchion\n; Gladius, Tulwar\n; Falcata, Hydra Edge\n25,28,118,121,221,224+5#1 = 0\n; Crystal Sword, Dimensional Blade\n29,122+5#1 = 0\n; Broad Sword, War Sword\n; Battle Sword, Ancient Sword\n; Conquest Sword, Mythical Sword\n30,32,123,125,226,228+5#1 = 0\n; Axe, Double Axe, Military Pick, War Axe\n; Cleaver, Twin Axe, Crowbill, Naga\n; Small Crescent, Ettin Axe, War Spike, Berserker Axe\n1-4,94-97,197-200+5#1 = 0\n; Morning Star, War Hammer\n; Jagged Star, Battle Hammer\n; Devil Star, Legendary Mallet\n20,22,113,115,216,218+5#1 = 0\n; Grand Scepter, War Scepter\n; Holy Water Sprinkler, Divine Scepter\n; Seraph Rod, Caduceus\n16-17,109-110,212-213+5#1 = 0\n; Large Axe, Broad Axe, Battle Axe, Great Axe, Giant Axe\n; Military Axe, Bearded Axe, Tabar, Gothic Axe, Ancient Axe\n; Feral Axe, Silver-edged Axe, Decapitator, Champion Axe, Glorious Axe\n5-9,98-102,201-205+5#1 = 0\n; Maul, Great Maul\n; War Club, Martel de Fer\n; Ogre Maul, Thunder Maul\n23-24,116-117,219-220+5#1 = 0\n; Two-Handed Sword, Claymore, Giant Sword, Bastard Sword, Flamberge, Great Sword\n; Espandon, Dacian Falx, Tusk Sword, Gothic Sword, Zweihander, Executioner Sword\n; Legend Sword, Highland Blade, Balrog Blade, Champion Sword, Colossus Sword, Colossus Blade\n33-38,126-131,229-234+5#1 = 0\n; Spear, Trident\n; War Spear, Fuscina\n; Hyperion Spear, Stygian Pike\n52-53,145-146,248-249+5#1 = 0\n; Spetum, Pike, Bardiche, Voulge, Scythe, Poleaxe, Halberd, War Scythe\n; Yari, Lance, Lochaber Axe, Bill, Battle Scythe, Partizan, Bec-de-Corbin, Grim Scythe\n; Ghost Spear, War Pike, Ogre Axe, Colossus Voulge, Thresher, Cryptic Axe, Great Poleaxe, Giant Thresher\n55-62,148-155,251-258+5#1 = 0\n; Maiden Spear, Maiden Pike\n; Ceremonial Spear, Ceremonial Pike\n; Matriarchal Spear, Matriarchal Pike\n283-284,293-294,303-304+5#1 = 0\n; Maiden Javelin, Ceremonial Javelin, Matriarchal Javelin\n285,295,305+5 = 0\n; Short Staff, Long Staff, Gnarled Staff, Battle Staff, War Staff\n; Jo Staff, Quarterstaff, Cedar Staff, Gothic Staff, Rune Staff\n; Walking Stick, Stalagmite, Elder Staff, Shillelagh, Archon Staff\n63-67,156-160,259-263+5#1 = 0\n; Throwing Knife, Throwing Axe, Balanced Knife, Balanced Axe, Javelin, Pilum, Short Spear, Glaive, Throwing Spear\n; Battle Dart, Francisca, War Dart, Hurlbat, War Javelin, Great Pilum, Simbilan, Spiculum, Harpoon\n; Flying Knife, Flying Axe, Winged Knife, Winged Axe, Hyperion Javelin, Stygian Pilum, Balrog Spear, Ghost Glaive, Winged Harpoon\n43-51,136-144,239-247+5#1 = 0\n; Maiden Javelin, Ceremonial Javelin, Matriarchal Javelin\n285,295,305+5#1 = 0\n; Short Bow, Hunter's Bow, Long Bow, Composite Bow, Short Battle Bow, Long Battle Bow, Short War Bow, Long War Bow\n; Edge Bow, Razor Bow, Cedar Bow, Double Bow, Short Siege Bow, Large Siege Bow, Rune Bow, Gothic Bow\n; Spider Bow, Blade Bow, Shadow Bow, Great Bow, Diamond Bow, Crusader Bow, Ward Bow, Hydra Bow\n68-75,161-168,264-271+5 = 0\n; Stag Bow, Reflex Bow\n; Ashwood Bow, Ceremonial Bow\n; Matriarchal Bow, Grand Matron Bow\n281-282,291-292,301-302+5 = 0\n; Light Crossbow, Crossbow, Heavy Crossbow, Repeating Crossbow\n; Arbalest, Siege Crossbow, Ballista, Chu-Ko-Nu\n; Pellet Bow, Gorgon Crossbow, Colossus Crossbow, Demon Crossbow\n76-79,169-172,272-275+5 = 0\n; Boots\n340-343,385-389,455-459+5 = 0\n; Gloves\n334-338,380-384,450-454+5 = 0\n; Claws\n175-195+5 = 0\n; Circlet, Coronet, Tiara, Diadem\n418-421+5 = 0\n; Sorc Orbs\n276-280,286-290,296-300+5 = 0\n; Necro Shields\n413-417,483-487,503-507+5 = 0\n; Amulet, Ring\n520,522+5 = 0\n; Necro Wands\n103-106,206-209+5 = 0\n\n; Set Items\n; Winged Helm = Guillaume's Face\n356+4 = 3\n; Diadem = M'avina's True Sight\n421+4 = 3\n; Lacquered Plate = Tal Rasha's Guardianship\n440+4 = 3\n; Mesh Belt = Tal Rasha's Fine-Spun Cloth\n392+4 = 3\n; Amulet = Tal Rasha's Adjudication or other set amulets\n520+4 = 3\n; Shadow Plate = Aldur's Deception\n441+4 = 3\n; Sacred Armor = Immortal King's Soul Cage\n442+4 = 3\n; Troll Belt = Trang-Oul's Girth\n463+4 = 3\n; Bone Visage = Trang-Oul's Guise\n465+4 = 3\n; Chaos Armor = Trang-Oul's Scales\n371+4 = 3\n; Heavy Bracers = Trang-Oul's Claws\n382+4 = 3\n; Cantor Trophy = Trang-Oul's Wing\n486+4 = 3\n; Corona = Griswold's Valor\n427+4 = 3\n; Vortex Shield = Griswold's Honor\n502+4 = 3\n; Caduceus = Griswold's Redemption\n213+4 = 3\n; Scissors Suwayyah = Natalya's Mark\n195+4 = 3\n; Colossus Blade = Bul-Kathos' Sacred Charge\n234+4 = 3\n; Mythical Sword = Bul-Kathos' Tribal Guardian\n228+4 = 3\n\n; Unique Items\n; Chain Gloves = Chance Guards\n336+6 = 3\n; Light Gauntlets = Magefist\n337+6 = 3\n; Vampirebone Gloves = Dracul's Grasp\n451+6 = 3\n; Ogre Gauntlets = Steelrend\n454+6 = 3\n; Serpentskin Armor = Skin of the Vipermagi\n360+6 = 3\n; Mesh Armor = Shaftstop\n365+6 = 3\n; Cuirass = Duriel's Shell\n366+6#1 = 3\n; Russet Armor = Skullder's Ire\n367+6 = 3\n; Templar Coat = Guardian Angel\n368+6 = 3\n; Dusk Shroud = Ormus' Robes\n429+6 = 3\n; Wire Fleece = The Gladiator's Bane\n432+6 = 3\n; Balrog Skin = Arkain's Valor\n437+6 = 3\n; Kraken Shell = Leviathan\n439+6 = 3\n; Sacred Armor = Templar's Might, Tyrael's Might\n442+6 = 3\n; Sharkskin Boots = Waterwalk\n386+6 = 3\n; Mesh Boots = Silkweave\n387+6 = 3\n; Battle Boots = Wartraveler\n388+6 = 3\n; War Boots = Gorerider\n389+6 = 3\n; Scarabshell Boots = Sandstorm Trek\n456+6 = 3\n; Boneweave Boots = Marrowwalk\n457+6 = 3\n; Myrmidon Greaves = Shadowdancer\n459+6 = 3\n; Sharkskin Belt = Razortail\n391+6 = 3\n; War Belt = Thundergold's Vigor\n394+6 = 3\n; Spiderweb Sash = Archnid Mesh\n460+6 = 3\n; Vampirefang Belt = Nosferatu's Coil\n461+6 = 3\n; Mithril Coil = Verdugo's Hearty Cord\n462+6 = 3\n; Monarch = Stormshield\n447+6 = 3\n; Gilded Shield = Herald of Zakarum\n481+6 = 3\n; Hierophant Trophy = Homunculus\n487+6 = 3\n; Succubus Skull = Boneflame\n506+6 = 3\n; Bloodlord Skull = Darkforce Spawn\n507+6 = 3\n; Sallet = Rockstopper\n353+6#1 = 3\n; Casque = Stealskull\n354+6 = 3\n; Grand Crown = Crown of Thieves\n357+6#1 = 3\n; Grim Helm = Vampiregaze\n395+6#1 = 3\n; Tiara = Kira's Guardian\n420+6 = 3\n; Shako = Harlequin Crest\n422+6 = 3\n; Spired Helm = Veil of Steel\n426+6 = 3\n; Demonhead = Andariel's Visage\n428+6 = 3\n; Totemic Mask = Jalal's Mane\n472+6 = 3\n; Slayer Guard = Arreat's Face\n477+6 = 3\n; Corona = Crown of Ages\n427+6 = 3\n; Diadem = Griffon's Eye\n421+6 = 3\n; Tomb Wand = Arm of King Leoric\n105+6 = 3\n; Battle Sword = Headstriker\n123+6#1 = 3\n; Fuscina = Kelpie Snare\n146+6#1 = 3\n; Yari = Hone Sundan\n148+6#1 = 3\n; Ballista = Buriza-Do Kyanon\n171+6 = 3\n; Greater Talons = Bartuc's Cut-Throat\n187+6 = 3\n; Lich Wand = Boneshade\n208+6 = 3\n; Mighty Scepter = Heaven's Light\n211+6 = 3\n; Scourge = Horizon's Tornado\n217+6 = 3\n; Phase Blade = Lightsabre, Azurewrath\n225+6 = 3\n; Champion Sword = Doombringer\n232+6 = 3\n; Winged Knife = Warshrike\n241+6#1 = 3\n; Winged Axe = Lacerator\n242+6#1 = 3\n; Hyperion Spear = Arioc's Needle\n248+6#1 = 3\n; Ogre Axe = Bonehew\n253+6#1 = 3\n; Thresher = The Reaper's Toll\n255+6 = 3\n; Cryptic Axe = Tomb Reaver\n256+6 = 3\n; Elder Staff = Ondal's Wisdom\n261+6 = 3\n; Crusader Bow = Eaglehorn\n269+6 = 3\n; Ward Bow = Widowmaker\n270+6 = 3\n; Swirling Crystal = The Oculus\n290+6 = 3\n; Eldritch Orb = Eschuta's Temper\n297+6 = 3\n; Ceremonial Javelin = Titan's Revenge\n295+6 = 3\n; Unearthed Wand = Death's Web\n209+6 = 3\n; Caduceus = Astreon's Iron Ward\n213+6 = 3\n; Archon Staff = Mang Song's Lesson\n263+6 = 3\n; Dimensional Shard = Death's Fathom\n300+6 = 3\n; Colossus Blade = Godfather\n234+6 = 3\n; Legend Spike = Ghostflame\n238+6 = 3\n; Berserker Axe = Death Cleaver\n200+6 = 3\n; Glorious Axe = Executioner's Justice\n205+6 = 3\n; Giant Thresher = Stormspire\n258+6 = 3\n; War Pike = Steel Pillar\n252+6 = 3\n; Hydra Bow = Windforce\n271+6 = 3\n; Winged Harpoon = Gargoyle's Bite\n247+6 = 3\n; Thunder Maul = Earth Shifter, The Cranium Basher\n220+6 = 3\n; Unique Amulet, Ring\n520,522+6 = 3\n; Unique Small Charm, Large Charm, Grand Charm\n603-605+6 = 3\n\n; Jewels\n643 = 3\n; Rare Jewel\n643+5 = 3\n; Unique Jewel\n643+6 = 3\n; Small Charm, Grand Charm\n603,605 = 3\n; Large Charm\n604 = 0\n\n; Items for Runewords\n; Grand Crown, Corona\n357,427+2*0#0 = 3\n; Grand Crown, Corona\n357,427+2*3#0 = 3\n; Zweihander\n130+1,2*0#0 = 3\n; Zweihander\n130+1,2*5#0 = 3\n; Colossus Blade\n234+2*0#1 = 3\n; Colossus Blade\n234+2*4#0 = 3\n; Colossus Blade\n234+2*4,5,6#1 = 3\n; Colossus Sword\n233+2*4#1 = 3\n; Berserker Axe\n200+1,2*0,4,5,6#1 = 3\n; Berserker Axe\n200+2*4,5#0 = 3\n; Berserker Axe\n200+1*0#0 = 3\n; Berserker Axe\n200+1*5#0 = 3\n; Ghost Spear, War Pike\n251,252+2*0,6#1 = 3\n; Matriarchal Spear, Matriarchal Pike\n303,304+2*0,6#1 = 3\n; Scythe\n59+1*0#0 = 0\n59+1*0#1 = 0\n59+1,2*4 = 0\n; Gnarled Staff, Battle Staff\n; Cedar Staff, Gothic Staff\n; Elder Staff, Shillelagh\n65-66,158-159,261-262+1,2*0#0 = 0\n65-66,158-159,261-262+1,2*0#1 = 0\n65-66,158-159,261-262+1,2*4 = 0\n; War Staff, Rune Staff, Archon Staff\n67,160,263+1*0#0 = 0\n67,160,263+1*0#1 = 0\n67,160,263+1,2*4 = 0\n; Thresher, Cryptic Axe\n255,256+1,2*0,4,5#1 = 0\n; Great Poleaxe\n257+1*0,4,5#1 = 3\n257+2*0,4,5,6#1 = 3\n; Giant Thresher\n258+1*0,4,5#1 = 3\n258+2*4,5#1 = 3\n; Crystal Sword\n29+1,2*6 = 0\n29+1*0#0 = 3\n29+1*0#1 = 3\n29+1,2*3,5 = 3\n; Phase Blade\n225+1,2*0#0 = 3\n225+1,2*3,5#0 = 3\n225+1,2*6#0 = 0\n; Flail\n21+1*0#0 = 3\n; Flail\n21+1*0#1 = 3\n21+1,2*4 = 3\n\n; War Scepter, Divine Scepter, Caduceus\n17,110,213+1,2*0#0 = 0\n17,110,213+1,2*0#1 = 0\n17,110,213+1,2*5 = 0\n\n; Great Bow\n267+2*0#0 = 3\n267+2*4#0 = 3\n; Shadow Bow\n266+2*4#0 = 3\n; Grand Matron Bow\n302+2*4#0 = 3\n\n; Suwayyah, Scissors Suwayyah, Runic Talons, Feral Claws\n189,195,194,193+1,2*0#0 = 3\n189,195,194,193+1,2*3#0 = 3\n; Sacred Targe, Sacred Rondache, Kurast Shield, Zakarum Shield, Vortex Shield\n498-502+1,2*0#0 = 3\n498-502+1,2*3,4#0 = 3\n498-502+1,2*0,4#1 = 3\n; Monarch\n447+1,2*0#0 = 3\n447+1,2*4#0 = 3\n; Troll Nest\n466+1,2*0#0 = 3\n466+1,2*3#0 = 3\n; Mage Plate\n373+2*0#0 = 3\n373+2*3#0 = 3\n; Lacquered Plate\n440+1*0#1 = 3\n; Sacred Armor\n442+2*0#0 = 3\n; Sacred Armor\n442+1*0#1 = 3\n; Sacred Armor\n442+2*3,4#0 = 3\n; Shadow Plate\n441+1*0#1 = 3\n; Archon Plate\n443+2*0#0 = 3\n; Archon Plate\n443+1*0#1 = 3\n; Archon Plate\n443+2*3,4#0 = 3\n; Dusk Shroud\n429+2*0,3,4#0 = 0\n; Great Hauberk\n436+2*0,3,4#0 = 0\n; Bone Wand, Grim Wand, Petrified Wand, Tomb Wand, Grave Wand, Polished Wand, Ghost Wand, Lich Wand, Unearthed Wand\n12,13,104-106,206-209+1,2*0#0 = 0\n12,13,104-106,206-209+1,2*2#0 = 0\n12,13,104-106,206-209+1,2*0,2#1 = 0\n; Preserved Head, Zombie Head, Unraveller Head, Gargoyle Head, Demon Head\n; Mummified Trophy, Fetish Trophy, Sexton Trophy, Cantor Trophy, Hierophant Trophy\n; Minion Skull, Hellspawn Skull, Overseer Skull, Succubus Skull, Bloodlord Skull\n413-417,483-487,503-507+1,2*0#0 = 0\n413-417,483-487,503-507+1,2*2#0 = 0\n\n; Key of Destruction\n649 = 3\n; Key of Hate\n648 = 3\n; Key of Terror\n647 = 3\n; Mephisto's Brain\n652 = 3\n; Baal's Eye\n651 = 3\n; Diablo's Horn\n650 = 3\n; Token of Absolution\n653 = 3\n; Twisted Essence of Suffering\n654 = 0\n; Charged Essence of Hatred\n655 = 0\n; Burning Essence of Terror\n656 = 0\n; Festering Essence of Destruction\n657 = 0\n; Wirt's Leg\n88 = 0\n\n; Act1\n; Scroll of Inifuss, Key to the Cairn Stones, Horadric Malus\n524,525,89 = 0\n\n; Act2\n; Horadric Scroll, Book of Skill, Horadric Cube, Shaft of the Horadric Staff, Top of the Horadric Staff, Horadric Staff\n550,552,549,92,521,91 = 0\n\n; Act3\n; The Gidbinn, Potion of Life, A Jade Figurine, The Golden Bird, Lam Esen's Tome, Khalim's Eye, Khalim's Heart, Khalim's Brain, Khalim's Flail, Khalim's Will\n87,545-548,553-555,173-174 = 0\n\n; Act4\n; Mephisto's Soulstone, Hell Forge Hammer\n551,90 = 0\n\n; Act5\n; Malah's Potion, Scroll of Resistance\n644,646 = 0\n\n; Arrows\n526 = 0\n\n; Bolts\n528 = 0\n\n; Key\n543 = 0\n\n; Minor Healing Potion, Light Healing Potion, Healing Potion, Greater Healing Potion, Super Healing Potion\n587-591 = 0\n; Minor Mana Potion, Light Mana Potion, Mana Potion, Greater Mana Potion, Super Mana Potion\n592-596 = 0\n\n; Tome of Town Portal, Tome of Identify\n518-519 = 0\n\n; Scroll of Town Portal, Scroll of Identify\n529-530 = 0\n\n; Rejuvenation Potion\n515 = 0\n; Full Rejuvenation Potion\n516 = 3\n\n; Flawed Emerald, Flawed Ruby, Flawed Diamond, Diamond\n573,578,583,584 = 0\n; Amethyst, Topaz, Sapphire, Emerald, Ruby\n559,564,569,574,579 = 0\n; Flawless Amethyst, Perfect Amethyst\n560-561 = 3\n; Flawless Topaz, Perfect Topaz\n565-566 = 3\n; Flawless Sapphire, Perfect Sapphire\n570-571 = 3\n; Flawless Emerald, Perfect Emerald\n575-576 = 3\n; Flawless Ruby, Perfect Ruby\n580-581 = 3\n; Flawless Diamond, Perfect Diamond\n585-586 = 3\n; Flawless Skull, Perfect Skull\n600-601 = 3\n\n; Runes\nr01-r13 = 3\nr14-r33 = 3,0,1\n"
  },
  {
    "path": "bin/plugins/chicken_life.lua",
    "content": "local text = create_text_list(\"default\")\n\nlocal chicken_life = function()\n    local player = get_player()\n    if player and player.map ~= 1 and player.map ~= 40 and player.map ~= 75 and player.map ~= 103 and player.map ~= 109 then\n        if player.stats[7] < player.stats[8] * 0.3 then\n            kill_process()\n        end\n    end\nend\n\nfunction chicken_life_toggle(on)\n    if on then\n        text:add('Chicken life enabled. Toggle hotkey: \\'Ctrl+/\\'', 5000, -1)\n    else\n        text:add('Chicken life disabled. Toggle hotkey: \\'Ctrl+/\\'', 5000, -1)\n    end\nend\n\nregister_plugin(\"Ctrl+/\", false, 250, chicken_life, chicken_life_toggle)\n"
  },
  {
    "path": "bin/plugins/hotkey.lua",
    "content": "local toggle_show = function()\n    local conf = get_config()\n    conf.show = conf.show + 1\n    if conf.show > 2 then\n        conf.show = 0\n    end\nend\n\nlocal zoom_in = function()\n    local conf = get_config()\n    if conf.scale < 4.0 then\n        conf.scale = conf.scale + 0.5\n        if conf.scale > 4.0 then\n            conf.scale = 4.0\n        end\n        flush_overlay()\n    end\nend\n\nlocal zoom_out = function()\n    local conf = get_config()\n    if conf.scale > 1.0 then\n        conf.scale = conf.scale - 0.5\n        if conf.scale < 1.0 then\n            conf.scale = 1.0\n        end\n        flush_overlay()\n    end\nend\n\nregister_hotkey('\\\\', toggle_show)\nregister_hotkey('OEM_PLUS', zoom_in)\nregister_hotkey('OEM_MINUS', zoom_out)\n"
  },
  {
    "path": "bin/plugins/town_portal_check.lua",
    "content": "local text = create_text_list(\"default\")\n\nlocal town_portal_check = function()\n    -- game fully loaded?\n    if not get_skill(0) then\n        return\n    end\n\n    local quantity\n    local portal_book = get_skill(220)\n    if portal_book then\n        quantity = portal_book.quantity\n    else\n        quantity = 0\n    end\n    if quantity < 3 then\n        text:add(string.format(\"\\x0BWARNING! Town portal scrolls quantity low: %d\", quantity), 1500, 0)\n    end\nend\nregister_plugin(1000, town_portal_check)\n"
  },
  {
    "path": "build_msvc2019.bat",
    "content": "@echo off\n\nsetlocal\nset BUILD_DIR=msvc2019\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\mingw64\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/main -G \"Visual Studio 16 2019\" -A x64 -DUSE_STATIC_CRT=ON .\ncmake --build build/%BUILD_DIR%/main --config Release --target D2RMH -j\nendlocal\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\mingw32\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/d2mapapi -G \"Visual Studio 16 2019\" -A Win32 -DUSE_STATIC_CRT=ON d2mapapi\ncmake --build build/%BUILD_DIR%/d2mapapi --config Release --target d2mapapi_piped -j\nendlocal\n\ncmake -E make_directory build/%BUILD_DIR%/dist\ncmake -E copy_if_different build\\%BUILD_DIR%\\main\\bin\\Release\\D2RMH.exe build\\%BUILD_DIR%\\d2mapapi\\bin\\Release\\d2mapapi_piped.exe build\\%BUILD_DIR%\\dist\\\n\ncall copy_dist.bat\n\nendlocal\n"
  },
  {
    "path": "build_msvc2022.bat",
    "content": "@echo off\n\nsetlocal\nset BUILD_DIR=msvc2022\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\mingw64\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/main -G \"Visual Studio 17 2022\" -A x64 -DUSE_STATIC_CRT=ON .\ncmake --build build/%BUILD_DIR%/main --config Release --target D2RMH -j\nendlocal\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\mingw32\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/d2mapapi -G \"Visual Studio 17 2022\" -A Win32 -DUSE_STATIC_CRT=ON d2mapapi\ncmake --build build/%BUILD_DIR%/d2mapapi --config Release --target d2mapapi_piped -j\nendlocal\n\ncmake -E make_directory build/%BUILD_DIR%/dist\ncmake -E copy_if_different build\\%BUILD_DIR%\\main\\bin\\Release\\D2RMH.exe build\\%BUILD_DIR%\\d2mapapi\\bin\\Release\\d2mapapi_piped.exe build\\%BUILD_DIR%\\dist\\\n\ncall copy_dist.bat\n\nendlocal\n"
  },
  {
    "path": "build_msys2_clang.bat",
    "content": "@echo off\n\nsetlocal\nset BUILD_DIR=msys2_clang\n\nsetlocal\nset MSYS2_BASE_PATH=%~1\nif \"%~1\" == \"\" set MSYS2_BASE_PATH=C:\\msys64\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\clang64\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/main -G \"MinGW Makefiles\" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON .\ncmake --build build/%BUILD_DIR%/main --target D2RMH -j\nendlocal\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\clang32\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/d2mapapi -G \"MinGW Makefiles\" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON d2mapapi\ncmake --build build/%BUILD_DIR%/d2mapapi --target d2mapapi_piped -j\nendlocal\n\nendlocal\n\ncmake -E make_directory build/%BUILD_DIR%/dist\ncmake -E copy_if_different build\\%BUILD_DIR%\\main\\bin\\D2RMH.exe build\\%BUILD_DIR%\\d2mapapi\\bin\\d2mapapi_piped.exe build\\%BUILD_DIR%\\dist\\\n\ncall copy_dist.bat\n\nendlocal"
  },
  {
    "path": "build_msys2_mingw.bat",
    "content": "@echo off\n\nsetlocal\nset BUILD_DIR=msys2_mingw\n\nsetlocal\nset MSYS2_BASE_PATH=%~1\nif \"%~1\" == \"\" set MSYS2_BASE_PATH=C:\\msys64\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\mingw64\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/main -G \"MinGW Makefiles\" -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON .\ncmake --build build/%BUILD_DIR%/main --target D2RMH -j\nendlocal\n\nsetlocal\nset PATH=%MSYS2_BASE_PATH%\\mingw32\\bin;%PATH%\ncmake -Bbuild/%BUILD_DIR%/d2mapapi -G \"MinGW Makefiles\" -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON d2mapapi\ncmake --build build/%BUILD_DIR%/d2mapapi --target d2mapapi_piped -j\nendlocal\n\nendlocal\n\ncmake -E make_directory build/%BUILD_DIR%/dist\ncmake -E copy_if_different build\\%BUILD_DIR%\\main\\bin\\D2RMH.exe build\\%BUILD_DIR%\\d2mapapi\\bin\\d2mapapi_piped.exe build\\%BUILD_DIR%\\dist\\\n\ncall copy_dist.bat\n\nendlocal\n"
  },
  {
    "path": "cmake/CustomCompilerOptions.cmake",
    "content": "macro(fix_compile_flags)\n    if(MSVC)\n        set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /utf-8\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /utf-8\")\n    endif()\nendmacro()\n\nmacro(fix_release_flags)\n    if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n        set(CMAKE_EXE_LINKER_FLAGS_RELEASE \"${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s -flto\")\n        set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL \"${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s -flto\")\n        set(CMAKE_SHARED_LINKER_FLAGS_RELEASE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -s -flto\")\n        set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL \"${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} -s -flto\")\n        set(CMAKE_C_FLAGS_RELEASE \"${CMAKE_C_FLAGS_RELEASE} -flto\")\n        set(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} -flto\")\n    endif()\n    if(MSVC)\n        add_compile_options(\n            $<$<CONFIG:Release>:/GL>\n            $<$<CONFIG:MinSizeRel>:/GL>\n        )\n        add_link_options(\n            $<$<CONFIG:Release>:/LTCG>\n            $<$<CONFIG:MinSizeRel>:/LTCG>\n        )\n    endif()\nendmacro()\n\nmacro(add_static_runtime_option)\n    option(USE_STATIC_CRT \"Use static C runtime\" OFF)\n\n    if(USE_STATIC_CRT)\n        if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n            set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++\")\n            set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++\")\n        elseif(MSVC)\n            set(CompilerFlags\n                CMAKE_CXX_FLAGS\n                CMAKE_CXX_FLAGS_DEBUG\n                CMAKE_CXX_FLAGS_RELEASE\n                CMAKE_CXX_FLAGS_MINSIZEREL\n                CMAKE_CXX_FLAGS_RELWITHDEBINFO\n                CMAKE_C_FLAGS\n                CMAKE_C_FLAGS_DEBUG\n                CMAKE_C_FLAGS_RELEASE\n                CMAKE_C_FLAGS_MINSIZEREL\n                CMAKE_C_FLAGS_RELWITHDEBINFO\n                )\n            foreach(CompilerFlag ${CompilerFlags})\n                string(REPLACE \"/MD\" \"/MT\" ${CompilerFlag} \"${${CompilerFlag}}\")\n                set(${CompilerFlag} \"${${CompilerFlag}}\" CACHE STRING \"msvc compiler flags\" FORCE)\n            endforeach()\n            add_compile_options(\n                $<$<CONFIG:>:/MT>\n                $<$<CONFIG:Debug>:/MTd>\n                $<$<CONFIG:Release>:/MT>\n                $<$<CONFIG:MinSizeRel>:/MT>\n                $<$<CONFIG:RelWithDebInfo>:/MT>\n            )\n        endif()\n    endif()\nendmacro()\n"
  },
  {
    "path": "cmake/GetVersion.cmake",
    "content": "macro(get_project_version VER_PROJ_NAME)\n    find_package(Git QUIET)\n\n    # Check if git is found...\n    if (GIT_FOUND)\n\n        # Get last tag from git\n        execute_process(COMMAND ${GIT_EXECUTABLE} describe --abbrev=0 --tags\n            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n            OUTPUT_VARIABLE ${VER_PROJ_NAME}_VERSION_STRING\n            OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n        # Get name of current branch\n        execute_process(COMMAND ${GIT_EXECUTABLE} symbolic-ref --short HEAD\n            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n            OUTPUT_VARIABLE ${VER_PROJ_NAME}_BRANCH_NAME\n            OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n        #How many commits since last tag\n        execute_process(COMMAND ${GIT_EXECUTABLE} rev-list ${${VER_PROJ_NAME}_BRANCH_NAME} ${${VER_PROJ_NAME}_VERSION_STRING}..HEAD --count\n            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n            OUTPUT_VARIABLE ${VER_PROJ_NAME}_VERSION_AHEAD\n            OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n        # Get current commit SHA from git\n        execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD\n            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n            OUTPUT_VARIABLE ${VER_PROJ_NAME}_VERSION_GIT_SHA\n            OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n        # Get partial versions into a list\n        string(REGEX MATCHALL \"-.*$|[0-9]+\" ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST\n            ${${VER_PROJ_NAME}_VERSION_STRING})\n\n        # Set the version numbers\n        list(GET ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST\n            0 ${VER_PROJ_NAME}_VERSION_MAJOR)\n        list(GET ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST\n            1 ${VER_PROJ_NAME}_VERSION_MINOR)\n        list(GET ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST\n            2 ${VER_PROJ_NAME}_VERSION_PATCH)\n\n        # The tweak part is optional, so check if the list contains it\n        list(LENGTH ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST\n            ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST_LEN)\n        if (${VER_PROJ_NAME}_PARTIAL_VERSION_LIST_LEN GREATER 3)\n            list(GET ${VER_PROJ_NAME}_PARTIAL_VERSION_LIST 3 ${VER_PROJ_NAME}_VERSION_TWEAK)\n            string(SUBSTRING ${${VER_PROJ_NAME}_VERSION_TWEAK} 1 -1 ${VER_PROJ_NAME}_VERSION_TWEAK)\n        endif()\n\n        # Unset the list\n        unset(${VER_PROJ_NAME}_PARTIAL_VERSION_LIST)\n\n        # Save version to file (which will be used when Git is not available\n        # or VERSION_UPDATE_FROM_GIT is disabled)\n        file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version_generated ${${VER_PROJ_NAME}_VERSION_STRING}\n            \"*\" ${${VER_PROJ_NAME}_VERSION_MAJOR}\n            \"*\" ${${VER_PROJ_NAME}_VERSION_MINOR}\n            \"*\" ${${VER_PROJ_NAME}_VERSION_PATCH}\n            \"*\" ${${VER_PROJ_NAME}_VERSION_TWEAK}\n            \"*\" ${${VER_PROJ_NAME}_VERSION_AHEAD}\n            \"*\" ${${VER_PROJ_NAME}_VERSION_GIT_SHA})\n\n    else()\n\n        # Git not available, get version from file\n        file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/version_generated ${VER_PROJ_NAME}_VERSION_LIST)\n        string(REPLACE \"*\" \";\" ${VER_PROJ_NAME}_VERSION_LIST \"${${VER_PROJ_NAME}_VERSION_LIST}\")\n        # Set partial versions\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 0 ${VER_PROJ_NAME}_VERSION_STRING)\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 1 ${VER_PROJ_NAME}_VERSION_MAJOR)\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 2 ${VER_PROJ_NAME}_VERSION_MINOR)\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 3 ${VER_PROJ_NAME}_VERSION_PATCH)\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 4 ${VER_PROJ_NAME}_VERSION_TWEAK)\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 5 ${VER_PROJ_NAME}_VERSION_AHEAD)\n        list(GET ${VER_PROJ_NAME}_VERSION_LIST 6 ${VER_PROJ_NAME}_VERSION_GIT_SHA)\n\n    endif()\n\n    # Set full project version string\n    if (${VER_PROJ_NAME}_VERSION_AHEAD GREATER 0)\n        set(${VER_PROJ_NAME}_VERSION_STRING_FULL\n            ${${VER_PROJ_NAME}_VERSION_STRING}+${${VER_PROJ_NAME}_VERSION_AHEAD}.${${VER_PROJ_NAME}_VERSION_GIT_SHA})\n    else()\n        set(${VER_PROJ_NAME}_VERSION_STRING_FULL\n            ${${VER_PROJ_NAME}_VERSION_STRING}.${${VER_PROJ_NAME}_VERSION_GIT_SHA})\n    endif()\n\n    # Set project version (without the preceding 'v')\n    set(${VER_PROJ_NAME}_VERSION ${${VER_PROJ_NAME}_VERSION_MAJOR}.${${VER_PROJ_NAME}_VERSION_MINOR}.${${VER_PROJ_NAME}_VERSION_PATCH})\n    if (${VER_PROJ_NAME}_VERSION_TWEAK)\n        set(${VER_PROJ_NAME}_VERSION ${${VER_PROJ_NAME}_VERSION}-${${VER_PROJ_NAME}_VERSION_TWEAK})\n    endif()\n\n    target_compile_definitions(${VER_PROJ_NAME} PRIVATE\n        VERSION_STRING_FULL=\"${${VER_PROJ_NAME}_VERSION_STRING_FULL}\"\n        VERSION_STRING=\"${${VER_PROJ_NAME}_VERSION_STRING}\"\n        VERSION_MAJOR=${${VER_PROJ_NAME}_VERSION_MAJOR}\n        VERSION_MINOR=${${VER_PROJ_NAME}_VERSION_MINOR}\n        VERSION_PATCH=${${VER_PROJ_NAME}_VERSION_PATCH}\n        VERSION_TWEAK=\"${${VER_PROJ_NAME}_VERSION_TWEAK}\"\n        VERSION_AHEAD=\"${${VER_PROJ_NAME}_VERSION_AHEAD}\"\n        VERSION_GIT_SHA=\"${${VER_PROJ_NAME}_VERSION_GIT_SHA}\"\n        )\nendmacro()\n"
  },
  {
    "path": "contrib/zhCN/D2RMH.ini",
    "content": "[main]\n; D2LOD 路径\n; 如果该路径不包含游戏，则D2RMH会尝试从注册表读取安装目录\nd2_path = .\n; 字体路径\nfont_file_path = C:\\Windows\\Fonts\\SimHei.ttf\n; 文字字体大小，你可以：\n; 1. 使用D2R自带的TTF，支持以下字体:\n;    所有语言 (尤其是 koKR, ruRU, zhCN):\n;      blizzardglobal-v5_81.ttf(默认)\n;    zhTW:\n;      blizzardglobaltcunicode.ttf(默认), arfangxinshuh7c95b5_eb_t.ttf\n;    jaJP:\n;      bljap_v8_3.ttf(默认), ik4ll3.ttf, tbgdb_0pp.ttf\n;    enUS, deDE, plPL 以及其他拉丁语系语言:\n;      formal436bt.ttf(默认), exocetblizzardot-medium.otf, irisl.ttf, kodia.ttf, philosopher-bolditalic.ttf\n;    留空会使用默认字体\n; 2. 使用TTF(扩展名为.ttf或.ttc), 以及D2/D2R的TBL/DC6字体\n;    a. 对于TTF字体，在 `font_file_path` 里放路径\n;    b. 对于TBL/DC6字体, 你需要放3个文件: base.dc6, base.tbl, base.pal(将data\\global\\palette\\fechar\\pal.dat复制出来改名),\n;       并将任何一个文件的路径设置在 `font_file_path` 里, 你还可以在后面用 `|` 分隔追加原字体大小，如果和 `msg_font_size` 不一致\n;       举例: font_file_path = font24.dc6|24\nfont_size = 14\n; 消息列表字体大小\nmsg_font_size = 24\n; 可选语言: enUS,deDE,esES,frFR,itIT,koKR,plPL,esMX,jpJP,ptBR,ruRU,zhTW,zhCN\n; 留空则使用 D2R 当前语言设置\nlanguage =\n\n[ui]\n; 帧数限制，正数表示限制帧率，负数表示垂直同步交换间隔：\n;   0=无限制并关闭垂直同步\n;  -1=开启垂直同步，帧率和显示器刷新率相同\n;  -2=开启垂直同步，帧率为显示器刷新率一半，依此类推\n; 注意：D2的逻辑是每秒25帧，所以这个值默认设为25\nfps = 25\n; 0-游戏内小地图关闭时显示\n; 1-游戏内小地图打开时显示\n; 2-总是显示\nshow = 0\n; 如果不想地图覆盖到底部游戏UI条请设为0\ndraw_on_game_bar = 0\n; 当特定面板打开时隐藏本地图, 0x1FF=所有面板\n;  0x01-物品面板\n;  0x02-角色面板\n;  0x04-技能树面板\n;  0x08-系统菜单\n;  0x10-任务面板\n;  0x20-组队面板\n;  0x40-雇佣兵面板\n;  0x80-传送站面板\n; 0x100-技能选择列表\npanel_mask = 0x1FF\n; 路线指示画线方式\n; 0-显示一条短线和一个点(d2hackmap的方式)\n; 1-直接连接到目的地\n; 2-通向目的地的行走路径(消耗更多CPU资源)\nline_style = 0\n; 0-左上\n; 1-右上\n; 2-正中\n; 注意: 如果设置为0或者1请认真阅读`map_area`的说明\nposition = 2\n; 限制显示范围(宽,高)，相对于D2R窗口的大小，范围在0.0到1.0之间\n; 如果设为0.0则为动态大小，随当前地图大小改变\n; 可以只设置一个值，表示宽高都使用这个值\n; 如果map_centered为0则整个地图会在指定区域居中显示\nmap_area = 0.0\n; 地图缩放，范围为[1.0,4.0]\n; 如果map_area不是动态大小，则超出显示范围的部分会被切去\n; 超出D2R窗口的部分也会被切去\nscale = 2.0\n; 0-静态地图\n; 1-保持玩家显示在正中的动态地图\nmap_centered = 1\n; 整个地图层的透明通道(0-255) 0为完全透明 255为完全不透明\n; 和其他颜色的透明通道叠加，例如:\n;   当颜色为 128,128,128,128(透明通道是128), alpha设为160时,\n;   绘制颜色的透明通道就是: 128*160/255=80\nalpha = 255\n; 相邻地图边界(点阵为单位)\n; 可以设为负数表示寻找相邻地图循环深度\n;   例如 -1 表示只显示相邻地图\n;        -2 还显示相邻地图的相邻地图\n; 设为0不显示相邻地图\n; 注意：设置较大的值，或设为负数但地图较大时会额外消耗一定的CPU和显存(2048最多大约消耗64M显存)\n;       请关闭此选项如果感受到较大的系统性能损失\nneighbour_map_bounds = -1\n; 可行走部分的颜色 (R,G,B) 每个颜色范围是0-255, 0,0,0,0表示透明\nwalkable_color = 20,20,20,50\n; 地图边缘的颜色 设为0,0,0,0隐藏边缘\nedge_color = 128,128,128,240\n; 文字颜色\ntext_color = 255,255,255,180\n; 玩家方块的内外侧颜色\nplayer_inner_color = 255,128,128,80\nplayer_outer_color = 51,255,255,180\n; 指示线颜色\nline_color = 204,204,204,144\n; 路点/传送门/箱子/任务/神殿/井的颜色\nwaypoint_color = 153,153,255,160\nportal_color = 255,255,102,160\nchest_color = 255,102,102,160\nquest_color = 102,102,255,160\nshrine_color = 255,51,178,160\nwell_color = 51,51,255,160\n; 怪物/金怪/npc的颜色\nmonster_color = 255,0,0,128\nunique_monster_color = 192,166,130,204\nnpc_color = 160,160,160,160\n; 门的颜色\ndoor_color = 80,255,80,180\n; 消息列表背景色\nmsg_bg_color = 1,1,1,128\n; 消息列表位置 (x,y,对齐)\n; x和y的范围是[0.0,1.0], 对齐可以是0(左), 1(中), 2(右)\nmsg_position = 0.95,0.25,2\n; 显示文字面板 (每秒更新)，留空则不显示\n; 支持模板:\n;   {newline}/{n} 换行\n;   {duration}    当前游戏持续时间，显示为hh:mm:ss\n;   {time}        当前系统时间: hh:mm:ss\n;   {difficulty}  当前难度\n;   {act}         当前ACT ('ACT I' 到 'ACT V')\n;   {mapname}     当前地图名\n;   {gamename}    当前游戏房间名\n;   {gamepass}    当前游戏房间密码\n;   {region}      游戏服务器所处区域代码\n;   {season}      当前游戏赛季\ntext_panel_pattern =\n;text_panel_pattern = {duration}\n;text_panel_pattern = {difficulty}{n}{act}-{mapname}{n}{time}{n}{duration}\n;text_panel_pattern = {gamename}{n}{gamepass}{n}{region} {season}{n}{difficulty}{n}{act}-{mapname}{n}{time}{n}{duration}\n\n; 面板位置, 同 `msg_position`\ntext_panel_position = 0.93,0.015,2\n\n; 显示玩家名\nshow_player_names = 1\n; 显示NPC名\nshow_npc_name = 1\n; 显示附近物件(目前显示神殿和井)\nshow_objects = 1\n; 地图上物件(门除外)的最小尺寸(按点阵)\nobject_size_minimal = 6\n; 显示附近的物品掉落，可以修改D2RMH_item.ini设定自己的掉落过滤表\nshow_items = 1\n; 显示附近的怪物\n;  0 - 不显示\n;  1 - 只有NPC/金怪/Boss会显示\n;  2 - 普通和仆从怪也显示\nshow_monsters = 2\n; 显示怪物名，怪物需要先在`show_monsters`中设置显示\n;  0 - 不显示\n;  1 - 只有NPC/金怪/Boss会显示\n;  2 - 普通和仆从怪也显示\nshow_monster_names = 1\n; 显示怪物强化类型，包括光环，更多配置请看[enchants]部分，怪物需要先在`show_monsters`中设置显示\n;  0 - 不显示\n;  1 - 只有NPC/金怪/Boss会显示\n;  2 - 普通和仆从怪也显示\nshow_monster_enchants = 1\n; 显示怪物的免疫，更多配置请看[enchants]部分，怪物需要先在`show_monsters`中设置显示\n;  0 - 不显示\n;  1 - 只有NPC/金怪/Boss会显示\n;  2 - 普通和仆从怪也显示\nshow_monster_immunities = 2\n\n[enchants]\n; 各种强化对应显示的字符串\n; 字符串可以用颜色来标识，写成'{n}'的形式, n和d2hackmap中一致:\n;  0-文本颜色 1-红 2-绿 3-蓝 4-金 5-灰 6-黑 7-金2\n;  8-橙 9-黄 10-绿2 11-紫 12-绿3 13~15-白\n; 如果不设置默认为白色\nextra_strong = 強壯\nextra_fast = 快速\ncursed = {2}詛咒\nmagic_resistant = 魔抗\nfire_enchanted = {1}火強\nligntning_enchanted = {9}電強\ncold_enchanted = {3}冰強\nmana_burn = {3}法燃\nteleportation = 傳送\nspectral_hit = 幽靈\nstone_skin = {4}石膚\nmultiple_shots = {12}多重\nfanatic = {11}癲狂\nberserker = {4}狂暴\n; 光环\nmight_aura = {4}力量\nholyFire_aura = {1}聖火\nblessedAim_aura = 瞄準\nholyFreeze_aura = {3}聖冰\nholyShock_aura = {9}聖雷\nconviction_aura = {11}信念\nfanaticism_aura = {5}狂熱\n; 免疫\nphysical_immunity = {4}物\nmagic_immunity = {8}魔\nfire_immunity = {1}火\nlightning_immunity = {9}電\ncold_immunity = {3}冰\npoison_immunity = {2}毒\n\n[sound]\n; 其他功能要用的声音文件设置\n; 支持WAVE文件，不以为.wav为扩展名的文件名将被视为系统事件声音\n; 常用系统事件声音:\n;   SystemAsterisk, SystemDefault, SystemExclamation, SystemHand\n; 可以查看注册表项 'HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default' 获取其他事件声音名\nsound[1] = SystemDefault\nsound[2] = SystemAsterisk\n; sound[3] = Beep.wav\n"
  },
  {
    "path": "contrib/zhCN/README.md",
    "content": "**README in other languages: [English](../../README.md)**\n\n# D2RMH\nDiablo II Resurrected 开图工具\n\n# 免责声明\n**D2RMH只从D2R读取内存，并没有注入代码、使用代码钩子以及写入内存，  \n但并不保证完全不会被封号，使用中出现任何问题概不负责。**  \n\n# 版本更新\n请看 [ChangeLog](../../doc/ChangeLog.md)\n\n# 需求依赖\n* 本工具需要暗黑2 1.11, 1.11b, 1.12, 1.13c或1.13d版本，你可以[由此](https://archive.org/details/diablo-ii-1.13c-minimal.-7z)下载最精简版的1.13c\n\n# 使用\n0. 病毒/木马检测警告:\n  * Windows Defender容易误报，建议禁用或者加入白名单\n  * 虽然D2RMH可以通过大多数杀毒软件的检测，但也容易被误报，如果担心预编译文件有问题，那么可以参考下面的`如何编译`部分自行编译\n1. 从 `Releases` 里下载最新发布版，或从 `Actions` 里下载最新的快照编译版(你需要登录GitHub) \n2. 修改 D2RMH.ini(中文用户可以使用contrib/D2RMH_CN.ini的内容作为默认设置), 设置 `d2_path` 为你的D2 1.13c目录，也可以直接把`D2MRH.exe`和所有`*.ini`放到D2 1.13c目录里去\n3. 运行 D2RMH.exe\n\n# Screenshots\n![Screenshot 1](screenshots/screenshot_0.png)\n![Screenshot 2](screenshots/screenshot_1.png)\n![Screenshot 3](screenshots/screenshot_2.png)\n\n# 插件系统\n* 插件加载自 `plugins` 目录里的所有 `.lua` 文件\n* 如果想自己写插件请阅读 [文档](../../doc/Plugin.md)\n\n# TODO\n请看 [TODO](../../doc/TODO.md)\n\n# 如何编译\n## 快速指引\n* 安装 [cmake](https://www.cmake.org/) 并将 `cmake\\bin` 路径添加到你的的环境变量 `PATH` 中，使得命令行下可以直接输入 `cmake` 使用\n* 运行 `build_msvc2019.bat`, `build_msvc2022.bat`, `build_msys2_clang.bat` 或 `build_msys2_mingw.bat` 调用对应的编译器进行编译  \n  注意: 你需要安装对应的编译器，如果是msys2编译，请参照下面的说明安装必要组件\n## 详细教程\n### MinGW GCC\n* 安装MSYS2(https://www.msys2.org), 打开MSYS2.exe，输入`pacman -Syu --noconfirm && pacman -S --noconfirm --needed make git mingw-w64-i686-toolchain mingw-w64-i686-cmake mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-cmake`安装必须的依赖组件\n* 编译 D2RMH(64位):\n  * 用 ucrt64.exe 打开命令行\n  * 克隆D2RMH的源代码： `git clone https://github.com/soarqin/D2RMH`\n  * 输入 `cd D2RMH && cmake -Bbuild -G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON`\n  * 然后 `make -Cbuild D2RMH` 就能在 `build/bin` 里生成编译好的exe\n* 编译 d2mapapi-piped(32位):\n  * 用 mingw32.exe 打开命令行\n  * 进入 D2RMH 所在目录\n  * 输入 `cmake -Bbuild_d2mapapi -G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC_CRT=ON d2mapapi`\n  * 然后 `make -Cbuild_d2mapapi d2mapapi-piped` 就能在 `build/bin` 里生成编译好的exe\n### MSYS2 Clang\n* 和 MinGW GCC 大致相同，除了以下改变:\n  * `mingw-w64-i686-toolchain`->`mingw-w64-clang-i686-toolchain`\n  * `mingw-w64-i686-cmake`->`mingw-w64-clang-i686-cmake`\n  * `mingw-w64-ucrt-x86_64-toolchain`->`mingw-w64-clang-x86_64-toolchain`\n  * `mingw-w64-ucrt-x86_64-cmake`->`mingw-w64-clang-x86_64-cmake`\n  * `ucrt64.exe`->`clang64.exe`\n  * `mingw32.exe`->`clang32.exe`\n### Microsoft Visual Studio 2019/2022\n* 安装Visual Studio 2019或2022社区版(或者你有专业/企业版也可以)\n* 解压下载的源代码文件，或者用git来clone仓库: `git clone https://github.com/soarqin/D2RMH` 注意: 你需要 [Git for windows](https://git-scm.com/download/win)\n* 编译 D2RMH(64位):\n  * (Visual Studio 2019) 输入 `cmake -Bbuild -G \"Visual Studio 16 2019\" -A x64 -DUSE_STATIC_CRT=ON`  \n    (Visual Studio 2022) 输入 `cmake -Bbuild -G \"Visual Studio 17 2022\" -A x64 -DUSE_STATIC_CRT=ON`\n  * 然后你可以选择:\n    * 输入 `cmake --build build --config Release --target D2RMH`\n    * 打开 `build\\D2RMH.sln` 编译目标 `D2RMH`\n  * 编译好的exe在 `build\\bin` 目录\n* 编译 d2mapapi-piped(32位):\n  * (Visual Studio 2019) 输入 `cmake -Bbuild_d2mapapi -G \"Visual Studio 16 2019\" -A Win32 -DUSE_STATIC_CRT=ON d2mapapi`  \n    (Visual Studio 2022) 输入 `cmake -Bbuild_d2mapapi -G \"Visual Studio 17 2022\" -A Win32 -DUSE_STATIC_CRT=ON d2mapapi`\n  * 然后你可以选择:\n    * 打开 `cmake --build build_d2mapapi --config Release --target d2mapapi_piped`\n    * 打开 `build_d2mapapi\\d2mapapi.sln` 编译目标 `d2mapapi_piped`\n  * 编译好的exe在 `build_d2mapapi\\bin` 目录\n\n# 鸣谢\n* [d2mapapi_mod](https://github.com/soarqin/d2mapapi_mod) 修改自 [d2mapapi](https://github.com/jcageman/d2mapapi).\n* 想法以及内存地址来自 [MapAssist](https://github.com/misterokaygo/MapAssist).\n* [Handmade Math](https://github.com/HandmadeMath/Handmade-Math) 处理向量和矩阵运算\n* [glad](https://glad.dav1d.de) 加载 OpenGL(Core)/WGL 函数\n* [inih](https://github.com/benhoyt/inih) 读取 ini 文件\n* [JSON for Modern C++](https://github.com/nlohmann/json) 读取 JSON 文件\n* [CascLib](https://github.com/ladislav-zezula/CascLib) 从D2R读取Casc存储\n* [stb](https://github.com/nothings/stb), 使用了stb_truetype和stb_rect_pack\n"
  },
  {
    "path": "contrib/zhCN/plugins/chicken_life.lua",
    "content": "local text = create_text_list(\"default\")\n\nlocal chicken_life = function()\n    local player = get_player()\n    if player and player.map ~= 1 and player.map ~= 40 and player.map ~= 75 and player.map ~= 103 and player.map ~= 109 then\n        if player.stats[7] < player.stats[8] * 0.3 then\n            kill_process()\n        end\n    end\nend\n\nfunction chicken_life_toggle(on)\n    if on then\n        text:add('生命安全线保护功能已开启  开关热键: \\'Ctrl+/\\'', 5000, -1)\n    else\n        text:add('生命安全线保护功能已关闭  开关热键: \\'Ctrl+/\\'', 5000, -1)\n    end\nend\n\nregister_plugin(\"Ctrl+/\", false, 250, chicken_life, chicken_life_toggle)\n"
  },
  {
    "path": "contrib/zhCN/plugins/town_portal_check.lua",
    "content": "local text = create_text_list(\"default\")\n\nlocal town_portal_check = function()\n    -- game fully loaded?\n    if not get_skill(0) then\n        return\n    end\n\n    local quantity\n    local portal_book = get_skill(220)\n    if portal_book then\n        quantity = portalbook.quantity\n    else\n        quantity = 0\n    end\n    if quantity < 3 then\n        text:add(string.format(\"\\x0B警告！回城卷轴数量不足: %d\", quantity), 1500, 0)\n    end\nend\nregister_plugin(1000, town_portal_check)\n"
  },
  {
    "path": "copy_dist.bat",
    "content": "@echo off\n\ncmake -E copy_if_different bin\\D2RMH.ini bin\\D2RMH_gamedata.ini bin\\D2RMH_item.ini build\\%BUILD_DIR%\\dist\\\ncmake -E copy_directory bin\\plugins build\\%BUILD_DIR%\\dist\\plugins\ncmake -E copy_directory doc build\\%BUILD_DIR%\\dist\\doc\ncmake -E copy_if_different README.md LICENSE build\\%BUILD_DIR%\\dist\\\ncmake -E copy_if_different doc\\LICENSE.lua54 build\\%BUILD_DIR%\\dist\\doc\\\ncmake -E copy_if_different deps\\CascLib\\LICENSE build\\%BUILD_DIR%\\dist\\doc\\LICENSE.CascLib\ncmake -E copy_if_different deps\\inih\\LICENSE.txt build\\%BUILD_DIR%\\dist\\doc\\LICENSE.inih\ncmake -E copy_if_different deps\\sol3\\LICENSE.txt build\\%BUILD_DIR%\\dist\\doc\\LICENSE.sol3\ncmake -E copy_if_different d2mapapi\\LICENSE build\\%BUILD_DIR%\\dist\\doc\\LICENSE.d2mapapi_mod\ncmake -E copy_if_different d2mapapi\\json\\LICENSE.MIT build\\%BUILD_DIR%\\dist\\doc\\LICENSE.nlohmann_json\n\npushd build\\%BUILD_DIR%\\dist >NUL\ncmake -E tar cf D2RMH-snapshot.zip --format=zip D2RMH.exe d2mapapi_piped.exe D2RMH.ini D2RMH_gamedata.ini D2RMH_item.ini README.md LICENSE doc plugins\npopd >NUL\n"
  },
  {
    "path": "d2mapapi/.gitignore",
    "content": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n"
  },
  {
    "path": "d2mapapi/.gitrepo",
    "content": "; DO NOT EDIT (unless you know what you are doing)\n;\n; This subdirectory is a git \"subrepo\", and this file is maintained by the\n; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme\n;\n[subrepo]\n\tremote = git@github.com:soarqin/d2mapapi_mod.git\n\tbranch = master\n\tcommit = f61d05244f323409aa48b326033639326d7c285c\n\tparent = 5ae01c80237b531a6a17de30e7c55907f6d30339\n\tmethod = rebase\n\tcmdver = 0.4.3\n"
  },
  {
    "path": "d2mapapi/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\n\nproject(d2mapapi VERSION 1.3.0)\n\nif(MSVC)\n    set(CMAKE_CXX_STANDARD 20)\nelse()\n    set(CMAKE_CXX_STANDARD 17)\nendif()\n\nif (\"${CMAKE_SOURCE_DIR}\" STREQUAL \"${PROJECT_SOURCE_DIR}\")\n    list(APPEND CMAKE_MODULE_PATH \"${PROJECT_SOURCE_DIR}/cmake\")\n    include(CustomCompilerOptions)\n    fix_compile_flags()\n    fix_release_flags()\n    add_static_runtime_option()\nendif()\n\nif(CMAKE_SIZEOF_VOID_P EQUAL 4)\n    add_subdirectory(simphttp)\n    add_library(d2mapapi STATIC EXCLUDE_FROM_ALL\n        crc32.h\n        collisionmap.cpp collisionmap.h\n        mapdata.cpp mapdata.h\n        pathfinder.cpp pathfinder.h\n        d2map.cpp d2map.h\n        d2ptrs.h d2structs.h\n        offset.cpp offset.cpp\n        session.cpp session.h)\n    target_include_directories(d2mapapi PUBLIC . PRIVATE json)\n    set_target_properties(d2mapapi PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\n\n    add_executable(d2mapapi_gen_image EXCLUDE_FROM_ALL genimage.cpp)\n    target_compile_definitions(d2mapapi_gen_image PRIVATE D2MAPAPI_VERSION=\"${PROJECT_VERSION}\")\n    target_link_libraries(d2mapapi_gen_image d2mapapi shlwapi)\n    if(MSVC)\n        target_link_options(d2mapapi_gen_image PRIVATE /ENTRY:wmainCRTStartup)\n    else()\n        target_link_options(d2mapapi_gen_image PRIVATE -municode)\n    endif()\n    set_target_properties(d2mapapi_gen_image PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n\n    add_executable(d2mapapi_httpd EXCLUDE_FROM_ALL httpd.cpp)\n    target_compile_definitions(d2mapapi_httpd PRIVATE D2MAPAPI_VERSION=\"${PROJECT_VERSION}\")\n    target_link_libraries(d2mapapi_httpd d2mapapi simphttp)\n    if(MSVC)\n        target_link_options(d2mapapi_httpd PRIVATE /ENTRY:wmainCRTStartup)\n    else()\n        target_link_options(d2mapapi_httpd PRIVATE -municode)\n    endif()\n    set_target_properties(d2mapapi_httpd PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n\n    add_executable(d2mapapi_piped WIN32 EXCLUDE_FROM_ALL piped.cpp)\n    target_compile_definitions(d2mapapi_piped PRIVATE D2MAPAPI_VERSION=\"${PROJECT_VERSION}\")\n    target_include_directories(d2mapapi_piped PRIVATE json)\n    target_link_libraries(d2mapapi_piped d2mapapi)\n    if(MSVC)\n        target_link_options(d2mapapi_piped PRIVATE /ENTRY:wmainCRTStartup)\n    else()\n        target_link_options(d2mapapi_piped PRIVATE -municode)\n    endif()\n    set_target_properties(d2mapapi_piped PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\nendif()\n\nadd_library(d2mapapi_pipehost STATIC EXCLUDE_FROM_ALL\n    collisionmap.cpp collisionmap.h\n    pathfinder.cpp pathfinder.h\n    pipehost.cpp pipehost.h)\ntarget_include_directories(d2mapapi_pipehost PUBLIC . PRIVATE json)\nset_target_properties(d2mapapi_pipehost PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\n\n# this is a test program for d2mapapi_pipehost functions\nadd_executable(d2mapapi_host EXCLUDE_FROM_ALL host.cpp)\ntarget_link_libraries(d2mapapi_host d2mapapi_pipehost)\nset_target_properties(d2mapapi_host PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n"
  },
  {
    "path": "d2mapapi/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 jcageman\nCopyright (c) 2021-2022 Soar Qin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "d2mapapi/README.md",
    "content": "# d2mapapi_mod\n**d2mapapi mod, original from [jcageman/d2mapapi](https://github.com/jcageman/d2mapapi)**\n\n# Projects\n* `d2mapapi`: basic library for generating map data\n* `d2mapapi_gen_image`: generate map into image files (support PNG, BMP, TGA and JPG)\n* `d2mapapi_httpd`: httpd server, depends on `d2mapapi`\n* `d2mapapi_piped`: pipe query server, depends on `d2mapapi`\n* `d2mapapi_pipehost`: pipe querying library for communicating with `d2mapapi_piped`\n* `d2mapapi_host`: example and test project for do pipe query using `d2mapapi_pipehost`\n\n# Usage for `d2mapapi_gen_image`\n* command line: `d2mapapi_gen_image [d2_path] <seed> <difficulty> <map> <image filename>`\n  * `d2_path` is an optional parameter, which set legacy Diablo II installation path, `d2mapapi_httpd` will search registry for installation path if this parameter is absent or does not point to a correct installed game path.\n    * supported Diablo II Legacy client version: `1.11`, `1.11b`, `1.12`, `1.13c`, `1.13d`\n  * `seed`, `difficulty`, `map`: d2 map seed, game difficualty and map area id\n  * `image filename`: image filename, format is determined by file extension, supported: `.png`, `.tga`, `.bmp` and `.jpg`\n\n# Usage for `d2mapapi_httpd`\n* command line: `d2mapapi_httpd [d2_path]`\n  * `d2_path` is an optional parameter, which set legacy Diablo II installation path, `d2mapapi_httpd` will search registry for installation path if this parameter is absent or does not point to a correct installed game path.\n    * supported Diablo II Legacy client version: `1.11`, `1.11b`, `1.12`, `1.13c`, `1.13d`\n* http server is listen on port `8000`\n* http url is in RESTful form:\n  * `http://localhost:8000/{seed}/{difficulty}/{map}/{indentation}`\n    * `{seed}`: d2 map seed\n    * `{difficulty}`: game difficulty\n      * 0: normal\n      * 1: nightmare\n      * 2: hell\n    * `{map}`: map area id\n    * `{indentation}`: optional field, JSON indentation spaces. JSON will be compactly encoded if this is not set\n* returns the JSON data described below\n\n# Usage for `d2mapapi_piped`\n* command line: `d2mapapi_httpd [d2_path]`\n  * `d2_path` is an optional parameter, which set legacy Diablo II installation path, `d2mapapi_httpd` will search registry for installation path if this parameter is absent or does not point to a correct installed game path.\n    * supported Diablo II Legacy client version: `1.11`, `1.11b`, `1.12`, `1.13c`, `1.13d`\n* use `PipedChildProcess::start()` to run the child process, you can pass `d2_path` as its second parameter, or pass `nullptr` for reading from registry.\n* use `PipedChildProcess::queryMapRaw()` to get the encoded JSON(described below) for map data.\n* use `PipedChildProcess::queryMap()` to get the decoded map data.\n  * Note: you should delete the returned `CollisionMap*` pointer while it is no more needed.\n\n# JSON structure for map data\n* encoded JSON data are generated by `d2mapapi::CollisionMap::encode()` and returned by `d2mapapi_httpd` and `d2mapapi_piped`\n* use `d2mapapi::CollisionMap::CollisionMap(const std::string&)` to build map data from encoded JSON\n* ```\n  {\n    # map id\n    \"id\": 1,\n    # map offset in whole act\n    \"offset\": [\"x\": 5520, \"y\": 5880],\n    # map size\n    \"size\": [\"width\": 280, \"height\": 200],\n    # crop area of map data\n    \"crop\": [\"x0\": 0, \"x1\": 280, \"y0\": 0, \"y1\": 200],\n    # mapData is an encoded array with area in [x0, y0]-[x1, y1]\n    # check description below to see how are map data encoded\n    \"mapData\": [1,5,1,-1,\n                2,3,2,-1,\n                1,5,1,-1],\n    # map exits\n    \"exits\": {\n      # exit to map id 2\n      \"2\": {\n        # this is not a portal (so that you can walk between the map areas)\n        \"isPortal\": false,\n        # exit offsets in list, sometimes there can be multiple exits to another map area\n        # note: the offsets are not always correct while `isPortal` is false, because they are calculated by an inaccurate algorithm\n        \"offsets\": [{\"x\": 5672, \"y\": 5880}]\n      }\n    },\n    # npcs on map\n    \"npcs\": {\n      # npc id is 147, with offset list so that there can be multiple npcs in the same id\n      \"147\": [{\"x\": 5615, \"y\": 5967}]\n    },\n    # objects on map\n    \"objects\": {\n      # object id is 147, with offset list so that there can be multiple objects in the same id\n      \"119\": [{\"x\": 5634, \"y\": 5889}]\n    }\n  }\n  ```\n* map data are encoded using a simple run length encoding to save memory space  \n  -1 ends of a row  \n  Given this small map:  \n  ```\n  [1,5,1,-1,\n   2,3,2,-1,\n   1,5,1,-1]\n  ```\n\n  Generates the following map where `X` is collision and `.` is open space\n  ```\n  X.....X\n  XX...XX\n  X.....X\n  ```\n\n# Build\n* Just use [cmake](https://cmake.org) to build\n  * Note: `d2mapapi`, `d2mapapi_httpd`, `d2mapapi_piped` and `d2mapapi_gen_image` can only be compiled in 32-bit.\n\n# Credits\n* Core functions modified from [d2mapapi](https://github.com/jcageman/d2mapapi).\n* [JSON for Modern C++](https://github.com/nlohmann/json) for processing JSON files.\n* [libuv](https://github.com/libuv/libuv) and [llhttp](https://github.com/nodejs/llhttp), for httpd server.\n* [stb](https://github.com/nothings/stb), stb_image_write is used to write to image files.\n"
  },
  {
    "path": "d2mapapi/cmake/CustomCompilerOptions.cmake",
    "content": "macro(fix_compile_flags)\n    if(MSVC)\n        set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /utf-8\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /utf-8\")\n    endif()\nendmacro()\n\nmacro(fix_release_flags)\n    if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n        set(CMAKE_EXE_LINKER_FLAGS_RELEASE \"${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s -flto\")\n        set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL \"${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s -flto\")\n        set(CMAKE_SHARED_LINKER_FLAGS_RELEASE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -s -flto\")\n        set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL \"${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} -s -flto\")\n        set(CMAKE_C_FLAGS_RELEASE \"${CMAKE_C_FLAGS_RELEASE} -flto\")\n        set(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} -flto\")\n    endif()\n    if(MSVC)\n        add_compile_options(\n            $<$<CONFIG:Release>:/GL>\n            $<$<CONFIG:MinSizeRel>:/GL>\n        )\n        add_link_options(\n            $<$<CONFIG:Release>:/LTCG>\n            $<$<CONFIG:MinSizeRel>:/LTCG>\n        )\n    endif()\nendmacro()\n\nmacro(add_static_runtime_option)\n    option(USE_STATIC_CRT \"Use static C runtime\" OFF)\n\n    if(USE_STATIC_CRT)\n        if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n            set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++\")\n            set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++\")\n        elseif(MSVC)\n            set(CompilerFlags\n                CMAKE_CXX_FLAGS\n                CMAKE_CXX_FLAGS_DEBUG\n                CMAKE_CXX_FLAGS_RELEASE\n                CMAKE_CXX_FLAGS_MINSIZEREL\n                CMAKE_CXX_FLAGS_RELWITHDEBINFO\n                CMAKE_C_FLAGS\n                CMAKE_C_FLAGS_DEBUG\n                CMAKE_C_FLAGS_RELEASE\n                CMAKE_C_FLAGS_MINSIZEREL\n                CMAKE_C_FLAGS_RELWITHDEBINFO\n                )\n            foreach(CompilerFlag ${CompilerFlags})\n                string(REPLACE \"/MD\" \"/MT\" ${CompilerFlag} \"${${CompilerFlag}}\")\n                set(${CompilerFlag} \"${${CompilerFlag}}\" CACHE STRING \"msvc compiler flags\" FORCE)\n            endforeach()\n            add_compile_options(\n                $<$<CONFIG:>:/MT>\n                $<$<CONFIG:Debug>:/MTd>\n                $<$<CONFIG:Release>:/MT>\n                $<$<CONFIG:MinSizeRel>:/MT>\n                $<$<CONFIG:RelWithDebInfo>:/MT>\n            )\n        endif()\n    endif()\nendmacro()\n"
  },
  {
    "path": "d2mapapi/collisionmap.cpp",
    "content": "#include \"collisionmap.h\"\n\n#include <json.hpp>\n\n#include <sstream>\n\nnamespace d2mapapi {\n\nCollisionMap::CollisionMap(std::string_view str) {\n    decode(str);\n}\n\nNLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Point, x, y)\nNLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Size, width, height)\nNLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Rect, x0, y0, x1, y1)\nNLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Exit, offsets, isPortal)\nNLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CollisionMap, id, offset, size, crop, mapData, exits, npcs, objects, pathData)\n\ntemplate<typename T>\nvoid to_json(nlohmann::json &j, const std::map<uint32_t, T> &objs) {\n    for (auto &p: objs) {\n        j[std::to_string(p.first)] = p.second;\n    }\n}\n\ntemplate<typename T>\nvoid from_json(const nlohmann::json &j, std::map<uint32_t, T> &objs) {\n    for (auto &[key, value]: j.items()) {\n        nlohmann::adl_serializer<T>::from_json(value, objs[uint32_t(strtoul(key.c_str(), nullptr, 0))]);\n    }\n}\n\nstd::string CollisionMap::encode(bool encPathData, int indentation) const {\n    if (!built) { return {}; }\n    nlohmann::json j = *this;\n    if (!encPathData) { j[\"pathData\"].clear(); }\n    return j.dump(indentation > 0 ? indentation : -1);\n}\n\nvoid CollisionMap::decode(std::string_view str) {\n    auto j = nlohmann::json::parse(str, nullptr, false);\n    if (j.empty()) {\n        built = false;\n        errorString = \"Wrong input.\";\n        return;\n    }\n    auto ite = j.find(\"error\");\n    if (ite != j.end()) {\n        built = false;\n        errorString = ite->get<std::string>();\n        return;\n    }\n\n    try {\n        from_json(j, *this);\n    } catch (const std::exception &e) {\n        built = false;\n        errorString = e.what();\n        return;\n    }\n    built = true;\n    errorString.clear();\n    if (pathData.empty()) { return; }\n    auto sz = pathData.size();\n    size_t currSize = 0;\n    path.clear();\n    path.reserve(((crop.x1 - crop.x0) / 5) * ((crop.y1 - crop.y0) / 5));\n    for (size_t i = 1; i < sz; i += 2) {\n        currSize += pathData[i];\n        path.resize(currSize, pathData[i - 1]);\n    }\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/collisionmap.h",
    "content": "#pragma once\n\n#include <map>\n#include <vector>\n#include <string>\n#include <string_view>\n\nnamespace d2mapapi {\n\nstruct Point {\n    int x = 0;\n    int y = 0;\n};\n\nstruct Size {\n    int width = 0;\n    int height = 0;\n};\n\nstruct Rect {\n    int x0, y0, x1, y1;\n};\n\nstruct Exit {\n    std::vector<Point> offsets;\n    bool isPortal = false;\n};\n\nclass CollisionMap {\npublic:\n    explicit CollisionMap(unsigned int areaId): id(areaId) {}\n    explicit CollisionMap(std::string_view str);\n    virtual ~CollisionMap() = default;\n\n    [[nodiscard]] std::string encode(bool encPathData = false, int indentation = 0) const;\n    void decode(std::string_view str);\n\n    template<typename T>\n    inline bool extractCellData(T *output, int width, int height, int originX, int originY, T nonwalkableVal, T walkableVal, T edgeVal = T()) const {\n        auto w = std::max(crop.x1 - crop.x0, 0);\n        auto h = std::max(crop.y1 - crop.y0, 0);\n        if (originX + w > width || originY + h > height) {\n            return false;\n        }\n        int x = 0, y = 0;\n        int index = originY * width + originX;\n        bool walkable = false;\n        bool hasEdge = edgeVal != T();\n        for (int v: mapData) {\n            if (v < 0) {\n                if (++y >= h) { break; }\n                x = 0;\n                index = (originY + y) * width + originX;\n                walkable = false;\n                continue;\n            }\n            v = std::min(int(v), w - x);\n            if (!walkable) {\n                std::fill_n(output + index, v, nonwalkableVal);\n                if (hasEdge && y > 0) {\n                    T *ptr = output + index - width;\n                    for (int z = v; z; z--, ptr++) {\n                        if (*ptr == walkableVal) {\n                            *ptr = edgeVal;\n                        }\n                    }\n                }\n                index += v;\n            } else {\n                if (hasEdge && y + 1 == crop.y1 && crop.y1 < height) {\n                    std::fill_n(output + index, v, edgeVal);\n                    index += v;\n                } else {\n                    int z = v;\n                    if (hasEdge) {\n                        *(output + index) = x > 0 ? edgeVal : walkableVal;\n                        index++;\n                        z -= 2;\n                    }\n                    if (z >= 0) {\n                        if (hasEdge && y > 0) {\n                            for (; z; z--) {\n                                *(output + index) = *(output + index - width) == nonwalkableVal ? edgeVal : walkableVal;\n                                index++;\n                            }\n                        } else {\n                            std::fill_n(output + index, z, walkableVal);\n                            index += z;\n                        }\n                        if (hasEdge) {\n                            *(output + index) = x + v < w ? edgeVal : walkableVal;\n                            index++;\n                        }\n                    }\n                }\n            }\n            x += v;\n            walkable = !walkable;\n        }\n        return true;\n    }\n\n    bool built = false;\n    std::string errorString;\n\n    unsigned int id = 0;\n\n    Point offset = {0, 0};\n    Size size = {0, 0};\n\n    /* Collission maps are cropped in rect [crop.x0, crop.y0] to [crop.x1, crop.y1] relative to [offset.x, offset.y] */\n    Rect crop = {-1, -1, -1, -1};\n\n    /* Collision maps are encoded using a simple run length encoding to save memory space\n     *  -1 ends of a row\n     * Given this small map:\n     *  [1,5,1,-1,\n     *   2,3,2,-1,\n     *   1,5,1,-1]\n     * It would generate the following map where `X` is collision and `.` is open space\n     *   X.....X\n     *   XX...XX\n     *   X.....X\n     */\n    std::vector<int16_t> mapData;\n    std::map<uint32_t, Exit> exits;\n    std::map<uint32_t, std::vector<Point>> npcs;\n    std::map<uint32_t, std::vector<Point>> objects;\n\n    std::vector<uint8_t> path;\n    std::vector<uint8_t> pathData;\n};\n\n}\n"
  },
  {
    "path": "d2mapapi/crc32.h",
    "content": "#include <cstdint>\n#include <cstddef>\n\nnamespace crc {\n\n// Small implementation of std::array, needed until constexpr\n// is added to the function 'reference operator[](size_type)'\ntemplate <typename T, std::size_t N>\nstruct array {\n    T m_data[N];\n\n    using value_type = T;\n    using reference = value_type &;\n    using const_reference = const value_type &;\n    using size_type = std::size_t;\n\n    // This is NOT constexpr in std::array until C++17\n    constexpr reference operator[](size_type i) noexcept {\n        return m_data[i];\n    }\n\n    constexpr const_reference operator[](size_type i) const noexcept {\n        return m_data[i];\n    }\n\n    constexpr size_type size() const noexcept {\n        return N;\n    }\n};\n\n\n// Generates CRC-32 table, algorithm based from this link:\n// http://www.hackersdelight.org/hdcodetxt/crc.c.txt\nconstexpr auto gen_crc32_table() {\n    constexpr auto num_bytes = 256;\n    constexpr auto num_iterations = 8;\n    constexpr auto polynomial = 0xEDB88320;\n\n    auto crc32_table = array<uint32_t, num_bytes>{};\n\n    for (auto byte = 0u; byte < num_bytes; ++byte) {\n        auto crc = byte;\n\n        for (auto i = 0; i < num_iterations; ++i) {\n            auto mask = -(crc & 1);\n            crc = (crc >> 1) ^ (polynomial & mask);\n        }\n\n        crc32_table[byte] = crc;\n    }\n\n    return crc32_table;\n}\n\n// Stores CRC-32 table and softly validates it.\nstatic constexpr auto crc32_table = gen_crc32_table();\nstatic_assert(\n    crc32_table.size() == 256 &&\n        crc32_table[1] == 0x77073096 &&\n        crc32_table[255] == 0x2D02EF8D,\n    \"gen_crc32_table generated unexpected result.\"\n);\n\nconstexpr auto crc32(const void *in, std::size_t sz) {\n    const auto *data = static_cast<const uint8_t*>(in);\n    auto crc = 0xFFFFFFFFu;\n    for (size_t i = 0; i < sz; ++i) {\n        crc = crc32_table[(crc ^ data[i]) & 0xFFu] ^ (crc >> 8);\n    }\n\n    return ~crc;\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/d2map.cpp",
    "content": "#include \"d2map.h\"\n\n#include \"d2ptrs.h\"\n#include \"offset.h\"\n\n#include <iostream>\n#include <windows.h>\n\nnamespace d2mapapi {\n\nd2client_struct D2Client;\n\nconst char *d2Init(const wchar_t *dir) {\n    wchar_t szPath[MAX_PATH] = {0};\n    GetCurrentDirectoryW(MAX_PATH, szPath);\n    if (dir[0] != 0 && dir[lstrlenW(dir) - 1] != '\\\\') {\n        wchar_t dira[MAX_PATH];\n        lstrcpyW(dira, dir);\n        lstrcatW(dira, L\"\\\\\");\n        SetCurrentDirectoryW(dira);\n    } else {\n        SetCurrentDirectoryW(dir);\n    }\n\n    memset(&D2Client, 0, sizeof(d2client_struct));\n    if (!defineOffsets()) {\n        return \"Diablo II Legacy: Failed to load DLLs!\";\n    }\n    auto version = getD2Version();\n\n    *p_STORM_MPQHashTable = 0;\n    if (version < D2_113c) {\n        D2Client.u112.dwInit = 1;\n        D2Client.u112.fpInit = (uint32_t)D2ClientInterface;\n    } else {\n        D2Client.u113.dwInit = 1;\n        D2Client.u113.fpInit = (uint32_t)D2ClientInterface;\n    }\n\n    FOG_10021(\"D2\");\n    FOG_10101(1, 0);\n    FOG_10089(1);\n\n    if (!FOG_10218()) {\n        return \"Diablo II Legacy: Initialize Failed!\";\n    }\n\n    if (!D2WIN_10086() || !D2WIN_10005(0, 0, 0, &D2Client)) {\n        return \"Diablo II Legacy: Couldn't load MPQ files.\\nPlease make sure you have a full install of Diablo II and copy the D2XMUSIC.MPQ and D2XVIDEO.MPQ from the Expansion CD\";\n    }\n\n    D2LANG_Init(0, \"ENG\", 0);\n\n    if (!D2COMMON_InitDataTables(0, 0, 0)) {\n        return \"Diablo II Legacy: Couldn't initialize sqptDataTable!\";\n    }\n\n    D2CLIENT_InitGameMisc();\n\n    SetCurrentDirectoryW(szPath);\n    return nullptr;\n}\n\nLevel *__fastcall getLevel(Act *act, uint32_t levelno) {\n    auto d2Ver = getD2Version();\n    for (Level *pLevel = act->pMisc(d2Ver)->pLevelFirst(d2Ver); pLevel; pLevel = pLevel->pNextLevel(d2Ver))\n        if (pLevel->dwLevelNo(d2Ver) == levelno)\n            return (Level*)pLevel;\n    return D2COMMON_GetLevel(act->pMisc(d2Ver), levelno);\n}\n\n#if defined(_MSC_VER)\nvoid __declspec(naked) D2CLIENT_InitGameMisc(void)\n{\n    __asm\n    {\n        PUSH ECX\n        PUSH EBP\n        PUSH ESI\n        PUSH EDI\n        JMP D2CLIENT_InitGameMisc_I\n        RETN\n    }\n}\n#else\nvoid __attribute__((naked)) D2CLIENT_InitGameMisc() {\n    asm volatile (\n    \"push %%ecx\\n\"\n    \"push %%ebp\\n\"\n    \"push %%esi\\n\"\n    \"push %%edi\\n\"\n    \"jmp *%0\\n\"\n    \"ret\"\n    :\n    : \"r\"(D2CLIENT_InitGameMisc_I)\n    );\n}\n#endif\n\nuint32_t D2ClientInterface() {\n    if (getD2Version() < D2_113c) {\n        return D2Client.u112.dwInit;\n    }\n    return D2Client.u113.dwInit;\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/d2map.h",
    "content": "#pragma once\n\n#include \"d2structs.h\"\n\nnamespace d2mapapi {\n\n#define ArraySize(x) (sizeof(x) / sizeof(x[0]))\n\n/* return NULL if no error,\n * otherwise return error message */\nconst char *d2Init(const wchar_t *dir);\n\nLevel *__fastcall getLevel(Act *act, uint32_t levelno);\nvoid D2CLIENT_InitGameMisc();\nuint32_t D2ClientInterface();\n\n}\n"
  },
  {
    "path": "d2mapapi/d2ptrs.h",
    "content": "#pragma once\n\n#include \"d2structs.h\"\n\n#if defined(_DEFINE_VARS)\n#define D2EXTERN\n#else\n#define D2EXTERN extern\n#endif\n\nnamespace d2mapapi {\n\nD2EXTERN uint32_t *p_STORM_MPQHashTable;\nD2EXTERN uint32_t D2CLIENT_LoadAct_1;\nD2EXTERN uint32_t D2CLIENT_LoadAct_2;\nD2EXTERN void (__stdcall* D2CLIENT_InitGameMisc_I)(uint32_t Dummy1, uint32_t Dummy2, uint32_t Dummy3);\nD2EXTERN void (__stdcall* D2COMMON_AddRoomData)(Act * ptAct, int LevelId, int Xpos, int Ypos, Room1 *pRoom);\nD2EXTERN void (__stdcall* D2COMMON_RemoveRoomData)(Act * ptAct, int LevelId, int Xpos, int Ypos, Room1 *pRoom);\nD2EXTERN Level * (__fastcall* D2COMMON_GetLevel)(ActMisc * pMisc, uint32_t dwLevelNo);\n\nD2EXTERN void (__stdcall* D2COMMON_InitLevel)(Level * pLevel);\nD2EXTERN Act* (__stdcall* D2COMMON_LoadAct)(uint32_t ActNumber, uint32_t Seed, uint32_t Unk, void *pGame, uint32_t Difficulty, void *pMempool, uint32_t TownLevelId, uint32_t Func_1, uint32_t Func_2);\nD2EXTERN void (__stdcall* D2COMMON_UnloadAct)(Act * pAct);\n\nD2EXTERN void (__fastcall* FOG_10021)(const char *szProg);\nD2EXTERN uint32_t (__fastcall* FOG_10101)(uint32_t Dummy1, uint32_t Dummy2);\nD2EXTERN uint32_t (__fastcall* FOG_10089)(uint32_t Dummy1);\nD2EXTERN uint32_t (__fastcall* FOG_10218)(void);\n\nD2EXTERN uint32_t (__fastcall* D2WIN_10086)(void);\nD2EXTERN uint32_t (__fastcall* D2WIN_10005)(uint32_t Dummy1, uint32_t Dummy2, uint32_t Dummy3, d2client_struct * pD2Client);\n\nD2EXTERN uint32_t (__fastcall* D2LANG_Init)(uint32_t Dummy1, const char *_2, uint32_t Dummy3);\nD2EXTERN uint32_t (__stdcall* D2COMMON_InitDataTables)(uint32_t Dummy1, uint32_t Dummy2, uint32_t Dummy3);\n\n}\n"
  },
  {
    "path": "d2mapapi/d2structs.h",
    "content": "#pragma once\n\n#include \"offset.h\"\n#include <cstdint>\n\nnamespace d2mapapi {\n\nstruct UnitAny;\nstruct Room1_111;\nstruct Room1_112;\nstruct Room1_113;\nstruct Room2_111;\nstruct Room2_112;\nstruct Room2_113;\nstruct Level111;\nstruct Level112;\nstruct Level113;\nstruct Act111;\nstruct Act112;\nstruct Act113;\nstruct ActMisc111;\nstruct ActMisc112;\nstruct ActMisc113;\n\nunion RoomTile;\nunion PresetUnit;\nunion Room1;\nunion Room2;\nunion Level;\nunion Act;\nunion ActMisc;\n\n#pragma pack(push)\n#pragma pack(1)\n\nstruct d2client_struct_112 {\n    uint32_t dwInit;                    //0x00\n    uint8_t _1[0x20C-4];                //0x04\n    uint32_t fpInit;                    //0x20C\n};\n\nstruct d2client_struct_113 {\n    uint32_t dwInit;                    //0x00\n    uint8_t _1[0x20D - 4];              //0x04\n    uint32_t fpInit;                    //0x20D\n};\n\nstruct CollMap {\n    uint32_t dwPosGameX;                //0x00\n    uint32_t dwPosGameY;                //0x04\n    uint32_t dwSizeGameX;               //0x08\n    uint32_t dwSizeGameY;               //0x0C\n    uint32_t dwPosRoomX;                //0x10\n    uint32_t dwPosRoomY;                //0x14\n    uint32_t dwSizeRoomX;               //0x18\n    uint32_t dwSizeRoomY;               //0x1C\n    uint16_t *pMapStart;                //0x20\n    uint16_t *pMapEnd;                  //0x24\n};\n\nstruct RoomTile111 {\n    uint32_t _1;\n    Room2 *pRoom2; //+04\n    RoomTile *pNext; //+08\n    uint32_t *nNum; //+0c\n};\n\nstruct RoomTile112 {\n    uint32_t *nNum;                     //0x00\n    Room2 *pRoom2;                      //0x04\n    uint32_t _1[2];                     //0x08\n    RoomTile *pNext;                    //0x10\n};\n\nstruct RoomTile113 {\n    Room2 *pRoom2;                      //0x00\n    RoomTile *pNext;                    //0x04\n    uint32_t _2[2];                     //0x08\n    uint32_t *nNum;                     //0x10\n};\n\nstruct PresetUnit111 {\n    uint32_t _1[2];\n    uint32_t dwPosY; //+08\n    uint32_t dwTxtFileNo; //+0c\n    uint32_t _2[1];\n    PresetUnit *pPresetNext; //+1c\n    uint32_t dwPosX; //+20\n    uint32_t dwType; //+24\n};\n\nstruct PresetUnit112 {\n    uint32_t dwTxtFileNo;               //0x00\n    uint32_t _1[2];                     //0x04\n    uint32_t dwPosX;                    //0x0C\n    uint32_t _2;                        //0x10\n    uint32_t dwPosY;                    //0x14\n    PresetUnit *pPresetNext;            //0x18\n    uint32_t dwType;                    //0x1C\n};\n\nstruct PresetUnit113 {\n    uint32_t _1;                        //0x00\n    uint32_t dwTxtFileNo;               //0x04\n    uint32_t dwPosX;                    //0x08\n    PresetUnit *pPresetNext;            //0x0C\n    uint32_t _3;                        //0x10\n    uint32_t dwType;                    //0x14\n    uint32_t dwPosY;                    //0x18\n};\n\nstruct Level111 {\n    uint32_t _1;\n    uint32_t dwPosX;\n    uint32_t dwPosY;\n    uint32_t dwSizeX;\n    uint32_t dwSizeY;\n    uint32_t dwLevelNo; //+14\n    uint32_t _1a[120];\n    uint32_t dwSeed[2]; //+1f8\n    uint32_t _2[1];\n    Room2 *pRoom2First; //+204\n    ActMisc *pMisc; //+208\n    uint32_t _3[8];\n    Level *pNextLevel; //+22c\n};\n\nstruct Level112 {\n    uint8_t _1[0x50];                   //0x00\n    uint32_t dwSeed[2];                 //0x50\n    uint32_t _2;                        //0x58\n    Level *pNextLevel;                  //0x5C\n    uint32_t _56;                       //0x60\n    ActMisc *pMisc;                     //0x64\n    uint32_t _3;                        //0x68\n    uint32_t dwPosX;                    //0x6C\n    uint32_t dwPosY;                    //0x70\n    uint32_t dwSizeX;                   //0x74\n    uint32_t dwSizeY;                   //0x78\n    uint32_t _4[6];                     //0x7C\n    uint32_t dwLevelNo;                 //0x94\n    uint32_t _5[0x61];                  //0x98\n    Room2 *pRoom2First;                 //0x21C\n};\n\nstruct Level113 {\n    uint32_t _1[4];                     //0x00\n    Room2 *pRoom2First;                 //0x10\n    uint32_t _2[2];                     //0x14\n    uint32_t dwPosX;                    //0x1C\n    uint32_t dwPosY;                    //0x20\n    uint32_t dwSizeX;                   //0x24\n    uint32_t dwSizeY;                   //0x28\n    uint32_t _3[96];                    //0x2C\n    Level *pNextLevel;                  //0x1AC\n    uint32_t _4;                        //0x1B0\n    ActMisc *pMisc;                     //0x1B4\n    uint32_t _5[6];                     //0x1BC\n    uint32_t dwLevelNo;                 //0x1D0\n};\n\nstruct Room2_111 {\n    RoomTile *pRoomTiles; //\n    uint32_t _1[1];\n    uint32_t dwPresetType; //+8\n    uint32_t _2[1];\n    uint32_t dwRoomsNear; //+10\n    uint32_t _2a[2];\n    Level *pLevel; //+1c\n    uint32_t dwPosX; //+20\n    uint32_t dwPosY; //+24\n    uint32_t dwSizeX; //+28\n    uint32_t dwSizeY; //+2c\n    Room2 **pRoom2Near; //+30\n    PresetUnit *pPreset; //+34\n    Room2 *pRoom2Next; //+38\n    uint32_t _4[38];\n    uint32_t dwSeed[2]; //+d4\n    uint32_t *pType2Info; //+dc\n    uint32_t _5[2];\n    Room1 *pRoom1; //+e8\n};\n\nstruct Room2_112 {\n    Level *pLevel;                      //0x00\n    uint32_t _1;                        //0x04\n    uint32_t dwRoomsNear;               //0x08\n    RoomTile *pRoomTiles;               //0x0C\n    Room2 **pRoom2Near;                 //0x10\n    uint32_t _3[6];                     //0x14\n    uint32_t dwPosX;                    //0x2C\n    uint32_t dwPosY;                    //0x30\n    uint32_t dwSizeX;                   //0x34\n    uint32_t dwSizeY;                   //0x38\n    uint32_t *pType2Info;               //0x3C\n    uint32_t _4[0x20];                  //0x40\n    uint32_t dwPresetType;              //0xC0\n    PresetUnit *pPreset;                //0xC4\n    uint32_t _5[0x3];                   //0xC8\n    Room2 *pRoom2Next;                  //0xD4\n    Room1 *pRoom1;                      //0xD8\n};\n\nstruct Room2_113 {\n    uint32_t _1[2];                     //0x00\n    Room2 **pRoom2Near;                 //0x08\n    uint32_t _2[6];                     //0x0C\n    Room2 *pRoom2Next;                  //0x24\n    uint32_t dwRoomFlags;               //0x28\n    uint32_t dwRoomsNear;               //0x2C\n    Room1 *pRoom1;                      //0x30\n    uint32_t dwPosX;                    //0x34\n    uint32_t dwPosY;                    //0x38\n    uint32_t dwSizeX;                   //0x3C\n    uint32_t dwSizeY;                   //0x40\n    uint32_t _3;                        //0x44\n    uint32_t dwPresetType;              //0x48\n    RoomTile *pRoomTiles;               //0x4C\n    uint32_t _4[2];                     //0x50\n    Level *pLevel;                      //0x58\n    PresetUnit *pPreset;                //0x5C\n};\n\nstruct Room1_111 {\n    uint32_t dwSeed[2]; //+00\n    uint32_t dwXStart; //+08\n    uint32_t dwYStart; //+0c\n    uint32_t dwXSize; //+10\n    uint32_t dwYSize; //+14\n    uint32_t dwXStart2; //+18\n    uint32_t dwYStart2; //+1c\n    uint32_t dwXSize2; //+20\n    uint32_t dwYSize2; //+24\n    uint32_t _2[3];\n    Room1 **pRoomsNear; //+34\n    Room2 *pRoom2; //+38\n    UnitAny *pUnitFirst; //+3c\n    uint32_t _3[8];\n    CollMap *Coll;\n    uint32_t _4[4];\n    Room1 *pRoomNext; // +74\n    uint32_t _5;\n    uint32_t dwRoomsNear; //+7c\n};\n\nstruct Room1_112 {\n    Room1 **pRoomsNear;                 //0x00\n    uint32_t _1[2];                     //0x04\n    uint32_t dwSeed[2];                 //0x0C\n    uint32_t _2;                        //0x14\n    uint32_t dwXStart;                  //0x18\n    uint32_t dwYStart;                  //0x1C\n    uint32_t dwXSize;                   //0x20\n    uint32_t dwYSize;                   //0x24\n    uint32_t _3[0x4];                   //0x28\n    Room1 *pRoomNext;                   //0x38\n    uint32_t _4;                        //0x3C\n    UnitAny *pUnitFirst;                //0x40\n    uint32_t _5[3];                     //0x44\n    CollMap *Coll;                      //0x50\n    uint32_t _6[0x7];                   //0x54\n    Room2 *pRoom2;                      //0x70\n    uint32_t _7;                        //0x74\n    uint32_t dwRoomsNear;               //0x78\n};\n\nstruct Room1_113 {\n    Room1 **pRoomsNear;                 //0x00\n    uint32_t _1[3];                     //0x04\n    Room2 *pRoom2;                      //0x10\n    uint32_t _2[3];                     //0x14\n    CollMap *Coll;                      //0x20\n    uint32_t dwRoomsNear;               //0x24\n    uint32_t _3[9];                     //0x28\n    uint32_t dwPosX;                    //0x4C\n    uint32_t dwPosY;                    //0x50\n    uint32_t dwSizeX;                   //0x54\n    uint32_t dwSizeY;                   //0x58\n    uint32_t _4[6];                     //0x5C\n    UnitAny *pUnitFirst;                //0x74\n    uint32_t _5;                        //0x78\n    Room1 *pRoomNext;                   //0x7C\n};\n\nstruct ActMisc111 {\n    uint32_t _1[33];\n    Act *pAct; //+84\n    uint32_t dwBossTombLvl; //+88\n    uint32_t _2[248];\n    Level *pLevelFirst; //+46c\n    uint32_t _3[2];\n    uint32_t dwStaffTombLevel; // +478\n};\n\nstruct ActMisc112 {\n    uint32_t _1;                        //0x00\n    Act *pAct;                          //0x04\n    uint32_t _2[238];                   //0x3BC\n    uint32_t dwStaffTombLevel;          //0x3C0\n    uint32_t _3[43];                    //0x470\n    Level *pLevelFirst;\n};\n\nstruct ActMisc113 {\n    uint32_t _1[37];                    //0x00\n    uint32_t dwStaffTombLevel;          //0x94\n    uint32_t _2[245];                   //0x98\n    Act *pAct;                          //0x46C\n    uint32_t _3[3];                     //0x470\n    Level *pLevelFirst;                 //0x47C\n};\n\nstruct Act111 {\n    uint32_t _1[2];\n    ActMisc *pMisc; //+08\n};\n\nstruct Act112 {\n    uint8_t _1[0x34];                   //0x00\n    Room1 *pRoom1;                      //0x34\n    ActMisc *pMisc;                     //0x38\n    uint32_t _2[2];                     //0x40\n    uint32_t dwAct;                     //0x44\n};\n\nstruct Act113 {\n    uint32_t _1[3];                     //0x00\n    uint32_t dwMapSeed;                 //0x0C\n    Room1 *pRoom1;                      //0x10\n    uint32_t dwAct;                     //0x14\n    uint32_t _2[12];                    //0x18\n    ActMisc *pMisc;                     //0x48\n};\n\n#define GETTER_BY_VER(n) \\\ninline decltype(u113.n) n(D2Version ver) { switch(ver) { case D2_111a: case D2_111b: return u111.n; case D2_112a: return u112.n; default: return u113.n; } }\n\nunion d2client_struct {\n    d2client_struct_112 u112;\n    d2client_struct_113 u113;\n};\n\nunion RoomTile {\n    RoomTile111 u111;\n    RoomTile112 u112;\n    RoomTile113 u113;\n\n    GETTER_BY_VER(pNext)\n    GETTER_BY_VER(nNum)\n    GETTER_BY_VER(pRoom2)\n};\n\nunion PresetUnit {\n    PresetUnit111 u111;\n    PresetUnit112 u112;\n    PresetUnit113 u113;\n\n    GETTER_BY_VER(pPresetNext)\n    GETTER_BY_VER(dwType)\n    GETTER_BY_VER(dwTxtFileNo)\n    GETTER_BY_VER(dwPosX)\n    GETTER_BY_VER(dwPosY)\n};\n\nunion Room1 {\n    Room1_111 u111;\n    Room1_112 u112;\n    Room1_113 u113;\n\n    GETTER_BY_VER(Coll)\n};\n\nunion Room2 {\n    Room2_111 u111;\n    Room2_112 u112;\n    Room2_113 u113;\n\n    GETTER_BY_VER(pRoom2Next)\n    GETTER_BY_VER(pRoom1)\n    GETTER_BY_VER(dwPosX)\n    GETTER_BY_VER(dwPosY)\n    GETTER_BY_VER(dwRoomsNear)\n    GETTER_BY_VER(pRoom2Near)\n    GETTER_BY_VER(pLevel)\n    GETTER_BY_VER(dwSizeX)\n    GETTER_BY_VER(dwSizeY)\n    GETTER_BY_VER(pPreset)\n    GETTER_BY_VER(pRoomTiles)\n};\n\nunion Level {\n    Level111 u111;\n    Level112 u112;\n    Level113 u113;\n    GETTER_BY_VER(pRoom2First)\n    GETTER_BY_VER(dwLevelNo)\n    GETTER_BY_VER(dwPosX)\n    GETTER_BY_VER(dwPosY)\n    GETTER_BY_VER(dwSizeX)\n    GETTER_BY_VER(dwSizeY)\n    GETTER_BY_VER(pNextLevel)\n};\n\nunion ActMisc {\n    ActMisc111 u111;\n    ActMisc112 u112;\n    ActMisc113 u113;\n    GETTER_BY_VER(pLevelFirst)\n};\n\nunion Act {\n    Act111 u111;\n    Act112 u112;\n    Act113 u113;\n    GETTER_BY_VER(pMisc)\n};\n\n#pragma pack(pop)\n\n}\n"
  },
  {
    "path": "d2mapapi/genimage.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"d2map.h\"\n#include \"session.h\"\n#include \"pathfinder.h\"\n\n#define STBIW_WINDOWS_UTF8\n#define STB_IMAGE_WRITE_IMPLEMENTATION\n#include \"stb/stb_image_write.h\"\n\n#include <windows.h>\n#include <shlwapi.h>\n#include <cstdio>\n#include <cstdint>\n#include <cwchar>\n\nint wmain(int argc, wchar_t *argv[]) {\n    if (argc < 5) {\n        fprintf(stderr, \"Usage: d2mapapi_gen_image [D2 Game Path] <seed> <difficulty> <map_id> <image filename>\\n\");\n        return -1;\n    }\n    const wchar_t *wfilename = argv[argc > 5 ? 5 : 4];\n    const wchar_t *ext = StrRChrW(wfilename, nullptr, L'.');\n    int filetype = -1;\n    if (ext) {\n        if (!StrCmpIW(ext, L\".png\")) {\n            filetype = 0;\n        } else if (!StrCmpIW(ext, L\".bmp\")) {\n            filetype = 1;\n        } else if (!StrCmpIW(ext, L\".tga\")) {\n            filetype = 2;\n        } else if (!StrCmpIW(ext, L\".jpg\")) {\n            filetype = 3;\n        }\n    }\n    if (filetype < 0) {\n        fprintf(stderr, \"Supported file extension: png, bmp, tga, jpg\\n\");\n        return -1;\n    }\n    const auto *errstr = argc > 5 ? d2mapapi::d2Init(argv[1]) : nullptr;\n    if (errstr) {\n        do {\n            HKEY key;\n            if (RegOpenKeyExW(HKEY_CURRENT_USER, L\"SOFTWARE\\\\Blizzard Entertainment\\\\Diablo II\", 0, KEY_READ, &key)\n                == ERROR_SUCCESS) {\n                wchar_t path[MAX_PATH];\n                DWORD pathSize = sizeof(path);\n                if (RegQueryValueExW(key, L\"InstallPath\", nullptr, nullptr, LPBYTE(path), &pathSize) == ERROR_SUCCESS) {\n                    errstr = d2mapapi::d2Init(path);\n                    if (!errstr) {\n                        RegCloseKey(key);\n                        break;\n                    }\n                }\n                RegCloseKey(key);\n            }\n            fprintf(stderr, \"[d2mapapi_gen_image v\" D2MAPAPI_VERSION \"] %s\\n\", errstr);\n            return -1;\n        } while (false);\n    }\n    std::uint32_t seed, difficulty, mapId;\n    seed = std::uint32_t(wcstoul(argv[argc > 5 ? 2 : 1], nullptr, 0));\n    difficulty = std::uint32_t(wcstoul(argv[argc > 5 ? 3 : 2], nullptr, 0));\n    mapId = std::uint32_t(wcstoul(argv[argc > 5 ? 4 : 3], nullptr, 0));\n    auto sess = std::make_unique<d2mapapi::Session>();\n    sess->update(seed, difficulty);\n    auto *map = sess->getMap(mapId);\n    auto str = map->encode();\n    auto *collmap = new d2mapapi::CollisionMap(str);\n\n    auto [x0, y0, x1, y1] = collmap->crop;\n    auto w = collmap->size.width;\n    auto h = collmap->size.height;\n    std::vector<uint8_t> vec(w * h);\n    collmap->extractCellData<uint8_t>(vec.data(), w, h, x0,y0, 0, 80, 160);\n    for (auto &e: collmap->exits) {\n        for (auto &o: e.second.offsets) {\n            auto ex = o.x - collmap->offset.x, ey = o.y - collmap->offset.y;\n            for (int j = -2; j < 3; ++j) {\n                for (int i = -2; i < 3; ++i) {\n                    vec[(ey + j) * w + ex + i] = 255;\n                }\n            }\n        }\n    }\n\n    stbi_write_png_compression_level = 9;\n    char filename[1024];\n    stbiw_convert_wchar_to_utf8(filename, 1024, wfilename);\n    switch (filetype) {\n    case 0:\n        stbi_write_png(filename, w, h, 1, vec.data(), w);\n        break;\n    case 1:\n        stbi_write_bmp(filename, w, h, 1, vec.data());\n        break;\n    case 2:\n        stbi_write_tga(filename, w, h, 1, vec.data());\n        break;\n    case 3:\n        stbi_write_jpg(filename, w, h, 1, vec.data(), 90);\n        break;\n    default:\n        break;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "d2mapapi/host.cpp",
    "content": "#include \"pipehost.h\"\n\n#include <windows.h>\n\nint main(int argc, char *argv[]) {\n    d2mapapi::PipedChildProcess pcp;\n    if (!pcp.start(L\"d2mapapi_piped.exe\", nullptr)) {\n        MessageBoxA(nullptr, pcp.errMsg().c_str(), nullptr, 0);\n        return -1;\n    }\n    for (int i = 1; i < argc; i += 3) {\n        auto *map = pcp.queryMap(strtoul(argv[i], nullptr, 0),\n                     strtoul(argv[i + 1], nullptr, 0),\n                     strtoul(argv[i + 2], nullptr, 0));\n        if (!map->built) {\n            MessageBoxA(nullptr, map->errorString.c_str(), nullptr, 0);\n        }\n        delete map;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "d2mapapi/httpd.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"simphttp.h\"\n\n#include \"d2map.h\"\n#include \"session.h\"\n\n#include <windows.h>\n#include <unordered_map>\n#include <memory>\n\nenum {\n    SessionsCacheSize = 8,\n};\n\nint wmain(int argc, wchar_t *argv[]) {\n    const auto *errstr = argc > 1 ? d2mapapi::d2Init(argv[1]) : \"Usage: d2mapapi_piped <D2 Game Path>\";\n    if (errstr) {\n        do {\n            HKEY key;\n            if (RegOpenKeyExW(HKEY_CURRENT_USER, L\"SOFTWARE\\\\Blizzard Entertainment\\\\Diablo II\", 0, KEY_READ, &key) == ERROR_SUCCESS) {\n                wchar_t path[MAX_PATH];\n                DWORD pathSize = sizeof(path);\n                if (RegQueryValueExW(key, L\"InstallPath\", nullptr, nullptr, LPBYTE(path), &pathSize) == ERROR_SUCCESS) {\n                    errstr = d2mapapi::d2Init(path);\n                    if (!errstr) {\n                        RegCloseKey(key);\n                        break;\n                    }\n                }\n                RegCloseKey(key);\n            }\n            fprintf(stderr, \"[d2mapapi_mod v\" D2MAPAPI_VERSION \"] %s\\n\", errstr);\n            return -1;\n        } while (false);\n    }\n\n    fprintf(stdout, \"[d2mapapi_mod v\" D2MAPAPI_VERSION \"] HTTP server is listening at localhost:8000\\n\");\n\n    std::unordered_map<uint64_t, std::unique_ptr<d2mapapi::Session>> sessions;\n    std::vector<uint64_t> sessionsOrder;\n    simphttp::Server server([&sessions, &sessionsOrder](auto &req, auto &res) {\n        uint32_t seed = 0;\n        uint8_t difficulty = 0;\n        uint32_t levelId = 0;\n        int indentation = 0;\n        bool success = false;\n        const char *url = req.url.c_str();\n        do {\n            if (*url != '/') break;\n            ++url;\n            char *next;\n            seed = uint32_t(strtoul(url, &next, 0));\n            if (url == next || *next != '/') break;\n\n            url = next + 1;\n            difficulty = uint32_t(strtoul(url, &next, 0));\n            if (url == next || *next != '/') break;\n\n            url = next + 1;\n            levelId = uint32_t(strtoul(url, &next, 0));\n            if (url == next || (*next != '/' && *next != 0)) break;\n\n            if (*next == '/') {\n                url = next + 1;\n                indentation = int(strtoul(url, &next, 0));\n                if (url == next && (*next == '/' || *next == 0)) {\n                    indentation = 0;\n                } else if (*next != '/' && *next != 0) {\n                    break;\n                }\n            }\n            success = true;\n        } while (false);\n        res.setStatus(200);\n        res.setHeader(\"Connection\", \"keep-alive\");\n        res.setHeader(\"Content-Type\", \"application/json\");\n        if (!success) {\n            const std::string errstr = R\"({\"error\":\"Invalid parameters!\")\";\n            res.setHeader(\"Content-Length\", std::to_string(errstr.size()));\n            res.end(errstr);\n            return;\n        }\n        auto key = uint64_t(seed) | (uint64_t(difficulty) << 32);\n        auto &session = sessions[key];\n        if (!session) {\n            sessionsOrder.emplace_back(key);\n            session = std::make_unique<d2mapapi::Session>();\n            session->update(seed, difficulty);\n            if (sessionsOrder.size() > SessionsCacheSize) {\n                auto oldKey = sessionsOrder[0];\n                sessionsOrder.erase(sessionsOrder.begin());\n                sessions.erase(oldKey);\n            }\n        }\n        const auto *map = session->getMap(levelId);\n        if (map) {\n            auto str = map->encode(false, indentation);\n            res.setHeader(\"Content-Length\", std::to_string(str.size()));\n            res.end(str);\n        } else {\n            const std::string errstr = R\"({\"error\":\"Invalid map id!\"})\";\n            res.setHeader(\"Content-Length\", std::to_string(errstr.size()));\n            res.end(errstr);\n        }\n    });\n    server.listen(\"::\", 8000);\n    return 0;\n}\n"
  },
  {
    "path": "d2mapapi/json/LICENSE.MIT",
    "content": "MIT License \n\nCopyright (c) 2013-2021 Niels Lohmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "d2mapapi/json/README.md",
    "content": "[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases)\n\n[![Build Status](https://app.travis-ci.com/nlohmann/json.svg?branch=develop)](https://app.travis-ci.com/nlohmann/json)\n[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json)\n[![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu)\n[![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AmacOS)\n[![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AWindows)\n[![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop)\n[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://www.codacy.com/gh/nlohmann/json/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nlohmann/json&amp;utm_campaign=Badge_Grade)\n[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp)\n[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json)\n[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7)\n[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](https://nlohmann.github.io/json/doxygen/index.html)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)\n[![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases)\n[![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases)\n[![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues)\n[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/nlohmann/json.svg)](https://isitmaintained.com/project/nlohmann/json \"Average time to resolve an issue\")\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289)\n[![GitHub Sponsors](https://img.shields.io/badge/GitHub-Sponsors-ff69b4)](https://github.com/sponsors/nlohmann)\n\n- [Design goals](#design-goals)\n- [Sponsors](#sponsors)\n- [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](http://127.0.0.1:8000/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues))\n- [Examples](#examples)\n  - [JSON as first-class data type](#json-as-first-class-data-type)\n  - [Serialization / Deserialization](#serialization--deserialization)\n  - [STL-like access](#stl-like-access)\n  - [Conversion from STL containers](#conversion-from-stl-containers)\n  - [JSON Pointer and JSON Patch](#json-pointer-and-json-patch)\n  - [JSON Merge Patch](#json-merge-patch)\n  - [Implicit conversions](#implicit-conversions)\n  - [Conversions to/from arbitrary types](#arbitrary-types-conversions)\n  - [Specializing enum conversion](#specializing-enum-conversion)\n  - [Binary formats (BSON, CBOR, MessagePack, and UBJSON)](#binary-formats-bson-cbor-messagepack-and-ubjson)\n- [Supported compilers](#supported-compilers)\n- [Integration](#integration)\n  - [CMake](#cmake)\n  - [Package Managers](#package-managers)\n  - [Pkg-config](#pkg-config)\n- [License](#license)\n- [Contact](#contact)\n- [Thanks](#thanks)\n- [Used third-party tools](#used-third-party-tools)\n- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c)\n- [Notes](#notes)\n- [Execute unit tests](#execute-unit-tests)\n\n## Design goals\n\nThere are myriads of [JSON](https://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals:\n\n- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean.\n\n- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.\n\n- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289).\n\nOther aspects were not so important to us:\n\n- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.\n\n- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set.\n\nSee the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information.\n\n\n## Sponsors\n\nYou can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann).\n\n### :label: Named Sponsors\n\n- [Michael Hartmann](https://github.com/reFX-Mike)\n- [Stefan Hagen](https://github.com/sthagen)\n- [Steve Sperandeo](https://github.com/homer6)\n- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe)\n- [Steve Wagner](https://github.com/ciroque)\n\nThanks everyone!\n\n## Support\n\n:question: If you have a **question**, please check if it is already answered in the [**FAQ**](https://json.nlohmann.me/home/faq/) or the [**Q&A**](https://github.com/nlohmann/json/discussions/categories/q-a) section. If not, please [**ask a new question**](https://github.com/nlohmann/json/discussions/new) there.\n\n:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/doc/examples), or browse through the [**help pages**](https://json.nlohmann.me).\n\n:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or the [**Doxygen documentation**](https://json.nlohmann.me/doxygen/index.html).\n\n:bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as many information as possible to help us understand and reproduce your issue.\n\nThere is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for the documentation browsers [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), and [Zeal](https://zealdocs.org) that contains the full [documentation](https://json.nlohmann.me) as offline resource.\n\n## Examples\n\nBeside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/api/basic_json/emplace/)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).\n\n### JSON as first-class data type\n\nHere are some examples to give you an idea how to use the class.\n\nAssume you want to create the JSON object\n\n```json\n{\n  \"pi\": 3.141,\n  \"happy\": true,\n  \"name\": \"Niels\",\n  \"nothing\": null,\n  \"answer\": {\n    \"everything\": 42\n  },\n  \"list\": [1, 0, 2],\n  \"object\": {\n    \"currency\": \"USD\",\n    \"value\": 42.99\n  }\n}\n```\n\nWith this library, you could write:\n\n```cpp\n// create an empty structure (null)\njson j;\n\n// add a number that is stored as double (note the implicit conversion of j to an object)\nj[\"pi\"] = 3.141;\n\n// add a Boolean that is stored as bool\nj[\"happy\"] = true;\n\n// add a string that is stored as std::string\nj[\"name\"] = \"Niels\";\n\n// add another null object by passing nullptr\nj[\"nothing\"] = nullptr;\n\n// add an object inside the object\nj[\"answer\"][\"everything\"] = 42;\n\n// add an array that is stored as std::vector (using an initializer list)\nj[\"list\"] = { 1, 0, 2 };\n\n// add another object (using an initializer list of pairs)\nj[\"object\"] = { {\"currency\", \"USD\"}, {\"value\", 42.99} };\n\n// instead, you could also write (which looks very similar to the JSON above)\njson j2 = {\n  {\"pi\", 3.141},\n  {\"happy\", true},\n  {\"name\", \"Niels\"},\n  {\"nothing\", nullptr},\n  {\"answer\", {\n    {\"everything\", 42}\n  }},\n  {\"list\", {1, 0, 2}},\n  {\"object\", {\n    {\"currency\", \"USD\"},\n    {\"value\", 42.99}\n  }}\n};\n```\n\nNote that in all these cases, you never need to \"tell\" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://nlohmann.github.io/json/api/basic_json/array/) and [`json::object()`](https://nlohmann.github.io/json/api/basic_json/object/) will help:\n\n```cpp\n// a way to express the empty array []\njson empty_array_explicit = json::array();\n\n// ways to express the empty object {}\njson empty_object_implicit = json({});\njson empty_object_explicit = json::object();\n\n// a way to express an _array_ of key/value pairs [[\"currency\", \"USD\"], [\"value\", 42.99]]\njson array_not_object = json::array({ {\"currency\", \"USD\"}, {\"value\", 42.99} });\n```\n\n### Serialization / Deserialization\n\n#### To/from strings\n\nYou can create a JSON value (deserialization) by appending `_json` to a string literal:\n\n```cpp\n// create object from string literal\njson j = \"{ \\\"happy\\\": true, \\\"pi\\\": 3.141 }\"_json;\n\n// or even nicer with a raw string literal\nauto j2 = R\"(\n  {\n    \"happy\": true,\n    \"pi\": 3.141\n  }\n)\"_json;\n```\n\nNote that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = \"{ \\\"happy\\\": true, \\\"pi\\\": 3.141 }\"` would just store the string `\"{ \"happy\": true, \"pi\": 3.141 }\"` rather than parsing the actual object.\n\nThe above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/api/basic_json/parse/):\n\n```cpp\n// parse explicitly\nauto j3 = json::parse(R\"({\"happy\": true, \"pi\": 3.141})\");\n```\n\nYou can also get a string representation of a JSON value (serialize):\n\n```cpp\n// explicit conversion to string\nstd::string s = j.dump();    // {\"happy\":true,\"pi\":3.141}\n\n// serialization with pretty printing\n// pass in the amount of spaces to indent\nstd::cout << j.dump(4) << std::endl;\n// {\n//     \"happy\": true,\n//     \"pi\": 3.141\n// }\n```\n\nNote the difference between serialization and assignment:\n\n```cpp\n// store a string in a JSON value\njson j_string = \"this is a string\";\n\n// retrieve the string value\nauto cpp_string = j_string.get<std::string>();\n// retrieve the string value (alternative when an variable already exists)\nstd::string cpp_string2;\nj_string.get_to(cpp_string2);\n\n// retrieve the serialized value (explicit JSON serialization)\nstd::string serialized_string = j_string.dump();\n\n// output of original string\nstd::cout << cpp_string << \" == \" << cpp_string2 << \" == \" << j_string.get<std::string>() << '\\n';\n// output of serialized value\nstd::cout << j_string << \" == \" << serialized_string << std::endl;\n```\n\n[`.dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) returns the originally stored string value.\n\nNote the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.\n\n#### To/from streams (e.g. files, string streams)\n\nYou can also use streams to serialize and deserialize:\n\n```cpp\n// deserialize from standard input\njson j;\nstd::cin >> j;\n\n// serialize to standard output\nstd::cout << j;\n\n// the setw manipulator was overloaded to set the indentation for pretty printing\nstd::cout << std::setw(4) << j << std::endl;\n```\n\nThese operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files:\n\n```cpp\n// read a JSON file\nstd::ifstream i(\"file.json\");\njson j;\ni >> j;\n\n// write prettified JSON to another file\nstd::ofstream o(\"pretty.json\");\no << std::setw(4) << j << std::endl;\n```\n\nPlease note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use.\n\n#### Read from iterator range\n\nYou can also parse JSON from an iterator range; that is, from any container accessible by iterators whose `value_type` is an integral type of 1, 2 or 4 bytes, which will be interpreted as UTF-8, UTF-16 and UTF-32 respectively. For instance, a `std::vector<std::uint8_t>`, or a `std::list<std::uint16_t>`:\n\n```cpp\nstd::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};\njson j = json::parse(v.begin(), v.end());\n```\n\nYou may leave the iterators for the range [begin, end):\n\n```cpp\nstd::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};\njson j = json::parse(v);\n```\n\n#### Custom data source\n\nSince the parse function accepts arbitrary iterator ranges, you can provide your own data sources by implementing the `LegacyInputIterator` concept.\n\n```cpp\nstruct MyContainer {\n  void advance();\n  const char& get_current();\n};\n\nstruct MyIterator {\n    using difference_type = std::ptrdiff_t;\n    using value_type = char;\n    using pointer = const char*;\n    using reference = const char&;\n    using iterator_category = std::input_iterator_tag;\n\n    MyIterator& operator++() {\n        MyContainer.advance();\n        return *this;\n    }\n\n    bool operator!=(const MyIterator& rhs) const {\n        return rhs.target != target;\n    }\n\n    reference operator*() const {\n        return target.get_current();\n    }\n\n    MyContainer* target = nullptr;\n};\n\nMyIterator begin(MyContainer& tgt) {\n    return MyIterator{&tgt};\n}\n\nMyIterator end(const MyContainer&) {\n    return {};\n}\n\nvoid foo() {\n    MyContainer c;\n    json j = json::parse(c);\n}\n```\n\n#### SAX interface\n\nThe library uses a SAX-like interface with the following functions:\n\n```cpp\n// called when null is parsed\nbool null();\n\n// called when a boolean is parsed; value is passed\nbool boolean(bool val);\n\n// called when a signed or unsigned integer number is parsed; value is passed\nbool number_integer(number_integer_t val);\nbool number_unsigned(number_unsigned_t val);\n\n// called when a floating-point number is parsed; value and original string is passed\nbool number_float(number_float_t val, const string_t& s);\n\n// called when a string is parsed; value is passed and can be safely moved away\nbool string(string_t& val);\n// called when a binary value is parsed; value is passed and can be safely moved away\nbool binary(binary_t& val);\n\n// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)\nbool start_object(std::size_t elements);\nbool end_object();\nbool start_array(std::size_t elements);\nbool end_array();\n// called when an object key is parsed; value is passed and can be safely moved away\nbool key(string_t& val);\n\n// called when a parse error occurs; byte position, the last token, and an exception is passed\nbool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);\n```\n\nThe return value of each function determines whether parsing should proceed.\n\nTo implement your own SAX handler, proceed as follows:\n\n1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax<json>` as base class, but you can also use any class where the functions described above are implemented and public.\n2. Create an object of your SAX interface class, e.g. `my_sax`.\n3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.\n\nNote the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a  `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp).\n\n### STL-like access\n\nWe designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement.\n\n```cpp\n// create an array using push_back\njson j;\nj.push_back(\"foo\");\nj.push_back(1);\nj.push_back(true);\n\n// also use emplace_back\nj.emplace_back(1.78);\n\n// iterate the array\nfor (json::iterator it = j.begin(); it != j.end(); ++it) {\n  std::cout << *it << '\\n';\n}\n\n// range-based for\nfor (auto& element : j) {\n  std::cout << element << '\\n';\n}\n\n// getter/setter\nconst auto tmp = j[0].get<std::string>();\nj[1] = 42;\nbool foo = j.at(2);\n\n// comparison\nj == R\"([\"foo\", 1, true, 1.78])\"_json;  // true\n\n// other stuff\nj.size();     // 4 entries\nj.empty();    // false\nj.type();     // json::value_t::array\nj.clear();    // the array is empty again\n\n// convenience type checkers\nj.is_null();\nj.is_boolean();\nj.is_number();\nj.is_object();\nj.is_array();\nj.is_string();\n\n// create an object\njson o;\no[\"foo\"] = 23;\no[\"bar\"] = false;\no[\"baz\"] = 3.141;\n\n// also use emplace\no.emplace(\"weather\", \"sunny\");\n\n// special iterator member functions for objects\nfor (json::iterator it = o.begin(); it != o.end(); ++it) {\n  std::cout << it.key() << \" : \" << it.value() << \"\\n\";\n}\n\n// the same code as range for\nfor (auto& el : o.items()) {\n  std::cout << el.key() << \" : \" << el.value() << \"\\n\";\n}\n\n// even easier with structured bindings (C++17)\nfor (auto& [key, value] : o.items()) {\n  std::cout << key << \" : \" << value << \"\\n\";\n}\n\n// find an entry\nif (o.contains(\"foo\")) {\n  // there is an entry with key \"foo\"\n}\n\n// or via find and an iterator\nif (o.find(\"foo\") != o.end()) {\n  // there is an entry with key \"foo\"\n}\n\n// or simpler using count()\nint foo_present = o.count(\"foo\"); // 1\nint fob_present = o.count(\"fob\"); // 0\n\n// delete an entry\no.erase(\"foo\");\n```\n\n\n### Conversion from STL containers\n\nAny sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container.\n\n```cpp\nstd::vector<int> c_vector {1, 2, 3, 4};\njson j_vec(c_vector);\n// [1, 2, 3, 4]\n\nstd::deque<double> c_deque {1.2, 2.3, 3.4, 5.6};\njson j_deque(c_deque);\n// [1.2, 2.3, 3.4, 5.6]\n\nstd::list<bool> c_list {true, true, false, true};\njson j_list(c_list);\n// [true, true, false, true]\n\nstd::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};\njson j_flist(c_flist);\n// [12345678909876, 23456789098765, 34567890987654, 45678909876543]\n\nstd::array<unsigned long, 4> c_array {{1, 2, 3, 4}};\njson j_array(c_array);\n// [1, 2, 3, 4]\n\nstd::set<std::string> c_set {\"one\", \"two\", \"three\", \"four\", \"one\"};\njson j_set(c_set); // only one entry for \"one\" is used\n// [\"four\", \"one\", \"three\", \"two\"]\n\nstd::unordered_set<std::string> c_uset {\"one\", \"two\", \"three\", \"four\", \"one\"};\njson j_uset(c_uset); // only one entry for \"one\" is used\n// maybe [\"two\", \"three\", \"four\", \"one\"]\n\nstd::multiset<std::string> c_mset {\"one\", \"two\", \"one\", \"four\"};\njson j_mset(c_mset); // both entries for \"one\" are used\n// maybe [\"one\", \"two\", \"one\", \"four\"]\n\nstd::unordered_multiset<std::string> c_umset {\"one\", \"two\", \"one\", \"four\"};\njson j_umset(c_umset); // both entries for \"one\" are used\n// maybe [\"one\", \"two\", \"one\", \"four\"]\n```\n\nLikewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container.\n\n```cpp\nstd::map<std::string, int> c_map { {\"one\", 1}, {\"two\", 2}, {\"three\", 3} };\njson j_map(c_map);\n// {\"one\": 1, \"three\": 3, \"two\": 2 }\n\nstd::unordered_map<const char*, double> c_umap { {\"one\", 1.2}, {\"two\", 2.3}, {\"three\", 3.4} };\njson j_umap(c_umap);\n// {\"one\": 1.2, \"two\": 2.3, \"three\": 3.4}\n\nstd::multimap<std::string, bool> c_mmap { {\"one\", true}, {\"two\", true}, {\"three\", false}, {\"three\", true} };\njson j_mmap(c_mmap); // only one entry for key \"three\" is used\n// maybe {\"one\": true, \"two\": true, \"three\": true}\n\nstd::unordered_multimap<std::string, bool> c_ummap { {\"one\", true}, {\"two\", true}, {\"three\", false}, {\"three\", true} };\njson j_ummap(c_ummap); // only one entry for key \"three\" is used\n// maybe {\"one\": true, \"two\": true, \"three\": true}\n```\n\n### JSON Pointer and JSON Patch\n\nThe library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows to describe differences between two JSON values - effectively allowing patch and diff operations known from Unix.\n\n```cpp\n// a JSON value\njson j_original = R\"({\n  \"baz\": [\"one\", \"two\", \"three\"],\n  \"foo\": \"bar\"\n})\"_json;\n\n// access members with a JSON pointer (RFC 6901)\nj_original[\"/baz/1\"_json_pointer];\n// \"two\"\n\n// a JSON patch (RFC 6902)\njson j_patch = R\"([\n  { \"op\": \"replace\", \"path\": \"/baz\", \"value\": \"boo\" },\n  { \"op\": \"add\", \"path\": \"/hello\", \"value\": [\"world\"] },\n  { \"op\": \"remove\", \"path\": \"/foo\"}\n])\"_json;\n\n// apply the patch\njson j_result = j_original.patch(j_patch);\n// {\n//    \"baz\": \"boo\",\n//    \"hello\": [\"world\"]\n// }\n\n// calculate a JSON patch from two JSON values\njson::diff(j_result, j_original);\n// [\n//   { \"op\":\" replace\", \"path\": \"/baz\", \"value\": [\"one\", \"two\", \"three\"] },\n//   { \"op\": \"remove\",\"path\": \"/hello\" },\n//   { \"op\": \"add\", \"path\": \"/foo\", \"value\": \"bar\" }\n// ]\n```\n\n### JSON Merge Patch\n\nThe library supports **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format. Instead of using JSON Pointer (see above) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified.\n\n```cpp\n// a JSON value\njson j_document = R\"({\n  \"a\": \"b\",\n  \"c\": {\n    \"d\": \"e\",\n    \"f\": \"g\"\n  }\n})\"_json;\n\n// a patch\njson j_patch = R\"({\n  \"a\":\"z\",\n  \"c\": {\n    \"f\": null\n  }\n})\"_json;\n\n// apply the patch\nj_document.merge_patch(j_patch);\n// {\n//  \"a\": \"z\",\n//  \"c\": {\n//    \"d\": \"e\"\n//  }\n// }\n```\n\n### Implicit conversions\n\nSupported types can be implicitly converted to JSON values.\n\nIt is recommended to **NOT USE** implicit conversions **FROM** a JSON value.\nYou can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958).\nYou can switch off implicit conversions by defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` before including the `json.hpp` header. When using CMake, you can also achieve this by setting the option `JSON_ImplicitConversions` to `OFF`.\n\n```cpp\n// strings\nstd::string s1 = \"Hello, world!\";\njson js = s1;\nauto s2 = js.get<std::string>();\n// NOT RECOMMENDED\nstd::string s3 = js;\nstd::string s4;\ns4 = js;\n\n// Booleans\nbool b1 = true;\njson jb = b1;\nauto b2 = jb.get<bool>();\n// NOT RECOMMENDED\nbool b3 = jb;\nbool b4;\nb4 = jb;\n\n// numbers\nint i = 42;\njson jn = i;\nauto f = jn.get<double>();\n// NOT RECOMMENDED\ndouble f2 = jb;\ndouble f3;\nf3 = jb;\n\n// etc.\n```\n\nNote that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly:\n\n```cpp\nchar ch = 'A';                       // ASCII value 65\njson j_default = ch;                 // stores integer number 65\njson j_string = std::string(1, ch);  // stores string \"A\"\n```\n\n### Arbitrary types conversions\n\nEvery type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines:\n\n```cpp\nnamespace ns {\n    // a simple struct to model a person\n    struct person {\n        std::string name;\n        std::string address;\n        int age;\n    };\n}\n\nns::person p = {\"Ned Flanders\", \"744 Evergreen Terrace\", 60};\n\n// convert to JSON: copy each value into the JSON object\njson j;\nj[\"name\"] = p.name;\nj[\"address\"] = p.address;\nj[\"age\"] = p.age;\n\n// ...\n\n// convert from JSON: copy each value from the JSON object\nns::person p {\n    j[\"name\"].get<std::string>(),\n    j[\"address\"].get<std::string>(),\n    j[\"age\"].get<int>()\n};\n```\n\nIt works, but that's quite a lot of boilerplate... Fortunately, there's a better way:\n\n```cpp\n// create a person\nns::person p {\"Ned Flanders\", \"744 Evergreen Terrace\", 60};\n\n// conversion: person -> json\njson j = p;\n\nstd::cout << j << std::endl;\n// {\"address\":\"744 Evergreen Terrace\",\"age\":60,\"name\":\"Ned Flanders\"}\n\n// conversion: json -> person\nauto p2 = j.get<ns::person>();\n\n// that's it\nassert(p == p2);\n```\n\n#### Basic usage\n\nTo make this work with one of your types, you only need to provide two functions:\n\n```cpp\nusing json = nlohmann::json;\n\nnamespace ns {\n    void to_json(json& j, const person& p) {\n        j = json{{\"name\", p.name}, {\"address\", p.address}, {\"age\", p.age}};\n    }\n\n    void from_json(const json& j, person& p) {\n        j.at(\"name\").get_to(p.name);\n        j.at(\"address\").get_to(p.address);\n        j.at(\"age\").get_to(p.age);\n    }\n} // namespace ns\n```\n\nThat's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called.\nLikewise, when calling `get<your_type>()` or `get_to(your_type&)`, the `from_json` method will be called.\n\nSome important things:\n\n* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).\n* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise.\n* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.)\n* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/api/basic_json/at/) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.\n* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.\n\n#### Simplify your life with macros\n\nIf you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate.\n\nThere are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object:\n\n- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for.\n- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members.\n\nIn both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members.\n\n##### Examples\n\nThe `to_json`/`from_json` functions for the `person` struct above can be created with:\n\n```cpp\nnamespace ns {\n    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)\n}\n```\n\nHere is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed:\n\n```cpp\nnamespace ns {\n    class address {\n      private:\n        std::string street;\n        int housenumber;\n        int postcode;\n\n      public:\n        NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)\n    };\n}\n```\n\n#### How do I convert third-party types?\n\nThis requires a bit more advanced technique. But first, let's see how this conversion mechanism works:\n\nThe library uses **JSON Serializers** to convert types to json.\nThe default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)).\n\nIt is implemented like this (simplified):\n\n```cpp\ntemplate <typename T>\nstruct adl_serializer {\n    static void to_json(json& j, const T& value) {\n        // calls the \"to_json\" method in T's namespace\n    }\n\n    static void from_json(const json& j, T& value) {\n        // same thing, but with the \"from_json\" method\n    }\n};\n```\n\nThis serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...\n\nTo solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:\n\n```cpp\n// partial specialization (full specialization works too)\nnamespace nlohmann {\n    template <typename T>\n    struct adl_serializer<boost::optional<T>> {\n        static void to_json(json& j, const boost::optional<T>& opt) {\n            if (opt == boost::none) {\n                j = nullptr;\n            } else {\n              j = *opt; // this will call adl_serializer<T>::to_json which will\n                        // find the free function to_json in T's namespace!\n            }\n        }\n\n        static void from_json(const json& j, boost::optional<T>& opt) {\n            if (j.is_null()) {\n                opt = boost::none;\n            } else {\n                opt = j.get<T>(); // same as above, but with\n                                  // adl_serializer<T>::from_json\n            }\n        }\n    };\n}\n```\n\n#### How can I use `get()` for non-default constructible/non-copyable types?\n\nThere is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:\n\n```cpp\nstruct move_only_type {\n    move_only_type() = delete;\n    move_only_type(int ii): i(ii) {}\n    move_only_type(const move_only_type&) = delete;\n    move_only_type(move_only_type&&) = default;\n\n    int i;\n};\n\nnamespace nlohmann {\n    template <>\n    struct adl_serializer<move_only_type> {\n        // note: the return type is no longer 'void', and the method only takes\n        // one argument\n        static move_only_type from_json(const json& j) {\n            return {j.get<int>()};\n        }\n\n        // Here's the catch! You must provide a to_json method! Otherwise you\n        // will not be able to convert move_only_type to json, since you fully\n        // specialized adl_serializer on that type\n        static void to_json(json& j, move_only_type t) {\n            j = t.i;\n        }\n    };\n}\n```\n\n#### Can I write my own serializer? (Advanced use)\n\nYes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp) in the test suite, to see a few examples.\n\nIf you write your own serializer, you'll need to do a few things:\n\n- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`)\n- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods\n- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL\n\nHere is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL.\n\n```cpp\n// You should use void as a second template argument\n// if you don't need compile-time checks on T\ntemplate<typename T, typename SFINAE = typename std::enable_if<sizeof(T) <= 32>::type>\nstruct less_than_32_serializer {\n    template <typename BasicJsonType>\n    static void to_json(BasicJsonType& j, T value) {\n        // we want to use ADL, and call the correct to_json overload\n        using nlohmann::to_json; // this method is called by adl_serializer,\n                                 // this is where the magic happens\n        to_json(j, value);\n    }\n\n    template <typename BasicJsonType>\n    static void from_json(const BasicJsonType& j, T& value) {\n        // same thing here\n        using nlohmann::from_json;\n        from_json(j, value);\n    }\n};\n```\n\nBe **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention:\n\n```cpp\ntemplate <typename T, void>\nstruct bad_serializer\n{\n    template <typename BasicJsonType>\n    static void to_json(BasicJsonType& j, const T& value) {\n      // this calls BasicJsonType::json_serializer<T>::to_json(j, value);\n      // if BasicJsonType::json_serializer == bad_serializer ... oops!\n      j = value;\n    }\n\n    template <typename BasicJsonType>\n    static void to_json(const BasicJsonType& j, T& value) {\n      // this calls BasicJsonType::json_serializer<T>::from_json(j, value);\n      // if BasicJsonType::json_serializer == bad_serializer ... oops!\n      value = j.template get<T>(); // oops!\n    }\n};\n```\n\n### Specializing enum conversion\n\nBy default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be undefined or a different enum value than was originally intended.\n\nIt is possible to more precisely specify how a given enum is mapped to and from JSON as shown below:\n\n```cpp\n// example enum type declaration\nenum TaskState {\n    TS_STOPPED,\n    TS_RUNNING,\n    TS_COMPLETED,\n    TS_INVALID=-1,\n};\n\n// map TaskState values to JSON as strings\nNLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {\n    {TS_INVALID, nullptr},\n    {TS_STOPPED, \"stopped\"},\n    {TS_RUNNING, \"running\"},\n    {TS_COMPLETED, \"completed\"},\n})\n```\n\nThe `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serialization code.\n\n**Usage:**\n\n```cpp\n// enum to JSON as string\njson j = TS_STOPPED;\nassert(j == \"stopped\");\n\n// json string to enum\njson j3 = \"running\";\nassert(j3.get<TaskState>() == TS_RUNNING);\n\n// undefined json value to enum (where the first map entry above is the default)\njson jPi = 3.14;\nassert(jPi.get<TaskState>() == TS_INVALID );\n```\n\nJust as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above,\n- `NLOHMANN_JSON_SERIALIZE_ENUM()` MUST be declared in your enum type's namespace (which can be the global namespace), or the library will not be able to locate it and it will default to integer serialization.\n- It MUST be available (e.g., proper headers must be included) everywhere you use the conversions.\n\nOther Important points:\n- When using `get<ENUM_TYPE>()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully.\n- If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON.\n\n### Binary formats (BSON, CBOR, MessagePack, and UBJSON)\n\nThough JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](https://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), and [UBJSON](https://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.\n\n```cpp\n// create a JSON value\njson j = R\"({\"compact\": true, \"schema\": 0})\"_json;\n\n// serialize to BSON\nstd::vector<std::uint8_t> v_bson = json::to_bson(j);\n\n// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\n// roundtrip\njson j_from_bson = json::from_bson(v_bson);\n\n// serialize to CBOR\nstd::vector<std::uint8_t> v_cbor = json::to_cbor(j);\n\n// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00\n\n// roundtrip\njson j_from_cbor = json::from_cbor(v_cbor);\n\n// serialize to MessagePack\nstd::vector<std::uint8_t> v_msgpack = json::to_msgpack(j);\n\n// 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00\n\n// roundtrip\njson j_from_msgpack = json::from_msgpack(v_msgpack);\n\n// serialize to UBJSON\nstd::vector<std::uint8_t> v_ubjson = json::to_ubjson(j);\n\n// 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D\n\n// roundtrip\njson j_from_ubjson = json::from_ubjson(v_ubjson);\n```\n\nThe library also supports binary types from BSON, CBOR (byte strings), and MessagePack (bin, ext, fixext). They are stored by default as `std::vector<std::uint8_t>` to be processed outside of the library.\n\n```cpp\n// CBOR byte string with payload 0xCAFE\nstd::vector<std::uint8_t> v = {0x42, 0xCA, 0xFE};\n\n// read value\njson j = json::from_cbor(v);\n\n// the JSON value has type binary\nj.is_binary(); // true\n\n// get reference to stored binary value\nauto& binary = j.get_binary();\n\n// the binary value has no subtype (CBOR has no binary subtypes)\nbinary.has_subtype(); // false\n\n// access std::vector<std::uint8_t> member functions\nbinary.size(); // 2\nbinary[0]; // 0xCA\nbinary[1]; // 0xFE\n\n// set subtype to 0x10\nbinary.set_subtype(0x10);\n\n// serialize to MessagePack\nauto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE\n```\n\n\n## Supported compilers\n\nThough it's 2021 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:\n\n- GCC 4.8 - 11.0 (and possibly later)\n- Clang 3.4 - 13.0 (and possibly later)\n- Apple Clang 9.1 - 12.4 (and possibly later)\n- Intel C++ Compiler 17.0.2 (and possibly later)\n- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)\n- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)\n- Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later)\n\nI would be happy to learn about other compilers/versions.\n\nPlease note:\n\n- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler.\n- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.\n\n    ```\n    APP_STL := c++_shared\n    NDK_TOOLCHAIN_VERSION := clang3.6\n    APP_CPPFLAGS += -frtti -fexceptions\n    ```\n\n    The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.\n\n- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code,  but rather with the compiler itself. On Android, see above to build with a newer environment.  For MinGW, please refer to [this site](https://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).\n\n- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.\n\nThe following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [Drone CI](https://cloud.drone.io/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions):\n\n| Compiler                                                          | Operating System   | CI Provider    |\n|-------------------------------------------------------------------|--------------------|----------------|\n| Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.2.1              | macOS 10.14.4      | Travis         |\n| Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.3                | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 11.0.0 (clang-1100.0.33.12); Xcode 11.2.1             | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 11.0.0 (clang-1100.0.33.17); Xcode 11.3.1             | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 11.0.3 (clang-1103.0.32.59); Xcode 11.4.1             | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.5               | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.6               | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.7               | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 12.0.0 (clang-1200.0.32.2); Xcode 12                  | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 12.0.0 (clang-1200.0.32.21); Xcode 12.1               | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 12.0.0 (clang-1200.0.32.21); Xcode 12.1.1             | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 12.0.0 (clang-1200.0.32.27); Xcode 12.2               | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 12.0.0 (clang-1200.0.32.28); Xcode 12.3               | macOS 10.15.7      | GitHub Actions |\n| Apple Clang 12.0.0 (clang-1200.0.32.29); Xcode 12.4               | macOS 10.15.7      | GitHub Actions |\n| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2)                                 | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 4.9.3 (Ubuntu 4.9.3-13ubuntu2)                                | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.12)                        | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 6.5.0 (Ubuntu 6.5.0-2ubuntu1~14.04.1)                         | Ubuntu 14.04.5 LTS | Travis         |\n| GCC 7.5.0 (Ubuntu 7.5.0-6ubuntu2)                                 | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)     | Windows-10.0.17763 | GitHub Actions |\n| GCC 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)     | Windows-10.0.17763 | GitHub Actions |\n| GCC 8.4.0 (Ubuntu 8.4.0-3ubuntu2)                                 | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)                          | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 10.2.0 (Ubuntu 10.2.0-5ubuntu1~20.04)                         | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 11.0.1 20210321 (experimental)                                | Ubuntu 20.04.2 LTS | GitHub Actions |\n| GCC 11.1.0                                                        | Ubuntu (aarch64)   | Drone CI       |\n| Clang 3.5.2 (3.5.2-3ubuntu1)                                      | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 3.6.2 (3.6.2-3ubuntu2)                                      | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 3.7.1 (3.7.1-2ubuntu2)                                      | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 3.8.0 (3.8.0-2ubuntu4)                                      | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 3.9.1 (3.9.1-4ubuntu3\\~16.04.2)                             | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 4.0.0 (4.0.0-1ubuntu1\\~16.04.2)                             | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 5.0.0 (5.0.0-3\\~16.04.1)                                    | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 6.0.1 (6.0.1-14)                                            | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 7.0.1 (7.0.1-12)                                            | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 8.0.1 (8.0.1-9)                                             | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 9.0.1 (9.0.1-12)                                            | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 10.0.0 (10.0.0-4ubuntu1)                                    | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 10.0.0 with GNU-like command-line                           | Windows-10.0.17763 | GitHub Actions |\n| Clang 11.0.0 with GNU-like command-line                           | Windows-10.0.17763 | GitHub Actions |\n| Clang 11.0.0 with MSVC-like command-line                          | Windows-10.0.17763 | GitHub Actions |\n| Clang 11.0.0 (11.0.0-2~ubuntu20.04.1)                             | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 12.0.0 (12.0.0-3ubuntu1~20.04.3)                            | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Clang 13.0.0 (13.0.0-++20210828094952+9c49fee5e7ac-1exp120210828075752.71 | Ubuntu 20.04.2 LTS | GitHub Actions |\n| Visual Studio 14 2015 MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor |\n| Visual Studio 15 2017 MSVC 19.16.27035.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor |\n| Visual Studio 15 2017 MSVC 19.16.27045.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | GitHub Actions |\n| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | GitHub Actions |\n| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | AppVeyor |\n\n\n## Integration\n\n[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add\n\n```cpp\n#include <nlohmann/json.hpp>\n\n// for convenience\nusing json = nlohmann::json;\n```\n\nto the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).\n\nYou can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`.\n\n### CMake\n\nYou can also use the `nlohmann_json::nlohmann_json` interface target in CMake.  This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags.\n\n#### External\n\nTo use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration:\n\n```cmake\n# CMakeLists.txt\nfind_package(nlohmann_json 3.2.0 REQUIRED)\n...\nadd_library(foo ...)\n...\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n\nThe package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree.\n\n#### Embedded\n\nTo embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file:\n\n```cmake\n# Typically you don't care so much for a third party library's tests to be\n# run from your own project's code.\nset(JSON_BuildTests OFF CACHE INTERNAL \"\")\n\n# If you only include this third party in PRIVATE source files, you do not\n# need to install it when your main project gets installed.\n# set(JSON_Install OFF CACHE INTERNAL \"\")\n\n# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it\n# unintended consequences that will break the build.  It's generally\n# discouraged (although not necessarily well documented as such) to use\n# include(...) for pulling in other CMake projects anyways.\nadd_subdirectory(nlohmann_json)\n...\nadd_library(foo ...)\n...\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n\n##### Embedded (FetchContent)\n\nSince CMake v3.11,\n[FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can\nbe used to automatically download the repository as a dependency at configure time.\n\nExample:\n```cmake\ninclude(FetchContent)\n\nFetchContent_Declare(json\n  GIT_REPOSITORY https://github.com/nlohmann/json.git\n  GIT_TAG v3.7.3)\n\nFetchContent_GetProperties(json)\nif(NOT json_POPULATED)\n  FetchContent_Populate(json)\n  add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)\nendif()\n\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n\n**Note**: The repository https://github.com/nlohmann/json download size is huge.\nIt contains all the dataset used for the benchmarks. You might want to depend on\na smaller repository. For instance, you might want to replace the URL above by\nhttps://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent\n\n#### Supporting Both\n\nTo allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following:\n\n``` cmake\n# Top level CMakeLists.txt\nproject(FOO)\n...\noption(FOO_USE_EXTERNAL_JSON \"Use an external JSON library\" OFF)\n...\nadd_subdirectory(thirdparty)\n...\nadd_library(foo ...)\n...\n# Note that the namespaced target will always be available regardless of the\n# import method\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n```cmake\n# thirdparty/CMakeLists.txt\n...\nif(FOO_USE_EXTERNAL_JSON)\n  find_package(nlohmann_json 3.2.0 REQUIRED)\nelse()\n  set(JSON_BuildTests OFF CACHE INTERNAL \"\")\n  add_subdirectory(nlohmann_json)\nendif()\n...\n```\n\n`thirdparty/nlohmann_json` is then a complete copy of this source tree.\n\n### Package Managers\n\n:beer: If you are using OS X and [Homebrew](https://brew.sh), just type `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for more information.\n\nIf you are using the [Meson Build System](https://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging.\n\nThe provided meson.build can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly.\n\nIf you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add [`nlohmann_json/x.y.z`](https://conan.io/center/nlohmann_json) to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages.\n\nIf you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging.\n\nIf you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging.\n\nIf you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).\n\nIf you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with `vcpkg install nlohmann-json` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging.\n\nIf you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).\n\nIf you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `\"nlohmann_json\", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).\n\nIf you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues).\n\nIf you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues).\n\nIf you are using [MSYS2](https://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages.\n\nIf you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package.\n\nIf you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository https://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml).\nPlease file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages.\n\nIf you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install \"https://github.com/nlohmann/json:develop\"` to get the latest version. Note you can change the branch \":develop\" to an existing tag or another branch.\n\nIf you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake:\n\n```cmake\nCPMAddPackage(\n    NAME nlohmann_json\n    GITHUB_REPOSITORY nlohmann/json\n    VERSION 3.9.1)\n```\n\n### Pkg-config\n\nIf you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed:\n\n```sh\npkg-config nlohmann_json --cflags\n```\n\nUsers of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`:\n\n```meson\njson = dependency('nlohmann_json', required: true)\n```\n\n\n## License\n\n<img align=\"right\" src=\"https://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png\">\n\nThe class is licensed under the [MIT License](https://opensource.org/licenses/MIT):\n\nCopyright &copy; 2013-2021 [Niels Lohmann](https://nlohmann.me)\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n\n* * *\n\nThe class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>\n\nThe class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](https://florian.loitsch.com/)\n\nThe class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).\n\nThe class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).\n\n## Contact\n\nIf you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new/choose). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases.\n\nOnly if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc).\n\n## Security\n\n[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69).\n\n## Thanks\n\nI deeply appreciate the help of the following people.\n\n<img src=\"https://raw.githubusercontent.com/nlohmann/json/develop/doc/avatars.png\" align=\"right\">\n\n- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization.\n- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes.\n- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries.\n- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang.\n- Tomas Åblad found a bug in the iterator implementation.\n- [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization.\n- [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing.\n- [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0.\n- [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators.\n- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping.\n- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.\n- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio.\n- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.\n- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.\n- [dariomt](https://github.com/dariomt) fixed some typos in the examples.\n- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.\n- [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue.\n- [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation.\n- [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference.\n- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values.\n- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK.\n- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio.\n- [406345](https://github.com/406345) fixed two small warnings.\n- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.\n- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.\n- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.\n- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.\n- [msm-](https://github.com/msm-) added support for American Fuzzy Lop.\n- [Annihil](https://github.com/Annihil) fixed an example in the README file.\n- [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.\n- [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.\n- [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212).\n- [zewt](https://github.com/zewt) added useful notes to the README file about Android.\n- [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake.\n- [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files.\n- [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).\n- [Mário Feroldi](https://github.com/thelostt) fixed a small typo.\n- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.\n- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.\n- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI.\n- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks.\n- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.\n- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.\n- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.\n- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.\n- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.\n- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.\n- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.\n- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.\n- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning.\n- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.\n- [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.\n- [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers.\n- [Jonathan Lee](https://github.com/vjon) fixed an example in the README file.\n- [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.\n- [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.\n- [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types.\n- [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example.\n- [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite.\n- [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section.\n- [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README.\n- [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s.\n- [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation.\n- [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings.\n- [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible.\n- [ftillier](https://github.com/ftillier) fixed a compiler warning.\n- [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped.\n- [Fytch](https://github.com/Fytch) found a bug in the documentation.\n- [Jay Sistar](https://github.com/Type1J) implemented a Meson build description.\n- [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation.\n- [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager.\n- [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`.\n- [Mike Tzou](https://github.com/Chocobo1) fixed some typos.\n- [amrcode](https://github.com/amrcode) noted a misleading documentation about comparison of floats.\n- [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `<iostream>` with `<iosfwd>`.\n- [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library.\n- [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists.\n- [Greg Hurrell](https://github.com/wincent) fixed a typo.\n- [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo.\n- [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler.\n- [Markus Werle](https://github.com/daixtrose) fixed a typo.\n- [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check.\n- [Alex](https://github.com/leha-bot) noted an error in a code sample.\n- [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped fixing them.\n- [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams.\n- [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error.\n- [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings.\n- [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file.\n- [pvleuven](https://github.com/pvleuven) helped fixing a warning in ICC.\n- [Pavel](https://github.com/crea7or) helped fixing some warnings in MSVC.\n- [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`.\n- [Mitja](https://github.com/Itja) fixed some typos.\n- [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links.\n- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view.\n- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.\n- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.\n- [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed.\n- [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README.\n- [zerodefect](https://github.com/zerodefect) fixed a compiler warning.\n- [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior.\n- [mark-99](https://github.com/mark-99) helped fixing an ICC error.\n- [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file.\n- [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings.\n- [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.\n- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.\n- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.\n- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type.\n- [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.\n- [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).\n- [Carlos O'Ryan](https://github.com/coryan) fixed a typo.\n- [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section.\n- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration.\n- [Jan Schöppach](https://github.com/dns13) fixed a typo.\n- [martin-mfg](https://github.com/martin-mfg) fixed a typo.\n- [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`.\n- [agrianius](https://github.com/agrianius) added code to use alternative string implementations.\n- [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function.\n- [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com).\n- [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode.\n- [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.\n- [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library.\n- [thyu](https://github.com/thyu) fixed a compiler warning.\n- [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2.\n- [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library.\n- [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition.\n- [Ben Berman](https://github.com/rivertam) made some error messages more understandable.\n- [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler.\n- [mandreyel](https://github.com/mandreyel) fixed a compilation problem.\n- [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file.\n- [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8.\n- [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory.\n- [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning.\n- [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define a enum/JSON mapping.\n- [efp](https://github.com/efp) added line and column information to parse errors.\n- [julian-becker](https://github.com/julian-becker) added BSON support.\n- [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings.\n- [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version).\n- [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`.\n- [kjpus](https://github.com/kjpus) fixed a link in the documentation.\n- [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation.\n- [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning.\n- [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.\n- [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.\n- [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.\n- [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace.\n- [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12.\n- [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion.\n- [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC.\n- [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers.\n- [John-Mark](https://github.com/johnmarkwayve) noted a missing header.\n- [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0.\n- [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0.\n- [Ivor Wanders](https://github.com/iwanders) helped reducing the CMake requirement to version 3.1.\n- [njlr](https://github.com/njlr) updated the Buckaroo instructions.\n- [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS.\n- [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and  implemented the `contains()` function.\n- [past-due](https://github.com/past-due) suppressed an unfixable warning.\n- [Elvis Oric](https://github.com/elvisoric) improved Meson support.\n- [Matěj Plch](https://github.com/Afforix) fixed an example in the README.\n- [Mark Beckwith](https://github.com/wythe) fixed a typo.\n- [scinart](https://github.com/scinart) fixed bug in the serializer.\n- [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers.\n- [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda.\n- [Michele Caini](https://github.com/skypjack) fixed links in the README.\n- [Hani](https://github.com/hnkb) documented how to install the library with NuGet.\n- [Mark Beckwith](https://github.com/wythe) fixed a typo.\n- [yann-morin-1998](https://github.com/yann-morin-1998) helped reducing the CMake requirement to version 3.1.\n- [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro.\n- [remyabel](https://github.com/remyabel) added GNUInstallDirs to the CMake files.\n- [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test.\n- [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method.\n- [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning.\n- [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/onqtam/doctest)\n- [Juncheng E](https://github.com/ejcjason) fixed a typo.\n- [tete17](https://github.com/tete17) fixed a bug in the `contains` function.\n- [Xav83](https://github.com/Xav83) fixed some cppcheck warnings.\n- [0xflotus](https://github.com/0xflotus) fixed some typos.\n- [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`.\n- [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types.\n- [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly.\n- [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos.\n- [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from  `std::pair` and `std::tuple` to `json`.\n- [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization.\n- [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check.\n- [Chen](https://github.com/dota17) fixed numerous issues in the library.\n- [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1.\n- [Alex](https://github.com/gistrec) fixed an MSVC warning.\n- [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR.\n- [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters.\n- [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`.\n- [Rimas Misevičius](https://github.com/rmisev) fixed an error message.\n- [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README.\n- [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent.\n- [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON.\n- [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak.\n- [Evgenii Sopov](https://github.com/sea-kg) integrated the library to the wsjcpp package manager.\n- [Sergey Linev](https://github.com/linev) fixed a compiler warning.\n- [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright.\n- [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) fixed a compilation issue with MSVC.\n- [Alexander “weej” Jones](https://github.com/alex-weej) fixed an example in the README.\n- [Antoine Cœur](https://github.com/Coeur) fixed some typos in the documentation.\n- [jothepro](https://github.com/jothepro) updated links to the Hunter package.\n- [Dave Lee](https://github.com/kastiglione) fixed link in the README.\n- [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager.\n- [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README.\n- [Sonu Lohani](https://github.com/sonulohani) fixed a warning.\n- [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source.\n- [Konstantin Podsvirov](https://github.com/podsvirov) fixed the MSYS2 package documentation.\n- [Tridacnid](https://github.com/Tridacnid) improved the CMake tests.\n- [Michael](https://github.com/MBalszun) fixed MSVC warnings.\n- [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation.\n- [XyFreak](https://github.com/XyFreak) fixed a compiler warning.\n- [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README.\n- [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input.\n- [AODQ](https://github.com/AODQ) fixed a compiler warning.\n- [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline.\n- [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.\n- [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values.\n- [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation.\n- [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes.\n- [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`.\n- [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config.\n- [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.\n- [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support.\n- [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`.\n- [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer.\n- Lars Wirzenius reviewed the README file.\n- [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts.\n- [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation.\n- [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds.\n- [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support.\n- [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning.\n- [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests.\n- [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files.\n- [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters.\n- [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file.\n- [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README.\n- [abbaswasim](https://github.com/abbaswasim) fixed an example from the README.\n- [Remy Jette](https://github.com/remyjette) fixed a warning.\n- [Fraser](https://github.com/frasermarlow) fixed the documentation.\n- [Ben Beasley](https://github.com/musicinmybrain) updated doctest.\n- [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc.\n- [raduteo](https://github.com/raduteo) fixed a warning.\n- [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support.\n- [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo.\n- [jpl-mac](https://github.com/jpl-mac) allowed to treat the library as a system header in CMake.\n- [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file.\n- [offa](https://github.com/offa) added a link to Conan Center to the documentation.\n- [TotalCaesar659](https://github.com/TotalCaesar659) updated the links in the documentation to use HTTPS.\n- [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch.\n- [Louis Dionne](https://github.com/ldionne) fixed a conversion operator.\n- [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent.\n- [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings.\n- [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings.\n- [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names.\n- [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core.\n- [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`.\n- [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS`.\n- [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers.\n- [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`.\n\nThanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.\n\n\n## Used third-party tools\n\nThe library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!\n\n- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file\n- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing\n- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows\n- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation\n- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers\n- [**CMake**](https://cmake.org) for build automation\n- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)\n- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)\n- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)\n- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis\n- [**doctest**](https://github.com/onqtam/doctest) for the unit tests\n- [**Doxygen**](https://www.doxygen.nl/index.html) to generate [documentation](https://nlohmann.github.io/json/doxygen/index.html)\n- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages\n- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)\n- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks\n- [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros\n- [**lcov**](http://ltp.sourceforge.net/coverage/lcov.php) to process coverage information and create a HTML view\n- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz\n- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json))\n- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.\n- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](https://wandbox.org)\n- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS\n- [**Valgrind**](https://valgrind.org) to check for correct memory management\n- [**Wandbox**](https://wandbox.org) for [online examples](https://wandbox.org/permlink/1mp10JbaANo6FUc7)\n\n\n## Projects using JSON for Modern C++\n\nThe library is currently used in Apple macOS Sierra and iOS 10. I am not sure what they are using the library for, but I am happy that it runs on so many devices.\n\n\n## Notes\n\n### Character encoding\n\nThe library supports **Unicode input** as follows:\n\n- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1).\n- `std::u16string` and `std::u32string` can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers.\n- Other encodings such as Latin-1 or ISO 8859-1 are **not** supported and will yield parse or serialization errors.\n- [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.\n- Invalid surrogates (e.g., incomplete pairs such as `\\uDEAD`) will yield parse errors.\n- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.\n- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.\n- To store wide strings (e.g., `std::wstring`), you need to convert them to a a UTF-8 encoded `std::string` before, see [an example](https://json.nlohmann.me/home/faq/#wide-string-handling).\n\n### Comments in JSON\n\nThis library does not support comments by default. It does so for three reasons:\n\n1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript.\n2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012:\n\n\t> I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability.  I know that the lack of comments makes some people sad, but it shouldn't.\n\n\t> Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser.\n\n3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.\n\nHowever, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.\n\n### Order of object keys\n\nBy default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as \"an unordered collection of zero or more name/value pairs\".\n\nIf you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).\n\n### Memory Release\n\nWe checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks.\n\nIf you find that a parsing program with this library does not release memory, please consider the following case and it maybe unrelated to this library.\n\n**Your program is compiled with glibc.** There is a tunable threshold that glibc uses to decide whether to actually return memory to the system or whether to cache it for later reuse. If in your program you make lots of small allocations and those small allocations are not a contiguous block and are presumably below the threshold, then they will not get returned to the OS.\nHere is a related issue [#1924](https://github.com/nlohmann/json/issues/1924).\n\n### Further notes\n\n- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/api/basic_json/operator%5B%5D/) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/api/basic_json/at/). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`.\n- As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.\n- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.\n- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not available for MSVC if exceptions are disabled, see [#2824](https://github.com/nlohmann/json/discussions/2824).\n\n## Execute unit tests\n\nTo compile and run the tests, you need to execute\n\n```sh\n$ mkdir build\n$ cd build\n$ cmake .. -DJSON_BuildTests=On\n$ cmake --build .\n$ ctest --output-on-failure\n```\n\nNote that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.\n\nIn case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.\n\nSome tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information.\n\nNote you need to call `cmake -LE \"not_reproducible|git_required\"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information.\n\nAs Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html) then.\n"
  },
  {
    "path": "d2mapapi/json/json.hpp",
    "content": "/*\n    __ _____ _____ _____\n __|  |   __|     |   | |  JSON for Modern C++\n|  |  |__   |  |  | | | |  version 3.10.4\n|_____|_____|_____|_|___|  https://github.com/nlohmann/json\n\nLicensed under the MIT License <http://opensource.org/licenses/MIT>.\nSPDX-License-Identifier: MIT\nCopyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.\n\nPermission is hereby  granted, free of charge, to any  person obtaining a copy\nof this software and associated  documentation files (the \"Software\"), to deal\nin the Software  without restriction, including without  limitation the rights\nto  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell\ncopies  of  the Software,  and  to  permit persons  to  whom  the Software  is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE  IS PROVIDED \"AS  IS\", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR\nIMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,\nFITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE\nAUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER\nLIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#ifndef INCLUDE_NLOHMANN_JSON_HPP_\n#define INCLUDE_NLOHMANN_JSON_HPP_\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3\n#define NLOHMANN_JSON_VERSION_MINOR 10\n#define NLOHMANN_JSON_VERSION_PATCH 4\n\n#include <algorithm> // all_of, find, for_each\n#include <cstddef> // nullptr_t, ptrdiff_t, size_t\n#include <functional> // hash, less\n#include <initializer_list> // initializer_list\n#ifndef JSON_NO_IO\n    #include <iosfwd> // istream, ostream\n#endif  // JSON_NO_IO\n#include <iterator> // random_access_iterator_tag\n#include <memory> // unique_ptr\n#include <numeric> // accumulate\n#include <string> // string, stoi, to_string\n#include <utility> // declval, forward, move, pair, swap\n#include <vector> // vector\n\n// #include <nlohmann/adl_serializer.hpp>\n\n\n#include <type_traits>\n#include <utility>\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n\n#include <algorithm> // transform\n#include <array> // array\n#include <forward_list> // forward_list\n#include <iterator> // inserter, front_inserter, end\n#include <map> // map\n#include <string> // string\n#include <tuple> // tuple, make_tuple\n#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible\n#include <unordered_map> // unordered_map\n#include <utility> // pair, declval\n#include <valarray> // valarray\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n\n#include <exception> // exception\n#include <stdexcept> // runtime_error\n#include <string> // to_string\n#include <vector> // vector\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t\n#include <string> // string\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////////////\n// JSON type enumeration //\n///////////////////////////\n\n/*!\n@brief the JSON type enumeration\n\nThis enumeration collects the different JSON types. It is internally used to\ndistinguish the stored values, and the functions @ref basic_json::is_null(),\n@ref basic_json::is_object(), @ref basic_json::is_array(),\n@ref basic_json::is_string(), @ref basic_json::is_boolean(),\n@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),\n@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),\n@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and\n@ref basic_json::is_structured() rely on it.\n\n@note There are three enumeration entries (number_integer, number_unsigned, and\nnumber_float), because the library distinguishes these three types for numbers:\n@ref basic_json::number_unsigned_t is used for unsigned integers,\n@ref basic_json::number_integer_t is used for signed integers, and\n@ref basic_json::number_float_t is used for floating-point numbers or to\napproximate integers which do not fit in the limits of their respective type.\n\n@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON\nvalue with the default value for a given type\n\n@since version 1.0.0\n*/\nenum class value_t : std::uint8_t\n{\n    null,             ///< null value\n    object,           ///< object (unordered set of name/value pairs)\n    array,            ///< array (ordered collection of values)\n    string,           ///< string value\n    boolean,          ///< boolean value\n    number_integer,   ///< number value (signed integer)\n    number_unsigned,  ///< number value (unsigned integer)\n    number_float,     ///< number value (floating-point)\n    binary,           ///< binary array (ordered collection of bytes)\n    discarded         ///< discarded by the parser callback function\n};\n\n/*!\n@brief comparison operator for JSON types\n\nReturns an ordering that is similar to Python:\n- order: null < boolean < number < object < array < string < binary\n- furthermore, each type is not smaller than itself\n- discarded values are not comparable\n- binary is represented as a b\"\" string in python and directly comparable to a\n  string; however, making a binary array directly comparable with a string would\n  be surprising behavior in a JSON file.\n\n@since version 1.0.0\n*/\ninline bool operator<(const value_t lhs, const value_t rhs) noexcept\n{\n    static constexpr std::array<std::uint8_t, 9> order = {{\n            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,\n            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,\n            6 /* binary */\n        }\n    };\n\n    const auto l_index = static_cast<std::size_t>(lhs);\n    const auto r_index = static_cast<std::size_t>(rhs);\n    return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/string_escape.hpp>\n\n\n#include <string>\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\n#include <utility> // declval, pair\n// #include <nlohmann/thirdparty/hedley/hedley.hpp>\n\n\n/* Hedley - https://nemequ.github.io/hedley\n * Created by Evan Nemerson <evan@nemerson.com>\n *\n * To the extent possible under law, the author(s) have dedicated all\n * copyright and related and neighboring rights to this software to\n * the public domain worldwide. This software is distributed without\n * any warranty.\n *\n * For details, see <http://creativecommons.org/publicdomain/zero/1.0/>.\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)\n#if defined(JSON_HEDLEY_VERSION)\n    #undef JSON_HEDLEY_VERSION\n#endif\n#define JSON_HEDLEY_VERSION 15\n\n#if defined(JSON_HEDLEY_STRINGIFY_EX)\n    #undef JSON_HEDLEY_STRINGIFY_EX\n#endif\n#define JSON_HEDLEY_STRINGIFY_EX(x) #x\n\n#if defined(JSON_HEDLEY_STRINGIFY)\n    #undef JSON_HEDLEY_STRINGIFY\n#endif\n#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)\n\n#if defined(JSON_HEDLEY_CONCAT_EX)\n    #undef JSON_HEDLEY_CONCAT_EX\n#endif\n#define JSON_HEDLEY_CONCAT_EX(a,b) a##b\n\n#if defined(JSON_HEDLEY_CONCAT)\n    #undef JSON_HEDLEY_CONCAT\n#endif\n#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)\n\n#if defined(JSON_HEDLEY_CONCAT3_EX)\n    #undef JSON_HEDLEY_CONCAT3_EX\n#endif\n#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c\n\n#if defined(JSON_HEDLEY_CONCAT3)\n    #undef JSON_HEDLEY_CONCAT3\n#endif\n#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)\n\n#if defined(JSON_HEDLEY_VERSION_ENCODE)\n    #undef JSON_HEDLEY_VERSION_ENCODE\n#endif\n#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)\n    #undef JSON_HEDLEY_VERSION_DECODE_MAJOR\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)\n    #undef JSON_HEDLEY_VERSION_DECODE_MINOR\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)\n    #undef JSON_HEDLEY_VERSION_DECODE_REVISION\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)\n\n#if defined(JSON_HEDLEY_GNUC_VERSION)\n    #undef JSON_HEDLEY_GNUC_VERSION\n#endif\n#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)\n    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#elif defined(__GNUC__)\n    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)\n    #undef JSON_HEDLEY_GNUC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_GNUC_VERSION)\n    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_MSVC_VERSION)\n    #undef JSON_HEDLEY_MSVC_VERSION\n#endif\n#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)\n#elif defined(_MSC_FULL_VER) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)\n#elif defined(_MSC_VER) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)\n    #undef JSON_HEDLEY_MSVC_VERSION_CHECK\n#endif\n#if !defined(JSON_HEDLEY_MSVC_VERSION)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)\n#elif defined(_MSC_VER) && (_MSC_VER >= 1400)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))\n#elif defined(_MSC_VER) && (_MSC_VER >= 1200)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))\n#else\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_VERSION)\n    #undef JSON_HEDLEY_INTEL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)\n    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)\n#elif defined(__INTEL_COMPILER) && !defined(__ICL)\n    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)\n    #undef JSON_HEDLEY_INTEL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_INTEL_VERSION)\n    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION)\n    #undef JSON_HEDLEY_INTEL_CL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)\n    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)\n    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION)\n    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_PGI_VERSION)\n    #undef JSON_HEDLEY_PGI_VERSION\n#endif\n#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)\n    #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)\n#endif\n\n#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)\n    #undef JSON_HEDLEY_PGI_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_PGI_VERSION)\n    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_SUNPRO_VERSION)\n    #undef JSON_HEDLEY_SUNPRO_VERSION\n#endif\n#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)\n#elif defined(__SUNPRO_C)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)\n#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)\n#elif defined(__SUNPRO_CC)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)\n#endif\n\n#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)\n    #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_SUNPRO_VERSION)\n    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)\n    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION\n#endif\n#if defined(__EMSCRIPTEN__)\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)\n#endif\n\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)\n    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_ARM_VERSION)\n    #undef JSON_HEDLEY_ARM_VERSION\n#endif\n#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)\n#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)\n#endif\n\n#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)\n    #undef JSON_HEDLEY_ARM_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_ARM_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_IBM_VERSION)\n    #undef JSON_HEDLEY_IBM_VERSION\n#endif\n#if defined(__ibmxl__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)\n#elif defined(__xlC__) && defined(__xlC_ver__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)\n#elif defined(__xlC__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)\n#endif\n\n#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)\n    #undef JSON_HEDLEY_IBM_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_IBM_VERSION)\n    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_VERSION)\n    #undef JSON_HEDLEY_TI_VERSION\n#endif\n#if \\\n    defined(__TI_COMPILER_VERSION__) && \\\n    ( \\\n      defined(__TMS470__) || defined(__TI_ARM__) || \\\n      defined(__MSP430__) || \\\n      defined(__TMS320C2000__) \\\n    )\n#if (__TI_COMPILER_VERSION__ >= 16000000)\n    #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n#endif\n\n#if defined(JSON_HEDLEY_TI_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_VERSION)\n    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION)\n    #undef JSON_HEDLEY_TI_CL2000_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)\n    #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION)\n    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL430_VERSION)\n    #undef JSON_HEDLEY_TI_CL430_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)\n    #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL430_VERSION)\n    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)\n    #undef JSON_HEDLEY_TI_ARMCL_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))\n    #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)\n    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION)\n    #undef JSON_HEDLEY_TI_CL6X_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)\n    #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION)\n    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION)\n    #undef JSON_HEDLEY_TI_CL7X_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)\n    #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION)\n    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)\n    #undef JSON_HEDLEY_TI_CLPRU_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)\n    #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)\n    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_CRAY_VERSION)\n    #undef JSON_HEDLEY_CRAY_VERSION\n#endif\n#if defined(_CRAYC)\n    #if defined(_RELEASE_PATCHLEVEL)\n        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)\n    #else\n        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)\n    #endif\n#endif\n\n#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)\n    #undef JSON_HEDLEY_CRAY_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_CRAY_VERSION)\n    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_IAR_VERSION)\n    #undef JSON_HEDLEY_IAR_VERSION\n#endif\n#if defined(__IAR_SYSTEMS_ICC__)\n    #if __VER__ > 1000\n        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))\n    #else\n        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)\n    #endif\n#endif\n\n#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)\n    #undef JSON_HEDLEY_IAR_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_IAR_VERSION)\n    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TINYC_VERSION)\n    #undef JSON_HEDLEY_TINYC_VERSION\n#endif\n#if defined(__TINYC__)\n    #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)\n#endif\n\n#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)\n    #undef JSON_HEDLEY_TINYC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TINYC_VERSION)\n    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_DMC_VERSION)\n    #undef JSON_HEDLEY_DMC_VERSION\n#endif\n#if defined(__DMC__)\n    #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)\n#endif\n\n#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)\n    #undef JSON_HEDLEY_DMC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_DMC_VERSION)\n    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_COMPCERT_VERSION)\n    #undef JSON_HEDLEY_COMPCERT_VERSION\n#endif\n#if defined(__COMPCERT_VERSION__)\n    #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)\n#endif\n\n#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)\n    #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_COMPCERT_VERSION)\n    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_PELLES_VERSION)\n    #undef JSON_HEDLEY_PELLES_VERSION\n#endif\n#if defined(__POCC__)\n    #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)\n    #undef JSON_HEDLEY_PELLES_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_PELLES_VERSION)\n    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_MCST_LCC_VERSION)\n    #undef JSON_HEDLEY_MCST_LCC_VERSION\n#endif\n#if defined(__LCC__) && defined(__LCC_MINOR__)\n    #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)\n#endif\n\n#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)\n    #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_MCST_LCC_VERSION)\n    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_VERSION)\n    #undef JSON_HEDLEY_GCC_VERSION\n#endif\n#if \\\n    defined(JSON_HEDLEY_GNUC_VERSION) && \\\n    !defined(__clang__) && \\\n    !defined(JSON_HEDLEY_INTEL_VERSION) && \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_ARM_VERSION) && \\\n    !defined(JSON_HEDLEY_CRAY_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL430_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \\\n    !defined(__COMPCERT__) && \\\n    !defined(JSON_HEDLEY_MCST_LCC_VERSION)\n    #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION\n#endif\n\n#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)\n    #undef JSON_HEDLEY_GCC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_GCC_VERSION)\n    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_ATTRIBUTE\n#endif\n#if \\\n  defined(__has_attribute) && \\\n  ( \\\n    (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \\\n  )\n#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)\n#else\n#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE\n#endif\n#if \\\n    defined(__has_cpp_attribute) && \\\n    defined(__cplusplus) && \\\n    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)\n    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS\n#endif\n#if !defined(__cplusplus) || !defined(__has_cpp_attribute)\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)\n#elif \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_IAR_VERSION) && \\\n    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \\\n    (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)\n#else\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_BUILTIN)\n    #undef JSON_HEDLEY_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)\n    #undef JSON_HEDLEY_GNUC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)\n    #undef JSON_HEDLEY_GCC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_FEATURE)\n    #undef JSON_HEDLEY_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_HAS_FEATURE(feature) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)\n    #undef JSON_HEDLEY_GNUC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)\n    #undef JSON_HEDLEY_GCC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_EXTENSION)\n    #undef JSON_HEDLEY_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)\n    #undef JSON_HEDLEY_GNUC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)\n    #undef JSON_HEDLEY_GCC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_WARNING)\n    #undef JSON_HEDLEY_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_HAS_WARNING(warning) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)\n    #undef JSON_HEDLEY_GNUC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_WARNING)\n    #undef JSON_HEDLEY_GCC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if \\\n    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n    defined(__clang__) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \\\n    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \\\n    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))\n    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)\n#else\n    #define JSON_HEDLEY_PRAGMA(value)\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)\n    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH\n#endif\n#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)\n    #undef JSON_HEDLEY_DIAGNOSTIC_POP\n#endif\n#if defined(__clang__)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"clang diagnostic push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"clang diagnostic pop\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"GCC diagnostic push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"GCC diagnostic pop\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))\n    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))\n#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"pop\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"diag_push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"diag_pop\")\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH\n    #define JSON_HEDLEY_DIAGNOSTIC_POP\n#endif\n\n/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for\n   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_\n#endif\n#if defined(__cplusplus)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wc++98-compat\")\n#    if JSON_HEDLEY_HAS_WARNING(\"-Wc++17-extensions\")\n#      if JSON_HEDLEY_HAS_WARNING(\"-Wc++1z-extensions\")\n#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++17-extensions\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++1z-extensions\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#      else\n#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++17-extensions\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#      endif\n#    else\n#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#    endif\n#  endif\n#endif\n#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x\n#endif\n\n#if defined(JSON_HEDLEY_CONST_CAST)\n    #undef JSON_HEDLEY_CONST_CAST\n#endif\n#if defined(__cplusplus)\n#  define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))\n#elif \\\n  JSON_HEDLEY_HAS_WARNING(\"-Wcast-qual\") || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \\\n        JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n        JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \\\n        ((T) (expr)); \\\n        JSON_HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_REINTERPRET_CAST)\n    #undef JSON_HEDLEY_REINTERPRET_CAST\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))\n#else\n    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_STATIC_CAST)\n    #undef JSON_HEDLEY_STATIC_CAST\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))\n#else\n    #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_CPP_CAST)\n    #undef JSON_HEDLEY_CPP_CAST\n#endif\n#if defined(__cplusplus)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wold-style-cast\")\n#    define JSON_HEDLEY_CPP_CAST(T, expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wold-style-cast\\\"\") \\\n    ((T) (expr)) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)\n#    define JSON_HEDLEY_CPP_CAST(T, expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"diag_suppress=Pe137\") \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))\n#  endif\n#else\n#  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wdeprecated-declarations\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"clang diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warning(disable:1478 1786)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1216,1444,1445\")\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1444\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1444\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1291,1718\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,symdeprecated,symdeprecated2)\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress=Pe1444,Pe1215\")\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warn(disable:2241)\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"clang diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"warning(disable:161)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 1675\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"GCC diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress=Pe161\")\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 161\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-attributes\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"clang diagnostic ignored \\\"-Wunknown-attributes\\\"\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"warning(disable:1292)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097,1098\")\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"error_messages(off,attrskipunsup)\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1173\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress=Pe1097\")\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wcast-qual\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"clang diagnostic ignored \\\"-Wcast-qual\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"warning(disable:2203 2331)\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"GCC diagnostic ignored \\\"-Wcast-qual\\\"\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunused-function\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma(\"clang diagnostic ignored \\\"-Wunused-function\\\"\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma(\"GCC diagnostic ignored \\\"-Wunused-function\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma(\"diag_suppress 3142\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION\n#endif\n\n#if defined(JSON_HEDLEY_DEPRECATED)\n    #undef JSON_HEDLEY_DEPRECATED\n#endif\n#if defined(JSON_HEDLEY_DEPRECATED_FOR)\n    #undef JSON_HEDLEY_DEPRECATED_FOR\n#endif\n#if \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated(\"Since \" # since))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated(\"Since \" #since \"; use \" #replacement))\n#elif \\\n    (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__(\"Since \" #since)))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__(\"Since \" #since \"; use \" #replacement)))\n#elif defined(__cplusplus) && (__cplusplus >= 201402L)\n    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated(\"Since \" #since)]])\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated(\"Since \" #since \"; use \" #replacement)]])\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DEPRECATED(since) _Pragma(\"deprecated\")\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma(\"deprecated\")\n#else\n    #define JSON_HEDLEY_DEPRECATED(since)\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)\n#endif\n\n#if defined(JSON_HEDLEY_UNAVAILABLE)\n    #undef JSON_HEDLEY_UNAVAILABLE\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__(\"Not available until \" #available_since)))\n#else\n    #define JSON_HEDLEY_UNAVAILABLE(available_since)\n#endif\n\n#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)\n    #undef JSON_HEDLEY_WARN_UNUSED_RESULT\n#endif\n#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)\n    #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))\n#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n#elif defined(_Check_return_) /* SAL */\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_\n#else\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)\n#endif\n\n#if defined(JSON_HEDLEY_SENTINEL)\n    #undef JSON_HEDLEY_SENTINEL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))\n#else\n    #define JSON_HEDLEY_SENTINEL(position)\n#endif\n\n#if defined(JSON_HEDLEY_NO_RETURN)\n    #undef JSON_HEDLEY_NO_RETURN\n#endif\n#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_NO_RETURN __noreturn\n#elif \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L\n    #define JSON_HEDLEY_NO_RETURN _Noreturn\n#elif defined(__cplusplus) && (__cplusplus >= 201103L)\n    #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_NO_RETURN _Pragma(\"does_not_return\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_NO_RETURN _Pragma(\"FUNC_NEVER_RETURNS;\")\n#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)\n#else\n    #define JSON_HEDLEY_NO_RETURN\n#endif\n\n#if defined(JSON_HEDLEY_NO_ESCAPE)\n    #undef JSON_HEDLEY_NO_ESCAPE\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)\n    #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))\n#else\n    #define JSON_HEDLEY_NO_ESCAPE\n#endif\n\n#if defined(JSON_HEDLEY_UNREACHABLE)\n    #undef JSON_HEDLEY_UNREACHABLE\n#endif\n#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)\n    #undef JSON_HEDLEY_UNREACHABLE_RETURN\n#endif\n#if defined(JSON_HEDLEY_ASSUME)\n    #undef JSON_HEDLEY_ASSUME\n#endif\n#if \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_ASSUME(expr) __assume(expr)\n#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)\n    #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)\n#elif \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)\n    #if defined(__cplusplus)\n        #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)\n    #else\n        #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)\n    #endif\n#endif\n#if \\\n    (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()\n#elif defined(JSON_HEDLEY_ASSUME)\n    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)\n#endif\n#if !defined(JSON_HEDLEY_ASSUME)\n    #if defined(JSON_HEDLEY_UNREACHABLE)\n        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))\n    #else\n        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)\n    #endif\n#endif\n#if defined(JSON_HEDLEY_UNREACHABLE)\n    #if  \\\n        JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)\n        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))\n    #else\n        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()\n    #endif\n#else\n    #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)\n#endif\n#if !defined(JSON_HEDLEY_UNREACHABLE)\n    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)\n#endif\n\nJSON_HEDLEY_DIAGNOSTIC_PUSH\n#if JSON_HEDLEY_HAS_WARNING(\"-Wpedantic\")\n    #pragma clang diagnostic ignored \"-Wpedantic\"\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wc++98-compat-pedantic\") && defined(__cplusplus)\n    #pragma clang diagnostic ignored \"-Wc++98-compat-pedantic\"\n#endif\n#if JSON_HEDLEY_GCC_HAS_WARNING(\"-Wvariadic-macros\",4,0,0)\n    #if defined(__clang__)\n        #pragma clang diagnostic ignored \"-Wvariadic-macros\"\n    #elif defined(JSON_HEDLEY_GCC_VERSION)\n        #pragma GCC diagnostic ignored \"-Wvariadic-macros\"\n    #endif\n#endif\n#if defined(JSON_HEDLEY_NON_NULL)\n    #undef JSON_HEDLEY_NON_NULL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)\n    #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))\n#else\n    #define JSON_HEDLEY_NON_NULL(...)\n#endif\nJSON_HEDLEY_DIAGNOSTIC_POP\n\n#if defined(JSON_HEDLEY_PRINTF_FORMAT)\n    #undef JSON_HEDLEY_PRINTF_FORMAT\n#endif\n#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))\n#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(format) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))\n#else\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)\n#endif\n\n#if defined(JSON_HEDLEY_CONSTEXPR)\n    #undef JSON_HEDLEY_CONSTEXPR\n#endif\n#if defined(__cplusplus)\n    #if __cplusplus >= 201103L\n        #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)\n    #endif\n#endif\n#if !defined(JSON_HEDLEY_CONSTEXPR)\n    #define JSON_HEDLEY_CONSTEXPR\n#endif\n\n#if defined(JSON_HEDLEY_PREDICT)\n    #undef JSON_HEDLEY_PREDICT\n#endif\n#if defined(JSON_HEDLEY_LIKELY)\n    #undef JSON_HEDLEY_LIKELY\n#endif\n#if defined(JSON_HEDLEY_UNLIKELY)\n    #undef JSON_HEDLEY_UNLIKELY\n#endif\n#if defined(JSON_HEDLEY_UNPREDICTABLE)\n    #undef JSON_HEDLEY_UNPREDICTABLE\n#endif\n#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)\n    #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))\n#endif\n#if \\\n  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability)  __builtin_expect_with_probability(!!(expr),    0   , (probability))\n#  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )\n#  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )\n#elif \\\n  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \\\n  JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#  define JSON_HEDLEY_PREDICT(expr, expected, probability) \\\n    (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \\\n    (__extension__ ({ \\\n        double hedley_probability_ = (probability); \\\n        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \\\n    }))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \\\n    (__extension__ ({ \\\n        double hedley_probability_ = (probability); \\\n        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \\\n    }))\n#  define JSON_HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)\n#  define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)\n#else\n#  define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))\n#  define JSON_HEDLEY_LIKELY(expr) (!!(expr))\n#  define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))\n#endif\n#if !defined(JSON_HEDLEY_UNPREDICTABLE)\n    #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)\n#endif\n\n#if defined(JSON_HEDLEY_MALLOC)\n    #undef JSON_HEDLEY_MALLOC\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_MALLOC _Pragma(\"returns_new_memory\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_MALLOC __declspec(restrict)\n#else\n    #define JSON_HEDLEY_MALLOC\n#endif\n\n#if defined(JSON_HEDLEY_PURE)\n    #undef JSON_HEDLEY_PURE\n#endif\n#if \\\n  JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#  define JSON_HEDLEY_PURE __attribute__((__pure__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n#  define JSON_HEDLEY_PURE _Pragma(\"does_not_write_global_data\")\n#elif defined(__cplusplus) && \\\n    ( \\\n      JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \\\n      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \\\n      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \\\n    )\n#  define JSON_HEDLEY_PURE _Pragma(\"FUNC_IS_PURE;\")\n#else\n#  define JSON_HEDLEY_PURE\n#endif\n\n#if defined(JSON_HEDLEY_CONST)\n    #undef JSON_HEDLEY_CONST\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(const) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_CONST __attribute__((__const__))\n#elif \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_CONST _Pragma(\"no_side_effect\")\n#else\n    #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE\n#endif\n\n#if defined(JSON_HEDLEY_RESTRICT)\n    #undef JSON_HEDLEY_RESTRICT\n#endif\n#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)\n    #define JSON_HEDLEY_RESTRICT restrict\n#elif \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n    defined(__clang__) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_RESTRICT __restrict\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)\n    #define JSON_HEDLEY_RESTRICT _Restrict\n#else\n    #define JSON_HEDLEY_RESTRICT\n#endif\n\n#if defined(JSON_HEDLEY_INLINE)\n    #undef JSON_HEDLEY_INLINE\n#endif\n#if \\\n    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n    (defined(__cplusplus) && (__cplusplus >= 199711L))\n    #define JSON_HEDLEY_INLINE inline\n#elif \\\n    defined(JSON_HEDLEY_GCC_VERSION) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)\n    #define JSON_HEDLEY_INLINE __inline__\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_INLINE __inline\n#else\n    #define JSON_HEDLEY_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_ALWAYS_INLINE)\n    #undef JSON_HEDLEY_ALWAYS_INLINE\n#endif\n#if \\\n  JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \\\n  JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE\n#elif \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE __forceinline\n#elif defined(__cplusplus) && \\\n    ( \\\n      JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n      JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n      JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n      JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \\\n    )\n#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma(\"FUNC_ALWAYS_INLINE;\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma(\"inline=forced\")\n#else\n#  define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_NEVER_INLINE)\n    #undef JSON_HEDLEY_NEVER_INLINE\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n    #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"noinline\")\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"FUNC_CANNOT_INLINE;\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"inline=never\")\n#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n    #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)\n#else\n    #define JSON_HEDLEY_NEVER_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_PRIVATE)\n    #undef JSON_HEDLEY_PRIVATE\n#endif\n#if defined(JSON_HEDLEY_PUBLIC)\n    #undef JSON_HEDLEY_PUBLIC\n#endif\n#if defined(JSON_HEDLEY_IMPORT)\n    #undef JSON_HEDLEY_IMPORT\n#endif\n#if defined(_WIN32) || defined(__CYGWIN__)\n#  define JSON_HEDLEY_PRIVATE\n#  define JSON_HEDLEY_PUBLIC   __declspec(dllexport)\n#  define JSON_HEDLEY_IMPORT   __declspec(dllimport)\n#else\n#  if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    ( \\\n      defined(__TI_EABI__) && \\\n      ( \\\n        (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \\\n      ) \\\n    ) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#    define JSON_HEDLEY_PRIVATE __attribute__((__visibility__(\"hidden\")))\n#    define JSON_HEDLEY_PUBLIC  __attribute__((__visibility__(\"default\")))\n#  else\n#    define JSON_HEDLEY_PRIVATE\n#    define JSON_HEDLEY_PUBLIC\n#  endif\n#  define JSON_HEDLEY_IMPORT    extern\n#endif\n\n#if defined(JSON_HEDLEY_NO_THROW)\n    #undef JSON_HEDLEY_NO_THROW\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)\n    #define JSON_HEDLEY_NO_THROW __declspec(nothrow)\n#else\n    #define JSON_HEDLEY_NO_THROW\n#endif\n\n#if defined(JSON_HEDLEY_FALL_THROUGH)\n    #undef JSON_HEDLEY_FALL_THROUGH\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)\n    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)\n    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])\n#elif defined(__fallthrough) /* SAL */\n    #define JSON_HEDLEY_FALL_THROUGH __fallthrough\n#else\n    #define JSON_HEDLEY_FALL_THROUGH\n#endif\n\n#if defined(JSON_HEDLEY_RETURNS_NON_NULL)\n    #undef JSON_HEDLEY_RETURNS_NON_NULL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))\n#elif defined(_Ret_notnull_) /* SAL */\n    #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_\n#else\n    #define JSON_HEDLEY_RETURNS_NON_NULL\n#endif\n\n#if defined(JSON_HEDLEY_ARRAY_PARAM)\n    #undef JSON_HEDLEY_ARRAY_PARAM\n#endif\n#if \\\n    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \\\n    !defined(__STDC_NO_VLA__) && \\\n    !defined(__cplusplus) && \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_TINYC_VERSION)\n    #define JSON_HEDLEY_ARRAY_PARAM(name) (name)\n#else\n    #define JSON_HEDLEY_ARRAY_PARAM(name)\n#endif\n\n#if defined(JSON_HEDLEY_IS_CONSTANT)\n    #undef JSON_HEDLEY_IS_CONSTANT\n#endif\n#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)\n    #undef JSON_HEDLEY_REQUIRE_CONSTEXPR\n#endif\n/* JSON_HEDLEY_IS_CONSTEXPR_ is for\n   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */\n#if defined(JSON_HEDLEY_IS_CONSTEXPR_)\n    #undef JSON_HEDLEY_IS_CONSTEXPR_\n#endif\n#if \\\n    JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)\n#endif\n#if !defined(__cplusplus)\n#  if \\\n       JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \\\n       JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n       JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n       JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n       JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \\\n       JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)\n#if defined(__INTPTR_TYPE__)\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)\n#else\n    #include <stdint.h>\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)\n#endif\n#  elif \\\n       ( \\\n          defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \\\n          !defined(JSON_HEDLEY_SUNPRO_VERSION) && \\\n          !defined(JSON_HEDLEY_PGI_VERSION) && \\\n          !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n       (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n       JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \\\n       JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \\\n       JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n       JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)\n#if defined(__INTPTR_TYPE__)\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)\n#else\n    #include <stdint.h>\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)\n#endif\n#  elif \\\n       defined(JSON_HEDLEY_GCC_VERSION) || \\\n       defined(JSON_HEDLEY_INTEL_VERSION) || \\\n       defined(JSON_HEDLEY_TINYC_VERSION) || \\\n       defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \\\n       JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \\\n       defined(JSON_HEDLEY_TI_CL2000_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CL6X_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CL7X_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \\\n       defined(__clang__)\n#    define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \\\n        sizeof(void) != \\\n        sizeof(*( \\\n                  1 ? \\\n                  ((void*) ((expr) * 0L) ) : \\\n((struct { char v[sizeof(void) * 2]; } *) 1) \\\n                ) \\\n              ) \\\n                                            )\n#  endif\n#endif\n#if defined(JSON_HEDLEY_IS_CONSTEXPR_)\n    #if !defined(JSON_HEDLEY_IS_CONSTANT)\n        #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)\n    #endif\n    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))\n#else\n    #if !defined(JSON_HEDLEY_IS_CONSTANT)\n        #define JSON_HEDLEY_IS_CONSTANT(expr) (0)\n    #endif\n    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)\n#endif\n\n#if defined(JSON_HEDLEY_BEGIN_C_DECLS)\n    #undef JSON_HEDLEY_BEGIN_C_DECLS\n#endif\n#if defined(JSON_HEDLEY_END_C_DECLS)\n    #undef JSON_HEDLEY_END_C_DECLS\n#endif\n#if defined(JSON_HEDLEY_C_DECL)\n    #undef JSON_HEDLEY_C_DECL\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_BEGIN_C_DECLS extern \"C\" {\n    #define JSON_HEDLEY_END_C_DECLS }\n    #define JSON_HEDLEY_C_DECL extern \"C\"\n#else\n    #define JSON_HEDLEY_BEGIN_C_DECLS\n    #define JSON_HEDLEY_END_C_DECLS\n    #define JSON_HEDLEY_C_DECL\n#endif\n\n#if defined(JSON_HEDLEY_STATIC_ASSERT)\n    #undef JSON_HEDLEY_STATIC_ASSERT\n#endif\n#if \\\n  !defined(__cplusplus) && ( \\\n      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \\\n      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \\\n      JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \\\n      JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n      defined(_Static_assert) \\\n    )\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)\n#elif \\\n  (defined(__cplusplus) && (__cplusplus >= 201103L)) || \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))\n#else\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message)\n#endif\n\n#if defined(JSON_HEDLEY_NULL)\n    #undef JSON_HEDLEY_NULL\n#endif\n#if defined(__cplusplus)\n    #if __cplusplus >= 201103L\n        #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)\n    #elif defined(NULL)\n        #define JSON_HEDLEY_NULL NULL\n    #else\n        #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)\n    #endif\n#elif defined(NULL)\n    #define JSON_HEDLEY_NULL NULL\n#else\n    #define JSON_HEDLEY_NULL ((void*) 0)\n#endif\n\n#if defined(JSON_HEDLEY_MESSAGE)\n    #undef JSON_HEDLEY_MESSAGE\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define JSON_HEDLEY_MESSAGE(msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n    JSON_HEDLEY_PRAGMA(message msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)\n#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#else\n#  define JSON_HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(JSON_HEDLEY_WARNING)\n    #undef JSON_HEDLEY_WARNING\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define JSON_HEDLEY_WARNING(msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n    JSON_HEDLEY_PRAGMA(clang warning msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \\\n  JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)\n#elif \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#else\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(JSON_HEDLEY_REQUIRE)\n    #undef JSON_HEDLEY_REQUIRE\n#endif\n#if defined(JSON_HEDLEY_REQUIRE_MSG)\n    #undef JSON_HEDLEY_REQUIRE_MSG\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wgcc-compat\")\n#    define JSON_HEDLEY_REQUIRE(expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n    __attribute__((diagnose_if(!(expr), #expr, \"error\"))) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n    __attribute__((diagnose_if(!(expr), msg, \"error\"))) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, \"error\")))\n#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, \"error\")))\n#  endif\n#else\n#  define JSON_HEDLEY_REQUIRE(expr)\n#  define JSON_HEDLEY_REQUIRE_MSG(expr,msg)\n#endif\n\n#if defined(JSON_HEDLEY_FLAGS)\n    #undef JSON_HEDLEY_FLAGS\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING(\"-Wbitfield-enum-conversion\"))\n    #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))\n#else\n    #define JSON_HEDLEY_FLAGS\n#endif\n\n#if defined(JSON_HEDLEY_FLAGS_CAST)\n    #undef JSON_HEDLEY_FLAGS_CAST\n#endif\n#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)\n#  define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \\\n        JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n        _Pragma(\"warning(disable:188)\") \\\n        ((T) (expr)); \\\n        JSON_HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)\n#endif\n\n#if defined(JSON_HEDLEY_EMPTY_BASES)\n    #undef JSON_HEDLEY_EMPTY_BASES\n#endif\n#if \\\n    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)\n#else\n    #define JSON_HEDLEY_EMPTY_BASES\n#endif\n\n/* Remaining macros are deprecated. */\n\n#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)\n    #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#endif\n#if defined(__clang__)\n    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)\n#else\n    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)\n    #undef JSON_HEDLEY_CLANG_HAS_BUILTIN\n#endif\n#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)\n    #undef JSON_HEDLEY_CLANG_HAS_FEATURE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)\n    #undef JSON_HEDLEY_CLANG_HAS_EXTENSION\n#endif\n#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)\n    #undef JSON_HEDLEY_CLANG_HAS_WARNING\n#endif\n#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)\n\n#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n\n#include <type_traits>\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename ...Ts> struct make_void\n{\n    using type = void;\n};\ntemplate<typename ...Ts> using void_t = typename make_void<Ts...>::type;\n} // namespace detail\n}  // namespace nlohmann\n\n\n// https://en.cppreference.com/w/cpp/experimental/is_detected\nnamespace nlohmann\n{\nnamespace detail\n{\nstruct nonesuch\n{\n    nonesuch() = delete;\n    ~nonesuch() = delete;\n    nonesuch(nonesuch const&) = delete;\n    nonesuch(nonesuch const&&) = delete;\n    void operator=(nonesuch const&) = delete;\n    void operator=(nonesuch&&) = delete;\n};\n\ntemplate<class Default,\n         class AlwaysVoid,\n         template<class...> class Op,\n         class... Args>\nstruct detector\n{\n    using value_t = std::false_type;\n    using type = Default;\n};\n\ntemplate<class Default, template<class...> class Op, class... Args>\nstruct detector<Default, void_t<Op<Args...>>, Op, Args...>\n{\n    using value_t = std::true_type;\n    using type = Op<Args...>;\n};\n\ntemplate<template<class...> class Op, class... Args>\nusing is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;\n\ntemplate<template<class...> class Op, class... Args>\nstruct is_detected_lazy : is_detected<Op, Args...> { };\n\ntemplate<template<class...> class Op, class... Args>\nusing detected_t = typename detector<nonesuch, void, Op, Args...>::type;\n\ntemplate<class Default, template<class...> class Op, class... Args>\nusing detected_or = detector<Default, void, Op, Args...>;\n\ntemplate<class Default, template<class...> class Op, class... Args>\nusing detected_or_t = typename detected_or<Default, Op, Args...>::type;\n\ntemplate<class Expected, template<class...> class Op, class... Args>\nusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\ntemplate<class To, template<class...> class Op, class... Args>\nusing is_detected_convertible =\n    std::is_convertible<detected_t<Op, Args...>, To>;\n}  // namespace detail\n}  // namespace nlohmann\n\n\n// This file contains all internal macro definitions\n// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them\n\n// exclude unsupported compilers\n#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)\n    #if defined(__clang__)\n        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400\n            #error \"unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))\n        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800\n            #error \"unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #endif\n#endif\n\n// C++ language standard detection\n// if the user manually specified the used c++ version this is skipped\n#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)\n    #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)\n        #define JSON_HAS_CPP_20\n        #define JSON_HAS_CPP_17\n        #define JSON_HAS_CPP_14\n    #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464\n        #define JSON_HAS_CPP_17\n        #define JSON_HAS_CPP_14\n    #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)\n        #define JSON_HAS_CPP_14\n    #endif\n    // the cpp 11 flag is always specified because it is the minimal required version\n    #define JSON_HAS_CPP_11\n#endif\n\n// disable documentation warnings on clang\n#if defined(__clang__)\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wdocumentation\"\n    #pragma clang diagnostic ignored \"-Wdocumentation-unknown-command\"\n#endif\n\n// allow to disable exceptions\n#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)\n    #define JSON_THROW(exception) throw exception\n    #define JSON_TRY try\n    #define JSON_CATCH(exception) catch(exception)\n    #define JSON_INTERNAL_CATCH(exception) catch(exception)\n#else\n    #include <cstdlib>\n    #define JSON_THROW(exception) std::abort()\n    #define JSON_TRY if(true)\n    #define JSON_CATCH(exception) if(false)\n    #define JSON_INTERNAL_CATCH(exception) if(false)\n#endif\n\n// override exception macros\n#if defined(JSON_THROW_USER)\n    #undef JSON_THROW\n    #define JSON_THROW JSON_THROW_USER\n#endif\n#if defined(JSON_TRY_USER)\n    #undef JSON_TRY\n    #define JSON_TRY JSON_TRY_USER\n#endif\n#if defined(JSON_CATCH_USER)\n    #undef JSON_CATCH\n    #define JSON_CATCH JSON_CATCH_USER\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_CATCH_USER\n#endif\n#if defined(JSON_INTERNAL_CATCH_USER)\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER\n#endif\n\n// allow to override assert\n#if !defined(JSON_ASSERT)\n    #include <cassert> // assert\n    #define JSON_ASSERT(x) assert(x)\n#endif\n\n// allow to access some private functions (needed by the test suite)\n#if defined(JSON_TESTS_PRIVATE)\n    #define JSON_PRIVATE_UNLESS_TESTED public\n#else\n    #define JSON_PRIVATE_UNLESS_TESTED private\n#endif\n\n/*!\n@brief macro to briefly define a mapping between an enum and JSON\n@def NLOHMANN_JSON_SERIALIZE_ENUM\n@since version 3.4.0\n*/\n#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                            \\\n    template<typename BasicJsonType>                                                            \\\n    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                   \\\n    {                                                                                           \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");          \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                      \\\n                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool  \\\n        {                                                                                       \\\n            return ej_pair.first == e;                                                          \\\n        });                                                                                     \\\n        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                 \\\n    }                                                                                           \\\n    template<typename BasicJsonType>                                                            \\\n    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                 \\\n    {                                                                                           \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");          \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                      \\\n                               [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                       \\\n            return ej_pair.second == j;                                                         \\\n        });                                                                                     \\\n        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                  \\\n    }\n\n// Ugly macros to avoid uglier copy-paste when specializing basic_json. They\n// may be removed in the future once the class is split.\n\n#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \\\n    template<template<typename, typename, typename...> class ObjectType,   \\\n             template<typename, typename...> class ArrayType,              \\\n             class StringType, class BooleanType, class NumberIntegerType, \\\n             class NumberUnsignedType, class NumberFloatType,              \\\n             template<typename> class AllocatorType,                       \\\n             template<typename, typename = void> class JSONSerializer,     \\\n             class BinaryType>\n\n#define NLOHMANN_BASIC_JSON_TPL                                            \\\n    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \\\n    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \\\n    AllocatorType, JSONSerializer, BinaryType>\n\n// Macros to simplify conversion from/to types\n\n#define NLOHMANN_JSON_EXPAND( x ) x\n#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME\n#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \\\n        NLOHMANN_JSON_PASTE64, \\\n        NLOHMANN_JSON_PASTE63, \\\n        NLOHMANN_JSON_PASTE62, \\\n        NLOHMANN_JSON_PASTE61, \\\n        NLOHMANN_JSON_PASTE60, \\\n        NLOHMANN_JSON_PASTE59, \\\n        NLOHMANN_JSON_PASTE58, \\\n        NLOHMANN_JSON_PASTE57, \\\n        NLOHMANN_JSON_PASTE56, \\\n        NLOHMANN_JSON_PASTE55, \\\n        NLOHMANN_JSON_PASTE54, \\\n        NLOHMANN_JSON_PASTE53, \\\n        NLOHMANN_JSON_PASTE52, \\\n        NLOHMANN_JSON_PASTE51, \\\n        NLOHMANN_JSON_PASTE50, \\\n        NLOHMANN_JSON_PASTE49, \\\n        NLOHMANN_JSON_PASTE48, \\\n        NLOHMANN_JSON_PASTE47, \\\n        NLOHMANN_JSON_PASTE46, \\\n        NLOHMANN_JSON_PASTE45, \\\n        NLOHMANN_JSON_PASTE44, \\\n        NLOHMANN_JSON_PASTE43, \\\n        NLOHMANN_JSON_PASTE42, \\\n        NLOHMANN_JSON_PASTE41, \\\n        NLOHMANN_JSON_PASTE40, \\\n        NLOHMANN_JSON_PASTE39, \\\n        NLOHMANN_JSON_PASTE38, \\\n        NLOHMANN_JSON_PASTE37, \\\n        NLOHMANN_JSON_PASTE36, \\\n        NLOHMANN_JSON_PASTE35, \\\n        NLOHMANN_JSON_PASTE34, \\\n        NLOHMANN_JSON_PASTE33, \\\n        NLOHMANN_JSON_PASTE32, \\\n        NLOHMANN_JSON_PASTE31, \\\n        NLOHMANN_JSON_PASTE30, \\\n        NLOHMANN_JSON_PASTE29, \\\n        NLOHMANN_JSON_PASTE28, \\\n        NLOHMANN_JSON_PASTE27, \\\n        NLOHMANN_JSON_PASTE26, \\\n        NLOHMANN_JSON_PASTE25, \\\n        NLOHMANN_JSON_PASTE24, \\\n        NLOHMANN_JSON_PASTE23, \\\n        NLOHMANN_JSON_PASTE22, \\\n        NLOHMANN_JSON_PASTE21, \\\n        NLOHMANN_JSON_PASTE20, \\\n        NLOHMANN_JSON_PASTE19, \\\n        NLOHMANN_JSON_PASTE18, \\\n        NLOHMANN_JSON_PASTE17, \\\n        NLOHMANN_JSON_PASTE16, \\\n        NLOHMANN_JSON_PASTE15, \\\n        NLOHMANN_JSON_PASTE14, \\\n        NLOHMANN_JSON_PASTE13, \\\n        NLOHMANN_JSON_PASTE12, \\\n        NLOHMANN_JSON_PASTE11, \\\n        NLOHMANN_JSON_PASTE10, \\\n        NLOHMANN_JSON_PASTE9, \\\n        NLOHMANN_JSON_PASTE8, \\\n        NLOHMANN_JSON_PASTE7, \\\n        NLOHMANN_JSON_PASTE6, \\\n        NLOHMANN_JSON_PASTE5, \\\n        NLOHMANN_JSON_PASTE4, \\\n        NLOHMANN_JSON_PASTE3, \\\n        NLOHMANN_JSON_PASTE2, \\\n        NLOHMANN_JSON_PASTE1)(__VA_ARGS__))\n#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)\n#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)\n#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)\n#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)\n#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)\n#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)\n#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)\n#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)\n#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)\n#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)\n#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)\n#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)\n#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)\n#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)\n#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)\n#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)\n#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)\n#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)\n#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)\n#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)\n#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)\n#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)\n#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)\n#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)\n#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)\n#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)\n#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)\n#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)\n#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)\n#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)\n#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)\n#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)\n#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)\n#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)\n#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)\n#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)\n#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)\n#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)\n#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)\n#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)\n#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)\n#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)\n#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)\n#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)\n#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)\n#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)\n#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)\n#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)\n#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)\n#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)\n#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)\n#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)\n#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)\n#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)\n#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)\n#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)\n#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)\n#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)\n#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)\n#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)\n#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)\n#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)\n#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)\n\n#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;\n#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_INTRUSIVE\n@since version 3.9.0\n*/\n#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \\\n    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE\n@since version 3.9.0\n*/\n#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \\\n    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n\n// inspired from https://stackoverflow.com/a/26745591\n// allows to call any std function as if (e.g. with begin):\n// using std::begin; begin(x);\n//\n// it allows using the detected idiom to retrieve the return type\n// of such an expression\n#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name)                                 \\\n    namespace detail {                                                            \\\n    using std::std_name;                                                          \\\n    \\\n    template<typename... T>                                                       \\\n    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \\\n    }                                                                             \\\n    \\\n    namespace detail2 {                                                           \\\n    struct std_name##_tag                                                         \\\n    {                                                                             \\\n    };                                                                            \\\n    \\\n    template<typename... T>                                                       \\\n    std_name##_tag std_name(T&&...);                                              \\\n    \\\n    template<typename... T>                                                       \\\n    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \\\n    \\\n    template<typename... T>                                                       \\\n    struct would_call_std_##std_name                                              \\\n    {                                                                             \\\n        static constexpr auto const value = ::nlohmann::detail::                  \\\n                                            is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \\\n    };                                                                            \\\n    } /* namespace detail2 */ \\\n    \\\n    template<typename... T>                                                       \\\n    struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...>   \\\n    {                                                                             \\\n    }\n\n#ifndef JSON_USE_IMPLICIT_CONVERSIONS\n    #define JSON_USE_IMPLICIT_CONVERSIONS 1\n#endif\n\n#if JSON_USE_IMPLICIT_CONVERSIONS\n    #define JSON_EXPLICIT\n#else\n    #define JSON_EXPLICIT explicit\n#endif\n\n#ifndef JSON_DIAGNOSTICS\n    #define JSON_DIAGNOSTICS 0\n#endif\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/*!\n@brief replace all occurrences of a substring by another string\n\n@param[in,out] s  the string to manipulate; changed so that all\n               occurrences of @a f are replaced with @a t\n@param[in]     f  the substring to replace with @a t\n@param[in]     t  the string to replace @a f\n\n@pre The search string @a f must not be empty. **This precondition is\nenforced with an assertion.**\n\n@since version 2.0.0\n*/\ninline void replace_substring(std::string& s, const std::string& f,\n                              const std::string& t)\n{\n    JSON_ASSERT(!f.empty());\n    for (auto pos = s.find(f);                // find first occurrence of f\n            pos != std::string::npos;         // make sure f was found\n            s.replace(pos, f.size(), t),      // replace with t, and\n            pos = s.find(f, pos + t.size()))  // find next occurrence of f\n    {}\n}\n\n/*!\n * @brief string escaping as described in RFC 6901 (Sect. 4)\n * @param[in] s string to escape\n * @return    escaped string\n *\n * Note the order of escaping \"~\" to \"~0\" and \"/\" to \"~1\" is important.\n */\ninline std::string escape(std::string s)\n{\n    replace_substring(s, \"~\", \"~0\");\n    replace_substring(s, \"/\", \"~1\");\n    return s;\n}\n\n/*!\n * @brief string unescaping as described in RFC 6901 (Sect. 4)\n * @param[in] s string to unescape\n * @return    unescaped string\n *\n * Note the order of escaping \"~1\" to \"/\" and \"~0\" to \"~\" is important.\n */\nstatic void unescape(std::string& s)\n{\n    replace_substring(s, \"~1\", \"/\");\n    replace_substring(s, \"~0\", \"~\");\n}\n\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n\n#include <cstddef> // size_t\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// struct to capture the start position of the current token\nstruct position_t\n{\n    /// the total number of characters read\n    std::size_t chars_read_total = 0;\n    /// the number of characters read in the current line\n    std::size_t chars_read_current_line = 0;\n    /// the number of lines read\n    std::size_t lines_read = 0;\n\n    /// conversion to size_t to preserve SAX interface\n    constexpr operator size_t() const\n    {\n        return chars_read_total;\n    }\n};\n\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////////\n// exceptions //\n////////////////\n\n/*!\n@brief general exception of the @ref basic_json class\n\nThis class is an extension of `std::exception` objects with a member @a id for\nexception ids. It is used as the base class for all exceptions thrown by the\n@ref basic_json class. This class can hence be used as \"wildcard\" to catch\nexceptions.\n\nSubclasses:\n- @ref parse_error for exceptions indicating a parse error\n- @ref invalid_iterator for exceptions indicating errors with iterators\n- @ref type_error for exceptions indicating executing a member function with\n                  a wrong type\n- @ref out_of_range for exceptions indicating access out of the defined range\n- @ref other_error for exceptions indicating other library errors\n\n@internal\n@note To have nothrow-copy-constructible exceptions, we internally use\n      `std::runtime_error` which can cope with arbitrary-length error messages.\n      Intermediate strings are built with static functions and then passed to\n      the actual constructor.\n@endinternal\n\n@liveexample{The following code shows how arbitrary library exceptions can be\ncaught.,exception}\n\n@since version 3.0.0\n*/\nclass exception : public std::exception\n{\n  public:\n    /// returns the explanatory string\n    const char* what() const noexcept override\n    {\n        return m.what();\n    }\n\n    /// the id of the exception\n    const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)\n\n  protected:\n    JSON_HEDLEY_NON_NULL(3)\n    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}\n\n    static std::string name(const std::string& ename, int id_)\n    {\n        return \"[json.exception.\" + ename + \".\" + std::to_string(id_) + \"] \";\n    }\n\n    template<typename BasicJsonType>\n    static std::string diagnostics(const BasicJsonType& leaf_element)\n    {\n#if JSON_DIAGNOSTICS\n        std::vector<std::string> tokens;\n        for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent)\n        {\n            switch (current->m_parent->type())\n            {\n                case value_t::array:\n                {\n                    for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)\n                    {\n                        if (&current->m_parent->m_value.array->operator[](i) == current)\n                        {\n                            tokens.emplace_back(std::to_string(i));\n                            break;\n                        }\n                    }\n                    break;\n                }\n\n                case value_t::object:\n                {\n                    for (const auto& element : *current->m_parent->m_value.object)\n                    {\n                        if (&element.second == current)\n                        {\n                            tokens.emplace_back(element.first.c_str());\n                            break;\n                        }\n                    }\n                    break;\n                }\n\n                case value_t::null: // LCOV_EXCL_LINE\n                case value_t::string: // LCOV_EXCL_LINE\n                case value_t::boolean: // LCOV_EXCL_LINE\n                case value_t::number_integer: // LCOV_EXCL_LINE\n                case value_t::number_unsigned: // LCOV_EXCL_LINE\n                case value_t::number_float: // LCOV_EXCL_LINE\n                case value_t::binary: // LCOV_EXCL_LINE\n                case value_t::discarded: // LCOV_EXCL_LINE\n                default:   // LCOV_EXCL_LINE\n                    break; // LCOV_EXCL_LINE\n            }\n        }\n\n        if (tokens.empty())\n        {\n            return \"\";\n        }\n\n        return \"(\" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},\n                                     [](const std::string & a, const std::string & b)\n        {\n            return a + \"/\" + detail::escape(b);\n        }) + \") \";\n#else\n        static_cast<void>(leaf_element);\n        return \"\";\n#endif\n    }\n\n  private:\n    /// an exception object as storage for error messages\n    std::runtime_error m;\n};\n\n/*!\n@brief exception indicating a parse error\n\nThis exception is thrown by the library when a parse error occurs. Parse errors\ncan occur during the deserialization of JSON text, CBOR, MessagePack, as well\nas when using JSON Patch.\n\nMember @a byte holds the byte index of the last read character in the input\nfile.\n\nExceptions have ids 1xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.\njson.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\\uxxxx` entries (\"surrogate pairs\"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.\njson.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.\njson.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.\njson.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one \"op\" member, whose value indicates the operation to perform. Its value must be one of \"add\", \"remove\", \"replace\", \"move\", \"copy\", or \"test\"; other values are errors.\njson.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.\njson.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.\njson.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.\njson.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.\njson.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.\njson.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.\njson.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.\njson.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).\njson.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed.\n\n@note For an input with n bytes, 1 is the index of the first character and n+1\n      is the index of the terminating null byte or the end of file. This also\n      holds true when reading a byte vector (CBOR or MessagePack).\n\n@liveexample{The following code shows how a `parse_error` exception can be\ncaught.,parse_error}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass parse_error : public exception\n{\n  public:\n    /*!\n    @brief create a parse error exception\n    @param[in] id_       the id of the exception\n    @param[in] pos       the position where the error occurred (or with\n                         chars_read_total=0 if the position cannot be\n                         determined)\n    @param[in] what_arg  the explanatory string\n    @return parse_error object\n    */\n    template<typename BasicJsonType>\n    static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        position_string(pos) + \": \" + exception::diagnostics(context) + what_arg;\n        return parse_error(id_, pos.chars_read_total, w.c_str());\n    }\n\n    template<typename BasicJsonType>\n    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        (byte_ != 0 ? (\" at byte \" + std::to_string(byte_)) : \"\") +\n                        \": \" + exception::diagnostics(context) + what_arg;\n        return parse_error(id_, byte_, w.c_str());\n    }\n\n    /*!\n    @brief byte index of the parse error\n\n    The byte index of the last read character in the input file.\n\n    @note For an input with n bytes, 1 is the index of the first character and\n          n+1 is the index of the terminating null byte or the end of file.\n          This also holds true when reading a byte vector (CBOR or MessagePack).\n    */\n    const std::size_t byte;\n\n  private:\n    parse_error(int id_, std::size_t byte_, const char* what_arg)\n        : exception(id_, what_arg), byte(byte_) {}\n\n    static std::string position_string(const position_t& pos)\n    {\n        return \" at line \" + std::to_string(pos.lines_read + 1) +\n               \", column \" + std::to_string(pos.chars_read_current_line);\n    }\n};\n\n/*!\n@brief exception indicating errors with iterators\n\nThis exception is thrown if iterators passed to a library function do not match\nthe expected semantics.\n\nExceptions have ids 2xx.\n\nname / id                           | example message | description\n----------------------------------- | --------------- | -------------------------\njson.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.\njson.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.\njson.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.\njson.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.\njson.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.\njson.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.\njson.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.\njson.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.\njson.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.\njson.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().\n\n@liveexample{The following code shows how an `invalid_iterator` exception can be\ncaught.,invalid_iterator}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass invalid_iterator : public exception\n{\n  public:\n    template<typename BasicJsonType>\n    static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context)\n    {\n        std::string w = exception::name(\"invalid_iterator\", id_) + exception::diagnostics(context) + what_arg;\n        return invalid_iterator(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    invalid_iterator(int id_, const char* what_arg)\n        : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating executing a member function with a wrong type\n\nThis exception is thrown in case of a type error; that is, a library function is\nexecuted on a JSON value whose type does not match the expected semantics.\n\nExceptions have ids 3xx.\n\nname / id                     | example message | description\n----------------------------- | --------------- | -------------------------\njson.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.\njson.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.\njson.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &.\njson.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.\njson.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.\njson.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.\njson.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.\njson.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.\njson.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.\njson.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.\njson.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.\njson.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.\njson.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.\njson.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.\njson.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.\njson.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |\njson.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |\n\n@liveexample{The following code shows how a `type_error` exception can be\ncaught.,type_error}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass type_error : public exception\n{\n  public:\n    template<typename BasicJsonType>\n    static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context)\n    {\n        std::string w = exception::name(\"type_error\", id_) + exception::diagnostics(context) + what_arg;\n        return type_error(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating access out of the defined range\n\nThis exception is thrown in case a library function is called on an input\nparameter that exceeds the expected range, for instance in case of array\nindices or nonexisting object keys.\n\nExceptions have ids 4xx.\n\nname / id                       | example message | description\n------------------------------- | --------------- | -------------------------\njson.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.\njson.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.\njson.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.\njson.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.\njson.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.\njson.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.\njson.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) |\njson.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |\njson.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |\n\n@liveexample{The following code shows how an `out_of_range` exception can be\ncaught.,out_of_range}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass out_of_range : public exception\n{\n  public:\n    template<typename BasicJsonType>\n    static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context)\n    {\n        std::string w = exception::name(\"out_of_range\", id_) + exception::diagnostics(context) + what_arg;\n        return out_of_range(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating other library errors\n\nThis exception is thrown in case of errors that cannot be classified with the\nother exception types.\n\nExceptions have ids 5xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.other_error.501 | unsuccessful: {\"op\":\"test\",\"path\":\"/baz\", \"value\":\"bar\"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n\n@liveexample{The following code shows how an `other_error` exception can be\ncaught.,other_error}\n\n@since version 3.0.0\n*/\nclass other_error : public exception\n{\n  public:\n    template<typename BasicJsonType>\n    static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context)\n    {\n        std::string w = exception::name(\"other_error\", id_) + exception::diagnostics(context) + what_arg;\n        return other_error(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\n#include <cstddef> // size_t\n#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type\n#include <utility> // index_sequence, make_index_sequence, index_sequence_for\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\ntemplate<typename T>\nusing uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n#ifdef JSON_HAS_CPP_14\n\n// the following utilities are natively available in C++14\nusing std::enable_if_t;\nusing std::index_sequence;\nusing std::make_index_sequence;\nusing std::index_sequence_for;\n\n#else\n\n// alias templates to reduce boilerplate\ntemplate<bool B, typename T = void>\nusing enable_if_t = typename std::enable_if<B, T>::type;\n\n// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h\n// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.\n\n//// START OF CODE FROM GOOGLE ABSEIL\n\n// integer_sequence\n//\n// Class template representing a compile-time integer sequence. An instantiation\n// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its\n// type through its template arguments (which is a common need when\n// working with C++11 variadic templates). `absl::integer_sequence` is designed\n// to be a drop-in replacement for C++14's `std::integer_sequence`.\n//\n// Example:\n//\n//   template< class T, T... Ints >\n//   void user_function(integer_sequence<T, Ints...>);\n//\n//   int main()\n//   {\n//     // user_function's `T` will be deduced to `int` and `Ints...`\n//     // will be deduced to `0, 1, 2, 3, 4`.\n//     user_function(make_integer_sequence<int, 5>());\n//   }\ntemplate <typename T, T... Ints>\nstruct integer_sequence\n{\n    using value_type = T;\n    static constexpr std::size_t size() noexcept\n    {\n        return sizeof...(Ints);\n    }\n};\n\n// index_sequence\n//\n// A helper template for an `integer_sequence` of `size_t`,\n// `absl::index_sequence` is designed to be a drop-in replacement for C++14's\n// `std::index_sequence`.\ntemplate <size_t... Ints>\nusing index_sequence = integer_sequence<size_t, Ints...>;\n\nnamespace utility_internal\n{\n\ntemplate <typename Seq, size_t SeqSize, size_t Rem>\nstruct Extend;\n\n// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.\ntemplate <typename T, T... Ints, size_t SeqSize>\nstruct Extend<integer_sequence<T, Ints...>, SeqSize, 0>\n{\n    using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;\n};\n\ntemplate <typename T, T... Ints, size_t SeqSize>\nstruct Extend<integer_sequence<T, Ints...>, SeqSize, 1>\n{\n    using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;\n};\n\n// Recursion helper for 'make_integer_sequence<T, N>'.\n// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.\ntemplate <typename T, size_t N>\nstruct Gen\n{\n    using type =\n        typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;\n};\n\ntemplate <typename T>\nstruct Gen<T, 0>\n{\n    using type = integer_sequence<T>;\n};\n\n}  // namespace utility_internal\n\n// Compile-time sequences of integers\n\n// make_integer_sequence\n//\n// This template alias is equivalent to\n// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in\n// replacement for C++14's `std::make_integer_sequence`.\ntemplate <typename T, T N>\nusing make_integer_sequence = typename utility_internal::Gen<T, N>::type;\n\n// make_index_sequence\n//\n// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,\n// and is designed to be a drop-in replacement for C++14's\n// `std::make_index_sequence`.\ntemplate <size_t N>\nusing make_index_sequence = make_integer_sequence<size_t, N>;\n\n// index_sequence_for\n//\n// Converts a typename pack into an index sequence of the same length, and\n// is designed to be a drop-in replacement for C++14's\n// `std::index_sequence_for()`\ntemplate <typename... Ts>\nusing index_sequence_for = make_index_sequence<sizeof...(Ts)>;\n\n//// END OF CODE FROM GOOGLE ABSEIL\n\n#endif\n\n// dispatch utility (taken from ranges-v3)\ntemplate<unsigned N> struct priority_tag : priority_tag < N - 1 > {};\ntemplate<> struct priority_tag<0> {};\n\n// taken from ranges-v3\ntemplate<typename T>\nstruct static_const\n{\n    static constexpr T value{};\n};\n\ntemplate<typename T>\nconstexpr T static_const<T>::value;\n\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/identity_tag.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// dispatching helper struct\ntemplate <class T> struct identity_tag {};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\n#include <limits> // numeric_limits\n#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type\n#include <utility> // declval\n#include <tuple> // tuple\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n\n#include <iterator> // random_access_iterator_tag\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename It, typename = void>\nstruct iterator_types {};\n\ntemplate<typename It>\nstruct iterator_types <\n    It,\n    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,\n    typename It::reference, typename It::iterator_category >>\n{\n    using difference_type = typename It::difference_type;\n    using value_type = typename It::value_type;\n    using pointer = typename It::pointer;\n    using reference = typename It::reference;\n    using iterator_category = typename It::iterator_category;\n};\n\n// This is required as some compilers implement std::iterator_traits in a way that\n// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.\ntemplate<typename T, typename = void>\nstruct iterator_traits\n{\n};\n\ntemplate<typename T>\nstruct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>\n            : iterator_types<T>\n{\n};\n\ntemplate<typename T>\nstruct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>\n{\n    using iterator_category = std::random_access_iterator_tag;\n    using value_type = T;\n    using difference_type = ptrdiff_t;\n    using pointer = T*;\n    using reference = T&;\n};\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/meta/call_std/begin.hpp>\n\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nNLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);\n} // namespace nlohmann\n\n// #include <nlohmann/detail/meta/call_std/end.hpp>\n\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nNLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/json_fwd.hpp>\n#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_\n#define INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n/*!\n@brief default JSONSerializer template argument\n\nThis serializer ignores the template arguments and uses ADL\n([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\nfor serialization.\n*/\ntemplate<typename T = void, typename SFINAE = void>\nstruct adl_serializer;\n\ntemplate<template<typename U, typename V, typename... Args> class ObjectType =\n         std::map,\n         template<typename U, typename... Args> class ArrayType = std::vector,\n         class StringType = std::string, class BooleanType = bool,\n         class NumberIntegerType = std::int64_t,\n         class NumberUnsignedType = std::uint64_t,\n         class NumberFloatType = double,\n         template<typename U> class AllocatorType = std::allocator,\n         template<typename T, typename SFINAE = void> class JSONSerializer =\n         adl_serializer,\n         class BinaryType = std::vector<std::uint8_t>>\nclass basic_json;\n\n/*!\n@brief JSON Pointer\n\nA JSON pointer defines a string syntax for identifying a specific value\nwithin a JSON document. It can be used with functions `at` and\n`operator[]`. Furthermore, JSON pointers are the base for JSON patches.\n\n@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)\n\n@since version 2.0.0\n*/\ntemplate<typename BasicJsonType>\nclass json_pointer;\n\n/*!\n@brief default JSON class\n\nThis type is the default specialization of the @ref basic_json class which\nuses the standard template types.\n\n@since version 1.0.0\n*/\nusing json = basic_json<>;\n\ntemplate<class Key, class T, class IgnoredLess, class Allocator>\nstruct ordered_map;\n\n/*!\n@brief ordered JSON class\n\nThis type preserves the insertion order of object keys.\n\n@since version 3.9.0\n*/\nusing ordered_json = basic_json<nlohmann::ordered_map>;\n\n}  // namespace nlohmann\n\n#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n\nnamespace nlohmann\n{\n/*!\n@brief detail namespace with internal helper functions\n\nThis namespace collects functions that should not be exposed,\nimplementations of some @ref basic_json methods, and meta-programming helpers.\n\n@since version 2.1.0\n*/\nnamespace detail\n{\n/////////////\n// helpers //\n/////////////\n\n// Note to maintainers:\n//\n// Every trait in this file expects a non CV-qualified type.\n// The only exceptions are in the 'aliases for detected' section\n// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))\n//\n// In this case, T has to be properly CV-qualified to constraint the function arguments\n// (e.g. to_json(BasicJsonType&, const T&))\n\ntemplate<typename> struct is_basic_json : std::false_type {};\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstruct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};\n\n//////////////////////\n// json_ref helpers //\n//////////////////////\n\ntemplate<typename>\nclass json_ref;\n\ntemplate<typename>\nstruct is_json_ref : std::false_type {};\n\ntemplate<typename T>\nstruct is_json_ref<json_ref<T>> : std::true_type {};\n\n//////////////////////////\n// aliases for detected //\n//////////////////////////\n\ntemplate<typename T>\nusing mapped_type_t = typename T::mapped_type;\n\ntemplate<typename T>\nusing key_type_t = typename T::key_type;\n\ntemplate<typename T>\nusing value_type_t = typename T::value_type;\n\ntemplate<typename T>\nusing difference_type_t = typename T::difference_type;\n\ntemplate<typename T>\nusing pointer_t = typename T::pointer;\n\ntemplate<typename T>\nusing reference_t = typename T::reference;\n\ntemplate<typename T>\nusing iterator_category_t = typename T::iterator_category;\n\ntemplate<typename T, typename... Args>\nusing to_json_function = decltype(T::to_json(std::declval<Args>()...));\n\ntemplate<typename T, typename... Args>\nusing from_json_function = decltype(T::from_json(std::declval<Args>()...));\n\ntemplate<typename T, typename U>\nusing get_template_function = decltype(std::declval<T>().template get<U>());\n\n// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_from_json : std::false_type {};\n\n// trait checking if j.get<T> is valid\n// use this trait instead of std::is_constructible or std::is_convertible,\n// both rely on, or make use of implicit conversions, and thus fail when T\n// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)\ntemplate <typename BasicJsonType, typename T>\nstruct is_getable\n{\n    static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;\n};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, from_json_function, serializer,\n        const BasicJsonType&, T&>::value;\n};\n\n// This trait checks if JSONSerializer<T>::from_json(json const&) exists\n// this overload is used for non-default-constructible user-defined-types\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_non_default_from_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<T, from_json_function, serializer,\n        const BasicJsonType&>::value;\n};\n\n// This trait checks if BasicJsonType::json_serializer<T>::to_json exists\n// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_to_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,\n        T>::value;\n};\n\n\n///////////////////\n// is_ functions //\n///////////////////\n\n// https://en.cppreference.com/w/cpp/types/conjunction\ntemplate<class...> struct conjunction : std::true_type { };\ntemplate<class B1> struct conjunction<B1> : B1 { };\ntemplate<class B1, class... Bn>\nstruct conjunction<B1, Bn...>\n: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};\n\n// https://en.cppreference.com/w/cpp/types/negation\ntemplate<class B> struct negation : std::integral_constant < bool, !B::value > { };\n\n// Reimplementation of is_constructible and is_default_constructible, due to them being broken for\n// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).\n// This causes compile errors in e.g. clang 3.5 or gcc 4.9.\ntemplate <typename T>\nstruct is_default_constructible : std::is_default_constructible<T> {};\n\ntemplate <typename T1, typename T2>\nstruct is_default_constructible<std::pair<T1, T2>>\n            : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};\n\ntemplate <typename T1, typename T2>\nstruct is_default_constructible<const std::pair<T1, T2>>\n            : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};\n\ntemplate <typename... Ts>\nstruct is_default_constructible<std::tuple<Ts...>>\n            : conjunction<is_default_constructible<Ts>...> {};\n\ntemplate <typename... Ts>\nstruct is_default_constructible<const std::tuple<Ts...>>\n            : conjunction<is_default_constructible<Ts>...> {};\n\n\ntemplate <typename T, typename... Args>\nstruct is_constructible : std::is_constructible<T, Args...> {};\n\ntemplate <typename T1, typename T2>\nstruct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};\n\ntemplate <typename T1, typename T2>\nstruct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};\n\ntemplate <typename... Ts>\nstruct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};\n\ntemplate <typename... Ts>\nstruct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};\n\n\ntemplate<typename T, typename = void>\nstruct is_iterator_traits : std::false_type {};\n\ntemplate<typename T>\nstruct is_iterator_traits<iterator_traits<T>>\n{\n  private:\n    using traits = iterator_traits<T>;\n\n  public:\n    static constexpr auto value =\n        is_detected<value_type_t, traits>::value &&\n        is_detected<difference_type_t, traits>::value &&\n        is_detected<pointer_t, traits>::value &&\n        is_detected<iterator_category_t, traits>::value &&\n        is_detected<reference_t, traits>::value;\n};\n\ntemplate<typename T>\nstruct is_range\n{\n  private:\n    using t_ref = typename std::add_lvalue_reference<T>::type;\n\n    using iterator = detected_t<result_of_begin, t_ref>;\n    using sentinel = detected_t<result_of_end, t_ref>;\n\n    // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator\n    // and https://en.cppreference.com/w/cpp/iterator/sentinel_for\n    // but reimplementing these would be too much work, as a lot of other concepts are used underneath\n    static constexpr auto is_iterator_begin =\n        is_iterator_traits<iterator_traits<iterator>>::value;\n\n  public:\n    static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;\n};\n\ntemplate<typename R>\nusing iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;\n\ntemplate<typename T>\nusing range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;\n\n// The following implementation of is_complete_type is taken from\n// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/\n// and is written by Xiang Fan who agreed to using it in this library.\n\ntemplate<typename T, typename = void>\nstruct is_complete_type : std::false_type {};\n\ntemplate<typename T>\nstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType,\n         typename = void>\nstruct is_compatible_object_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type_impl <\n    BasicJsonType, CompatibleObjectType,\n    enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&\n    is_detected<key_type_t, CompatibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    // macOS's is_constructible does not play well with nonesuch...\n    static constexpr bool value =\n        is_constructible<typename object_t::key_type,\n        typename CompatibleObjectType::key_type>::value &&\n        is_constructible<typename object_t::mapped_type,\n        typename CompatibleObjectType::mapped_type>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type\n    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         typename = void>\nstruct is_constructible_object_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type_impl <\n    BasicJsonType, ConstructibleObjectType,\n    enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&\n    is_detected<key_type_t, ConstructibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    static constexpr bool value =\n        (is_default_constructible<ConstructibleObjectType>::value &&\n         (std::is_move_assignable<ConstructibleObjectType>::value ||\n          std::is_copy_assignable<ConstructibleObjectType>::value) &&\n         (is_constructible<typename ConstructibleObjectType::key_type,\n          typename object_t::key_type>::value &&\n          std::is_same <\n          typename object_t::mapped_type,\n          typename ConstructibleObjectType::mapped_type >::value)) ||\n        (has_from_json<BasicJsonType,\n         typename ConstructibleObjectType::mapped_type>::value ||\n         has_non_default_from_json <\n         BasicJsonType,\n         typename ConstructibleObjectType::mapped_type >::value);\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type\n    : is_constructible_object_type_impl<BasicJsonType,\n      ConstructibleObjectType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleStringType>\nstruct is_compatible_string_type\n{\n    static constexpr auto value =\n        is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type\n{\n    static constexpr auto value =\n        is_constructible<ConstructibleStringType,\n        typename BasicJsonType::string_t>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType, typename = void>\nstruct is_compatible_array_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type_impl <\n    BasicJsonType, CompatibleArrayType,\n    enable_if_t <\n    is_detected<iterator_t, CompatibleArrayType>::value&&\n    is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&\n// special case for types like std::filesystem::path whose iterator's value_type are themselves\n// c.f. https://github.com/nlohmann/json/pull/3073\n    !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>\n{\n    static constexpr bool value =\n        is_constructible<BasicJsonType,\n        range_value_t<CompatibleArrayType>>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type\n    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType, typename = void>\nstruct is_constructible_array_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value >>\n            : std::true_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t < !std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value&&\n    !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&\n    is_default_constructible<ConstructibleArrayType>::value&&\n(std::is_move_assignable<ConstructibleArrayType>::value ||\n std::is_copy_assignable<ConstructibleArrayType>::value)&&\nis_detected<iterator_t, ConstructibleArrayType>::value&&\nis_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&\nis_detected<range_value_t, ConstructibleArrayType>::value&&\n// special case for types like std::filesystem::path whose iterator's value_type are themselves\n// c.f. https://github.com/nlohmann/json/pull/3073\n!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&\n        is_complete_type <\n        detected_t<range_value_t, ConstructibleArrayType >>::value >>\n{\n    using value_type = range_value_t<ConstructibleArrayType>;\n\n    static constexpr bool value =\n        std::is_same<value_type,\n        typename BasicJsonType::array_t::value_type>::value ||\n        has_from_json<BasicJsonType,\n        value_type>::value ||\n        has_non_default_from_json <\n        BasicJsonType,\n        value_type >::value;\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type\n    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType,\n         typename = void>\nstruct is_compatible_integer_type_impl : std::false_type {};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type_impl <\n    RealIntegerType, CompatibleNumberIntegerType,\n    enable_if_t < std::is_integral<RealIntegerType>::value&&\n    std::is_integral<CompatibleNumberIntegerType>::value&&\n    !std::is_same<bool, CompatibleNumberIntegerType>::value >>\n{\n    // is there an assert somewhere on overflows?\n    using RealLimits = std::numeric_limits<RealIntegerType>;\n    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;\n\n    static constexpr auto value =\n        is_constructible<RealIntegerType,\n        CompatibleNumberIntegerType>::value &&\n        CompatibleLimits::is_integer &&\n        RealLimits::is_signed == CompatibleLimits::is_signed;\n};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type\n    : is_compatible_integer_type_impl<RealIntegerType,\n      CompatibleNumberIntegerType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleType, typename = void>\nstruct is_compatible_type_impl: std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type_impl <\n    BasicJsonType, CompatibleType,\n    enable_if_t<is_complete_type<CompatibleType>::value >>\n{\n    static constexpr bool value =\n        has_to_json<BasicJsonType, CompatibleType>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type\n    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};\n\ntemplate<typename T1, typename T2>\nstruct is_constructible_tuple : std::false_type {};\n\ntemplate<typename T1, typename... Args>\nstruct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};\n\n// a naive helper to check if a type is an ordered_map (exploits the fact that\n// ordered_map inherits capacity() from std::vector)\ntemplate <typename T>\nstruct is_ordered_map\n{\n    using one = char;\n\n    struct two\n    {\n        char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n    };\n\n    template <typename C> static one test( decltype(&C::capacity) ) ;\n    template <typename C> static two test(...);\n\n    enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n};\n\n// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)\ntemplate < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >\nT conditional_static_cast(U value)\n{\n    return static_cast<T>(value);\n}\n\ntemplate<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>\nT conditional_static_cast(U value)\n{\n    return value;\n}\n\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\n#ifdef JSON_HAS_CPP_17\n    #include <filesystem>\n#endif\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename std::nullptr_t& n)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_null()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be null, but is \" + std::string(j.type_name()), j));\n    }\n    n = nullptr;\n}\n\n// overloads for basic_json template parameters\ntemplate < typename BasicJsonType, typename ArithmeticType,\n           enable_if_t < std::is_arithmetic<ArithmeticType>::value&&\n                         !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n                         int > = 0 >\nvoid get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n\n        case value_t::null:\n        case value_t::object:\n        case value_t::array:\n        case value_t::string:\n        case value_t::boolean:\n        case value_t::binary:\n        case value_t::discarded:\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name()), j));\n    }\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(j.type_name()), j));\n    }\n    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name()), j));\n    }\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate <\n    typename BasicJsonType, typename ConstructibleStringType,\n    enable_if_t <\n        is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&\n        !std::is_same<typename BasicJsonType::string_t,\n                      ConstructibleStringType>::value,\n        int > = 0 >\nvoid from_json(const BasicJsonType& j, ConstructibleStringType& s)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name()), j));\n    }\n\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, EnumType& e)\n{\n    typename std::underlying_type<EnumType>::type val;\n    get_arithmetic_value(j, val);\n    e = static_cast<EnumType>(val);\n}\n\n// forward_list doesn't have an insert method\ntemplate<typename BasicJsonType, typename T, typename Allocator,\n         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n    l.clear();\n    std::transform(j.rbegin(), j.rend(),\n                   std::front_inserter(l), [](const BasicJsonType & i)\n    {\n        return i.template get<T>();\n    });\n}\n\n// valarray doesn't have an insert method\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::valarray<T>& l)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n    l.resize(j.size());\n    std::transform(j.begin(), j.end(), std::begin(l),\n                   [](const BasicJsonType & elem)\n    {\n        return elem.template get<T>();\n    });\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N>\nauto from_json(const BasicJsonType& j, T (&arr)[N])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)\n{\n    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N>\nauto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,\n                          priority_tag<2> /*unused*/)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType,\n         enable_if_t<\n             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,\n             int> = 0>\nauto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)\n-> decltype(\n    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),\n    j.template get<typename ConstructibleArrayType::value_type>(),\n    void())\n{\n    using std::end;\n\n    ConstructibleArrayType ret;\n    ret.reserve(j.size());\n    std::transform(j.begin(), j.end(),\n                   std::inserter(ret, end(ret)), [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n    arr = std::move(ret);\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType,\n         enable_if_t<\n             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,\n             int> = 0>\nvoid from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,\n                          priority_tag<0> /*unused*/)\n{\n    using std::end;\n\n    ConstructibleArrayType ret;\n    std::transform(\n        j.begin(), j.end(), std::inserter(ret, end(ret)),\n        [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n    arr = std::move(ret);\n}\n\ntemplate < typename BasicJsonType, typename ConstructibleArrayType,\n           enable_if_t <\n               is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&\n               !is_basic_json<ConstructibleArrayType>::value,\n               int > = 0 >\nauto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)\n-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),\nj.template get<typename ConstructibleArrayType::value_type>(),\nvoid())\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n\n    from_json_array_impl(j, arr, priority_tag<3> {});\n}\n\ntemplate < typename BasicJsonType, typename T, std::size_t... Idx >\nstd::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,\n        identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)\n{\n    return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };\n}\n\ntemplate < typename BasicJsonType, typename T, std::size_t N >\nauto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)\n-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n\n    return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be binary, but is \" + std::string(j.type_name()), j));\n    }\n\n    bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, ConstructibleObjectType& obj)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_object()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be object, but is \" + std::string(j.type_name()), j));\n    }\n\n    ConstructibleObjectType ret;\n    const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();\n    using value_type = typename ConstructibleObjectType::value_type;\n    std::transform(\n        inner_object->begin(), inner_object->end(),\n        std::inserter(ret, ret.begin()),\n        [](typename BasicJsonType::object_t::value_type const & p)\n    {\n        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());\n    });\n    obj = std::move(ret);\n}\n\n// overload for arithmetic types, not chosen for basic_json template arguments\n// (BooleanType, etc..); note: Is it really necessary to provide explicit\n// overloads for boolean_t etc. in case of a custom BooleanType which is not\n// an arithmetic type?\ntemplate < typename BasicJsonType, typename ArithmeticType,\n           enable_if_t <\n               std::is_arithmetic<ArithmeticType>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n               int > = 0 >\nvoid from_json(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n        case value_t::boolean:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());\n            break;\n        }\n\n        case value_t::null:\n        case value_t::object:\n        case value_t::array:\n        case value_t::string:\n        case value_t::binary:\n        case value_t::discarded:\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name()), j));\n    }\n}\n\ntemplate<typename BasicJsonType, typename... Args, std::size_t... Idx>\nstd::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)\n{\n    return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);\n}\n\ntemplate < typename BasicJsonType, class A1, class A2 >\nstd::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)\n{\n    return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),\n            std::forward<BasicJsonType>(j).at(1).template get<A2>()};\n}\n\ntemplate<typename BasicJsonType, typename A1, typename A2>\nvoid from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)\n{\n    p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nstd::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)\n{\n    return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)\n{\n    t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});\n}\n\ntemplate<typename BasicJsonType, typename TupleRelated>\nauto from_json(BasicJsonType&& j, TupleRelated&& t)\n-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n\n    return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});\n}\n\ntemplate < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,\n           typename = enable_if_t < !std::is_constructible <\n                                        typename BasicJsonType::string_t, Key >::value >>\nvoid from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n    m.clear();\n    for (const auto& p : j)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name()), j));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\ntemplate < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,\n           typename = enable_if_t < !std::is_constructible <\n                                        typename BasicJsonType::string_t, Key >::value >>\nvoid from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name()), j));\n    }\n    m.clear();\n    for (const auto& p : j)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name()), j));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\n#ifdef JSON_HAS_CPP_17\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, std::filesystem::path& p)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name()), j));\n    }\n    p = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n#endif\n\nstruct from_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(const BasicJsonType& j, T&& val) const\n    noexcept(noexcept(from_json(j, std::forward<T>(val))))\n    -> decltype(from_json(j, std::forward<T>(val)))\n    {\n        return from_json(j, std::forward<T>(val));\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `from_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)\n{\nconstexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value; // NOLINT(misc-definitions-in-headers)\n} // namespace\n} // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n\n#include <algorithm> // copy\n#include <iterator> // begin, end\n#include <string> // string\n#include <tuple> // tuple, get\n#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type\n#include <utility> // move, forward, declval, pair\n#include <valarray> // valarray\n#include <vector> // vector\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n\n#include <cstddef> // size_t\n#include <iterator> // input_iterator_tag\n#include <string> // string, to_string\n#include <tuple> // tuple_size, get, tuple_element\n#include <utility> // move\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename string_type>\nvoid int_to_string( string_type& target, std::size_t value )\n{\n    // For ADL\n    using std::to_string;\n    target = to_string(value);\n}\ntemplate<typename IteratorType> class iteration_proxy_value\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    using value_type = iteration_proxy_value;\n    using pointer = value_type * ;\n    using reference = value_type & ;\n    using iterator_category = std::input_iterator_tag;\n    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;\n\n  private:\n    /// the iterator\n    IteratorType anchor;\n    /// an index for arrays (used to create key names)\n    std::size_t array_index = 0;\n    /// last stringified array index\n    mutable std::size_t array_index_last = 0;\n    /// a string representation of the array index\n    mutable string_type array_index_str = \"0\";\n    /// an empty string (to return a reference for primitive values)\n    const string_type empty_str{};\n\n  public:\n    explicit iteration_proxy_value(IteratorType it) noexcept\n        : anchor(std::move(it))\n    {}\n\n    /// dereference operator (needed for range-based for)\n    iteration_proxy_value& operator*()\n    {\n        return *this;\n    }\n\n    /// increment operator (needed for range-based for)\n    iteration_proxy_value& operator++()\n    {\n        ++anchor;\n        ++array_index;\n\n        return *this;\n    }\n\n    /// equality operator (needed for InputIterator)\n    bool operator==(const iteration_proxy_value& o) const\n    {\n        return anchor == o.anchor;\n    }\n\n    /// inequality operator (needed for range-based for)\n    bool operator!=(const iteration_proxy_value& o) const\n    {\n        return anchor != o.anchor;\n    }\n\n    /// return key of the iterator\n    const string_type& key() const\n    {\n        JSON_ASSERT(anchor.m_object != nullptr);\n\n        switch (anchor.m_object->type())\n        {\n            // use integer array index as key\n            case value_t::array:\n            {\n                if (array_index != array_index_last)\n                {\n                    int_to_string( array_index_str, array_index );\n                    array_index_last = array_index;\n                }\n                return array_index_str;\n            }\n\n            // use key from the object\n            case value_t::object:\n                return anchor.key();\n\n            // use an empty key for all primitive types\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return empty_str;\n        }\n    }\n\n    /// return value of the iterator\n    typename IteratorType::reference value() const\n    {\n        return anchor.value();\n    }\n};\n\n/// proxy class for the items() function\ntemplate<typename IteratorType> class iteration_proxy\n{\n  private:\n    /// the container to iterate\n    typename IteratorType::reference container;\n\n  public:\n    /// construct iteration proxy from a container\n    explicit iteration_proxy(typename IteratorType::reference cont) noexcept\n        : container(cont) {}\n\n    /// return iterator begin (needed for range-based for)\n    iteration_proxy_value<IteratorType> begin() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.begin());\n    }\n\n    /// return iterator end (needed for range-based for)\n    iteration_proxy_value<IteratorType> end() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.end());\n    }\n};\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())\n{\n    return i.key();\n}\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())\n{\n    return i.value();\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n// The Addition to the STD Namespace is required to add\n// Structured Bindings Support to the iteration_proxy_value class\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\nnamespace std\n{\n#if defined(__clang__)\n    // Fix: https://github.com/nlohmann/json/issues/1401\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wmismatched-tags\"\n#endif\ntemplate<typename IteratorType>\nclass tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>\n            : public std::integral_constant<std::size_t, 2> {};\n\ntemplate<std::size_t N, typename IteratorType>\nclass tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>\n{\n  public:\n    using type = decltype(\n                     get<N>(std::declval <\n                            ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));\n};\n#if defined(__clang__)\n    #pragma clang diagnostic pop\n#endif\n} // namespace std\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\n#ifdef JSON_HAS_CPP_17\n    #include <filesystem>\n#endif\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////\n// constructors //\n//////////////////\n\n/*\n * Note all external_constructor<>::construct functions need to call\n * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an\n * allocated value (e.g., a string). See bug issue\n * https://github.com/nlohmann/json/issues/2865 for more information.\n */\n\ntemplate<value_t> struct external_constructor;\n\ntemplate<>\nstruct external_constructor<value_t::boolean>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::boolean;\n        j.m_value = b;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::string>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::string;\n        j.m_value = s;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::string;\n        j.m_value = std::move(s);\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleStringType,\n               enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,\n                             int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleStringType& str)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::string;\n        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::binary>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::binary;\n        j.m_value = typename BasicJsonType::binary_t(b);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::binary;\n        j.m_value = typename BasicJsonType::binary_t(std::move(b));\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_float>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::number_float;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_unsigned>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::number_unsigned;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_integer>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::number_integer;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::array>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::array;\n        j.m_value = arr;\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::array;\n        j.m_value = std::move(arr);\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleArrayType,\n               enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,\n                             int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::array;\n        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const std::vector<bool>& arr)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->reserve(arr.size());\n        for (const bool x : arr)\n        {\n            j.m_value.array->push_back(x);\n            j.set_parent(j.m_value.array->back());\n        }\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename T,\n             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n    static void construct(BasicJsonType& j, const std::valarray<T>& arr)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->resize(arr.size());\n        if (arr.size() > 0)\n        {\n            std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());\n        }\n        j.set_parents();\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::object>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::object;\n        j.m_value = obj;\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n    {\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::object;\n        j.m_value = std::move(obj);\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleObjectType,\n               enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_value.destroy(j.m_type);\n        j.m_type = value_t::object;\n        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));\n        j.set_parents();\n        j.assert_invariant();\n    }\n};\n\n/////////////\n// to_json //\n/////////////\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>\nvoid to_json(BasicJsonType& j, T b) noexcept\n{\n    external_constructor<value_t::boolean>::construct(j, b);\n}\n\ntemplate<typename BasicJsonType, typename CompatibleString,\n         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleString& s)\n{\n    external_constructor<value_t::string>::construct(j, s);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n{\n    external_constructor<value_t::string>::construct(j, std::move(s));\n}\n\ntemplate<typename BasicJsonType, typename FloatType,\n         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, FloatType val) noexcept\n{\n    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberUnsignedType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept\n{\n    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberIntegerType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept\n{\n    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, EnumType e) noexcept\n{\n    using underlying_type = typename std::underlying_type<EnumType>::type;\n    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const std::vector<bool>& e)\n{\n    external_constructor<value_t::array>::construct(j, e);\n}\n\ntemplate < typename BasicJsonType, typename CompatibleArrayType,\n           enable_if_t < is_compatible_array_type<BasicJsonType,\n                         CompatibleArrayType>::value&&\n                         !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&\n                         !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&\n                         !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&\n                         !is_basic_json<CompatibleArrayType>::value,\n                         int > = 0 >\nvoid to_json(BasicJsonType& j, const CompatibleArrayType& arr)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)\n{\n    external_constructor<value_t::binary>::construct(j, bin);\n}\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const std::valarray<T>& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate < typename BasicJsonType, typename CompatibleObjectType,\n           enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >\nvoid to_json(BasicJsonType& j, const CompatibleObjectType& obj)\n{\n    external_constructor<value_t::object>::construct(j, obj);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n{\n    external_constructor<value_t::object>::construct(j, std::move(obj));\n}\n\ntemplate <\n    typename BasicJsonType, typename T, std::size_t N,\n    enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,\n                  const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n                  int > = 0 >\nvoid to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >\nvoid to_json(BasicJsonType& j, const std::pair<T1, T2>& p)\n{\n    j = { p.first, p.second };\n}\n\n// for https://github.com/nlohmann/json/pull/1134\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const T& b)\n{\n    j = { {b.key(), b.value()} };\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    j = { std::get<Idx>(t)... };\n}\n\ntemplate<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>\nvoid to_json(BasicJsonType& j, const T& t)\n{\n    to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});\n}\n\n#ifdef JSON_HAS_CPP_17\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const std::filesystem::path& p)\n{\n    j = p.string();\n}\n#endif\n\nstruct to_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))\n    -> decltype(to_json(j, std::forward<T>(val)), void())\n    {\n        return to_json(j, std::forward<T>(val));\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `to_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)\n{\nconstexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value; // NOLINT(misc-definitions-in-headers)\n} // namespace\n} // namespace nlohmann\n\n// #include <nlohmann/detail/meta/identity_tag.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\n\ntemplate<typename ValueType, typename>\nstruct adl_serializer\n{\n    /*!\n    @brief convert a JSON value to any value type\n\n    This function is usually called by the `get()` function of the\n    @ref basic_json class (either explicit or via conversion operators).\n\n    @note This function is chosen for default-constructible value types.\n\n    @param[in] j        JSON value to read from\n    @param[in,out] val  value to write to\n    */\n    template<typename BasicJsonType, typename TargetType = ValueType>\n    static auto from_json(BasicJsonType && j, TargetType& val) noexcept(\n        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())\n    {\n        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);\n    }\n\n    /*!\n    @brief convert a JSON value to any value type\n\n    This function is usually called by the `get()` function of the\n    @ref basic_json class (either explicit or via conversion operators).\n\n    @note This function is chosen for value types which are not default-constructible.\n\n    @param[in] j  JSON value to read from\n\n    @return copy of the JSON value, converted to @a ValueType\n    */\n    template<typename BasicJsonType, typename TargetType = ValueType>\n    static auto from_json(BasicJsonType && j) noexcept(\n    noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))\n    {\n        return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});\n    }\n\n    /*!\n    @brief convert any value type to a JSON value\n\n    This function is usually called by the constructors of the @ref basic_json\n    class.\n\n    @param[in,out] j  JSON value to write to\n    @param[in] val    value to read from\n    */\n    template<typename BasicJsonType, typename TargetType = ValueType>\n    static auto to_json(BasicJsonType& j, TargetType && val) noexcept(\n        noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))\n    -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())\n    {\n        ::nlohmann::to_json(j, std::forward<TargetType>(val));\n    }\n};\n}  // namespace nlohmann\n\n// #include <nlohmann/byte_container_with_subtype.hpp>\n\n\n#include <cstdint> // uint8_t, uint64_t\n#include <tuple> // tie\n#include <utility> // move\n\nnamespace nlohmann\n{\n\n/*!\n@brief an internal type for a backed binary type\n\nThis type extends the template parameter @a BinaryType provided to `basic_json`\nwith a subtype used by BSON and MessagePack. This type exists so that the user\ndoes not have to specify a type themselves with a specific naming scheme in\norder to override the binary type.\n\n@tparam BinaryType container to store bytes (`std::vector<std::uint8_t>` by\n                   default)\n\n@since version 3.8.0; changed type of subtypes to std::uint64_t in 3.10.0.\n*/\ntemplate<typename BinaryType>\nclass byte_container_with_subtype : public BinaryType\n{\n  public:\n    /// the type of the underlying container\n    using container_type = BinaryType;\n    /// the type of the subtype\n    using subtype_type = std::uint64_t;\n\n    byte_container_with_subtype() noexcept(noexcept(container_type()))\n        : container_type()\n    {}\n\n    byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))\n        : container_type(b)\n    {}\n\n    byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))\n        : container_type(std::move(b))\n    {}\n\n    byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))\n        : container_type(b)\n        , m_subtype(subtype_)\n        , m_has_subtype(true)\n    {}\n\n    byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))\n        : container_type(std::move(b))\n        , m_subtype(subtype_)\n        , m_has_subtype(true)\n    {}\n\n    bool operator==(const byte_container_with_subtype& rhs) const\n    {\n        return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==\n               std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);\n    }\n\n    bool operator!=(const byte_container_with_subtype& rhs) const\n    {\n        return !(rhs == *this);\n    }\n\n    /*!\n    @brief sets the binary subtype\n\n    Sets the binary subtype of the value, also flags a binary JSON value as\n    having a subtype, which has implications for serialization.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa see @ref subtype() -- return the binary subtype\n    @sa see @ref clear_subtype() -- clears the binary subtype\n    @sa see @ref has_subtype() -- returns whether or not the binary value has a\n    subtype\n\n    @since version 3.8.0\n    */\n    void set_subtype(subtype_type subtype_) noexcept\n    {\n        m_subtype = subtype_;\n        m_has_subtype = true;\n    }\n\n    /*!\n    @brief return the binary subtype\n\n    Returns the numerical subtype of the value if it has a subtype. If it does\n    not have a subtype, this function will return subtype_type(-1) as a sentinel\n    value.\n\n    @return the numerical subtype of the binary value\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa see @ref set_subtype() -- sets the binary subtype\n    @sa see @ref clear_subtype() -- clears the binary subtype\n    @sa see @ref has_subtype() -- returns whether or not the binary value has a\n    subtype\n\n    @since version 3.8.0; fixed return value to properly return\n           subtype_type(-1) as documented in version 3.10.0\n    */\n    constexpr subtype_type subtype() const noexcept\n    {\n        return m_has_subtype ? m_subtype : subtype_type(-1);\n    }\n\n    /*!\n    @brief return whether the value has a subtype\n\n    @return whether the value has a subtype\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa see @ref subtype() -- return the binary subtype\n    @sa see @ref set_subtype() -- sets the binary subtype\n    @sa see @ref clear_subtype() -- clears the binary subtype\n\n    @since version 3.8.0\n    */\n    constexpr bool has_subtype() const noexcept\n    {\n        return m_has_subtype;\n    }\n\n    /*!\n    @brief clears the binary subtype\n\n    Clears the binary subtype and flags the value as not having a subtype, which\n    has implications for serialization; for instance MessagePack will prefer the\n    bin family over the ext family.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa see @ref subtype() -- return the binary subtype\n    @sa see @ref set_subtype() -- sets the binary subtype\n    @sa see @ref has_subtype() -- returns whether or not the binary value has a\n    subtype\n\n    @since version 3.8.0\n    */\n    void clear_subtype() noexcept\n    {\n        m_subtype = 0;\n        m_has_subtype = false;\n    }\n\n  private:\n    subtype_type m_subtype = 0;\n    bool m_has_subtype = false;\n};\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/hash.hpp>\n\n\n#include <cstdint> // uint8_t\n#include <cstddef> // size_t\n#include <functional> // hash\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n// boost::hash_combine\ninline std::size_t combine(std::size_t seed, std::size_t h) noexcept\n{\n    seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);\n    return seed;\n}\n\n/*!\n@brief hash a JSON value\n\nThe hash function tries to rely on std::hash where possible. Furthermore, the\ntype of the JSON value is taken into account to have different hash values for\nnull, 0, 0U, and false, etc.\n\n@tparam BasicJsonType basic_json specialization\n@param j JSON value to hash\n@return hash value of j\n*/\ntemplate<typename BasicJsonType>\nstd::size_t hash(const BasicJsonType& j)\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n\n    const auto type = static_cast<std::size_t>(j.type());\n    switch (j.type())\n    {\n        case BasicJsonType::value_t::null:\n        case BasicJsonType::value_t::discarded:\n        {\n            return combine(type, 0);\n        }\n\n        case BasicJsonType::value_t::object:\n        {\n            auto seed = combine(type, j.size());\n            for (const auto& element : j.items())\n            {\n                const auto h = std::hash<string_t> {}(element.key());\n                seed = combine(seed, h);\n                seed = combine(seed, hash(element.value()));\n            }\n            return seed;\n        }\n\n        case BasicJsonType::value_t::array:\n        {\n            auto seed = combine(type, j.size());\n            for (const auto& element : j)\n            {\n                seed = combine(seed, hash(element));\n            }\n            return seed;\n        }\n\n        case BasicJsonType::value_t::string:\n        {\n            const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::boolean:\n        {\n            const auto h = std::hash<bool> {}(j.template get<bool>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_integer:\n        {\n            const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_unsigned:\n        {\n            const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_float:\n        {\n            const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::binary:\n        {\n            auto seed = combine(type, j.get_binary().size());\n            const auto h = std::hash<bool> {}(j.get_binary().has_subtype());\n            seed = combine(seed, h);\n            seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));\n            for (const auto byte : j.get_binary())\n            {\n                seed = combine(seed, std::hash<std::uint8_t> {}(byte));\n            }\n            return seed;\n        }\n\n        default:                   // LCOV_EXCL_LINE\n            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n            return 0;              // LCOV_EXCL_LINE\n    }\n}\n\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n\n#include <algorithm> // generate_n\n#include <array> // array\n#include <cmath> // ldexp\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstdio> // snprintf\n#include <cstring> // memcpy\n#include <iterator> // back_inserter\n#include <limits> // numeric_limits\n#include <string> // char_traits, string\n#include <utility> // make_pair, move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <cstring> // strlen\n#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next\n#include <memory> // shared_ptr, make_shared, addressof\n#include <numeric> // accumulate\n#include <string> // string, char_traits\n#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer\n#include <utility> // pair, declval\n\n#ifndef JSON_NO_IO\n    #include <cstdio>   // FILE *\n    #include <istream>  // istream\n#endif                  // JSON_NO_IO\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// the supported input formats\nenum class input_format_t { json, cbor, msgpack, ubjson, bson };\n\n////////////////////\n// input adapters //\n////////////////////\n\n#ifndef JSON_NO_IO\n/*!\nInput adapter for stdio file access. This adapter read only 1 byte and do not use any\n buffer. This adapter is a very low level adapter.\n*/\nclass file_input_adapter\n{\n  public:\n    using char_type = char;\n\n    JSON_HEDLEY_NON_NULL(2)\n    explicit file_input_adapter(std::FILE* f) noexcept\n        : m_file(f)\n    {}\n\n    // make class move-only\n    file_input_adapter(const file_input_adapter&) = delete;\n    file_input_adapter(file_input_adapter&&) noexcept = default;\n    file_input_adapter& operator=(const file_input_adapter&) = delete;\n    file_input_adapter& operator=(file_input_adapter&&) = delete;\n    ~file_input_adapter() = default;\n\n    std::char_traits<char>::int_type get_character() noexcept\n    {\n        return std::fgetc(m_file);\n    }\n\n  private:\n    /// the file pointer to read from\n    std::FILE* m_file;\n};\n\n\n/*!\nInput adapter for a (caching) istream. Ignores a UFT Byte Order Mark at\nbeginning of input. Does not support changing the underlying std::streambuf\nin mid-input. Maintains underlying std::istream and std::streambuf to support\nsubsequent use of standard std::istream operations to process any input\ncharacters following those used in parsing the JSON input.  Clears the\nstd::istream flags; any input errors (e.g., EOF) will be detected by the first\nsubsequent call for input from the std::istream.\n*/\nclass input_stream_adapter\n{\n  public:\n    using char_type = char;\n\n    ~input_stream_adapter()\n    {\n        // clear stream flags; we use underlying streambuf I/O, do not\n        // maintain ifstream flags, except eof\n        if (is != nullptr)\n        {\n            is->clear(is->rdstate() & std::ios::eofbit);\n        }\n    }\n\n    explicit input_stream_adapter(std::istream& i)\n        : is(&i), sb(i.rdbuf())\n    {}\n\n    // delete because of pointer members\n    input_stream_adapter(const input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&&) = delete;\n\n    input_stream_adapter(input_stream_adapter&& rhs) noexcept\n        : is(rhs.is), sb(rhs.sb)\n    {\n        rhs.is = nullptr;\n        rhs.sb = nullptr;\n    }\n\n    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to\n    // ensure that std::char_traits<char>::eof() and the character 0xFF do not\n    // end up as the same value, eg. 0xFFFFFFFF.\n    std::char_traits<char>::int_type get_character()\n    {\n        auto res = sb->sbumpc();\n        // set eof manually, as we don't use the istream interface.\n        if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))\n        {\n            is->clear(is->rdstate() | std::ios::eofbit);\n        }\n        return res;\n    }\n\n  private:\n    /// the associated input stream\n    std::istream* is = nullptr;\n    std::streambuf* sb = nullptr;\n};\n#endif  // JSON_NO_IO\n\n// General-purpose iterator-based adapter. It might not be as fast as\n// theoretically possible for some containers, but it is extremely versatile.\ntemplate<typename IteratorType>\nclass iterator_input_adapter\n{\n  public:\n    using char_type = typename std::iterator_traits<IteratorType>::value_type;\n\n    iterator_input_adapter(IteratorType first, IteratorType last)\n        : current(std::move(first)), end(std::move(last))\n    {}\n\n    typename std::char_traits<char_type>::int_type get_character()\n    {\n        if (JSON_HEDLEY_LIKELY(current != end))\n        {\n            auto result = std::char_traits<char_type>::to_int_type(*current);\n            std::advance(current, 1);\n            return result;\n        }\n\n        return std::char_traits<char_type>::eof();\n    }\n\n  private:\n    IteratorType current;\n    IteratorType end;\n\n    template<typename BaseInputAdapter, size_t T>\n    friend struct wide_string_input_helper;\n\n    bool empty() const\n    {\n        return current == end;\n    }\n};\n\n\ntemplate<typename BaseInputAdapter, size_t T>\nstruct wide_string_input_helper;\n\ntemplate<typename BaseInputAdapter>\nstruct wide_string_input_helper<BaseInputAdapter, 4>\n{\n    // UTF-32\n    static void fill_buffer(BaseInputAdapter& input,\n                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n                            size_t& utf8_bytes_index,\n                            size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (JSON_HEDLEY_UNLIKELY(input.empty()))\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = input.get_character();\n\n            // UTF-32 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 2;\n            }\n            else if (wc <= 0xFFFF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 3;\n            }\n            else if (wc <= 0x10FFFF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 4;\n            }\n            else\n            {\n                // unknown character\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n        }\n    }\n};\n\ntemplate<typename BaseInputAdapter>\nstruct wide_string_input_helper<BaseInputAdapter, 2>\n{\n    // UTF-16\n    static void fill_buffer(BaseInputAdapter& input,\n                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n                            size_t& utf8_bytes_index,\n                            size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (JSON_HEDLEY_UNLIKELY(input.empty()))\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = input.get_character();\n\n            // UTF-16 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 2;\n            }\n            else if (0xD800 > wc || wc >= 0xE000)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 3;\n            }\n            else\n            {\n                if (JSON_HEDLEY_UNLIKELY(!input.empty()))\n                {\n                    const auto wc2 = static_cast<unsigned int>(input.get_character());\n                    const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));\n                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));\n                    utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));\n                    utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));\n                    utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));\n                    utf8_bytes_filled = 4;\n                }\n                else\n                {\n                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                    utf8_bytes_filled = 1;\n                }\n            }\n        }\n    }\n};\n\n// Wraps another input apdater to convert wide character types into individual bytes.\ntemplate<typename BaseInputAdapter, typename WideCharType>\nclass wide_string_input_adapter\n{\n  public:\n    using char_type = char;\n\n    wide_string_input_adapter(BaseInputAdapter base)\n        : base_adapter(base) {}\n\n    typename std::char_traits<char>::int_type get_character() noexcept\n    {\n        // check if buffer needs to be filled\n        if (utf8_bytes_index == utf8_bytes_filled)\n        {\n            fill_buffer<sizeof(WideCharType)>();\n\n            JSON_ASSERT(utf8_bytes_filled > 0);\n            JSON_ASSERT(utf8_bytes_index == 0);\n        }\n\n        // use buffer\n        JSON_ASSERT(utf8_bytes_filled > 0);\n        JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);\n        return utf8_bytes[utf8_bytes_index++];\n    }\n\n  private:\n    BaseInputAdapter base_adapter;\n\n    template<size_t T>\n    void fill_buffer()\n    {\n        wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);\n    }\n\n    /// a buffer for UTF-8 bytes\n    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};\n\n    /// index to the utf8_codes array for the next valid byte\n    std::size_t utf8_bytes_index = 0;\n    /// number of valid bytes in the utf8_codes array\n    std::size_t utf8_bytes_filled = 0;\n};\n\n\ntemplate<typename IteratorType, typename Enable = void>\nstruct iterator_input_adapter_factory\n{\n    using iterator_type = IteratorType;\n    using char_type = typename std::iterator_traits<iterator_type>::value_type;\n    using adapter_type = iterator_input_adapter<iterator_type>;\n\n    static adapter_type create(IteratorType first, IteratorType last)\n    {\n        return adapter_type(std::move(first), std::move(last));\n    }\n};\n\ntemplate<typename T>\nstruct is_iterator_of_multibyte\n{\n    using value_type = typename std::iterator_traits<T>::value_type;\n    enum\n    {\n        value = sizeof(value_type) > 1\n    };\n};\n\ntemplate<typename IteratorType>\nstruct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>\n{\n    using iterator_type = IteratorType;\n    using char_type = typename std::iterator_traits<iterator_type>::value_type;\n    using base_adapter_type = iterator_input_adapter<iterator_type>;\n    using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;\n\n    static adapter_type create(IteratorType first, IteratorType last)\n    {\n        return adapter_type(base_adapter_type(std::move(first), std::move(last)));\n    }\n};\n\n// General purpose iterator-based input\ntemplate<typename IteratorType>\ntypename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)\n{\n    using factory_type = iterator_input_adapter_factory<IteratorType>;\n    return factory_type::create(first, last);\n}\n\n// Convenience shorthand from container to iterator\n// Enables ADL on begin(container) and end(container)\n// Encloses the using declarations in namespace for not to leak them to outside scope\n\nnamespace container_input_adapter_factory_impl\n{\n\nusing std::begin;\nusing std::end;\n\ntemplate<typename ContainerType, typename Enable = void>\nstruct container_input_adapter_factory {};\n\ntemplate<typename ContainerType>\nstruct container_input_adapter_factory< ContainerType,\n       void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>\n       {\n           using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));\n\n           static adapter_type create(const ContainerType& container)\n{\n    return input_adapter(begin(container), end(container));\n}\n       };\n\n} // namespace container_input_adapter_factory_impl\n\ntemplate<typename ContainerType>\ntypename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)\n{\n    return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);\n}\n\n#ifndef JSON_NO_IO\n// Special cases with fast paths\ninline file_input_adapter input_adapter(std::FILE* file)\n{\n    return file_input_adapter(file);\n}\n\ninline input_stream_adapter input_adapter(std::istream& stream)\n{\n    return input_stream_adapter(stream);\n}\n\ninline input_stream_adapter input_adapter(std::istream&& stream)\n{\n    return input_stream_adapter(stream);\n}\n#endif  // JSON_NO_IO\n\nusing contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));\n\n// Null-delimited strings, and the like.\ntemplate < typename CharT,\n           typename std::enable_if <\n               std::is_pointer<CharT>::value&&\n               !std::is_array<CharT>::value&&\n               std::is_integral<typename std::remove_pointer<CharT>::type>::value&&\n               sizeof(typename std::remove_pointer<CharT>::type) == 1,\n               int >::type = 0 >\ncontiguous_bytes_input_adapter input_adapter(CharT b)\n{\n    auto length = std::strlen(reinterpret_cast<const char*>(b));\n    const auto* ptr = reinterpret_cast<const char*>(b);\n    return input_adapter(ptr, ptr + length);\n}\n\ntemplate<typename T, std::size_t N>\nauto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n{\n    return input_adapter(array, array + N);\n}\n\n// This class only handles inputs of input_buffer_adapter type.\n// It's required so that expressions like {ptr, len} can be implicitely casted\n// to the correct adapter.\nclass span_input_adapter\n{\n  public:\n    template < typename CharT,\n               typename std::enable_if <\n                   std::is_pointer<CharT>::value&&\n                   std::is_integral<typename std::remove_pointer<CharT>::type>::value&&\n                   sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                   int >::type = 0 >\n    span_input_adapter(CharT b, std::size_t l)\n        : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}\n\n    template<class IteratorType,\n             typename std::enable_if<\n                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,\n                 int>::type = 0>\n    span_input_adapter(IteratorType first, IteratorType last)\n        : ia(input_adapter(first, last)) {}\n\n    contiguous_bytes_input_adapter&& get()\n    {\n        return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)\n    }\n\n  private:\n    contiguous_bytes_input_adapter ia;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n\n#include <cstddef>\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\n/*!\n@brief SAX interface\n\nThis class describes the SAX interface used by @ref nlohmann::json::sax_parse.\nEach function is called in different situations while the input is parsed. The\nboolean return value informs the parser whether to continue processing the\ninput.\n*/\ntemplate<typename BasicJsonType>\nstruct json_sax\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    /*!\n    @brief a null value was read\n    @return whether parsing should proceed\n    */\n    virtual bool null() = 0;\n\n    /*!\n    @brief a boolean value was read\n    @param[in] val  boolean value\n    @return whether parsing should proceed\n    */\n    virtual bool boolean(bool val) = 0;\n\n    /*!\n    @brief an integer number was read\n    @param[in] val  integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_integer(number_integer_t val) = 0;\n\n    /*!\n    @brief an unsigned integer number was read\n    @param[in] val  unsigned integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_unsigned(number_unsigned_t val) = 0;\n\n    /*!\n    @brief an floating-point number was read\n    @param[in] val  floating-point value\n    @param[in] s    raw token value\n    @return whether parsing should proceed\n    */\n    virtual bool number_float(number_float_t val, const string_t& s) = 0;\n\n    /*!\n    @brief a string was read\n    @param[in] val  string value\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool string(string_t& val) = 0;\n\n    /*!\n    @brief a binary string was read\n    @param[in] val  binary value\n    @return whether parsing should proceed\n    @note It is safe to move the passed binary.\n    */\n    virtual bool binary(binary_t& val) = 0;\n\n    /*!\n    @brief the beginning of an object was read\n    @param[in] elements  number of object elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_object(std::size_t elements) = 0;\n\n    /*!\n    @brief an object key was read\n    @param[in] val  object key\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool key(string_t& val) = 0;\n\n    /*!\n    @brief the end of an object was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_object() = 0;\n\n    /*!\n    @brief the beginning of an array was read\n    @param[in] elements  number of array elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_array(std::size_t elements) = 0;\n\n    /*!\n    @brief the end of an array was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_array() = 0;\n\n    /*!\n    @brief a parse error occurred\n    @param[in] position    the position in the input where the error occurs\n    @param[in] last_token  the last read token\n    @param[in] ex          an exception object describing the error\n    @return whether parsing should proceed (must return false)\n    */\n    virtual bool parse_error(std::size_t position,\n                             const std::string& last_token,\n                             const detail::exception& ex) = 0;\n\n    json_sax() = default;\n    json_sax(const json_sax&) = default;\n    json_sax(json_sax&&) noexcept = default;\n    json_sax& operator=(const json_sax&) = default;\n    json_sax& operator=(json_sax&&) noexcept = default;\n    virtual ~json_sax() = default;\n};\n\n\nnamespace detail\n{\n/*!\n@brief SAX implementation to create a JSON value from SAX events\n\nThis class implements the @ref json_sax interface and processes the SAX events\nto create a JSON value which makes it basically a DOM parser. The structure or\nhierarchy of the JSON value is managed by the stack `ref_stack` which contains\na pointer to the respective array or object for each recursion depth.\n\nAfter successful parsing, the value that is passed by reference to the\nconstructor contains the parsed value.\n\n@tparam BasicJsonType  the JSON type\n*/\ntemplate<typename BasicJsonType>\nclass json_sax_dom_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    /*!\n    @param[in,out] r  reference to a JSON value that is manipulated while\n                       parsing\n    @param[in] allow_exceptions_  whether parse errors yield exceptions\n    */\n    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)\n        : root(r), allow_exceptions(allow_exceptions_)\n    {}\n\n    // make class move-only\n    json_sax_dom_parser(const json_sax_dom_parser&) = delete;\n    json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;\n    json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~json_sax_dom_parser() = default;\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool binary(binary_t& val)\n    {\n        handle_value(std::move(val));\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));\n\n        if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, \"excessive object size: \" + std::to_string(len), *ref_stack.back()));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        // add null at given key and store the reference for later\n        object_element = &(ref_stack.back()->m_value.object->operator[](val));\n        return true;\n    }\n\n    bool end_object()\n    {\n        ref_stack.back()->set_parents();\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));\n\n        if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, \"excessive array size: \" + std::to_string(len), *ref_stack.back()));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        ref_stack.back()->set_parents();\n        ref_stack.pop_back();\n        return true;\n    }\n\n    template<class Exception>\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const Exception& ex)\n    {\n        errored = true;\n        static_cast<void>(ex);\n        if (allow_exceptions)\n        {\n            JSON_THROW(ex);\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n    */\n    template<typename Value>\n    JSON_HEDLEY_RETURNS_NON_NULL\n    BasicJsonType* handle_value(Value&& v)\n    {\n        if (ref_stack.empty())\n        {\n            root = BasicJsonType(std::forward<Value>(v));\n            return &root;\n        }\n\n        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));\n            return &(ref_stack.back()->m_value.array->back());\n        }\n\n        JSON_ASSERT(ref_stack.back()->is_object());\n        JSON_ASSERT(object_element);\n        *object_element = BasicJsonType(std::forward<Value>(v));\n        return object_element;\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack {};\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_dom_callback_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using parser_callback_t = typename BasicJsonType::parser_callback_t;\n    using parse_event_t = typename BasicJsonType::parse_event_t;\n\n    json_sax_dom_callback_parser(BasicJsonType& r,\n                                 const parser_callback_t cb,\n                                 const bool allow_exceptions_ = true)\n        : root(r), callback(cb), allow_exceptions(allow_exceptions_)\n    {\n        keep_stack.push_back(true);\n    }\n\n    // make class move-only\n    json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;\n    json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;\n    json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~json_sax_dom_callback_parser() = default;\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool binary(binary_t& val)\n    {\n        handle_value(std::move(val));\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        // check callback for object start\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::object, true);\n        ref_stack.push_back(val.second);\n\n        // check object limit\n        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, \"excessive object size: \" + std::to_string(len), *ref_stack.back()));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        BasicJsonType k = BasicJsonType(val);\n\n        // check callback for key\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);\n        key_keep_stack.push_back(keep);\n\n        // add discarded value at given key and store the reference for later\n        if (keep && ref_stack.back())\n        {\n            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);\n        }\n\n        return true;\n    }\n\n    bool end_object()\n    {\n        if (ref_stack.back())\n        {\n            if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))\n            {\n                // discard object\n                *ref_stack.back() = discarded;\n            }\n            else\n            {\n                ref_stack.back()->set_parents();\n            }\n        }\n\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(!keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())\n        {\n            // remove discarded value\n            for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)\n            {\n                if (it->is_discarded())\n                {\n                    ref_stack.back()->erase(it);\n                    break;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::array, true);\n        ref_stack.push_back(val.second);\n\n        // check array limit\n        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, \"excessive array size: \" + std::to_string(len), *ref_stack.back()));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        bool keep = true;\n\n        if (ref_stack.back())\n        {\n            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());\n            if (keep)\n            {\n                ref_stack.back()->set_parents();\n            }\n            else\n            {\n                // discard array\n                *ref_stack.back() = discarded;\n            }\n        }\n\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(!keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        // remove discarded value\n        if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->pop_back();\n        }\n\n        return true;\n    }\n\n    template<class Exception>\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const Exception& ex)\n    {\n        errored = true;\n        static_cast<void>(ex);\n        if (allow_exceptions)\n        {\n            JSON_THROW(ex);\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @param[in] v  value to add to the JSON value we build during parsing\n    @param[in] skip_callback  whether we should skip calling the callback\n               function; this is required after start_array() and\n               start_object() SAX events, because otherwise we would call the\n               callback function with an empty array or object, respectively.\n\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n\n    @return pair of boolean (whether value should be kept) and pointer (to the\n            passed value in the ref_stack hierarchy; nullptr if not kept)\n    */\n    template<typename Value>\n    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)\n    {\n        JSON_ASSERT(!keep_stack.empty());\n\n        // do not handle this value if we know it would be added to a discarded\n        // container\n        if (!keep_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // create value\n        auto value = BasicJsonType(std::forward<Value>(v));\n\n        // check callback\n        const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);\n\n        // do not handle this value if we just learnt it shall be discarded\n        if (!keep)\n        {\n            return {false, nullptr};\n        }\n\n        if (ref_stack.empty())\n        {\n            root = std::move(value);\n            return {true, &root};\n        }\n\n        // skip this value if we already decided to skip the parent\n        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)\n        if (!ref_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // we now only expect arrays and objects\n        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());\n\n        // array\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->emplace_back(std::move(value));\n            return {true, &(ref_stack.back()->m_value.array->back())};\n        }\n\n        // object\n        JSON_ASSERT(ref_stack.back()->is_object());\n        // check if we should store an element for the current key\n        JSON_ASSERT(!key_keep_stack.empty());\n        const bool store_element = key_keep_stack.back();\n        key_keep_stack.pop_back();\n\n        if (!store_element)\n        {\n            return {false, nullptr};\n        }\n\n        JSON_ASSERT(object_element);\n        *object_element = std::move(value);\n        return {true, object_element};\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack {};\n    /// stack to manage which values to keep\n    std::vector<bool> keep_stack {};\n    /// stack to manage which object keys to keep\n    std::vector<bool> key_keep_stack {};\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n    /// a discarded value for the callback\n    BasicJsonType discarded = BasicJsonType::value_t::discarded;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_acceptor\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    bool null()\n    {\n        return true;\n    }\n\n    bool boolean(bool /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_integer(number_integer_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool string(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool binary(binary_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool start_object(std::size_t /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool key(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool end_object()\n    {\n        return true;\n    }\n\n    bool start_array(std::size_t /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool end_array()\n    {\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)\n    {\n        return false;\n    }\n};\n}  // namespace detail\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n\n#include <array> // array\n#include <clocale> // localeconv\n#include <cstddef> // size_t\n#include <cstdio> // snprintf\n#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull\n#include <initializer_list> // initializer_list\n#include <string> // char_traits, string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////\n// lexer //\n///////////\n\ntemplate<typename BasicJsonType>\nclass lexer_base\n{\n  public:\n    /// token types for the parser\n    enum class token_type\n    {\n        uninitialized,    ///< indicating the scanner is uninitialized\n        literal_true,     ///< the `true` literal\n        literal_false,    ///< the `false` literal\n        literal_null,     ///< the `null` literal\n        value_string,     ///< a string -- use get_string() for actual value\n        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value\n        value_integer,    ///< a signed integer -- use get_number_integer() for actual value\n        value_float,      ///< an floating point number -- use get_number_float() for actual value\n        begin_array,      ///< the character for array begin `[`\n        begin_object,     ///< the character for object begin `{`\n        end_array,        ///< the character for array end `]`\n        end_object,       ///< the character for object end `}`\n        name_separator,   ///< the name separator `:`\n        value_separator,  ///< the value separator `,`\n        parse_error,      ///< indicating a parse error\n        end_of_input,     ///< indicating the end of the input buffer\n        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)\n    };\n\n    /// return name of values of type token_type (only used for errors)\n    JSON_HEDLEY_RETURNS_NON_NULL\n    JSON_HEDLEY_CONST\n    static const char* token_type_name(const token_type t) noexcept\n    {\n        switch (t)\n        {\n            case token_type::uninitialized:\n                return \"<uninitialized>\";\n            case token_type::literal_true:\n                return \"true literal\";\n            case token_type::literal_false:\n                return \"false literal\";\n            case token_type::literal_null:\n                return \"null literal\";\n            case token_type::value_string:\n                return \"string literal\";\n            case token_type::value_unsigned:\n            case token_type::value_integer:\n            case token_type::value_float:\n                return \"number literal\";\n            case token_type::begin_array:\n                return \"'['\";\n            case token_type::begin_object:\n                return \"'{'\";\n            case token_type::end_array:\n                return \"']'\";\n            case token_type::end_object:\n                return \"'}'\";\n            case token_type::name_separator:\n                return \"':'\";\n            case token_type::value_separator:\n                return \"','\";\n            case token_type::parse_error:\n                return \"<parse error>\";\n            case token_type::end_of_input:\n                return \"end of input\";\n            case token_type::literal_or_value:\n                return \"'[', '{', or a literal\";\n            // LCOV_EXCL_START\n            default: // catch non-enum values\n                return \"unknown token\";\n                // LCOV_EXCL_STOP\n        }\n    }\n};\n/*!\n@brief lexical analysis\n\nThis class organizes the lexical analysis during JSON deserialization.\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass lexer : public lexer_base<BasicJsonType>\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using char_type = typename InputAdapterType::char_type;\n    using char_int_type = typename std::char_traits<char_type>::int_type;\n\n  public:\n    using token_type = typename lexer_base<BasicJsonType>::token_type;\n\n    explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept\n        : ia(std::move(adapter))\n        , ignore_comments(ignore_comments_)\n        , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))\n    {}\n\n    // delete because of pointer members\n    lexer(const lexer&) = delete;\n    lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    lexer& operator=(lexer&) = delete;\n    lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~lexer() = default;\n\n  private:\n    /////////////////////\n    // locales\n    /////////////////////\n\n    /// return the locale-dependent decimal point\n    JSON_HEDLEY_PURE\n    static char get_decimal_point() noexcept\n    {\n        const auto* loc = localeconv();\n        JSON_ASSERT(loc != nullptr);\n        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);\n    }\n\n    /////////////////////\n    // scan functions\n    /////////////////////\n\n    /*!\n    @brief get codepoint from 4 hex characters following `\\u`\n\n    For input \"\\u c1 c2 c3 c4\" the codepoint is:\n      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4\n    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)\n\n    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'\n    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The\n    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)\n    between the ASCII value of the character and the desired integer value.\n\n    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or\n            non-hex character)\n    */\n    int get_codepoint()\n    {\n        // this function only makes sense after reading `\\u`\n        JSON_ASSERT(current == 'u');\n        int codepoint = 0;\n\n        const auto factors = { 12u, 8u, 4u, 0u };\n        for (const auto factor : factors)\n        {\n            get();\n\n            if (current >= '0' && current <= '9')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);\n            }\n            else if (current >= 'A' && current <= 'F')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);\n            }\n            else if (current >= 'a' && current <= 'f')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);\n            }\n            else\n            {\n                return -1;\n            }\n        }\n\n        JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);\n        return codepoint;\n    }\n\n    /*!\n    @brief check if the next byte(s) are inside a given range\n\n    Adds the current byte and, for each passed range, reads a new byte and\n    checks if it is inside the range. If a violation was detected, set up an\n    error message and return false. Otherwise, return true.\n\n    @param[in] ranges  list of integers; interpreted as list of pairs of\n                       inclusive lower and upper bound, respectively\n\n    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,\n         1, 2, or 3 pairs. This precondition is enforced by an assertion.\n\n    @return true if and only if no range violation was detected\n    */\n    bool next_byte_in_range(std::initializer_list<char_int_type> ranges)\n    {\n        JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);\n        add(current);\n\n        for (auto range = ranges.begin(); range != ranges.end(); ++range)\n        {\n            get();\n            if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))\n            {\n                add(current);\n            }\n            else\n            {\n                error_message = \"invalid string: ill-formed UTF-8 byte\";\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief scan a string literal\n\n    This function scans a string according to Sect. 7 of RFC 8259. While\n    scanning, bytes are escaped and copied into buffer token_buffer. Then the\n    function returns successfully, token_buffer is *not* null-terminated (as it\n    may contain \\0 bytes), and token_buffer.size() is the number of bytes in the\n    string.\n\n    @return token_type::value_string if string could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note In case of errors, variable error_message contains a textual\n          description.\n    */\n    token_type scan_string()\n    {\n        // reset token_buffer (ignore opening quote)\n        reset();\n\n        // we entered the function by reading an open quote\n        JSON_ASSERT(current == '\\\"');\n\n        while (true)\n        {\n            // get next character\n            switch (get())\n            {\n                // end of file while parsing string\n                case std::char_traits<char_type>::eof():\n                {\n                    error_message = \"invalid string: missing closing quote\";\n                    return token_type::parse_error;\n                }\n\n                // closing quote\n                case '\\\"':\n                {\n                    return token_type::value_string;\n                }\n\n                // escapes\n                case '\\\\':\n                {\n                    switch (get())\n                    {\n                        // quotation mark\n                        case '\\\"':\n                            add('\\\"');\n                            break;\n                        // reverse solidus\n                        case '\\\\':\n                            add('\\\\');\n                            break;\n                        // solidus\n                        case '/':\n                            add('/');\n                            break;\n                        // backspace\n                        case 'b':\n                            add('\\b');\n                            break;\n                        // form feed\n                        case 'f':\n                            add('\\f');\n                            break;\n                        // line feed\n                        case 'n':\n                            add('\\n');\n                            break;\n                        // carriage return\n                        case 'r':\n                            add('\\r');\n                            break;\n                        // tab\n                        case 't':\n                            add('\\t');\n                            break;\n\n                        // unicode escapes\n                        case 'u':\n                        {\n                            const int codepoint1 = get_codepoint();\n                            int codepoint = codepoint1; // start with codepoint1\n\n                            if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))\n                            {\n                                error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                return token_type::parse_error;\n                            }\n\n                            // check if code point is a high surrogate\n                            if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)\n                            {\n                                // expect next \\uxxxx entry\n                                if (JSON_HEDLEY_LIKELY(get() == '\\\\' && get() == 'u'))\n                                {\n                                    const int codepoint2 = get_codepoint();\n\n                                    if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))\n                                    {\n                                        error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                        return token_type::parse_error;\n                                    }\n\n                                    // check if codepoint2 is a low surrogate\n                                    if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))\n                                    {\n                                        // overwrite codepoint\n                                        codepoint = static_cast<int>(\n                                                        // high surrogate occupies the most significant 22 bits\n                                                        (static_cast<unsigned int>(codepoint1) << 10u)\n                                                        // low surrogate occupies the least significant 15 bits\n                                                        + static_cast<unsigned int>(codepoint2)\n                                                        // there is still the 0xD800, 0xDC00 and 0x10000 noise\n                                                        // in the result so we have to subtract with:\n                                                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00\n                                                        - 0x35FDC00u);\n                                    }\n                                    else\n                                    {\n                                        error_message = \"invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF\";\n                                        return token_type::parse_error;\n                                    }\n                                }\n                                else\n                                {\n                                    error_message = \"invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n                            else\n                            {\n                                if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n\n                            // result of the above calculation yields a proper codepoint\n                            JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);\n\n                            // translate codepoint into bytes\n                            if (codepoint < 0x80)\n                            {\n                                // 1-byte characters: 0xxxxxxx (ASCII)\n                                add(static_cast<char_int_type>(codepoint));\n                            }\n                            else if (codepoint <= 0x7FF)\n                            {\n                                // 2-byte characters: 110xxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n                            else if (codepoint <= 0xFFFF)\n                            {\n                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n                            else\n                            {\n                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n\n                            break;\n                        }\n\n                        // other characters after escape\n                        default:\n                            error_message = \"invalid string: forbidden character after backslash\";\n                            return token_type::parse_error;\n                    }\n\n                    break;\n                }\n\n                // invalid control characters\n                case 0x00:\n                {\n                    error_message = \"invalid string: control character U+0000 (NUL) must be escaped to \\\\u0000\";\n                    return token_type::parse_error;\n                }\n\n                case 0x01:\n                {\n                    error_message = \"invalid string: control character U+0001 (SOH) must be escaped to \\\\u0001\";\n                    return token_type::parse_error;\n                }\n\n                case 0x02:\n                {\n                    error_message = \"invalid string: control character U+0002 (STX) must be escaped to \\\\u0002\";\n                    return token_type::parse_error;\n                }\n\n                case 0x03:\n                {\n                    error_message = \"invalid string: control character U+0003 (ETX) must be escaped to \\\\u0003\";\n                    return token_type::parse_error;\n                }\n\n                case 0x04:\n                {\n                    error_message = \"invalid string: control character U+0004 (EOT) must be escaped to \\\\u0004\";\n                    return token_type::parse_error;\n                }\n\n                case 0x05:\n                {\n                    error_message = \"invalid string: control character U+0005 (ENQ) must be escaped to \\\\u0005\";\n                    return token_type::parse_error;\n                }\n\n                case 0x06:\n                {\n                    error_message = \"invalid string: control character U+0006 (ACK) must be escaped to \\\\u0006\";\n                    return token_type::parse_error;\n                }\n\n                case 0x07:\n                {\n                    error_message = \"invalid string: control character U+0007 (BEL) must be escaped to \\\\u0007\";\n                    return token_type::parse_error;\n                }\n\n                case 0x08:\n                {\n                    error_message = \"invalid string: control character U+0008 (BS) must be escaped to \\\\u0008 or \\\\b\";\n                    return token_type::parse_error;\n                }\n\n                case 0x09:\n                {\n                    error_message = \"invalid string: control character U+0009 (HT) must be escaped to \\\\u0009 or \\\\t\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0A:\n                {\n                    error_message = \"invalid string: control character U+000A (LF) must be escaped to \\\\u000A or \\\\n\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0B:\n                {\n                    error_message = \"invalid string: control character U+000B (VT) must be escaped to \\\\u000B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0C:\n                {\n                    error_message = \"invalid string: control character U+000C (FF) must be escaped to \\\\u000C or \\\\f\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0D:\n                {\n                    error_message = \"invalid string: control character U+000D (CR) must be escaped to \\\\u000D or \\\\r\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0E:\n                {\n                    error_message = \"invalid string: control character U+000E (SO) must be escaped to \\\\u000E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0F:\n                {\n                    error_message = \"invalid string: control character U+000F (SI) must be escaped to \\\\u000F\";\n                    return token_type::parse_error;\n                }\n\n                case 0x10:\n                {\n                    error_message = \"invalid string: control character U+0010 (DLE) must be escaped to \\\\u0010\";\n                    return token_type::parse_error;\n                }\n\n                case 0x11:\n                {\n                    error_message = \"invalid string: control character U+0011 (DC1) must be escaped to \\\\u0011\";\n                    return token_type::parse_error;\n                }\n\n                case 0x12:\n                {\n                    error_message = \"invalid string: control character U+0012 (DC2) must be escaped to \\\\u0012\";\n                    return token_type::parse_error;\n                }\n\n                case 0x13:\n                {\n                    error_message = \"invalid string: control character U+0013 (DC3) must be escaped to \\\\u0013\";\n                    return token_type::parse_error;\n                }\n\n                case 0x14:\n                {\n                    error_message = \"invalid string: control character U+0014 (DC4) must be escaped to \\\\u0014\";\n                    return token_type::parse_error;\n                }\n\n                case 0x15:\n                {\n                    error_message = \"invalid string: control character U+0015 (NAK) must be escaped to \\\\u0015\";\n                    return token_type::parse_error;\n                }\n\n                case 0x16:\n                {\n                    error_message = \"invalid string: control character U+0016 (SYN) must be escaped to \\\\u0016\";\n                    return token_type::parse_error;\n                }\n\n                case 0x17:\n                {\n                    error_message = \"invalid string: control character U+0017 (ETB) must be escaped to \\\\u0017\";\n                    return token_type::parse_error;\n                }\n\n                case 0x18:\n                {\n                    error_message = \"invalid string: control character U+0018 (CAN) must be escaped to \\\\u0018\";\n                    return token_type::parse_error;\n                }\n\n                case 0x19:\n                {\n                    error_message = \"invalid string: control character U+0019 (EM) must be escaped to \\\\u0019\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1A:\n                {\n                    error_message = \"invalid string: control character U+001A (SUB) must be escaped to \\\\u001A\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1B:\n                {\n                    error_message = \"invalid string: control character U+001B (ESC) must be escaped to \\\\u001B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1C:\n                {\n                    error_message = \"invalid string: control character U+001C (FS) must be escaped to \\\\u001C\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1D:\n                {\n                    error_message = \"invalid string: control character U+001D (GS) must be escaped to \\\\u001D\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1E:\n                {\n                    error_message = \"invalid string: control character U+001E (RS) must be escaped to \\\\u001E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1F:\n                {\n                    error_message = \"invalid string: control character U+001F (US) must be escaped to \\\\u001F\";\n                    return token_type::parse_error;\n                }\n\n                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))\n                case 0x20:\n                case 0x21:\n                case 0x23:\n                case 0x24:\n                case 0x25:\n                case 0x26:\n                case 0x27:\n                case 0x28:\n                case 0x29:\n                case 0x2A:\n                case 0x2B:\n                case 0x2C:\n                case 0x2D:\n                case 0x2E:\n                case 0x2F:\n                case 0x30:\n                case 0x31:\n                case 0x32:\n                case 0x33:\n                case 0x34:\n                case 0x35:\n                case 0x36:\n                case 0x37:\n                case 0x38:\n                case 0x39:\n                case 0x3A:\n                case 0x3B:\n                case 0x3C:\n                case 0x3D:\n                case 0x3E:\n                case 0x3F:\n                case 0x40:\n                case 0x41:\n                case 0x42:\n                case 0x43:\n                case 0x44:\n                case 0x45:\n                case 0x46:\n                case 0x47:\n                case 0x48:\n                case 0x49:\n                case 0x4A:\n                case 0x4B:\n                case 0x4C:\n                case 0x4D:\n                case 0x4E:\n                case 0x4F:\n                case 0x50:\n                case 0x51:\n                case 0x52:\n                case 0x53:\n                case 0x54:\n                case 0x55:\n                case 0x56:\n                case 0x57:\n                case 0x58:\n                case 0x59:\n                case 0x5A:\n                case 0x5B:\n                case 0x5D:\n                case 0x5E:\n                case 0x5F:\n                case 0x60:\n                case 0x61:\n                case 0x62:\n                case 0x63:\n                case 0x64:\n                case 0x65:\n                case 0x66:\n                case 0x67:\n                case 0x68:\n                case 0x69:\n                case 0x6A:\n                case 0x6B:\n                case 0x6C:\n                case 0x6D:\n                case 0x6E:\n                case 0x6F:\n                case 0x70:\n                case 0x71:\n                case 0x72:\n                case 0x73:\n                case 0x74:\n                case 0x75:\n                case 0x76:\n                case 0x77:\n                case 0x78:\n                case 0x79:\n                case 0x7A:\n                case 0x7B:\n                case 0x7C:\n                case 0x7D:\n                case 0x7E:\n                case 0x7F:\n                {\n                    add(current);\n                    break;\n                }\n\n                // U+0080..U+07FF: bytes C2..DF 80..BF\n                case 0xC2:\n                case 0xC3:\n                case 0xC4:\n                case 0xC5:\n                case 0xC6:\n                case 0xC7:\n                case 0xC8:\n                case 0xC9:\n                case 0xCA:\n                case 0xCB:\n                case 0xCC:\n                case 0xCD:\n                case 0xCE:\n                case 0xCF:\n                case 0xD0:\n                case 0xD1:\n                case 0xD2:\n                case 0xD3:\n                case 0xD4:\n                case 0xD5:\n                case 0xD6:\n                case 0xD7:\n                case 0xD8:\n                case 0xD9:\n                case 0xDA:\n                case 0xDB:\n                case 0xDC:\n                case 0xDD:\n                case 0xDE:\n                case 0xDF:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF\n                case 0xE0:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF\n                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF\n                case 0xE1:\n                case 0xE2:\n                case 0xE3:\n                case 0xE4:\n                case 0xE5:\n                case 0xE6:\n                case 0xE7:\n                case 0xE8:\n                case 0xE9:\n                case 0xEA:\n                case 0xEB:\n                case 0xEC:\n                case 0xEE:\n                case 0xEF:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+D000..U+D7FF: bytes ED 80..9F 80..BF\n                case 0xED:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF\n                case 0xF0:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF\n                case 0xF1:\n                case 0xF2:\n                case 0xF3:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF\n                case 0xF4:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // remaining bytes (80..C1 and F5..FF) are ill-formed\n                default:\n                {\n                    error_message = \"invalid string: ill-formed UTF-8 byte\";\n                    return token_type::parse_error;\n                }\n            }\n        }\n    }\n\n    /*!\n     * @brief scan a comment\n     * @return whether comment could be scanned successfully\n     */\n    bool scan_comment()\n    {\n        switch (get())\n        {\n            // single-line comments skip input until a newline or EOF is read\n            case '/':\n            {\n                while (true)\n                {\n                    switch (get())\n                    {\n                        case '\\n':\n                        case '\\r':\n                        case std::char_traits<char_type>::eof():\n                        case '\\0':\n                            return true;\n\n                        default:\n                            break;\n                    }\n                }\n            }\n\n            // multi-line comments skip input until */ is read\n            case '*':\n            {\n                while (true)\n                {\n                    switch (get())\n                    {\n                        case std::char_traits<char_type>::eof():\n                        case '\\0':\n                        {\n                            error_message = \"invalid comment; missing closing '*/'\";\n                            return false;\n                        }\n\n                        case '*':\n                        {\n                            switch (get())\n                            {\n                                case '/':\n                                    return true;\n\n                                default:\n                                {\n                                    unget();\n                                    continue;\n                                }\n                            }\n                        }\n\n                        default:\n                            continue;\n                    }\n                }\n            }\n\n            // unexpected character after reading '/'\n            default:\n            {\n                error_message = \"invalid comment; expecting '/' or '*' after '/'\";\n                return false;\n            }\n        }\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(float& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtof(str, endptr);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtod(str, endptr);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(long double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtold(str, endptr);\n    }\n\n    /*!\n    @brief scan a number literal\n\n    This function scans a string according to Sect. 6 of RFC 8259.\n\n    The function is realized with a deterministic finite state machine derived\n    from the grammar described in RFC 8259. Starting in state \"d2Init\", the\n    input is read and used to determined the next state. Only state \"done\"\n    accepts the number. State \"error\" is a trap state to model errors. In the\n    table below, \"anything\" means any character but the ones listed before.\n\n    state    | 0        | 1-9      | e E      | +       | -       | .        | anything\n    ---------|----------|----------|----------|---------|---------|----------|-----------\n    d2Init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]\n    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]\n    zero     | done     | done     | exponent | done    | done    | decimal1 | done\n    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done\n    decimal1 | decimal2 | decimal2 | [error]  | [error] | [error] | [error]  | [error]\n    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done\n    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]\n    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]\n    any2     | any2     | any2     | done     | done    | done    | done     | done\n\n    The state machine is realized with one label per state (prefixed with\n    \"scan_number_\") and `goto` statements between them. The state machine\n    contains cycles, but any cycle can be left when EOF is read. Therefore,\n    the function is guaranteed to terminate.\n\n    During scanning, the read bytes are stored in token_buffer. This string is\n    then converted to a signed integer, an unsigned integer, or a\n    floating-point number.\n\n    @return token_type::value_unsigned, token_type::value_integer, or\n            token_type::value_float if number could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note The scanner is independent of the current locale. Internally, the\n          locale's decimal point is used instead of `.` to work with the\n          locale-dependent converters.\n    */\n    token_type scan_number()  // lgtm [cpp/use-of-goto]\n    {\n        // reset token_buffer to store the number's bytes\n        reset();\n\n        // the type of the parsed number; initially set to unsigned; will be\n        // changed if minus sign, decimal point or exponent is read\n        token_type number_type = token_type::value_unsigned;\n\n        // state (init): we just found out we need to scan a number\n        switch (current)\n        {\n            case '-':\n            {\n                add(current);\n                goto scan_number_minus;\n            }\n\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            // all other characters are rejected outside scan_number()\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n\nscan_number_minus:\n        // state: we just parsed a leading minus sign\n        number_type = token_type::value_integer;\n        switch (get())\n        {\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '-'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_zero:\n        // state: we just parse a zero (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_any1:\n        // state: we just parsed a number 0-9 (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_decimal1:\n        // state: we just parsed a decimal point\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '.'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_decimal2:\n        // we just parsed at least one number after a decimal point\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_exponent:\n        // we just parsed an exponent\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '+':\n            case '-':\n            {\n                add(current);\n                goto scan_number_sign;\n            }\n\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message =\n                    \"invalid number; expected '+', '-', or digit after exponent\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_sign:\n        // we just parsed an exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after exponent sign\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_any2:\n        // we just parsed a number after the exponent or exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_done:\n        // unget the character after the number (we only read it to know that\n        // we are done scanning a number)\n        unget();\n\n        char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n        errno = 0;\n\n        // try to parse integers first and fall back to floats\n        if (number_type == token_type::value_unsigned)\n        {\n            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_unsigned = static_cast<number_unsigned_t>(x);\n                if (value_unsigned == x)\n                {\n                    return token_type::value_unsigned;\n                }\n            }\n        }\n        else if (number_type == token_type::value_integer)\n        {\n            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_integer = static_cast<number_integer_t>(x);\n                if (value_integer == x)\n                {\n                    return token_type::value_integer;\n                }\n            }\n        }\n\n        // this code is reached if we parse a floating-point number or if an\n        // integer conversion above failed\n        strtof(value_float, token_buffer.data(), &endptr);\n\n        // we checked the number format before\n        JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n        return token_type::value_float;\n    }\n\n    /*!\n    @param[in] literal_text  the literal text to expect\n    @param[in] length        the length of the passed literal text\n    @param[in] return_type   the token type to return on success\n    */\n    JSON_HEDLEY_NON_NULL(2)\n    token_type scan_literal(const char_type* literal_text, const std::size_t length,\n                            token_type return_type)\n    {\n        JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);\n        for (std::size_t i = 1; i < length; ++i)\n        {\n            if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))\n            {\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n            }\n        }\n        return return_type;\n    }\n\n    /////////////////////\n    // input management\n    /////////////////////\n\n    /// reset token_buffer; current character is beginning of token\n    void reset() noexcept\n    {\n        token_buffer.clear();\n        token_string.clear();\n        token_string.push_back(std::char_traits<char_type>::to_char_type(current));\n    }\n\n    /*\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a\n    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters\n    for use in error messages.\n\n    @return character read from the input\n    */\n    char_int_type get()\n    {\n        ++position.chars_read_total;\n        ++position.chars_read_current_line;\n\n        if (next_unget)\n        {\n            // just reset the next_unget variable and work with current\n            next_unget = false;\n        }\n        else\n        {\n            current = ia.get_character();\n        }\n\n        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))\n        {\n            token_string.push_back(std::char_traits<char_type>::to_char_type(current));\n        }\n\n        if (current == '\\n')\n        {\n            ++position.lines_read;\n            position.chars_read_current_line = 0;\n        }\n\n        return current;\n    }\n\n    /*!\n    @brief unget current character (read it again on next get)\n\n    We implement unget by setting variable next_unget to true. The input is not\n    changed - we just simulate ungetting by modifying chars_read_total,\n    chars_read_current_line, and token_string. The next call to get() will\n    behave as if the unget character is read again.\n    */\n    void unget()\n    {\n        next_unget = true;\n\n        --position.chars_read_total;\n\n        // in case we \"unget\" a newline, we have to also decrement the lines_read\n        if (position.chars_read_current_line == 0)\n        {\n            if (position.lines_read > 0)\n            {\n                --position.lines_read;\n            }\n        }\n        else\n        {\n            --position.chars_read_current_line;\n        }\n\n        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))\n        {\n            JSON_ASSERT(!token_string.empty());\n            token_string.pop_back();\n        }\n    }\n\n    /// add a character to token_buffer\n    void add(char_int_type c)\n    {\n        token_buffer.push_back(static_cast<typename string_t::value_type>(c));\n    }\n\n  public:\n    /////////////////////\n    // value getters\n    /////////////////////\n\n    /// return integer value\n    constexpr number_integer_t get_number_integer() const noexcept\n    {\n        return value_integer;\n    }\n\n    /// return unsigned integer value\n    constexpr number_unsigned_t get_number_unsigned() const noexcept\n    {\n        return value_unsigned;\n    }\n\n    /// return floating-point value\n    constexpr number_float_t get_number_float() const noexcept\n    {\n        return value_float;\n    }\n\n    /// return current string value (implicitly resets the token; useful only once)\n    string_t& get_string()\n    {\n        return token_buffer;\n    }\n\n    /////////////////////\n    // diagnostics\n    /////////////////////\n\n    /// return position of last read token\n    constexpr position_t get_position() const noexcept\n    {\n        return position;\n    }\n\n    /// return the last read token (for errors only).  Will never contain EOF\n    /// (an arbitrary value that is not a valid char value, often -1), because\n    /// 255 may legitimately occur.  May contain NUL, which should be escaped.\n    std::string get_token_string() const\n    {\n        // escape control characters\n        std::string result;\n        for (const auto c : token_string)\n        {\n            if (static_cast<unsigned char>(c) <= '\\x1F')\n            {\n                // escape control characters\n                std::array<char, 9> cs{{}};\n                (std::snprintf)(cs.data(), cs.size(), \"<U+%.4X>\", static_cast<unsigned char>(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                result += cs.data();\n            }\n            else\n            {\n                // add character as is\n                result.push_back(static_cast<std::string::value_type>(c));\n            }\n        }\n\n        return result;\n    }\n\n    /// return syntax error message\n    JSON_HEDLEY_RETURNS_NON_NULL\n    constexpr const char* get_error_message() const noexcept\n    {\n        return error_message;\n    }\n\n    /////////////////////\n    // actual scanner\n    /////////////////////\n\n    /*!\n    @brief skip the UTF-8 byte order mark\n    @return true iff there is no BOM or the correct BOM has been skipped\n    */\n    bool skip_bom()\n    {\n        if (get() == 0xEF)\n        {\n            // check if we completely parse the BOM\n            return get() == 0xBB && get() == 0xBF;\n        }\n\n        // the first character is not the beginning of the BOM; unget it to\n        // process is later\n        unget();\n        return true;\n    }\n\n    void skip_whitespace()\n    {\n        do\n        {\n            get();\n        }\n        while (current == ' ' || current == '\\t' || current == '\\n' || current == '\\r');\n    }\n\n    token_type scan()\n    {\n        // initially, skip the BOM\n        if (position.chars_read_total == 0 && !skip_bom())\n        {\n            error_message = \"invalid BOM; must be 0xEF 0xBB 0xBF if given\";\n            return token_type::parse_error;\n        }\n\n        // read next character and ignore whitespace\n        skip_whitespace();\n\n        // ignore comments\n        while (ignore_comments && current == '/')\n        {\n            if (!scan_comment())\n            {\n                return token_type::parse_error;\n            }\n\n            // skip following whitespace\n            skip_whitespace();\n        }\n\n        switch (current)\n        {\n            // structural characters\n            case '[':\n                return token_type::begin_array;\n            case ']':\n                return token_type::end_array;\n            case '{':\n                return token_type::begin_object;\n            case '}':\n                return token_type::end_object;\n            case ':':\n                return token_type::name_separator;\n            case ',':\n                return token_type::value_separator;\n\n            // literals\n            case 't':\n            {\n                std::array<char_type, 4> true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}};\n                return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);\n            }\n            case 'f':\n            {\n                std::array<char_type, 5> false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}};\n                return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);\n            }\n            case 'n':\n            {\n                std::array<char_type, 4> null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}};\n                return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);\n            }\n\n            // string\n            case '\\\"':\n                return scan_string();\n\n            // number\n            case '-':\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                return scan_number();\n\n            // end of input (the null byte is needed when parsing from\n            // string literals)\n            case '\\0':\n            case std::char_traits<char_type>::eof():\n                return token_type::end_of_input;\n\n            // error\n            default:\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n        }\n    }\n\n  private:\n    /// input adapter\n    InputAdapterType ia;\n\n    /// whether comments should be ignored (true) or signaled as errors (false)\n    const bool ignore_comments = false;\n\n    /// the current character\n    char_int_type current = std::char_traits<char_type>::eof();\n\n    /// whether the next get() call should just return current\n    bool next_unget = false;\n\n    /// the start position of the current token\n    position_t position {};\n\n    /// raw input token string (for error messages)\n    std::vector<char_type> token_string {};\n\n    /// buffer for variable-length tokens (numbers, strings)\n    string_t token_buffer {};\n\n    /// a description of occurred lexer errors\n    const char* error_message = \"\";\n\n    // number values\n    number_integer_t value_integer = 0;\n    number_unsigned_t value_unsigned = 0;\n    number_float_t value_float = 0;\n\n    /// the decimal point\n    const char_int_type decimal_point_char = '.';\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n\n#include <cstdint> // size_t\n#include <utility> // declval\n#include <string> // string\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename T>\nusing null_function_t = decltype(std::declval<T&>().null());\n\ntemplate<typename T>\nusing boolean_function_t =\n    decltype(std::declval<T&>().boolean(std::declval<bool>()));\n\ntemplate<typename T, typename Integer>\nusing number_integer_function_t =\n    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));\n\ntemplate<typename T, typename Unsigned>\nusing number_unsigned_function_t =\n    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));\n\ntemplate<typename T, typename Float, typename String>\nusing number_float_function_t = decltype(std::declval<T&>().number_float(\n                                    std::declval<Float>(), std::declval<const String&>()));\n\ntemplate<typename T, typename String>\nusing string_function_t =\n    decltype(std::declval<T&>().string(std::declval<String&>()));\n\ntemplate<typename T, typename Binary>\nusing binary_function_t =\n    decltype(std::declval<T&>().binary(std::declval<Binary&>()));\n\ntemplate<typename T>\nusing start_object_function_t =\n    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));\n\ntemplate<typename T, typename String>\nusing key_function_t =\n    decltype(std::declval<T&>().key(std::declval<String&>()));\n\ntemplate<typename T>\nusing end_object_function_t = decltype(std::declval<T&>().end_object());\n\ntemplate<typename T>\nusing start_array_function_t =\n    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));\n\ntemplate<typename T>\nusing end_array_function_t = decltype(std::declval<T&>().end_array());\n\ntemplate<typename T, typename Exception>\nusing parse_error_function_t = decltype(std::declval<T&>().parse_error(\n        std::declval<std::size_t>(), std::declval<const std::string&>(),\n        std::declval<const Exception&>()));\n\ntemplate<typename SAX, typename BasicJsonType>\nstruct is_sax\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static constexpr bool value =\n        is_detected_exact<bool, null_function_t, SAX>::value &&\n        is_detected_exact<bool, boolean_function_t, SAX>::value &&\n        is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&\n        is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&\n        is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&\n        is_detected_exact<bool, start_object_function_t, SAX>::value &&\n        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, end_object_function_t, SAX>::value &&\n        is_detected_exact<bool, start_array_function_t, SAX>::value &&\n        is_detected_exact<bool, end_array_function_t, SAX>::value &&\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;\n};\n\ntemplate<typename SAX, typename BasicJsonType>\nstruct is_sax_static_asserts\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,\n                  \"Missing/invalid function: bool null()\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(\n        is_detected_exact<bool, number_integer_function_t, SAX,\n        number_integer_t>::value,\n        \"Missing/invalid function: bool number_integer(number_integer_t)\");\n    static_assert(\n        is_detected_exact<bool, number_unsigned_function_t, SAX,\n        number_unsigned_t>::value,\n        \"Missing/invalid function: bool number_unsigned(number_unsigned_t)\");\n    static_assert(is_detected_exact<bool, number_float_function_t, SAX,\n                  number_float_t, string_t>::value,\n                  \"Missing/invalid function: bool number_float(number_float_t, const string_t&)\");\n    static_assert(\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value,\n        \"Missing/invalid function: bool string(string_t&)\");\n    static_assert(\n        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,\n        \"Missing/invalid function: bool binary(binary_t&)\");\n    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_object(std::size_t)\");\n    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,\n                  \"Missing/invalid function: bool key(string_t&)\");\n    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_object()\");\n    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_array(std::size_t)\");\n    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_array()\");\n    static_assert(\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,\n        \"Missing/invalid function: bool parse_error(std::size_t, const \"\n        \"std::string&, const exception&)\");\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/// how to treat CBOR tags\nenum class cbor_tag_handler_t\n{\n    error,   ///< throw a parse_error exception in case of a tag\n    ignore,  ///< ignore tags\n    store    ///< store tags as binary type\n};\n\n/*!\n@brief determine system byte order\n\n@return true if and only if system's byte order is little endian\n\n@note from https://stackoverflow.com/a/1001328/266378\n*/\nstatic inline bool little_endianess(int num = 1) noexcept\n{\n    return *reinterpret_cast<char*>(&num) == 1;\n}\n\n\n///////////////////\n// binary reader //\n///////////////////\n\n/*!\n@brief deserialization of CBOR, MessagePack, and UBJSON values\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>\nclass binary_reader\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using json_sax_t = SAX;\n    using char_type = typename InputAdapterType::char_type;\n    using char_int_type = typename std::char_traits<char_type>::int_type;\n\n  public:\n    /*!\n    @brief create a binary reader\n\n    @param[in] adapter  input adapter to read from\n    */\n    explicit binary_reader(InputAdapterType&& adapter) noexcept : ia(std::move(adapter))\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n    }\n\n    // make class move-only\n    binary_reader(const binary_reader&) = delete;\n    binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    binary_reader& operator=(const binary_reader&) = delete;\n    binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~binary_reader() = default;\n\n    /*!\n    @param[in] format  the binary format to parse\n    @param[in] sax_    a SAX event processor\n    @param[in] strict  whether to expect the input to be consumed completed\n    @param[in] tag_handler  how to treat CBOR tags\n\n    @return whether parsing was successful\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    bool sax_parse(const input_format_t format,\n                   json_sax_t* sax_,\n                   const bool strict = true,\n                   const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        sax = sax_;\n        bool result = false;\n\n        switch (format)\n        {\n            case input_format_t::bson:\n                result = parse_bson_internal();\n                break;\n\n            case input_format_t::cbor:\n                result = parse_cbor_internal(true, tag_handler);\n                break;\n\n            case input_format_t::msgpack:\n                result = parse_msgpack_internal();\n                break;\n\n            case input_format_t::ubjson:\n                result = parse_ubjson_internal();\n                break;\n\n            case input_format_t::json: // LCOV_EXCL_LINE\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n\n        // strict mode: next byte must be EOF\n        if (result && strict)\n        {\n            if (format == input_format_t::ubjson)\n            {\n                get_ignore_noop();\n            }\n            else\n            {\n                get();\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))\n            {\n                return sax->parse_error(chars_read, get_token_string(),\n                                        parse_error::create(110, chars_read, exception_message(format, \"expected end of input; last byte: 0x\" + get_token_string(), \"value\"), BasicJsonType()));\n            }\n        }\n\n        return result;\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @brief Reads in a BSON-object and passes it to the SAX-parser.\n    @return whether a valid BSON-value was passed to the SAX parser\n    */\n    bool parse_bson_internal()\n    {\n        std::int32_t document_size{};\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))\n        {\n            return false;\n        }\n\n        return sax->end_object();\n    }\n\n    /*!\n    @brief Parses a C-style string from the BSON input.\n    @param[in,out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @return `true` if the \\x00-byte indicating the end of the string was\n             encountered before the EOF; false` indicates an unexpected EOF.\n    */\n    bool get_bson_cstr(string_t& result)\n    {\n        auto out = std::back_inserter(result);\n        while (true)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, \"cstring\")))\n            {\n                return false;\n            }\n            if (current == 0x00)\n            {\n                return true;\n            }\n            *out++ = static_cast<typename string_t::value_type>(current);\n        }\n    }\n\n    /*!\n    @brief Parses a zero-terminated string of length @a len from the BSON\n           input.\n    @param[in] len  The length (including the zero-byte at the end) of the\n                    string to be read.\n    @param[in,out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 1\n    @return `true` if the string was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_string(const NumberType len, string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(len < 1))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"string length must be at least 1, is \" + std::to_string(len), \"string\"), BasicJsonType()));\n        }\n\n        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();\n    }\n\n    /*!\n    @brief Parses a byte array input of length @a len from the BSON input.\n    @param[in] len  The length of the byte array to be read.\n    @param[in,out] result  A reference to the binary variable where the read\n                            array is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 0\n    @return `true` if the byte array was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_binary(const NumberType len, binary_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(len < 0))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"byte array length cannot be negative, is \" + std::to_string(len), \"binary\"), BasicJsonType()));\n        }\n\n        // All BSON binary values have a subtype\n        std::uint8_t subtype{};\n        get_number<std::uint8_t>(input_format_t::bson, subtype);\n        result.set_subtype(subtype);\n\n        return get_binary(input_format_t::bson, len, result);\n    }\n\n    /*!\n    @brief Read a BSON document element of the given @a element_type.\n    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html\n    @param[in] element_type_parse_position The position in the input stream,\n               where the `element_type` was read.\n    @warning Not all BSON element types are supported yet. An unsupported\n             @a element_type will give rise to a parse_error.114:\n             Unsupported BSON record type 0x...\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_internal(const char_int_type element_type,\n                                     const std::size_t element_type_parse_position)\n    {\n        switch (element_type)\n        {\n            case 0x01: // double\n            {\n                double number{};\n                return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0x02: // string\n            {\n                std::int32_t len{};\n                string_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);\n            }\n\n            case 0x03: // object\n            {\n                return parse_bson_internal();\n            }\n\n            case 0x04: // array\n            {\n                return parse_bson_array();\n            }\n\n            case 0x05: // binary\n            {\n                std::int32_t len{};\n                binary_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);\n            }\n\n            case 0x08: // boolean\n            {\n                return sax->boolean(get() != 0);\n            }\n\n            case 0x0A: // null\n            {\n                return sax->null();\n            }\n\n            case 0x10: // int32\n            {\n                std::int32_t value{};\n                return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);\n            }\n\n            case 0x12: // int64\n            {\n                std::int64_t value{};\n                return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);\n            }\n\n            default: // anything else not supported (yet)\n            {\n                std::array<char, 3> cr{{}};\n                (std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(element_type)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, \"Unsupported BSON record type 0x\" + std::string(cr.data()), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @brief Read a BSON element list (as specified in the BSON-spec)\n\n    The same binary layout is used for objects and arrays, hence it must be\n    indicated with the argument @a is_array which one is expected\n    (true --> array, false --> object).\n\n    @param[in] is_array Determines if the element list being read is to be\n                        treated as an object (@a is_array == false), or as an\n                        array (@a is_array == true).\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_list(const bool is_array)\n    {\n        string_t key;\n\n        while (auto element_type = get())\n        {\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, \"element list\")))\n            {\n                return false;\n            }\n\n            const std::size_t element_type_parse_position = chars_read;\n            if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))\n            {\n                return false;\n            }\n\n            if (!is_array && !sax->key(key))\n            {\n                return false;\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))\n            {\n                return false;\n            }\n\n            // get_bson_cstr only appends\n            key.clear();\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Reads an array from the BSON input and passes it to the SAX-parser.\n    @return whether a valid BSON-array was passed to the SAX parser\n    */\n    bool parse_bson_array()\n    {\n        std::int32_t document_size{};\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))\n        {\n            return false;\n        }\n\n        return sax->end_array();\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true) or whether the last read character should\n                         be considered instead (false)\n    @param[in] tag_handler how CBOR tags should be treated\n\n    @return whether a valid CBOR value was passed to the SAX parser\n    */\n    bool parse_cbor_internal(const bool get_char,\n                             const cbor_tag_handler_t tag_handler)\n    {\n        switch (get_char ? get() : current)\n        {\n            // EOF\n            case std::char_traits<char_type>::eof():\n                return unexpect_eof(input_format_t::cbor, \"value\");\n\n            // Integer 0x00..0x17 (0..23)\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            case 0x18: // Unsigned integer (one-byte uint8_t follows)\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x19: // Unsigned integer (two-byte uint16_t follows)\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x1A: // Unsigned integer (four-byte uint32_t follows)\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            // Negative integer -1-0x00..-1-0x17 (-1..-24)\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n                return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));\n\n            case 0x38: // Negative integer (one-byte uint8_t follows)\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)\n                        - static_cast<number_integer_t>(number));\n            }\n\n            // Binary data (0x00..0x17 bytes follow)\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58: // Binary data (one-byte uint8_t for n follows)\n            case 0x59: // Binary data (two-byte uint16_t for n follow)\n            case 0x5A: // Binary data (four-byte uint32_t for n follow)\n            case 0x5B: // Binary data (eight-byte uint64_t for n follow)\n            case 0x5F: // Binary data (indefinite length)\n            {\n                binary_t b;\n                return get_cbor_binary(b) && sax->binary(b);\n            }\n\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                string_t s;\n                return get_cbor_string(s) && sax->string(s);\n            }\n\n            // array (0x00..0x17 data items follow)\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n                return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);\n\n            case 0x98: // array (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x99: // array (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9A: // array (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9B: // array (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(detail::conditional_static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9F: // array (indefinite length)\n                return get_cbor_array(std::size_t(-1), tag_handler);\n\n            // map (0x00..0x17 pairs of data items follow)\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n                return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);\n\n            case 0xB8: // map (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xB9: // map (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBA: // map (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBB: // map (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(detail::conditional_static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBF: // map (indefinite length)\n                return get_cbor_object(std::size_t(-1), tag_handler);\n\n            case 0xC6: // tagged item\n            case 0xC7:\n            case 0xC8:\n            case 0xC9:\n            case 0xCA:\n            case 0xCB:\n            case 0xCC:\n            case 0xCD:\n            case 0xCE:\n            case 0xCF:\n            case 0xD0:\n            case 0xD1:\n            case 0xD2:\n            case 0xD3:\n            case 0xD4:\n            case 0xD8: // tagged item (1 bytes follow)\n            case 0xD9: // tagged item (2 bytes follow)\n            case 0xDA: // tagged item (4 bytes follow)\n            case 0xDB: // tagged item (8 bytes follow)\n            {\n                switch (tag_handler)\n                {\n                    case cbor_tag_handler_t::error:\n                    {\n                        auto last_token = get_token_string();\n                        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\"), BasicJsonType()));\n                    }\n\n                    case cbor_tag_handler_t::ignore:\n                    {\n                        // ignore binary subtype\n                        switch (current)\n                        {\n                            case 0xD8:\n                            {\n                                std::uint8_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            case 0xD9:\n                            {\n                                std::uint16_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            case 0xDA:\n                            {\n                                std::uint32_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            case 0xDB:\n                            {\n                                std::uint64_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            default:\n                                break;\n                        }\n                        return parse_cbor_internal(true, tag_handler);\n                    }\n\n                    case cbor_tag_handler_t::store:\n                    {\n                        binary_t b;\n                        // use binary subtype and store in binary container\n                        switch (current)\n                        {\n                            case 0xD8:\n                            {\n                                std::uint8_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            case 0xD9:\n                            {\n                                std::uint16_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            case 0xDA:\n                            {\n                                std::uint32_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            case 0xDB:\n                            {\n                                std::uint64_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            default:\n                                return parse_cbor_internal(true, tag_handler);\n                        }\n                        get();\n                        return get_cbor_binary(b) && sax->binary(b);\n                    }\n\n                    default:                 // LCOV_EXCL_LINE\n                        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n                        return false;        // LCOV_EXCL_LINE\n                }\n            }\n\n            case 0xF4: // false\n                return sax->boolean(false);\n\n            case 0xF5: // true\n                return sax->boolean(true);\n\n            case 0xF6: // null\n                return sax->null();\n\n            case 0xF9: // Half-Precision Float (two-byte IEEE 754)\n            {\n                const auto byte1_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n                const auto byte2_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n\n                const auto byte1 = static_cast<unsigned char>(byte1_raw);\n                const auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n                // code from RFC 7049, Appendix D, Figure 3:\n                // As half-precision floating-point numbers were only added\n                // to IEEE 754 in 2008, today's programming platforms often\n                // still only have limited support for them. It is very\n                // easy to include at least decoding support for them even\n                // without such support. An example of a small decoder for\n                // half-precision floating-point numbers in the C language\n                // is shown in Fig. 3.\n                const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);\n                const double val = [&half]\n                {\n                    const int exp = (half >> 10u) & 0x1Fu;\n                    const unsigned int mant = half & 0x3FFu;\n                    JSON_ASSERT(0 <= exp&& exp <= 32);\n                    JSON_ASSERT(mant <= 1024);\n                    switch (exp)\n                    {\n                        case 0:\n                            return std::ldexp(mant, -24);\n                        case 31:\n                            return (mant == 0)\n                            ? std::numeric_limits<double>::infinity()\n                            : std::numeric_limits<double>::quiet_NaN();\n                        default:\n                            return std::ldexp(mant + 1024, exp - 25);\n                    }\n                }();\n                return sax->number_float((half & 0x8000u) != 0\n                                         ? static_cast<number_float_t>(-val)\n                                         : static_cast<number_float_t>(val), \"\");\n            }\n\n            case 0xFA: // Single-Precision Float (four-byte IEEE 754)\n            {\n                float number{};\n                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)\n            {\n                double number{};\n                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            default: // anything else (0xFF is handled inside the other types)\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n    Additionally, CBOR's strings with indefinite lengths are supported.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_cbor_string(string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            {\n                return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    string_t chunk;\n                    if (!get_cbor_string(chunk))\n                    {\n                        return false;\n                    }\n                    result.append(chunk);\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x\" + last_token, \"string\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR byte array\n\n    This function first reads starting bytes to determine the expected\n    byte array length and then copies this number of bytes into the byte array.\n    Additionally, CBOR's byte arrays with indefinite lengths are supported.\n\n    @param[out] result  created byte array\n\n    @return whether byte array creation completed\n    */\n    bool get_cbor_binary(binary_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"binary\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // Binary data (0x00..0x17 bytes follow)\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            {\n                return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0x58: // Binary data (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x59: // Binary data (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5A: // Binary data (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5B: // Binary data (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5F: // Binary data (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    binary_t chunk;\n                    if (!get_cbor_binary(chunk))\n                    {\n                        return false;\n                    }\n                    result.insert(result.end(), chunk.begin(), chunk.end());\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x\" + last_token, \"binary\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array or std::size_t(-1) for an\n                    array of indefinite size\n    @param[in] tag_handler how CBOR tags should be treated\n    @return whether array creation completed\n    */\n    bool get_cbor_array(const std::size_t len,\n                        const cbor_tag_handler_t tag_handler)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))\n        {\n            return false;\n        }\n\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                {\n                    return false;\n                }\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))\n                {\n                    return false;\n                }\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object or std::size_t(-1) for an\n                    object of indefinite size\n    @param[in] tag_handler how CBOR tags should be treated\n    @return whether object creation completed\n    */\n    bool get_cbor_object(const std::size_t len,\n                         const cbor_tag_handler_t tag_handler)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))\n        {\n            return false;\n        }\n\n        if (len != 0)\n        {\n            string_t key;\n            if (len != std::size_t(-1))\n            {\n                for (std::size_t i = 0; i < len; ++i)\n                {\n                    get();\n                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n\n                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                while (get() != 0xFF)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n\n                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    /*!\n    @return whether a valid MessagePack value was passed to the SAX parser\n    */\n    bool parse_msgpack_internal()\n    {\n        switch (get())\n        {\n            // EOF\n            case std::char_traits<char_type>::eof():\n                return unexpect_eof(input_format_t::msgpack, \"value\");\n\n            // positive fixint\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n            case 0x18:\n            case 0x19:\n            case 0x1A:\n            case 0x1B:\n            case 0x1C:\n            case 0x1D:\n            case 0x1E:\n            case 0x1F:\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n            case 0x38:\n            case 0x39:\n            case 0x3A:\n            case 0x3B:\n            case 0x3C:\n            case 0x3D:\n            case 0x3E:\n            case 0x3F:\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58:\n            case 0x59:\n            case 0x5A:\n            case 0x5B:\n            case 0x5C:\n            case 0x5D:\n            case 0x5E:\n            case 0x5F:\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78:\n            case 0x79:\n            case 0x7A:\n            case 0x7B:\n            case 0x7C:\n            case 0x7D:\n            case 0x7E:\n            case 0x7F:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            // fixmap\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n                return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n            // fixarray\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n            case 0x98:\n            case 0x99:\n            case 0x9A:\n            case 0x9B:\n            case 0x9C:\n            case 0x9D:\n            case 0x9E:\n            case 0x9F:\n                return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            case 0xD9: // str 8\n            case 0xDA: // str 16\n            case 0xDB: // str 32\n            {\n                string_t s;\n                return get_msgpack_string(s) && sax->string(s);\n            }\n\n            case 0xC0: // nil\n                return sax->null();\n\n            case 0xC2: // false\n                return sax->boolean(false);\n\n            case 0xC3: // true\n                return sax->boolean(true);\n\n            case 0xC4: // bin 8\n            case 0xC5: // bin 16\n            case 0xC6: // bin 32\n            case 0xC7: // ext 8\n            case 0xC8: // ext 16\n            case 0xC9: // ext 32\n            case 0xD4: // fixext 1\n            case 0xD5: // fixext 2\n            case 0xD6: // fixext 4\n            case 0xD7: // fixext 8\n            case 0xD8: // fixext 16\n            {\n                binary_t b;\n                return get_msgpack_binary(b) && sax->binary(b);\n            }\n\n            case 0xCA: // float 32\n            {\n                float number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCB: // float 64\n            {\n                double number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCC: // uint 8\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCD: // uint 16\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCE: // uint 32\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCF: // uint 64\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xD0: // int 8\n            {\n                std::int8_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD1: // int 16\n            {\n                std::int16_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD2: // int 32\n            {\n                std::int32_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD3: // int 64\n            {\n                std::int64_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xDC: // array 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDD: // array 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDE: // map 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xDF: // map 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            // negative fixint\n            case 0xE0:\n            case 0xE1:\n            case 0xE2:\n            case 0xE3:\n            case 0xE4:\n            case 0xE5:\n            case 0xE6:\n            case 0xE7:\n            case 0xE8:\n            case 0xE9:\n            case 0xEA:\n            case 0xEB:\n            case 0xEC:\n            case 0xED:\n            case 0xEE:\n            case 0xEF:\n            case 0xF0:\n            case 0xF1:\n            case 0xF2:\n            case 0xF3:\n            case 0xF4:\n            case 0xF5:\n            case 0xF6:\n            case 0xF7:\n            case 0xF8:\n            case 0xF9:\n            case 0xFA:\n            case 0xFB:\n            case 0xFC:\n            case 0xFD:\n            case 0xFE:\n            case 0xFF:\n                return sax->number_integer(static_cast<std::int8_t>(current));\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, \"invalid byte: 0x\" + last_token, \"value\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_msgpack_string(string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0xD9: // str 8\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDA: // str 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDB: // str 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, \"expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x\" + last_token, \"string\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack byte array\n\n    This function first reads starting bytes to determine the expected\n    byte array length and then copies this number of bytes into a byte array.\n\n    @param[out] result  created byte array\n\n    @return whether byte array creation completed\n    */\n    bool get_msgpack_binary(binary_t& result)\n    {\n        // helper function to set the subtype\n        auto assign_and_return_true = [&result](std::int8_t subtype)\n        {\n            result.set_subtype(static_cast<std::uint8_t>(subtype));\n            return true;\n        };\n\n        switch (current)\n        {\n            case 0xC4: // bin 8\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC5: // bin 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC6: // bin 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC7: // ext 8\n            {\n                std::uint8_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xC8: // ext 16\n            {\n                std::uint16_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xC9: // ext 32\n            {\n                std::uint32_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD4: // fixext 1\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 1, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD5: // fixext 2\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 2, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD6: // fixext 4\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 4, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD7: // fixext 8\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 8, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD8: // fixext 16\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 16, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            default:           // LCOV_EXCL_LINE\n                return false;  // LCOV_EXCL_LINE\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array\n    @return whether array creation completed\n    */\n    bool get_msgpack_array(const std::size_t len)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))\n        {\n            return false;\n        }\n\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))\n            {\n                return false;\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object\n    @return whether object creation completed\n    */\n    bool get_msgpack_object(const std::size_t len)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))\n            {\n                return false;\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))\n            {\n                return false;\n            }\n            key.clear();\n        }\n\n        return sax->end_object();\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid UBJSON value was passed to the SAX parser\n    */\n    bool parse_ubjson_internal(const bool get_char = true)\n    {\n        return get_ubjson_value(get_char ? get_ignore_noop() : current);\n    }\n\n    /*!\n    @brief reads a UBJSON string\n\n    This function is either called after reading the 'S' byte explicitly\n    indicating a string, or in case of an object key where the 'S' byte can be\n    left out.\n\n    @param[out] result   created string\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether string creation completed\n    */\n    bool get_ubjson_string(string_t& result, const bool get_char = true)\n    {\n        if (get_char)\n        {\n            get();  // TODO(niels): may we ignore N here?\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"value\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            case 'U':\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'i':\n            {\n                std::int8_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'I':\n            {\n                std::int16_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'l':\n            {\n                std::int32_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'L':\n            {\n                std::int64_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            default:\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L); last byte: 0x\" + last_token, \"string\"), BasicJsonType()));\n        }\n    }\n\n    /*!\n    @param[out] result  determined size\n    @return whether size determination completed\n    */\n    bool get_ubjson_size_value(std::size_t& result)\n    {\n        switch (get_ignore_noop())\n        {\n            case 'U':\n            {\n                std::uint8_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'i':\n            {\n                std::int8_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char\n                return true;\n            }\n\n            case 'I':\n            {\n                std::int16_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'l':\n            {\n                std::int32_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'L':\n            {\n                std::int64_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L) after '#'; last byte: 0x\" + last_token, \"size\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @brief determine the type and size for a container\n\n    In the optimized UBJSON format, a type and a size can be provided to allow\n    for a more compact representation.\n\n    @param[out] result  pair of the size and the type\n\n    @return whether pair creation completed\n    */\n    bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result)\n    {\n        result.first = string_t::npos; // size\n        result.second = 0; // type\n\n        get_ignore_noop();\n\n        if (current == '$')\n        {\n            result.second = get();  // must not ignore 'N', because 'N' maybe the type\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"type\")))\n            {\n                return false;\n            }\n\n            get_ignore_noop();\n            if (JSON_HEDLEY_UNLIKELY(current != '#'))\n            {\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"value\")))\n                {\n                    return false;\n                }\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"expected '#' after type information; last byte: 0x\" + last_token, \"size\"), BasicJsonType()));\n            }\n\n            return get_ubjson_size_value(result.first);\n        }\n\n        if (current == '#')\n        {\n            return get_ubjson_size_value(result.first);\n        }\n\n        return true;\n    }\n\n    /*!\n    @param prefix  the previously read or set type prefix\n    @return whether value creation completed\n    */\n    bool get_ubjson_value(const char_int_type prefix)\n    {\n        switch (prefix)\n        {\n            case std::char_traits<char_type>::eof():  // EOF\n                return unexpect_eof(input_format_t::ubjson, \"value\");\n\n            case 'T':  // true\n                return sax->boolean(true);\n            case 'F':  // false\n                return sax->boolean(false);\n\n            case 'Z':  // null\n                return sax->null();\n\n            case 'U':\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number);\n            }\n\n            case 'i':\n            {\n                std::int8_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'I':\n            {\n                std::int16_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'l':\n            {\n                std::int32_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'L':\n            {\n                std::int64_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'd':\n            {\n                float number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'D':\n            {\n                double number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'H':\n            {\n                return get_ubjson_high_precision_number();\n            }\n\n            case 'C':  // char\n            {\n                get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"char\")))\n                {\n                    return false;\n                }\n                if (JSON_HEDLEY_UNLIKELY(current > 127))\n                {\n                    auto last_token = get_token_string();\n                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"byte after 'C' must be in range 0x00..0x7F; last byte: 0x\" + last_token, \"char\"), BasicJsonType()));\n                }\n                string_t s(1, static_cast<typename string_t::value_type>(current));\n                return sax->string(s);\n            }\n\n            case 'S':  // string\n            {\n                string_t s;\n                return get_ubjson_string(s) && sax->string(s);\n            }\n\n            case '[':  // array\n                return get_ubjson_array();\n\n            case '{':  // object\n                return get_ubjson_object();\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"invalid byte: 0x\" + last_token, \"value\"), BasicJsonType()));\n            }\n        }\n    }\n\n    /*!\n    @return whether array creation completed\n    */\n    bool get_ubjson_array()\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                if (size_and_type.second != 'N')\n                {\n                    for (std::size_t i = 0; i < size_and_type.first; ++i)\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                        {\n                            return false;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != ']')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @return whether object creation completed\n    */\n    bool get_ubjson_object()\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n        else\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != '}')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))\n                {\n                    return false;\n                }\n                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    // Note, no reader for UBJSON binary types is implemented because they do\n    // not exist\n\n    bool get_ubjson_high_precision_number()\n    {\n        // get size of following number string\n        std::size_t size{};\n        auto res = get_ubjson_size_value(size);\n        if (JSON_HEDLEY_UNLIKELY(!res))\n        {\n            return res;\n        }\n\n        // get number string\n        std::vector<char> number_vector;\n        for (std::size_t i = 0; i < size; ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"number\")))\n            {\n                return false;\n            }\n            number_vector.push_back(static_cast<char>(current));\n        }\n\n        // parse number string\n        using ia_type = decltype(detail::input_adapter(number_vector));\n        auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);\n        const auto result_number = number_lexer.scan();\n        const auto number_string = number_lexer.get_token_string();\n        const auto result_remainder = number_lexer.scan();\n\n        using token_type = typename detail::lexer_base<BasicJsonType>::token_type;\n\n        if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))\n        {\n            return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, \"invalid number text: \" + number_lexer.get_token_string(), \"high-precision number\"), BasicJsonType()));\n        }\n\n        switch (result_number)\n        {\n            case token_type::value_integer:\n                return sax->number_integer(number_lexer.get_number_integer());\n            case token_type::value_unsigned:\n                return sax->number_unsigned(number_lexer.get_number_unsigned());\n            case token_type::value_float:\n                return sax->number_float(number_lexer.get_number_float(), std::move(number_string));\n            case token_type::uninitialized:\n            case token_type::literal_true:\n            case token_type::literal_false:\n            case token_type::literal_null:\n            case token_type::value_string:\n            case token_type::begin_array:\n            case token_type::begin_object:\n            case token_type::end_array:\n            case token_type::end_object:\n            case token_type::name_separator:\n            case token_type::value_separator:\n            case token_type::parse_error:\n            case token_type::end_of_input:\n            case token_type::literal_or_value:\n            default:\n                return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, \"invalid number text: \" + number_lexer.get_token_string(), \"high-precision number\"), BasicJsonType()));\n        }\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*!\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a -'ve valued\n    `std::char_traits<char_type>::eof()` in that case.\n\n    @return character read from the input\n    */\n    char_int_type get()\n    {\n        ++chars_read;\n        return current = ia.get_character();\n    }\n\n    /*!\n    @return character read from the input after ignoring all 'N' entries\n    */\n    char_int_type get_ignore_noop()\n    {\n        do\n        {\n            get();\n        }\n        while (current == 'N');\n\n        return current;\n    }\n\n    /*\n    @brief read a number from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format   the current format (for diagnostics)\n    @param[out] result  number of type @a NumberType\n\n    @return whether conversion completed\n\n    @note This function needs to respect the system's endianess, because\n          bytes in CBOR, MessagePack, and UBJSON are stored in network order\n          (big endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool InputIsLittleEndian = false>\n    bool get_number(const input_format_t format, NumberType& result)\n    {\n        // step 1: read input into array with system's byte order\n        std::array<std::uint8_t, sizeof(NumberType)> vec{};\n        for (std::size_t i = 0; i < sizeof(NumberType); ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"number\")))\n            {\n                return false;\n            }\n\n            // reverse byte order prior to conversion if necessary\n            if (is_little_endian != InputIsLittleEndian)\n            {\n                vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);\n            }\n            else\n            {\n                vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE\n            }\n        }\n\n        // step 2: convert array into number of type T and return\n        std::memcpy(&result, vec.data(), sizeof(NumberType));\n        return true;\n    }\n\n    /*!\n    @brief create a string by reading characters from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of characters to read\n    @param[out] result string created by reading @a len bytes\n\n    @return whether string creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of string memory.\n    */\n    template<typename NumberType>\n    bool get_string(const input_format_t format,\n                    const NumberType len,\n                    string_t& result)\n    {\n        bool success = true;\n        for (NumberType i = 0; i < len; i++)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"string\")))\n            {\n                success = false;\n                break;\n            }\n            result.push_back(static_cast<typename string_t::value_type>(current));\n        }\n        return success;\n    }\n\n    /*!\n    @brief create a byte array by reading bytes from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of bytes to read\n    @param[out] result byte array created by reading @a len bytes\n\n    @return whether byte array creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of memory.\n    */\n    template<typename NumberType>\n    bool get_binary(const input_format_t format,\n                    const NumberType len,\n                    binary_t& result)\n    {\n        bool success = true;\n        for (NumberType i = 0; i < len; i++)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"binary\")))\n            {\n                success = false;\n                break;\n            }\n            result.push_back(static_cast<std::uint8_t>(current));\n        }\n        return success;\n    }\n\n    /*!\n    @param[in] format   the current format (for diagnostics)\n    @param[in] context  further context information (for diagnostics)\n    @return whether the last read character is not EOF\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    bool unexpect_eof(const input_format_t format, const char* context) const\n    {\n        if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))\n        {\n            return sax->parse_error(chars_read, \"<end of file>\",\n                                    parse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context), BasicJsonType()));\n        }\n        return true;\n    }\n\n    /*!\n    @return a string representation of the last read byte\n    */\n    std::string get_token_string() const\n    {\n        std::array<char, 3> cr{{}};\n        (std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(current)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n        return std::string{cr.data()};\n    }\n\n    /*!\n    @param[in] format   the current format\n    @param[in] detail   a detailed error message\n    @param[in] context  further context information\n    @return a message string to use in the parse_error exceptions\n    */\n    std::string exception_message(const input_format_t format,\n                                  const std::string& detail,\n                                  const std::string& context) const\n    {\n        std::string error_msg = \"syntax error while parsing \";\n\n        switch (format)\n        {\n            case input_format_t::cbor:\n                error_msg += \"CBOR\";\n                break;\n\n            case input_format_t::msgpack:\n                error_msg += \"MessagePack\";\n                break;\n\n            case input_format_t::ubjson:\n                error_msg += \"UBJSON\";\n                break;\n\n            case input_format_t::bson:\n                error_msg += \"BSON\";\n                break;\n\n            case input_format_t::json: // LCOV_EXCL_LINE\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n\n        return error_msg + \" \" + context + \": \" + detail;\n    }\n\n  private:\n    /// input adapter\n    InputAdapterType ia;\n\n    /// the current character\n    char_int_type current = std::char_traits<char_type>::eof();\n\n    /// the number of characters read\n    std::size_t chars_read = 0;\n\n    /// whether we can assume little endianess\n    const bool is_little_endian = little_endianess();\n\n    /// the SAX parser\n    json_sax_t* sax = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/input/parser.hpp>\n\n\n#include <cmath> // isfinite\n#include <cstdint> // uint8_t\n#include <functional> // function\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////\n// parser //\n////////////\n\nenum class parse_event_t : std::uint8_t\n{\n    /// the parser read `{` and started to process a JSON object\n    object_start,\n    /// the parser read `}` and finished processing a JSON object\n    object_end,\n    /// the parser read `[` and started to process a JSON array\n    array_start,\n    /// the parser read `]` and finished processing a JSON array\n    array_end,\n    /// the parser read a key of a value in an object\n    key,\n    /// the parser finished reading a JSON value\n    value\n};\n\ntemplate<typename BasicJsonType>\nusing parser_callback_t =\n    std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;\n\n/*!\n@brief syntax analysis\n\nThis class implements a recursive descent parser.\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass parser\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using lexer_t = lexer<BasicJsonType, InputAdapterType>;\n    using token_type = typename lexer_t::token_type;\n\n  public:\n    /// a parser reading from an input adapter\n    explicit parser(InputAdapterType&& adapter,\n                    const parser_callback_t<BasicJsonType> cb = nullptr,\n                    const bool allow_exceptions_ = true,\n                    const bool skip_comments = false)\n        : callback(cb)\n        , m_lexer(std::move(adapter), skip_comments)\n        , allow_exceptions(allow_exceptions_)\n    {\n        // read first token\n        get_token();\n    }\n\n    /*!\n    @brief public parser interface\n\n    @param[in] strict      whether to expect the last token to be EOF\n    @param[in,out] result  parsed JSON value\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    void parse(const bool strict, BasicJsonType& result)\n    {\n        if (callback)\n        {\n            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);\n            sax_parse_internal(&sdp);\n\n            // in strict mode, input must be completely read\n            if (strict && (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\"), BasicJsonType()));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n\n            // set top-level value to null if it was discarded by the callback\n            // function\n            if (result.is_discarded())\n            {\n                result = nullptr;\n            }\n        }\n        else\n        {\n            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);\n            sax_parse_internal(&sdp);\n\n            // in strict mode, input must be completely read\n            if (strict && (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, \"value\"), BasicJsonType()));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n        }\n\n        result.assert_invariant();\n    }\n\n    /*!\n    @brief public accept interface\n\n    @param[in] strict  whether to expect the last token to be EOF\n    @return whether the input is a proper JSON text\n    */\n    bool accept(const bool strict = true)\n    {\n        json_sax_acceptor<BasicJsonType> sax_acceptor;\n        return sax_parse(&sax_acceptor, strict);\n    }\n\n    template<typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    bool sax_parse(SAX* sax, const bool strict = true)\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        const bool result = sax_parse_internal(sax);\n\n        // strict mode: next byte must be EOF\n        if (result && strict && (get_token() != token_type::end_of_input))\n        {\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, \"value\"), BasicJsonType()));\n        }\n\n        return result;\n    }\n\n  private:\n    template<typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    bool sax_parse_internal(SAX* sax)\n    {\n        // stack to remember the hierarchy of structured values we are parsing\n        // true = array; false = object\n        std::vector<bool> states;\n        // value to avoid a goto (see comment where set to true)\n        bool skip_to_state_evaluation = false;\n\n        while (true)\n        {\n            if (!skip_to_state_evaluation)\n            {\n                // invariant: get_token() was called before each iteration\n                switch (last_token)\n                {\n                    case token_type::begin_object:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing } -> we are done\n                        if (get_token() == token_type::end_object)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // parse key\n                        if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, \"object key\"), BasicJsonType()));\n                        }\n                        if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        // parse separator (:)\n                        if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, \"object separator\"), BasicJsonType()));\n                        }\n\n                        // remember we are now inside an object\n                        states.push_back(false);\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    case token_type::begin_array:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing ] -> we are done\n                        if (get_token() == token_type::end_array)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // remember we are now inside an array\n                        states.push_back(true);\n\n                        // parse values (no need to call get_token)\n                        continue;\n                    }\n\n                    case token_type::value_float:\n                    {\n                        const auto res = m_lexer.get_number_float();\n\n                        if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    out_of_range::create(406, \"number overflow parsing '\" + m_lexer.get_token_string() + \"'\", BasicJsonType()));\n                        }\n\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        break;\n                    }\n\n                    case token_type::literal_false:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_null:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->null()))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_true:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_integer:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_string:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_unsigned:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::parse_error:\n                    {\n                        // using \"uninitialized\" to avoid \"expected\" message\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, \"value\"), BasicJsonType()));\n                    }\n\n                    case token_type::uninitialized:\n                    case token_type::end_array:\n                    case token_type::end_object:\n                    case token_type::name_separator:\n                    case token_type::value_separator:\n                    case token_type::end_of_input:\n                    case token_type::literal_or_value:\n                    default: // the last token was unexpected\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, \"value\"), BasicJsonType()));\n                    }\n                }\n            }\n            else\n            {\n                skip_to_state_evaluation = false;\n            }\n\n            // we reached this line after we successfully parsed a value\n            if (states.empty())\n            {\n                // empty stack: we reached the end of the hierarchy: done\n                return true;\n            }\n\n            if (states.back())  // array\n            {\n                // comma -> next value\n                if (get_token() == token_type::value_separator)\n                {\n                    // parse a new value\n                    get_token();\n                    continue;\n                }\n\n                // closing ]\n                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))\n                    {\n                        return false;\n                    }\n\n                    // We are done with this array. Before we can parse a\n                    // new value, we need to evaluate the new state first.\n                    // By setting skip_to_state_evaluation to false, we\n                    // are effectively jumping to the beginning of this if.\n                    JSON_ASSERT(!states.empty());\n                    states.pop_back();\n                    skip_to_state_evaluation = true;\n                    continue;\n                }\n\n                return sax->parse_error(m_lexer.get_position(),\n                                        m_lexer.get_token_string(),\n                                        parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, \"array\"), BasicJsonType()));\n            }\n\n            // states.back() is false -> object\n\n            // comma -> next value\n            if (get_token() == token_type::value_separator)\n            {\n                // parse key\n                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))\n                {\n                    return sax->parse_error(m_lexer.get_position(),\n                                            m_lexer.get_token_string(),\n                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, \"object key\"), BasicJsonType()));\n                }\n\n                if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))\n                {\n                    return false;\n                }\n\n                // parse separator (:)\n                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))\n                {\n                    return sax->parse_error(m_lexer.get_position(),\n                                            m_lexer.get_token_string(),\n                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, \"object separator\"), BasicJsonType()));\n                }\n\n                // parse values\n                get_token();\n                continue;\n            }\n\n            // closing }\n            if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))\n            {\n                if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))\n                {\n                    return false;\n                }\n\n                // We are done with this object. Before we can parse a\n                // new value, we need to evaluate the new state first.\n                // By setting skip_to_state_evaluation to false, we\n                // are effectively jumping to the beginning of this if.\n                JSON_ASSERT(!states.empty());\n                states.pop_back();\n                skip_to_state_evaluation = true;\n                continue;\n            }\n\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, \"object\"), BasicJsonType()));\n        }\n    }\n\n    /// get next token from lexer\n    token_type get_token()\n    {\n        return last_token = m_lexer.scan();\n    }\n\n    std::string exception_message(const token_type expected, const std::string& context)\n    {\n        std::string error_msg = \"syntax error \";\n\n        if (!context.empty())\n        {\n            error_msg += \"while parsing \" + context + \" \";\n        }\n\n        error_msg += \"- \";\n\n        if (last_token == token_type::parse_error)\n        {\n            error_msg += std::string(m_lexer.get_error_message()) + \"; last read: '\" +\n                         m_lexer.get_token_string() + \"'\";\n        }\n        else\n        {\n            error_msg += \"unexpected \" + std::string(lexer_t::token_type_name(last_token));\n        }\n\n        if (expected != token_type::uninitialized)\n        {\n            error_msg += \"; expected \" + std::string(lexer_t::token_type_name(expected));\n        }\n\n        return error_msg;\n    }\n\n  private:\n    /// callback function\n    const parser_callback_t<BasicJsonType> callback = nullptr;\n    /// the type of the last read token\n    token_type last_token = token_type::uninitialized;\n    /// the lexer\n    lexer_t m_lexer;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <limits>  // numeric_limits\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*\n@brief an iterator for primitive JSON types\n\nThis class models an iterator for primitive JSON types (boolean, number,\nstring). It's only purpose is to allow the iterator/const_iterator classes\nto \"iterate\" over primitive values. Internally, the iterator is modeled by\na `difference_type` variable. Value begin_value (`0`) models the begin,\nend_value (`1`) models past the end.\n*/\nclass primitive_iterator_t\n{\n  private:\n    using difference_type = std::ptrdiff_t;\n    static constexpr difference_type begin_value = 0;\n    static constexpr difference_type end_value = begin_value + 1;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// iterator as signed integer type\n    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();\n\n  public:\n    constexpr difference_type get_value() const noexcept\n    {\n        return m_it;\n    }\n\n    /// set iterator to a defined beginning\n    void set_begin() noexcept\n    {\n        m_it = begin_value;\n    }\n\n    /// set iterator to a defined past the end\n    void set_end() noexcept\n    {\n        m_it = end_value;\n    }\n\n    /// return whether the iterator can be dereferenced\n    constexpr bool is_begin() const noexcept\n    {\n        return m_it == begin_value;\n    }\n\n    /// return whether the iterator is at end\n    constexpr bool is_end() const noexcept\n    {\n        return m_it == end_value;\n    }\n\n    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it == rhs.m_it;\n    }\n\n    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it < rhs.m_it;\n    }\n\n    primitive_iterator_t operator+(difference_type n) noexcept\n    {\n        auto result = *this;\n        result += n;\n        return result;\n    }\n\n    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it - rhs.m_it;\n    }\n\n    primitive_iterator_t& operator++() noexcept\n    {\n        ++m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type)\n    {\n        auto result = *this;\n        ++m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator--() noexcept\n    {\n        --m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type)\n    {\n        auto result = *this;\n        --m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator+=(difference_type n) noexcept\n    {\n        m_it += n;\n        return *this;\n    }\n\n    primitive_iterator_t& operator-=(difference_type n) noexcept\n    {\n        m_it -= n;\n        return *this;\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*!\n@brief an iterator value\n\n@note This structure could easily be a union, but MSVC currently does not allow\nunions members with complex constructors, see https://github.com/nlohmann/json/pull/105.\n*/\ntemplate<typename BasicJsonType> struct internal_iterator\n{\n    /// iterator for JSON objects\n    typename BasicJsonType::object_t::iterator object_iterator {};\n    /// iterator for JSON arrays\n    typename BasicJsonType::array_t::iterator array_iterator {};\n    /// generic iterator for all other types\n    primitive_iterator_t primitive_iterator {};\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iter_impl.hpp>\n\n\n#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next\n#include <type_traits> // conditional, is_const, remove_const\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// forward declare, to be able to friend it later on\ntemplate<typename IteratorType> class iteration_proxy;\ntemplate<typename IteratorType> class iteration_proxy_value;\n\n/*!\n@brief a template for a bidirectional iterator for the @ref basic_json class\nThis class implements a both iterators (iterator and const_iterator) for the\n@ref basic_json class.\n@note An iterator is called *initialized* when a pointer to a JSON value has\n      been set (e.g., by a constructor or a copy assignment). If the iterator is\n      default-constructed, it is *uninitialized* and most methods are undefined.\n      **The library uses assertions to detect calls on uninitialized iterators.**\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n@since version 1.0.0, simplified in version 2.0.9, change to bidirectional\n       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)\n*/\ntemplate<typename BasicJsonType>\nclass iter_impl\n{\n    /// the iterator with BasicJsonType of different const-ness\n    using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;\n    /// allow basic_json to access private members\n    friend other_iter_impl;\n    friend BasicJsonType;\n    friend iteration_proxy<iter_impl>;\n    friend iteration_proxy_value<iter_impl>;\n\n    using object_t = typename BasicJsonType::object_t;\n    using array_t = typename BasicJsonType::array_t;\n    // make sure BasicJsonType is basic_json or const basic_json\n    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,\n                  \"iter_impl only accepts (const) basic_json\");\n\n  public:\n\n    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.\n    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.\n    /// A user-defined iterator should provide publicly accessible typedefs named\n    /// iterator_category, value_type, difference_type, pointer, and reference.\n    /// Note that value_type is required to be non-const, even for constant iterators.\n    using iterator_category = std::bidirectional_iterator_tag;\n\n    /// the type of the values when the iterator is dereferenced\n    using value_type = typename BasicJsonType::value_type;\n    /// a type to represent differences between iterators\n    using difference_type = typename BasicJsonType::difference_type;\n    /// defines a pointer to the type iterated over (value_type)\n    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,\n          typename BasicJsonType::const_pointer,\n          typename BasicJsonType::pointer>::type;\n    /// defines a reference to the type iterated over (value_type)\n    using reference =\n        typename std::conditional<std::is_const<BasicJsonType>::value,\n        typename BasicJsonType::const_reference,\n        typename BasicJsonType::reference>::type;\n\n    iter_impl() = default;\n    ~iter_impl() = default;\n    iter_impl(iter_impl&&) noexcept = default;\n    iter_impl& operator=(iter_impl&&) noexcept = default;\n\n    /*!\n    @brief constructor for a given JSON instance\n    @param[in] object  pointer to a JSON object for this iterator\n    @pre object != nullptr\n    @post The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    explicit iter_impl(pointer object) noexcept : m_object(object)\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = typename object_t::iterator();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = typename array_t::iterator();\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator = primitive_iterator_t();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @note The conventional copy constructor and copy assignment are implicitly\n          defined. Combined with the following converting constructor and\n          assignment, they support: (1) copy from iterator to iterator, (2)\n          copy from const iterator to const iterator, and (3) conversion from\n          iterator to const iterator. However conversion from const iterator\n          to iterator is not defined.\n    */\n\n    /*!\n    @brief const copy constructor\n    @param[in] other const iterator to copy from\n    @note This copy constructor had to be defined explicitly to circumvent a bug\n          occurring on msvc v19.0 compiler (VS 2015) debug build. For more\n          information refer to: https://github.com/nlohmann/json/issues/1608\n    */\n    iter_impl(const iter_impl<const BasicJsonType>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it)\n    {}\n\n    /*!\n    @brief converting assignment\n    @param[in] other const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept\n    {\n        if (&other != this)\n        {\n            m_object = other.m_object;\n            m_it = other.m_it;\n        }\n        return *this;\n    }\n\n    /*!\n    @brief converting constructor\n    @param[in] other  non-const iterator to copy from\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it)\n    {}\n\n    /*!\n    @brief converting assignment\n    @param[in] other  non-const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)\n    {\n        m_object = other.m_object;\n        m_it = other.m_it;\n        return *this;\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief set the iterator to the first value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_begin() noexcept\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->begin();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->begin();\n                break;\n            }\n\n            case value_t::null:\n            {\n                // set to end so begin()==end() is true: null is empty\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator.set_begin();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @brief set the iterator past the last value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_end() noexcept\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->end();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->end();\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n        }\n    }\n\n  public:\n    /*!\n    @brief return a reference to the value pointed to by the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator*() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());\n                return m_it.object_iterator->second;\n            }\n\n            case value_t::array:\n            {\n                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());\n                return *m_it.array_iterator;\n            }\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", *m_object));\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", *m_object));\n            }\n        }\n    }\n\n    /*!\n    @brief dereference the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    pointer operator->() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());\n                return &(m_it.object_iterator->second);\n            }\n\n            case value_t::array:\n            {\n                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());\n                return &*m_it.array_iterator;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", *m_object));\n            }\n        }\n    }\n\n    /*!\n    @brief post-increment (it++)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator++(int) // NOLINT(readability-const-return-type)\n    {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-increment (++it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator++()\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, 1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, 1);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                ++m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief post-decrement (it--)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator--(int) // NOLINT(readability-const-return-type)\n    {\n        auto result = *this;\n        --(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-decrement (--it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator--()\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, -1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, -1);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                --m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief comparison: equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >\n    bool operator==(const IterImpl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\", *m_object));\n        }\n\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                return (m_it.object_iterator == other.m_it.object_iterator);\n\n            case value_t::array:\n                return (m_it.array_iterator == other.m_it.array_iterator);\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return (m_it.primitive_iterator == other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief comparison: not equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >\n    bool operator!=(const IterImpl& other) const\n    {\n        return !operator==(other);\n    }\n\n    /*!\n    @brief comparison: smaller\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\", *m_object));\n        }\n\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(213, \"cannot compare order of object iterators\", *m_object));\n\n            case value_t::array:\n                return (m_it.array_iterator < other.m_it.array_iterator);\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return (m_it.primitive_iterator < other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<=(const iter_impl& other) const\n    {\n        return !other.operator < (*this);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>(const iter_impl& other) const\n    {\n        return !operator<=(other);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>=(const iter_impl& other) const\n    {\n        return !operator<(other);\n    }\n\n    /*!\n    @brief add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator+=(difference_type i)\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\", *m_object));\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, i);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator += i;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator-=(difference_type i)\n    {\n        return operator+=(-i);\n    }\n\n    /*!\n    @brief add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator+(difference_type i) const\n    {\n        auto result = *this;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief addition of distance and iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    friend iter_impl operator+(difference_type i, const iter_impl& it)\n    {\n        auto result = it;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator-(difference_type i) const\n    {\n        auto result = *this;\n        result -= i;\n        return result;\n    }\n\n    /*!\n    @brief return difference\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    difference_type operator-(const iter_impl& other) const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\", *m_object));\n\n            case value_t::array:\n                return m_it.array_iterator - other.m_it.array_iterator;\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return m_it.primitive_iterator - other.m_it.primitive_iterator;\n        }\n    }\n\n    /*!\n    @brief access to successor\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator[](difference_type n) const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(208, \"cannot use operator[] for object iterators\", *m_object));\n\n            case value_t::array:\n                return *std::next(m_it.array_iterator, n);\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", *m_object));\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", *m_object));\n            }\n        }\n    }\n\n    /*!\n    @brief return the key of an object iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    const typename object_t::key_type& key() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        if (JSON_HEDLEY_LIKELY(m_object->is_object()))\n        {\n            return m_it.object_iterator->first;\n        }\n\n        JSON_THROW(invalid_iterator::create(207, \"cannot use key() for non-object iterators\", *m_object));\n    }\n\n    /*!\n    @brief return the value of an iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference value() const\n    {\n        return operator*();\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// associated JSON instance\n    pointer m_object = nullptr;\n    /// the actual iterator of the associated instance\n    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};\n};\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <iterator> // reverse_iterator\n#include <utility> // declval\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////////\n// reverse_iterator //\n//////////////////////\n\n/*!\n@brief a template for a reverse iterator class\n\n@tparam Base the base iterator type to reverse. Valid types are @ref\niterator (to create @ref reverse_iterator) and @ref const_iterator (to\ncreate @ref const_reverse_iterator).\n\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):\n  It is possible to write to the pointed-to element (only if @a Base is\n  @ref iterator).\n\n@since version 1.0.0\n*/\ntemplate<typename Base>\nclass json_reverse_iterator : public std::reverse_iterator<Base>\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    /// shortcut to the reverse iterator adapter\n    using base_iterator = std::reverse_iterator<Base>;\n    /// the reference type for the pointed-to element\n    using reference = typename Base::reference;\n\n    /// create reverse iterator from iterator\n    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept\n        : base_iterator(it) {}\n\n    /// create reverse iterator from base class\n    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}\n\n    /// post-increment (it++)\n    json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));\n    }\n\n    /// pre-increment (++it)\n    json_reverse_iterator& operator++()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator++());\n    }\n\n    /// post-decrement (it--)\n    json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));\n    }\n\n    /// pre-decrement (--it)\n    json_reverse_iterator& operator--()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator--());\n    }\n\n    /// add to iterator\n    json_reverse_iterator& operator+=(difference_type i)\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));\n    }\n\n    /// add to iterator\n    json_reverse_iterator operator+(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));\n    }\n\n    /// subtract from iterator\n    json_reverse_iterator operator-(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));\n    }\n\n    /// return difference\n    difference_type operator-(const json_reverse_iterator& other) const\n    {\n        return base_iterator(*this) - base_iterator(other);\n    }\n\n    /// access to successor\n    reference operator[](difference_type n) const\n    {\n        return *(this->operator+(n));\n    }\n\n    /// return the key of an object iterator\n    auto key() const -> decltype(std::declval<Base>().key())\n    {\n        auto it = --this->base();\n        return it.key();\n    }\n\n    /// return the value of an iterator\n    reference value() const\n    {\n        auto it = --this->base();\n        return it.operator * ();\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/json_pointer.hpp>\n\n\n#include <algorithm> // all_of\n#include <cctype> // isdigit\n#include <limits> // max\n#include <numeric> // accumulate\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/string_escape.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\ntemplate<typename BasicJsonType>\nclass json_pointer\n{\n    // allow basic_json to access private members\n    NLOHMANN_BASIC_JSON_TPL_DECLARATION\n    friend class basic_json;\n\n  public:\n    /*!\n    @brief create JSON pointer\n\n    Create a JSON pointer according to the syntax described in\n    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).\n\n    @param[in] s  string representing the JSON pointer; if omitted, the empty\n                  string is assumed which references the whole JSON value\n\n    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does\n                           not begin with a slash (`/`); see example below\n\n    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is\n    not followed by `0` (representing `~`) or `1` (representing `/`); see\n    example below\n\n    @liveexample{The example shows the construction several valid JSON pointers\n    as well as the exceptional behavior.,json_pointer}\n\n    @since version 2.0.0\n    */\n    explicit json_pointer(const std::string& s = \"\")\n        : reference_tokens(split(s))\n    {}\n\n    /*!\n    @brief return a string representation of the JSON pointer\n\n    @invariant For each JSON pointer `ptr`, it holds:\n    @code {.cpp}\n    ptr == json_pointer(ptr.to_string());\n    @endcode\n\n    @return a string representation of the JSON pointer\n\n    @liveexample{The example shows the result of `to_string`.,json_pointer__to_string}\n\n    @since version 2.0.0\n    */\n    std::string to_string() const\n    {\n        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),\n                               std::string{},\n                               [](const std::string & a, const std::string & b)\n        {\n            return a + \"/\" + detail::escape(b);\n        });\n    }\n\n    /// @copydoc to_string()\n    operator std::string() const\n    {\n        return to_string();\n    }\n\n    /*!\n    @brief append another JSON pointer at the end of this JSON pointer\n\n    @param[in] ptr  JSON pointer to append\n    @return JSON pointer with @a ptr appended\n\n    @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n    @complexity Linear in the length of @a ptr.\n\n    @sa see @ref operator/=(std::string) to append a reference token\n    @sa see @ref operator/=(std::size_t) to append an array index\n    @sa see @ref operator/(const json_pointer&, const json_pointer&) for a binary operator\n\n    @since version 3.6.0\n    */\n    json_pointer& operator/=(const json_pointer& ptr)\n    {\n        reference_tokens.insert(reference_tokens.end(),\n                                ptr.reference_tokens.begin(),\n                                ptr.reference_tokens.end());\n        return *this;\n    }\n\n    /*!\n    @brief append an unescaped reference token at the end of this JSON pointer\n\n    @param[in] token  reference token to append\n    @return JSON pointer with @a token appended without escaping @a token\n\n    @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n    @complexity Amortized constant.\n\n    @sa see @ref operator/=(const json_pointer&) to append a JSON pointer\n    @sa see @ref operator/=(std::size_t) to append an array index\n    @sa see @ref operator/(const json_pointer&, std::size_t) for a binary operator\n\n    @since version 3.6.0\n    */\n    json_pointer& operator/=(std::string token)\n    {\n        push_back(std::move(token));\n        return *this;\n    }\n\n    /*!\n    @brief append an array index at the end of this JSON pointer\n\n    @param[in] array_idx  array index to append\n    @return JSON pointer with @a array_idx appended\n\n    @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n    @complexity Amortized constant.\n\n    @sa see @ref operator/=(const json_pointer&) to append a JSON pointer\n    @sa see @ref operator/=(std::string) to append a reference token\n    @sa see @ref operator/(const json_pointer&, std::string) for a binary operator\n\n    @since version 3.6.0\n    */\n    json_pointer& operator/=(std::size_t array_idx)\n    {\n        return *this /= std::to_string(array_idx);\n    }\n\n    /*!\n    @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer\n\n    @param[in] lhs  JSON pointer\n    @param[in] rhs  JSON pointer\n    @return a new JSON pointer with @a rhs appended to @a lhs\n\n    @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n    @complexity Linear in the length of @a lhs and @a rhs.\n\n    @sa see @ref operator/=(const json_pointer&) to append a JSON pointer\n\n    @since version 3.6.0\n    */\n    friend json_pointer operator/(const json_pointer& lhs,\n                                  const json_pointer& rhs)\n    {\n        return json_pointer(lhs) /= rhs;\n    }\n\n    /*!\n    @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer\n\n    @param[in] ptr  JSON pointer\n    @param[in] token  reference token\n    @return a new JSON pointer with unescaped @a token appended to @a ptr\n\n    @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n    @complexity Linear in the length of @a ptr.\n\n    @sa see @ref operator/=(std::string) to append a reference token\n\n    @since version 3.6.0\n    */\n    friend json_pointer operator/(const json_pointer& ptr, std::string token) // NOLINT(performance-unnecessary-value-param)\n    {\n        return json_pointer(ptr) /= std::move(token);\n    }\n\n    /*!\n    @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer\n\n    @param[in] ptr  JSON pointer\n    @param[in] array_idx  array index\n    @return a new JSON pointer with @a array_idx appended to @a ptr\n\n    @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n    @complexity Linear in the length of @a ptr.\n\n    @sa see @ref operator/=(std::size_t) to append an array index\n\n    @since version 3.6.0\n    */\n    friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx)\n    {\n        return json_pointer(ptr) /= array_idx;\n    }\n\n    /*!\n    @brief returns the parent of this JSON pointer\n\n    @return parent of this JSON pointer; in case this JSON pointer is the root,\n            the root itself is returned\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @liveexample{The example shows the result of `parent_pointer` for different\n    JSON Pointers.,json_pointer__parent_pointer}\n\n    @since version 3.6.0\n    */\n    json_pointer parent_pointer() const\n    {\n        if (empty())\n        {\n            return *this;\n        }\n\n        json_pointer res = *this;\n        res.pop_back();\n        return res;\n    }\n\n    /*!\n    @brief remove last reference token\n\n    @pre not `empty()`\n\n    @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back}\n\n    @complexity Constant.\n\n    @throw out_of_range.405 if JSON pointer has no parent\n\n    @since version 3.6.0\n    */\n    void pop_back()\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\", BasicJsonType()));\n        }\n\n        reference_tokens.pop_back();\n    }\n\n    /*!\n    @brief return last reference token\n\n    @pre not `empty()`\n    @return last reference token\n\n    @liveexample{The example shows the usage of `back`.,json_pointer__back}\n\n    @complexity Constant.\n\n    @throw out_of_range.405 if JSON pointer has no parent\n\n    @since version 3.6.0\n    */\n    const std::string& back() const\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\", BasicJsonType()));\n        }\n\n        return reference_tokens.back();\n    }\n\n    /*!\n    @brief append an unescaped token at the end of the reference pointer\n\n    @param[in] token  token to add\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows the result of `push_back` for different\n    JSON Pointers.,json_pointer__push_back}\n\n    @since version 3.6.0\n    */\n    void push_back(const std::string& token)\n    {\n        reference_tokens.push_back(token);\n    }\n\n    /// @copydoc push_back(const std::string&)\n    void push_back(std::string&& token)\n    {\n        reference_tokens.push_back(std::move(token));\n    }\n\n    /*!\n    @brief return whether pointer points to the root document\n\n    @return true iff the JSON pointer points to the root document\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example shows the result of `empty` for different JSON\n    Pointers.,json_pointer__empty}\n\n    @since version 3.6.0\n    */\n    bool empty() const noexcept\n    {\n        return reference_tokens.empty();\n    }\n\n  private:\n    /*!\n    @param[in] s  reference token to be converted into an array index\n\n    @return integer representation of @a s\n\n    @throw parse_error.106  if an array index begins with '0'\n    @throw parse_error.109  if an array index begins not with a digit\n    @throw out_of_range.404 if string @a s could not be converted to an integer\n    @throw out_of_range.410 if an array index exceeds size_type\n    */\n    static typename BasicJsonType::size_type array_index(const std::string& s)\n    {\n        using size_type = typename BasicJsonType::size_type;\n\n        // error condition (cf. RFC 6901, Sect. 4)\n        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))\n        {\n            JSON_THROW(detail::parse_error::create(106, 0, \"array index '\" + s + \"' must not begin with '0'\", BasicJsonType()));\n        }\n\n        // error condition (cf. RFC 6901, Sect. 4)\n        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))\n        {\n            JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + s + \"' is not a number\", BasicJsonType()));\n        }\n\n        std::size_t processed_chars = 0;\n        unsigned long long res = 0;  // NOLINT(runtime/int)\n        JSON_TRY\n        {\n            res = std::stoull(s, &processed_chars);\n        }\n        JSON_CATCH(std::out_of_range&)\n        {\n            JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\", BasicJsonType()));\n        }\n\n        // check if the string was completely read\n        if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))\n        {\n            JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\", BasicJsonType()));\n        }\n\n        // only triggered on special platforms (like 32bit), see also\n        // https://github.com/nlohmann/json/pull/2203\n        if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))  // NOLINT(runtime/int)\n        {\n            JSON_THROW(detail::out_of_range::create(410, \"array index \" + s + \" exceeds size_type\", BasicJsonType())); // LCOV_EXCL_LINE\n        }\n\n        return static_cast<size_type>(res);\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    json_pointer top() const\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\", BasicJsonType()));\n        }\n\n        json_pointer result = *this;\n        result.reference_tokens = {reference_tokens[0]};\n        return result;\n    }\n\n  private:\n    /*!\n    @brief create and return a reference to the pointed to value\n\n    @complexity Linear in the number of reference tokens.\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.313 if value cannot be unflattened\n    */\n    BasicJsonType& get_and_create(BasicJsonType& j) const\n    {\n        auto* result = &j;\n\n        // in case no reference tokens exist, return a reference to the JSON value\n        // j which will be overwritten by a primitive value\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (result->type())\n            {\n                case detail::value_t::null:\n                {\n                    if (reference_token == \"0\")\n                    {\n                        // start a new array if reference token is 0\n                        result = &result->operator[](0);\n                    }\n                    else\n                    {\n                        // start a new object otherwise\n                        result = &result->operator[](reference_token);\n                    }\n                    break;\n                }\n\n                case detail::value_t::object:\n                {\n                    // create an entry in the object\n                    result = &result->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // create an entry in the array\n                    result = &result->operator[](array_index(reference_token));\n                    break;\n                }\n\n                /*\n                The following code is only reached if there exists a reference\n                token _and_ the current value is primitive. In this case, we have\n                an error situation, because primitive values may only occur as\n                single value; that is, with an empty list of reference tokens.\n                */\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::type_error::create(313, \"invalid value to unflatten\", j));\n            }\n        }\n\n        return *result;\n    }\n\n    /*!\n    @brief return a reference to the pointed to value\n\n    @note This version does not throw if a value is not present, but tries to\n          create nested values instead. For instance, calling this function\n          with pointer `\"/this/that\"` on a null value is equivalent to calling\n          `operator[](\"this\").operator[](\"that\")` on that value, effectively\n          changing the null value to an object.\n\n    @param[in] ptr  a JSON value\n\n    @return reference to the JSON value pointed to by the JSON pointer\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_unchecked(BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            // convert null values to arrays or objects before continuing\n            if (ptr->is_null())\n            {\n                // check if reference token is a number\n                const bool nums =\n                    std::all_of(reference_token.begin(), reference_token.end(),\n                                [](const unsigned char x)\n                {\n                    return std::isdigit(x);\n                });\n\n                // change value to array for numbers or \"-\" or to object otherwise\n                *ptr = (nums || reference_token == \"-\")\n                       ? detail::value_t::array\n                       : detail::value_t::object;\n            }\n\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (reference_token == \"-\")\n                    {\n                        // explicitly treat \"-\" as index beyond the end\n                        ptr = &ptr->operator[](ptr->m_value.array->size());\n                    }\n                    else\n                    {\n                        // convert array index to number; unchecked access\n                        ptr = &ptr->operator[](array_index(reference_token));\n                    }\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\", *ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_checked(BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\", *ptr));\n                    }\n\n                    // note: at performs range check\n                    ptr = &ptr->at(array_index(reference_token));\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\", *ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief return a const reference to the pointed to value\n\n    @param[in] ptr  a JSON value\n\n    @return const reference to the JSON value pointed to by the JSON\n    pointer\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" cannot be used for const access\n                        JSON_THROW(detail::out_of_range::create(402, \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) + \") is out of range\", *ptr));\n                    }\n\n                    // use unchecked array access\n                    ptr = &ptr->operator[](array_index(reference_token));\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\", *ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_checked(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\", *ptr));\n                    }\n\n                    // note: at performs range check\n                    ptr = &ptr->at(array_index(reference_token));\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\", *ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    */\n    bool contains(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    if (!ptr->contains(reference_token))\n                    {\n                        // we did not find the key in the object\n                        return false;\n                    }\n\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !(\"0\" <= reference_token && reference_token <= \"9\")))\n                    {\n                        // invalid char\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))\n                        {\n                            // first char should be between '1' and '9'\n                            return false;\n                        }\n                        for (std::size_t i = 1; i < reference_token.size(); i++)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))\n                            {\n                                // other char should be between '0' and '9'\n                                return false;\n                            }\n                        }\n                    }\n\n                    const auto idx = array_index(reference_token);\n                    if (idx >= ptr->size())\n                    {\n                        // index out of range\n                        return false;\n                    }\n\n                    ptr = &ptr->operator[](idx);\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                {\n                    // we do not expect primitive values if there is still a\n                    // reference token to process\n                    return false;\n                }\n            }\n        }\n\n        // no reference token left means we found a primitive value\n        return true;\n    }\n\n    /*!\n    @brief split the string input to reference tokens\n\n    @note This function is only called by the json_pointer constructor.\n          All exceptions below are documented there.\n\n    @throw parse_error.107  if the pointer is not empty or begins with '/'\n    @throw parse_error.108  if character '~' is not followed by '0' or '1'\n    */\n    static std::vector<std::string> split(const std::string& reference_string)\n    {\n        std::vector<std::string> result;\n\n        // special case: empty reference string -> no reference tokens\n        if (reference_string.empty())\n        {\n            return result;\n        }\n\n        // check if nonempty reference string begins with slash\n        if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))\n        {\n            JSON_THROW(detail::parse_error::create(107, 1, \"JSON pointer must be empty or begin with '/' - was: '\" + reference_string + \"'\", BasicJsonType()));\n        }\n\n        // extract the reference tokens:\n        // - slash: position of the last read slash (or end of string)\n        // - start: position after the previous slash\n        for (\n            // search for the first slash after the first character\n            std::size_t slash = reference_string.find_first_of('/', 1),\n            // set the beginning of the first reference token\n            start = 1;\n            // we can stop if start == 0 (if slash == std::string::npos)\n            start != 0;\n            // set the beginning of the next reference token\n            // (will eventually be 0 if slash == std::string::npos)\n            start = (slash == std::string::npos) ? 0 : slash + 1,\n            // find next slash\n            slash = reference_string.find_first_of('/', start))\n        {\n            // use the text between the beginning of the reference token\n            // (start) and the last slash (slash).\n            auto reference_token = reference_string.substr(start, slash - start);\n\n            // check reference tokens are properly escaped\n            for (std::size_t pos = reference_token.find_first_of('~');\n                    pos != std::string::npos;\n                    pos = reference_token.find_first_of('~', pos + 1))\n            {\n                JSON_ASSERT(reference_token[pos] == '~');\n\n                // ~ must be followed by 0 or 1\n                if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||\n                                         (reference_token[pos + 1] != '0' &&\n                                          reference_token[pos + 1] != '1')))\n                {\n                    JSON_THROW(detail::parse_error::create(108, 0, \"escape character '~' must be followed with '0' or '1'\", BasicJsonType()));\n                }\n            }\n\n            // finally, store the reference token\n            detail::unescape(reference_token);\n            result.push_back(reference_token);\n        }\n\n        return result;\n    }\n\n  private:\n    /*!\n    @param[in] reference_string  the reference string to the current value\n    @param[in] value             the value to consider\n    @param[in,out] result        the result object to insert values to\n\n    @note Empty objects or arrays are flattened to `null`.\n    */\n    static void flatten(const std::string& reference_string,\n                        const BasicJsonType& value,\n                        BasicJsonType& result)\n    {\n        switch (value.type())\n        {\n            case detail::value_t::array:\n            {\n                if (value.m_value.array->empty())\n                {\n                    // flatten empty array as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate array and use index as reference string\n                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)\n                    {\n                        flatten(reference_string + \"/\" + std::to_string(i),\n                                value.m_value.array->operator[](i), result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::object:\n            {\n                if (value.m_value.object->empty())\n                {\n                    // flatten empty object as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate object and use keys as reference string\n                    for (const auto& element : *value.m_value.object)\n                    {\n                        flatten(reference_string + \"/\" + detail::escape(element.first), element.second, result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::null:\n            case detail::value_t::string:\n            case detail::value_t::boolean:\n            case detail::value_t::number_integer:\n            case detail::value_t::number_unsigned:\n            case detail::value_t::number_float:\n            case detail::value_t::binary:\n            case detail::value_t::discarded:\n            default:\n            {\n                // add primitive value with its reference string\n                result[reference_string] = value;\n                break;\n            }\n        }\n    }\n\n    /*!\n    @param[in] value  flattened JSON\n\n    @return unflattened JSON\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n    @throw type_error.313  if value cannot be unflattened\n    */\n    static BasicJsonType\n    unflatten(const BasicJsonType& value)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!value.is_object()))\n        {\n            JSON_THROW(detail::type_error::create(314, \"only objects can be unflattened\", value));\n        }\n\n        BasicJsonType result;\n\n        // iterate the JSON object values\n        for (const auto& element : *value.m_value.object)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))\n            {\n                JSON_THROW(detail::type_error::create(315, \"values in object must be primitive\", element.second));\n            }\n\n            // assign value to reference pointed to by JSON pointer; Note that if\n            // the JSON pointer is \"\" (i.e., points to the whole value), function\n            // get_and_create returns a reference to result itself. An assignment\n            // will then create a primitive value.\n            json_pointer(element.first).get_and_create(result) = element.second;\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief compares two JSON pointers for equality\n\n    @param[in] lhs  JSON pointer to compare\n    @param[in] rhs  JSON pointer to compare\n    @return whether @a lhs is equal to @a rhs\n\n    @complexity Linear in the length of the JSON pointer\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n    */\n    friend bool operator==(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return lhs.reference_tokens == rhs.reference_tokens;\n    }\n\n    /*!\n    @brief compares two JSON pointers for inequality\n\n    @param[in] lhs  JSON pointer to compare\n    @param[in] rhs  JSON pointer to compare\n    @return whether @a lhs is not equal @a rhs\n\n    @complexity Linear in the length of the JSON pointer\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n    */\n    friend bool operator!=(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return !(lhs == rhs);\n    }\n\n    /// the reference tokens\n    std::vector<std::string> reference_tokens;\n};\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/json_ref.hpp>\n\n\n#include <initializer_list>\n#include <utility>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nclass json_ref\n{\n  public:\n    using value_type = BasicJsonType;\n\n    json_ref(value_type&& value)\n        : owned_value(std::move(value))\n    {}\n\n    json_ref(const value_type& value)\n        : value_ref(&value)\n    {}\n\n    json_ref(std::initializer_list<json_ref> init)\n        : owned_value(init)\n    {}\n\n    template <\n        class... Args,\n        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >\n    json_ref(Args && ... args)\n        : owned_value(std::forward<Args>(args)...)\n    {}\n\n    // class should be movable only\n    json_ref(json_ref&&) noexcept = default;\n    json_ref(const json_ref&) = delete;\n    json_ref& operator=(const json_ref&) = delete;\n    json_ref& operator=(json_ref&&) = delete;\n    ~json_ref() = default;\n\n    value_type moved_or_copied() const\n    {\n        if (value_ref == nullptr)\n        {\n            return std::move(owned_value);\n        }\n        return *value_ref;\n    }\n\n    value_type const& operator*() const\n    {\n        return value_ref ? *value_ref : owned_value;\n    }\n\n    value_type const* operator->() const\n    {\n        return &** this;\n    }\n\n  private:\n    mutable value_type owned_value = nullptr;\n    value_type const* value_ref = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/string_escape.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n\n#include <algorithm> // reverse\n#include <array> // array\n#include <cmath> // isnan, isinf\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstring> // memcpy\n#include <limits> // numeric_limits\n#include <string> // string\n#include <utility> // move\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n\n#include <algorithm> // copy\n#include <cstddef> // size_t\n#include <iterator> // back_inserter\n#include <memory> // shared_ptr, make_shared\n#include <string> // basic_string\n#include <vector> // vector\n\n#ifndef JSON_NO_IO\n    #include <ios>      // streamsize\n    #include <ostream>  // basic_ostream\n#endif  // JSON_NO_IO\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// abstract output adapter interface\ntemplate<typename CharType> struct output_adapter_protocol\n{\n    virtual void write_character(CharType c) = 0;\n    virtual void write_characters(const CharType* s, std::size_t length) = 0;\n    virtual ~output_adapter_protocol() = default;\n\n    output_adapter_protocol() = default;\n    output_adapter_protocol(const output_adapter_protocol&) = default;\n    output_adapter_protocol(output_adapter_protocol&&) noexcept = default;\n    output_adapter_protocol& operator=(const output_adapter_protocol&) = default;\n    output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;\n};\n\n/// a type to simplify interfaces\ntemplate<typename CharType>\nusing output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;\n\n/// output adapter for byte vectors\ntemplate<typename CharType, typename AllocatorType = std::allocator<CharType>>\nclass output_vector_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept\n        : v(vec)\n    {}\n\n    void write_character(CharType c) override\n    {\n        v.push_back(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        std::copy(s, s + length, std::back_inserter(v));\n    }\n\n  private:\n    std::vector<CharType, AllocatorType>& v;\n};\n\n#ifndef JSON_NO_IO\n/// output adapter for output streams\ntemplate<typename CharType>\nclass output_stream_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept\n        : stream(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        stream.put(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        stream.write(s, static_cast<std::streamsize>(length));\n    }\n\n  private:\n    std::basic_ostream<CharType>& stream;\n};\n#endif  // JSON_NO_IO\n\n/// output adapter for basic_string\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_string_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_string_adapter(StringType& s) noexcept\n        : str(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        str.push_back(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        str.append(s, length);\n    }\n\n  private:\n    StringType& str;\n};\n\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_adapter\n{\n  public:\n    template<typename AllocatorType = std::allocator<CharType>>\n    output_adapter(std::vector<CharType, AllocatorType>& vec)\n        : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}\n\n#ifndef JSON_NO_IO\n    output_adapter(std::basic_ostream<CharType>& s)\n        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}\n#endif  // JSON_NO_IO\n\n    output_adapter(StringType& s)\n        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}\n\n    operator output_adapter_t<CharType>()\n    {\n        return oa;\n    }\n\n  private:\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// binary writer //\n///////////////////\n\n/*!\n@brief serialization to CBOR and MessagePack values\n*/\ntemplate<typename BasicJsonType, typename CharType>\nclass binary_writer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n\n  public:\n    /*!\n    @brief create a binary writer\n\n    @param[in] adapter  output adapter to write to\n    */\n    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))\n    {\n        JSON_ASSERT(oa);\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n            {\n                write_bson_object(*j.m_value.object);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::array:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                JSON_THROW(type_error::create(317, \"to serialize to BSON, top-level type must be object, but is \" + std::string(j.type_name()), j));\n            }\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_cbor(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                oa->write_character(to_char_type(0xF6));\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xF5)\n                                    : to_char_type(0xF4));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // CBOR does not differentiate between positive signed\n                    // integers and unsigned integers. Therefore, we used the\n                    // code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_integer <= 0x17)\n                    {\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x18));\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x19));\n                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x1A));\n                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x1B));\n                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    // The conversions below encode the sign in the first\n                    // byte, and the value is converted to a positive number.\n                    const auto positive_number = -1 - j.m_value.number_integer;\n                    if (j.m_value.number_integer >= -24)\n                    {\n                        write_number(static_cast<std::uint8_t>(0x20 + positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x38));\n                        write_number(static_cast<std::uint8_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x39));\n                        write_number(static_cast<std::uint16_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x3A));\n                        write_number(static_cast<std::uint32_t>(positive_number));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x3B));\n                        write_number(static_cast<std::uint64_t>(positive_number));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x18));\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x19));\n                    write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x1A));\n                    write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));\n                }\n                else\n                {\n                    oa->write_character(to_char_type(0x1B));\n                    write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                if (std::isnan(j.m_value.number_float))\n                {\n                    // NaN is 0xf97e00 in CBOR\n                    oa->write_character(to_char_type(0xF9));\n                    oa->write_character(to_char_type(0x7E));\n                    oa->write_character(to_char_type(0x00));\n                }\n                else if (std::isinf(j.m_value.number_float))\n                {\n                    // Infinity is 0xf97c00, -Infinity is 0xf9fc00\n                    oa->write_character(to_char_type(0xf9));\n                    oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));\n                    oa->write_character(to_char_type(0x00));\n                }\n                else\n                {\n                    write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);\n                }\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x60 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x78));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x79));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x80 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x98));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x99));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_cbor(el);\n                }\n                break;\n            }\n\n            case value_t::binary:\n            {\n                if (j.m_value.binary->has_subtype())\n                {\n                    if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xd8));\n                        write_number(static_cast<std::uint8_t>(j.m_value.binary->subtype()));\n                    }\n                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xd9));\n                        write_number(static_cast<std::uint16_t>(j.m_value.binary->subtype()));\n                    }\n                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xda));\n                        write_number(static_cast<std::uint32_t>(j.m_value.binary->subtype()));\n                    }\n                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xdb));\n                        write_number(static_cast<std::uint64_t>(j.m_value.binary->subtype()));\n                    }\n                }\n\n                // step 1: write control byte and the binary array size\n                const auto N = j.m_value.binary->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x40 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x58));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x59));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x5A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x5B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),\n                    N);\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0xA0 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB8));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB9));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBA));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBB));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_cbor(el.first);\n                    write_cbor(el.second);\n                }\n                break;\n            }\n\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_msgpack(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null: // nil\n            {\n                oa->write_character(to_char_type(0xC0));\n                break;\n            }\n\n            case value_t::boolean: // true and false\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xC3)\n                                    : to_char_type(0xC2));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // MessagePack does not differentiate between positive\n                    // signed integers and unsigned integers. Therefore, we used\n                    // the code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_unsigned < 128)\n                    {\n                        // positive fixnum\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        // uint 8\n                        oa->write_character(to_char_type(0xCC));\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        // uint 16\n                        oa->write_character(to_char_type(0xCD));\n                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        // uint 32\n                        oa->write_character(to_char_type(0xCE));\n                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                    {\n                        // uint 64\n                        oa->write_character(to_char_type(0xCF));\n                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    if (j.m_value.number_integer >= -32)\n                    {\n                        // negative fixnum\n                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n                    {\n                        // int 8\n                        oa->write_character(to_char_type(0xD0));\n                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n                    {\n                        // int 16\n                        oa->write_character(to_char_type(0xD1));\n                        write_number(static_cast<std::int16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n                    {\n                        // int 32\n                        oa->write_character(to_char_type(0xD2));\n                        write_number(static_cast<std::int32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n                    {\n                        // int 64\n                        oa->write_character(to_char_type(0xD3));\n                        write_number(static_cast<std::int64_t>(j.m_value.number_integer));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned < 128)\n                {\n                    // positive fixnum\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    // uint 8\n                    oa->write_character(to_char_type(0xCC));\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // uint 16\n                    oa->write_character(to_char_type(0xCD));\n                    write_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // uint 32\n                    oa->write_character(to_char_type(0xCE));\n                    write_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    // uint 64\n                    oa->write_character(to_char_type(0xCF));\n                    write_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 31)\n                {\n                    // fixstr\n                    write_number(static_cast<std::uint8_t>(0xA0 | N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    // str 8\n                    oa->write_character(to_char_type(0xD9));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // str 16\n                    oa->write_character(to_char_type(0xDA));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // str 32\n                    oa->write_character(to_char_type(0xDB));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 15)\n                {\n                    // fixarray\n                    write_number(static_cast<std::uint8_t>(0x90 | N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // array 16\n                    oa->write_character(to_char_type(0xDC));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // array 32\n                    oa->write_character(to_char_type(0xDD));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_msgpack(el);\n                }\n                break;\n            }\n\n            case value_t::binary:\n            {\n                // step 0: determine if the binary type has a set subtype to\n                // determine whether or not to use the ext or fixext types\n                const bool use_ext = j.m_value.binary->has_subtype();\n\n                // step 1: write control byte and the byte string length\n                const auto N = j.m_value.binary->size();\n                if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    std::uint8_t output_type{};\n                    bool fixed = true;\n                    if (use_ext)\n                    {\n                        switch (N)\n                        {\n                            case 1:\n                                output_type = 0xD4; // fixext 1\n                                break;\n                            case 2:\n                                output_type = 0xD5; // fixext 2\n                                break;\n                            case 4:\n                                output_type = 0xD6; // fixext 4\n                                break;\n                            case 8:\n                                output_type = 0xD7; // fixext 8\n                                break;\n                            case 16:\n                                output_type = 0xD8; // fixext 16\n                                break;\n                            default:\n                                output_type = 0xC7; // ext 8\n                                fixed = false;\n                                break;\n                        }\n\n                    }\n                    else\n                    {\n                        output_type = 0xC4; // bin 8\n                        fixed = false;\n                    }\n\n                    oa->write_character(to_char_type(output_type));\n                    if (!fixed)\n                    {\n                        write_number(static_cast<std::uint8_t>(N));\n                    }\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    std::uint8_t output_type = use_ext\n                                               ? 0xC8 // ext 16\n                                               : 0xC5; // bin 16\n\n                    oa->write_character(to_char_type(output_type));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    std::uint8_t output_type = use_ext\n                                               ? 0xC9 // ext 32\n                                               : 0xC6; // bin 32\n\n                    oa->write_character(to_char_type(output_type));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 1.5: if this is an ext type, write the subtype\n                if (use_ext)\n                {\n                    write_number(static_cast<std::int8_t>(j.m_value.binary->subtype()));\n                }\n\n                // step 2: write the byte string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),\n                    N);\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 15)\n                {\n                    // fixmap\n                    write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // map 16\n                    oa->write_character(to_char_type(0xDE));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // map 32\n                    oa->write_character(to_char_type(0xDF));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_msgpack(el.first);\n                    write_msgpack(el.second);\n                }\n                break;\n            }\n\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @param[in] use_count   whether to use '#' prefixes (optimized format)\n    @param[in] use_type    whether to use '$' prefixes (optimized format)\n    @param[in] add_prefix  whether prefixes need to be used for this value\n    */\n    void write_ubjson(const BasicJsonType& j, const bool use_count,\n                      const bool use_type, const bool add_prefix = true)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('Z'));\n                }\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(j.m_value.boolean\n                                        ? to_char_type('T')\n                                        : to_char_type('F'));\n                }\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);\n                break;\n            }\n\n            case value_t::string:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('S'));\n                }\n                write_number_with_ubjson_prefix(j.m_value.string->size(), true);\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                bool prefix_required = true;\n                if (use_type && !j.m_value.array->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.array->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_ubjson(el, use_count, use_type, prefix_required);\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::binary:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                if (use_type && !j.m_value.binary->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    oa->write_character(to_char_type('$'));\n                    oa->write_character('U');\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.binary->size(), true);\n                }\n\n                if (use_type)\n                {\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(j.m_value.binary->data()),\n                        j.m_value.binary->size());\n                }\n                else\n                {\n                    for (size_t i = 0; i < j.m_value.binary->size(); ++i)\n                    {\n                        oa->write_character(to_char_type('U'));\n                        oa->write_character(j.m_value.binary->data()[i]);\n                    }\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('{'));\n                }\n\n                bool prefix_required = true;\n                if (use_type && !j.m_value.object->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin(), j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.object->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_number_with_ubjson_prefix(el.first.size(), true);\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(el.first.c_str()),\n                        el.first.size());\n                    write_ubjson(el.second, use_count, use_type, prefix_required);\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type('}'));\n                }\n\n                break;\n            }\n\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @return The size of a BSON document entry header, including the id marker\n            and the entry name size (and its null-terminator).\n    */\n    static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)\n    {\n        const auto it = name.find(static_cast<typename string_t::value_type>(0));\n        if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))\n        {\n            JSON_THROW(out_of_range::create(409, \"BSON key cannot contain code point U+0000 (at byte \" + std::to_string(it) + \")\", j));\n            static_cast<void>(j);\n        }\n\n        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;\n    }\n\n    /*!\n    @brief Writes the given @a element_type and @a name to the output adapter\n    */\n    void write_bson_entry_header(const string_t& name,\n                                 const std::uint8_t element_type)\n    {\n        oa->write_character(to_char_type(element_type)); // boolean\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(name.c_str()),\n            name.size() + 1u);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and boolean value @a value\n    */\n    void write_bson_boolean(const string_t& name,\n                            const bool value)\n    {\n        write_bson_entry_header(name, 0x08);\n        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and double value @a value\n    */\n    void write_bson_double(const string_t& name,\n                           const double value)\n    {\n        write_bson_entry_header(name, 0x01);\n        write_number<double, true>(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded string in @a value\n    */\n    static std::size_t calc_bson_string_size(const string_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and string value @a value\n    */\n    void write_bson_string(const string_t& name,\n                           const string_t& value)\n    {\n        write_bson_entry_header(name, 0x02);\n\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(value.c_str()),\n            value.size() + 1);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and null value\n    */\n    void write_bson_null(const string_t& name)\n    {\n        write_bson_entry_header(name, 0x0A);\n    }\n\n    /*!\n    @return The size of the BSON-encoded integer @a value\n    */\n    static std::size_t calc_bson_integer_size(const std::int64_t value)\n    {\n        return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and integer @a value\n    */\n    void write_bson_integer(const string_t& name,\n                            const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            write_bson_entry_header(name, 0x10); // int32\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else\n        {\n            write_bson_entry_header(name, 0x12); // int64\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n    }\n\n    /*!\n    @return The size of the BSON-encoded unsigned integer in @a j\n    */\n    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept\n    {\n        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and unsigned @a value\n    */\n    void write_bson_unsigned(const string_t& name,\n                             const BasicJsonType& j)\n    {\n        if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x10 /* int32 */);\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(j.m_value.number_unsigned));\n        }\n        else if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x12 /* int64 */);\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(j.m_value.number_unsigned));\n        }\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(j.m_value.number_unsigned) + \" cannot be represented by BSON as it does not fit int64\", j));\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and object @a value\n    */\n    void write_bson_object_entry(const string_t& name,\n                                 const typename BasicJsonType::object_t& value)\n    {\n        write_bson_entry_header(name, 0x03); // object\n        write_bson_object(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded array @a value\n    */\n    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)\n    {\n        std::size_t array_index = 0ul;\n\n        const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)\n        {\n            return result + calc_bson_element_size(std::to_string(array_index++), el);\n        });\n\n        return sizeof(std::int32_t) + embedded_document_size + 1ul;\n    }\n\n    /*!\n    @return The size of the BSON-encoded binary array @a value\n    */\n    static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and array @a value\n    */\n    void write_bson_array(const string_t& name,\n                          const typename BasicJsonType::array_t& value)\n    {\n        write_bson_entry_header(name, 0x04); // array\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));\n\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            write_bson_element(std::to_string(array_index++), el);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and binary value @a value\n    */\n    void write_bson_binary(const string_t& name,\n                           const binary_t& value)\n    {\n        write_bson_entry_header(name, 0x05);\n\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size()));\n        write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : std::uint8_t(0x00));\n\n        oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());\n    }\n\n    /*!\n    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name\n    @return The calculated size for the BSON document entry for @a j with the given @a name.\n    */\n    static std::size_t calc_bson_element_size(const string_t& name,\n            const BasicJsonType& j)\n    {\n        const auto header_size = calc_bson_entry_header_size(name, j);\n        switch (j.type())\n        {\n            case value_t::object:\n                return header_size + calc_bson_object_size(*j.m_value.object);\n\n            case value_t::array:\n                return header_size + calc_bson_array_size(*j.m_value.array);\n\n            case value_t::binary:\n                return header_size + calc_bson_binary_size(*j.m_value.binary);\n\n            case value_t::boolean:\n                return header_size + 1ul;\n\n            case value_t::number_float:\n                return header_size + 8ul;\n\n            case value_t::number_integer:\n                return header_size + calc_bson_integer_size(j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);\n\n            case value_t::string:\n                return header_size + calc_bson_string_size(*j.m_value.string);\n\n            case value_t::null:\n                return header_size + 0ul;\n\n            // LCOV_EXCL_START\n            case value_t::discarded:\n            default:\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)\n                return 0ul;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Serializes the JSON value @a j to BSON and associates it with the\n           key @a name.\n    @param name The name to associate with the JSON entity @a j within the\n                current BSON document\n    */\n    void write_bson_element(const string_t& name,\n                            const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n                return write_bson_object_entry(name, *j.m_value.object);\n\n            case value_t::array:\n                return write_bson_array(name, *j.m_value.array);\n\n            case value_t::binary:\n                return write_bson_binary(name, *j.m_value.binary);\n\n            case value_t::boolean:\n                return write_bson_boolean(name, j.m_value.boolean);\n\n            case value_t::number_float:\n                return write_bson_double(name, j.m_value.number_float);\n\n            case value_t::number_integer:\n                return write_bson_integer(name, j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return write_bson_unsigned(name, j);\n\n            case value_t::string:\n                return write_bson_string(name, *j.m_value.string);\n\n            case value_t::null:\n                return write_bson_null(name);\n\n            // LCOV_EXCL_START\n            case value_t::discarded:\n            default:\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)\n                return;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Calculates the size of the BSON serialization of the given\n           JSON-object @a j.\n    @param[in] value  JSON value to serialize\n    @pre       value.type() == value_t::object\n    */\n    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)\n    {\n        std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0),\n                                    [](size_t result, const typename BasicJsonType::object_t::value_type & el)\n        {\n            return result += calc_bson_element_size(el.first, el.second);\n        });\n\n        return sizeof(std::int32_t) + document_size + 1ul;\n    }\n\n    /*!\n    @param[in] value  JSON value to serialize\n    @pre       value.type() == value_t::object\n    */\n    void write_bson_object(const typename BasicJsonType::object_t& value)\n    {\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));\n\n        for (const auto& el : value)\n        {\n            write_bson_element(el.first, el.second);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    static constexpr CharType get_cbor_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xFA);  // Single-Precision Float\n    }\n\n    static constexpr CharType get_cbor_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xFB);  // Double-Precision Float\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xCA);  // float 32\n    }\n\n    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xCB);  // float 64\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    // UBJSON: write number (floating point)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (add_prefix)\n        {\n            oa->write_character(get_ubjson_float_prefix(n));\n        }\n        write_number(n);\n    }\n\n    // UBJSON: write number (unsigned integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_unsigned<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<std::uint8_t>(n));\n        }\n        else if (n <= (std::numeric_limits<std::uint8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<std::uint8_t>(n));\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<std::int16_t>(n));\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<std::int32_t>(n));\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<std::int64_t>(n));\n        }\n        else\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('H'));  // high-precision number\n            }\n\n            const auto number = BasicJsonType(n).dump();\n            write_number_with_ubjson_prefix(number.size(), true);\n            for (std::size_t i = 0; i < number.size(); ++i)\n            {\n                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));\n            }\n        }\n    }\n\n    // UBJSON: write number (signed integer)\n    template < typename NumberType, typename std::enable_if <\n                   std::is_signed<NumberType>::value&&\n                   !std::is_floating_point<NumberType>::value, int >::type = 0 >\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<std::int8_t>(n));\n        }\n        else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<std::uint8_t>(n));\n        }\n        else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<std::int16_t>(n));\n        }\n        else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<std::int32_t>(n));\n        }\n        else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<std::int64_t>(n));\n        }\n        // LCOV_EXCL_START\n        else\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('H'));  // high-precision number\n            }\n\n            const auto number = BasicJsonType(n).dump();\n            write_number_with_ubjson_prefix(number.size(), true);\n            for (std::size_t i = 0; i < number.size(); ++i)\n            {\n                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));\n            }\n        }\n        // LCOV_EXCL_STOP\n    }\n\n    /*!\n    @brief determine the type prefix of container values\n    */\n    CharType ubjson_prefix(const BasicJsonType& j) const noexcept\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n                return 'Z';\n\n            case value_t::boolean:\n                return j.m_value.boolean ? 'T' : 'F';\n\n            case value_t::number_integer:\n            {\n                if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n                {\n                    return 'l';\n                }\n                if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n                {\n                    return 'L';\n                }\n                // anything else is treated as high-precision number\n                return 'H'; // LCOV_EXCL_LINE\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n                {\n                    return 'i';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))\n                {\n                    return 'U';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n                {\n                    return 'I';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n                {\n                    return 'l';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n                {\n                    return 'L';\n                }\n                // anything else is treated as high-precision number\n                return 'H'; // LCOV_EXCL_LINE\n            }\n\n            case value_t::number_float:\n                return get_ubjson_float_prefix(j.m_value.number_float);\n\n            case value_t::string:\n                return 'S';\n\n            case value_t::array: // fallthrough\n            case value_t::binary:\n                return '[';\n\n            case value_t::object:\n                return '{';\n\n            case value_t::discarded:\n            default:  // discarded values\n                return 'N';\n        }\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)\n    {\n        return 'd';  // float 32\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)\n    {\n        return 'D';  // float 64\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*\n    @brief write a number to output input\n    @param[in] n number of type @a NumberType\n    @tparam NumberType the type of the number\n    @tparam OutputIsLittleEndian Set to true if output data is\n                                 required to be little endian\n\n    @note This function needs to respect the system's endianess, because bytes\n          in CBOR, MessagePack, and UBJSON are stored in network order (big\n          endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool OutputIsLittleEndian = false>\n    void write_number(const NumberType n)\n    {\n        // step 1: write number to array of length NumberType\n        std::array<CharType, sizeof(NumberType)> vec{};\n        std::memcpy(vec.data(), &n, sizeof(NumberType));\n\n        // step 2: write array to output (with possible reordering)\n        if (is_little_endian != OutputIsLittleEndian)\n        {\n            // reverse byte order prior to conversion if necessary\n            std::reverse(vec.begin(), vec.end());\n        }\n\n        oa->write_characters(vec.data(), sizeof(NumberType));\n    }\n\n    void write_compact_float(const number_float_t n, detail::input_format_t format)\n    {\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n        if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&\n                static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&\n                static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))\n        {\n            oa->write_character(format == detail::input_format_t::cbor\n                                ? get_cbor_float_prefix(static_cast<float>(n))\n                                : get_msgpack_float_prefix(static_cast<float>(n)));\n            write_number(static_cast<float>(n));\n        }\n        else\n        {\n            oa->write_character(format == detail::input_format_t::cbor\n                                ? get_cbor_float_prefix(n)\n                                : get_msgpack_float_prefix(n));\n            write_number(n);\n        }\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n    }\n\n  public:\n    // The following to_char_type functions are implement the conversion\n    // between uint8_t and CharType. In case CharType is not unsigned,\n    // such a conversion is required to allow values greater than 128.\n    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return *reinterpret_cast<char*>(&x);\n    }\n\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >\n    static CharType to_char_type(std::uint8_t x) noexcept\n    {\n        static_assert(sizeof(std::uint8_t) == sizeof(CharType), \"size of CharType must be equal to std::uint8_t\");\n        static_assert(std::is_trivial<CharType>::value, \"CharType must be trivial\");\n        CharType result;\n        std::memcpy(&result, &x, sizeof(x));\n        return result;\n    }\n\n    template<typename C = CharType,\n             enable_if_t<std::is_unsigned<C>::value>* = nullptr>\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return x;\n    }\n\n    template < typename InputCharType, typename C = CharType,\n               enable_if_t <\n                   std::is_signed<C>::value &&\n                   std::is_signed<char>::value &&\n                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value\n                   > * = nullptr >\n    static constexpr CharType to_char_type(InputCharType x) noexcept\n    {\n        return x;\n    }\n\n  private:\n    /// whether we can assume little endianess\n    const bool is_little_endian = little_endianess();\n\n    /// the output\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/output/serializer.hpp>\n\n\n#include <algorithm> // reverse, remove, fill, find, none_of\n#include <array> // array\n#include <clocale> // localeconv, lconv\n#include <cmath> // labs, isfinite, isnan, signbit\n#include <cstddef> // size_t, ptrdiff_t\n#include <cstdint> // uint8_t\n#include <cstdio> // snprintf\n#include <limits> // numeric_limits\n#include <string> // string, char_traits\n#include <type_traits> // is_same\n#include <utility> // move\n\n// #include <nlohmann/detail/conversions/to_chars.hpp>\n\n\n#include <array> // array\n#include <cmath>   // signbit, isfinite\n#include <cstdint> // intN_t, uintN_t\n#include <cstring> // memcpy, memmove\n#include <limits> // numeric_limits\n#include <type_traits> // conditional\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/*!\n@brief implements the Grisu2 algorithm for binary to decimal floating-point\nconversion.\n\nThis implementation is a slightly modified version of the reference\nimplementation which may be obtained from\nhttp://florian.loitsch.com/publications (bench.tar.gz).\n\nThe code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.\n\nFor a detailed description of the algorithm see:\n\n[1] Loitsch, \"Printing Floating-Point Numbers Quickly and Accurately with\n    Integers\", Proceedings of the ACM SIGPLAN 2010 Conference on Programming\n    Language Design and Implementation, PLDI 2010\n[2] Burger, Dybvig, \"Printing Floating-Point Numbers Quickly and Accurately\",\n    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language\n    Design and Implementation, PLDI 1996\n*/\nnamespace dtoa_impl\n{\n\ntemplate<typename Target, typename Source>\nTarget reinterpret_bits(const Source source)\n{\n    static_assert(sizeof(Target) == sizeof(Source), \"size mismatch\");\n\n    Target target;\n    std::memcpy(&target, &source, sizeof(Source));\n    return target;\n}\n\nstruct diyfp // f * 2^e\n{\n    static constexpr int kPrecision = 64; // = q\n\n    std::uint64_t f = 0;\n    int e = 0;\n\n    constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}\n\n    /*!\n    @brief returns x - y\n    @pre x.e == y.e and x.f >= y.f\n    */\n    static diyfp sub(const diyfp& x, const diyfp& y) noexcept\n    {\n        JSON_ASSERT(x.e == y.e);\n        JSON_ASSERT(x.f >= y.f);\n\n        return {x.f - y.f, x.e};\n    }\n\n    /*!\n    @brief returns x * y\n    @note The result is rounded. (Only the upper q bits are returned.)\n    */\n    static diyfp mul(const diyfp& x, const diyfp& y) noexcept\n    {\n        static_assert(kPrecision == 64, \"internal error\");\n\n        // Computes:\n        //  f = round((x.f * y.f) / 2^q)\n        //  e = x.e + y.e + q\n\n        // Emulate the 64-bit * 64-bit multiplication:\n        //\n        // p = u * v\n        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)\n        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )\n        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )\n        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )\n        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)\n        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )\n        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )\n        //\n        // (Since Q might be larger than 2^32 - 1)\n        //\n        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)\n        //\n        // (Q_hi + H does not overflow a 64-bit int)\n        //\n        //   = p_lo + 2^64 p_hi\n\n        const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;\n        const std::uint64_t u_hi = x.f >> 32u;\n        const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;\n        const std::uint64_t v_hi = y.f >> 32u;\n\n        const std::uint64_t p0 = u_lo * v_lo;\n        const std::uint64_t p1 = u_lo * v_hi;\n        const std::uint64_t p2 = u_hi * v_lo;\n        const std::uint64_t p3 = u_hi * v_hi;\n\n        const std::uint64_t p0_hi = p0 >> 32u;\n        const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;\n        const std::uint64_t p1_hi = p1 >> 32u;\n        const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;\n        const std::uint64_t p2_hi = p2 >> 32u;\n\n        std::uint64_t Q = p0_hi + p1_lo + p2_lo;\n\n        // The full product might now be computed as\n        //\n        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)\n        // p_lo = p0_lo + (Q << 32)\n        //\n        // But in this particular case here, the full p_lo is not required.\n        // Effectively we only need to add the highest bit in p_lo to p_hi (and\n        // Q_hi + 1 does not overflow).\n\n        Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up\n\n        const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);\n\n        return {h, x.e + y.e + 64};\n    }\n\n    /*!\n    @brief normalize x such that the significand is >= 2^(q-1)\n    @pre x.f != 0\n    */\n    static diyfp normalize(diyfp x) noexcept\n    {\n        JSON_ASSERT(x.f != 0);\n\n        while ((x.f >> 63u) == 0)\n        {\n            x.f <<= 1u;\n            x.e--;\n        }\n\n        return x;\n    }\n\n    /*!\n    @brief normalize x such that the result has the exponent E\n    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.\n    */\n    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept\n    {\n        const int delta = x.e - target_exponent;\n\n        JSON_ASSERT(delta >= 0);\n        JSON_ASSERT(((x.f << delta) >> delta) == x.f);\n\n        return {x.f << delta, target_exponent};\n    }\n};\n\nstruct boundaries\n{\n    diyfp w;\n    diyfp minus;\n    diyfp plus;\n};\n\n/*!\nCompute the (normalized) diyfp representing the input number 'value' and its\nboundaries.\n\n@pre value must be finite and positive\n*/\ntemplate<typename FloatType>\nboundaries compute_boundaries(FloatType value)\n{\n    JSON_ASSERT(std::isfinite(value));\n    JSON_ASSERT(value > 0);\n\n    // Convert the IEEE representation into a diyfp.\n    //\n    // If v is denormal:\n    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))\n    // If v is normalized:\n    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))\n\n    static_assert(std::numeric_limits<FloatType>::is_iec559,\n                  \"internal error: dtoa_short requires an IEEE-754 floating-point implementation\");\n\n    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)\n    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);\n    constexpr int      kMinExp    = 1 - kBias;\n    constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)\n\n    using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;\n\n    const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));\n    const std::uint64_t E = bits >> (kPrecision - 1);\n    const std::uint64_t F = bits & (kHiddenBit - 1);\n\n    const bool is_denormal = E == 0;\n    const diyfp v = is_denormal\n                    ? diyfp(F, kMinExp)\n                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);\n\n    // Compute the boundaries m- and m+ of the floating-point value\n    // v = f * 2^e.\n    //\n    // Determine v- and v+, the floating-point predecessor and successor if v,\n    // respectively.\n    //\n    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)\n    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)\n    //\n    //      v+ = v + 2^e\n    //\n    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_\n    // between m- and m+ round to v, regardless of how the input rounding\n    // algorithm breaks ties.\n    //\n    //      ---+-------------+-------------+-------------+-------------+---  (A)\n    //         v-            m-            v             m+            v+\n    //\n    //      -----------------+------+------+-------------+-------------+---  (B)\n    //                       v-     m-     v             m+            v+\n\n    const bool lower_boundary_is_closer = F == 0 && E > 1;\n    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);\n    const diyfp m_minus = lower_boundary_is_closer\n                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)\n                          : diyfp(2 * v.f - 1, v.e - 1); // (A)\n\n    // Determine the normalized w+ = m+.\n    const diyfp w_plus = diyfp::normalize(m_plus);\n\n    // Determine w- = m- such that e_(w-) = e_(w+).\n    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);\n\n    return {diyfp::normalize(v), w_minus, w_plus};\n}\n\n// Given normalized diyfp w, Grisu needs to find a (normalized) cached\n// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies\n// within a certain range [alpha, gamma] (Definition 3.2 from [1])\n//\n//      alpha <= e = e_c + e_w + q <= gamma\n//\n// or\n//\n//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q\n//                          <= f_c * f_w * 2^gamma\n//\n// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies\n//\n//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma\n//\n// or\n//\n//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)\n//\n// The choice of (alpha,gamma) determines the size of the table and the form of\n// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well\n// in practice:\n//\n// The idea is to cut the number c * w = f * 2^e into two parts, which can be\n// processed independently: An integral part p1, and a fractional part p2:\n//\n//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e\n//              = (f div 2^-e) + (f mod 2^-e) * 2^e\n//              = p1 + p2 * 2^e\n//\n// The conversion of p1 into decimal form requires a series of divisions and\n// modulos by (a power of) 10. These operations are faster for 32-bit than for\n// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be\n// achieved by choosing\n//\n//      -e >= 32   or   e <= -32 := gamma\n//\n// In order to convert the fractional part\n//\n//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...\n//\n// into decimal form, the fraction is repeatedly multiplied by 10 and the digits\n// d[-i] are extracted in order:\n//\n//      (10 * p2) div 2^-e = d[-1]\n//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...\n//\n// The multiplication by 10 must not overflow. It is sufficient to choose\n//\n//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.\n//\n// Since p2 = f mod 2^-e < 2^-e,\n//\n//      -e <= 60   or   e >= -60 := alpha\n\nconstexpr int kAlpha = -60;\nconstexpr int kGamma = -32;\n\nstruct cached_power // c = f * 2^e ~= 10^k\n{\n    std::uint64_t f;\n    int e;\n    int k;\n};\n\n/*!\nFor a normalized diyfp w = f * 2^e, this function returns a (normalized) cached\npower-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c\nsatisfies (Definition 3.2 from [1])\n\n     alpha <= e_c + e + q <= gamma.\n*/\ninline cached_power get_cached_power_for_binary_exponent(int e)\n{\n    // Now\n    //\n    //      alpha <= e_c + e + q <= gamma                                    (1)\n    //      ==> f_c * 2^alpha <= c * 2^e * 2^q\n    //\n    // and since the c's are normalized, 2^(q-1) <= f_c,\n    //\n    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)\n    //      ==> 2^(alpha - e - 1) <= c\n    //\n    // If c were an exact power of ten, i.e. c = 10^k, one may determine k as\n    //\n    //      k = ceil( log_10( 2^(alpha - e - 1) ) )\n    //        = ceil( (alpha - e - 1) * log_10(2) )\n    //\n    // From the paper:\n    // \"In theory the result of the procedure could be wrong since c is rounded,\n    //  and the computation itself is approximated [...]. In practice, however,\n    //  this simple function is sufficient.\"\n    //\n    // For IEEE double precision floating-point numbers converted into\n    // normalized diyfp's w = f * 2^e, with q = 64,\n    //\n    //      e >= -1022      (min IEEE exponent)\n    //           -52        (p - 1)\n    //           -52        (p - 1, possibly normalize denormal IEEE numbers)\n    //           -11        (normalize the diyfp)\n    //         = -1137\n    //\n    // and\n    //\n    //      e <= +1023      (max IEEE exponent)\n    //           -52        (p - 1)\n    //           -11        (normalize the diyfp)\n    //         = 960\n    //\n    // This binary exponent range [-1137,960] results in a decimal exponent\n    // range [-307,324]. One does not need to store a cached power for each\n    // k in this range. For each such k it suffices to find a cached power\n    // such that the exponent of the product lies in [alpha,gamma].\n    // This implies that the difference of the decimal exponents of adjacent\n    // table entries must be less than or equal to\n    //\n    //      floor( (gamma - alpha) * log_10(2) ) = 8.\n    //\n    // (A smaller distance gamma-alpha would require a larger table.)\n\n    // NB:\n    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.\n\n    constexpr int kCachedPowersMinDecExp = -300;\n    constexpr int kCachedPowersDecStep = 8;\n\n    static constexpr std::array<cached_power, 79> kCachedPowers =\n    {\n        {\n            { 0xAB70FE17C79AC6CA, -1060, -300 },\n            { 0xFF77B1FCBEBCDC4F, -1034, -292 },\n            { 0xBE5691EF416BD60C, -1007, -284 },\n            { 0x8DD01FAD907FFC3C,  -980, -276 },\n            { 0xD3515C2831559A83,  -954, -268 },\n            { 0x9D71AC8FADA6C9B5,  -927, -260 },\n            { 0xEA9C227723EE8BCB,  -901, -252 },\n            { 0xAECC49914078536D,  -874, -244 },\n            { 0x823C12795DB6CE57,  -847, -236 },\n            { 0xC21094364DFB5637,  -821, -228 },\n            { 0x9096EA6F3848984F,  -794, -220 },\n            { 0xD77485CB25823AC7,  -768, -212 },\n            { 0xA086CFCD97BF97F4,  -741, -204 },\n            { 0xEF340A98172AACE5,  -715, -196 },\n            { 0xB23867FB2A35B28E,  -688, -188 },\n            { 0x84C8D4DFD2C63F3B,  -661, -180 },\n            { 0xC5DD44271AD3CDBA,  -635, -172 },\n            { 0x936B9FCEBB25C996,  -608, -164 },\n            { 0xDBAC6C247D62A584,  -582, -156 },\n            { 0xA3AB66580D5FDAF6,  -555, -148 },\n            { 0xF3E2F893DEC3F126,  -529, -140 },\n            { 0xB5B5ADA8AAFF80B8,  -502, -132 },\n            { 0x87625F056C7C4A8B,  -475, -124 },\n            { 0xC9BCFF6034C13053,  -449, -116 },\n            { 0x964E858C91BA2655,  -422, -108 },\n            { 0xDFF9772470297EBD,  -396, -100 },\n            { 0xA6DFBD9FB8E5B88F,  -369,  -92 },\n            { 0xF8A95FCF88747D94,  -343,  -84 },\n            { 0xB94470938FA89BCF,  -316,  -76 },\n            { 0x8A08F0F8BF0F156B,  -289,  -68 },\n            { 0xCDB02555653131B6,  -263,  -60 },\n            { 0x993FE2C6D07B7FAC,  -236,  -52 },\n            { 0xE45C10C42A2B3B06,  -210,  -44 },\n            { 0xAA242499697392D3,  -183,  -36 },\n            { 0xFD87B5F28300CA0E,  -157,  -28 },\n            { 0xBCE5086492111AEB,  -130,  -20 },\n            { 0x8CBCCC096F5088CC,  -103,  -12 },\n            { 0xD1B71758E219652C,   -77,   -4 },\n            { 0x9C40000000000000,   -50,    4 },\n            { 0xE8D4A51000000000,   -24,   12 },\n            { 0xAD78EBC5AC620000,     3,   20 },\n            { 0x813F3978F8940984,    30,   28 },\n            { 0xC097CE7BC90715B3,    56,   36 },\n            { 0x8F7E32CE7BEA5C70,    83,   44 },\n            { 0xD5D238A4ABE98068,   109,   52 },\n            { 0x9F4F2726179A2245,   136,   60 },\n            { 0xED63A231D4C4FB27,   162,   68 },\n            { 0xB0DE65388CC8ADA8,   189,   76 },\n            { 0x83C7088E1AAB65DB,   216,   84 },\n            { 0xC45D1DF942711D9A,   242,   92 },\n            { 0x924D692CA61BE758,   269,  100 },\n            { 0xDA01EE641A708DEA,   295,  108 },\n            { 0xA26DA3999AEF774A,   322,  116 },\n            { 0xF209787BB47D6B85,   348,  124 },\n            { 0xB454E4A179DD1877,   375,  132 },\n            { 0x865B86925B9BC5C2,   402,  140 },\n            { 0xC83553C5C8965D3D,   428,  148 },\n            { 0x952AB45CFA97A0B3,   455,  156 },\n            { 0xDE469FBD99A05FE3,   481,  164 },\n            { 0xA59BC234DB398C25,   508,  172 },\n            { 0xF6C69A72A3989F5C,   534,  180 },\n            { 0xB7DCBF5354E9BECE,   561,  188 },\n            { 0x88FCF317F22241E2,   588,  196 },\n            { 0xCC20CE9BD35C78A5,   614,  204 },\n            { 0x98165AF37B2153DF,   641,  212 },\n            { 0xE2A0B5DC971F303A,   667,  220 },\n            { 0xA8D9D1535CE3B396,   694,  228 },\n            { 0xFB9B7CD9A4A7443C,   720,  236 },\n            { 0xBB764C4CA7A44410,   747,  244 },\n            { 0x8BAB8EEFB6409C1A,   774,  252 },\n            { 0xD01FEF10A657842C,   800,  260 },\n            { 0x9B10A4E5E9913129,   827,  268 },\n            { 0xE7109BFBA19C0C9D,   853,  276 },\n            { 0xAC2820D9623BF429,   880,  284 },\n            { 0x80444B5E7AA7CF85,   907,  292 },\n            { 0xBF21E44003ACDD2D,   933,  300 },\n            { 0x8E679C2F5E44FF8F,   960,  308 },\n            { 0xD433179D9C8CB841,   986,  316 },\n            { 0x9E19DB92B4E31BA9,  1013,  324 },\n        }\n    };\n\n    // This computation gives exactly the same results for k as\n    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)\n    // for |e| <= 1500, but doesn't require floating-point operations.\n    // NB: log_10(2) ~= 78913 / 2^18\n    JSON_ASSERT(e >= -1500);\n    JSON_ASSERT(e <=  1500);\n    const int f = kAlpha - e - 1;\n    const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);\n\n    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;\n    JSON_ASSERT(index >= 0);\n    JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());\n\n    const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];\n    JSON_ASSERT(kAlpha <= cached.e + e + 64);\n    JSON_ASSERT(kGamma >= cached.e + e + 64);\n\n    return cached;\n}\n\n/*!\nFor n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.\nFor n == 0, returns 1 and sets pow10 := 1.\n*/\ninline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)\n{\n    // LCOV_EXCL_START\n    if (n >= 1000000000)\n    {\n        pow10 = 1000000000;\n        return 10;\n    }\n    // LCOV_EXCL_STOP\n    if (n >= 100000000)\n    {\n        pow10 = 100000000;\n        return  9;\n    }\n    if (n >= 10000000)\n    {\n        pow10 = 10000000;\n        return  8;\n    }\n    if (n >= 1000000)\n    {\n        pow10 = 1000000;\n        return  7;\n    }\n    if (n >= 100000)\n    {\n        pow10 = 100000;\n        return  6;\n    }\n    if (n >= 10000)\n    {\n        pow10 = 10000;\n        return  5;\n    }\n    if (n >= 1000)\n    {\n        pow10 = 1000;\n        return  4;\n    }\n    if (n >= 100)\n    {\n        pow10 = 100;\n        return  3;\n    }\n    if (n >= 10)\n    {\n        pow10 = 10;\n        return  2;\n    }\n\n    pow10 = 1;\n    return 1;\n}\n\ninline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,\n                         std::uint64_t rest, std::uint64_t ten_k)\n{\n    JSON_ASSERT(len >= 1);\n    JSON_ASSERT(dist <= delta);\n    JSON_ASSERT(rest <= delta);\n    JSON_ASSERT(ten_k > 0);\n\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    //                                  ten_k\n    //                                <------>\n    //                                       <---- rest ---->\n    // --------------[------------------+----+--------------]--------------\n    //                                  w    V\n    //                                       = buf * 10^k\n    //\n    // ten_k represents a unit-in-the-last-place in the decimal representation\n    // stored in buf.\n    // Decrement buf by ten_k while this takes buf closer to w.\n\n    // The tests are written in this order to avoid overflow in unsigned\n    // integer arithmetic.\n\n    while (rest < dist\n            && delta - rest >= ten_k\n            && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))\n    {\n        JSON_ASSERT(buf[len - 1] != '0');\n        buf[len - 1]--;\n        rest += ten_k;\n    }\n}\n\n/*!\nGenerates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.\nM- and M+ must be normalized and share the same exponent -60 <= e <= -32.\n*/\ninline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,\n                             diyfp M_minus, diyfp w, diyfp M_plus)\n{\n    static_assert(kAlpha >= -60, \"internal error\");\n    static_assert(kGamma <= -32, \"internal error\");\n\n    // Generates the digits (and the exponent) of a decimal floating-point\n    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's\n    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.\n    //\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    // Grisu2 generates the digits of M+ from left to right and stops as soon as\n    // V is in [M-,M+].\n\n    JSON_ASSERT(M_plus.e >= kAlpha);\n    JSON_ASSERT(M_plus.e <= kGamma);\n\n    std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)\n    std::uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)\n\n    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):\n    //\n    //      M+ = f * 2^e\n    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e\n    //         = ((p1        ) * 2^-e + (p2        )) * 2^e\n    //         = p1 + p2 * 2^e\n\n    const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);\n\n    auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)\n    std::uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e\n\n    // 1)\n    //\n    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]\n\n    JSON_ASSERT(p1 > 0);\n\n    std::uint32_t pow10{};\n    const int k = find_largest_pow10(p1, pow10);\n\n    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)\n    //\n    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))\n    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))\n    //\n    //      M+ = p1                                             + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e\n    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e\n    //\n    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)\n    //\n    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]\n    //\n    // but stop as soon as\n    //\n    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e\n\n    int n = k;\n    while (n > 0)\n    {\n        // Invariants:\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        //\n        const std::uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)\n        const std::uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)\n        //\n        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e\n        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)\n        //\n        JSON_ASSERT(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)\n        //\n        p1 = r;\n        n--;\n        //\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)\n        //      pow10 = 10^n\n        //\n\n        // Now check if enough digits have been generated.\n        // Compute\n        //\n        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e\n        //\n        // Note:\n        // Since rest and delta share the same exponent e, it suffices to\n        // compare the significands.\n        const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;\n        if (rest <= delta)\n        {\n            // V = buffer * 10^n, with M- <= V <= M+.\n\n            decimal_exponent += n;\n\n            // We may now just stop. But instead look if the buffer could be\n            // decremented to bring V closer to w.\n            //\n            // pow10 = 10^n is now 1 ulp in the decimal representation V.\n            // The rounding procedure works with diyfp's with an implicit\n            // exponent of e.\n            //\n            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e\n            //\n            const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;\n            grisu2_round(buffer, length, dist, delta, rest, ten_n);\n\n            return;\n        }\n\n        pow10 /= 10;\n        //\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        // Invariants restored.\n    }\n\n    // 2)\n    //\n    // The digits of the integral part have been generated:\n    //\n    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e\n    //         = buffer            + p2 * 2^e\n    //\n    // Now generate the digits of the fractional part p2 * 2^e.\n    //\n    // Note:\n    // No decimal point is generated: the exponent is adjusted instead.\n    //\n    // p2 actually represents the fraction\n    //\n    //      p2 * 2^e\n    //          = p2 / 2^-e\n    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...\n    //\n    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)\n    //\n    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m\n    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)\n    //\n    // using\n    //\n    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)\n    //                = (                   d) * 2^-e + (                   r)\n    //\n    // or\n    //      10^m * p2 * 2^e = d + r * 2^e\n    //\n    // i.e.\n    //\n    //      M+ = buffer + p2 * 2^e\n    //         = buffer + 10^-m * (d + r * 2^e)\n    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e\n    //\n    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e\n\n    JSON_ASSERT(p2 > delta);\n\n    int m = 0;\n    for (;;)\n    {\n        // Invariant:\n        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e\n        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e\n        //\n        JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);\n        p2 *= 10;\n        const std::uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e\n        const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e\n        //\n        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))\n        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        JSON_ASSERT(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        p2 = r;\n        m++;\n        //\n        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e\n        // Invariant restored.\n\n        // Check if enough digits have been generated.\n        //\n        //      10^-m * p2 * 2^e <= delta * 2^e\n        //              p2 * 2^e <= 10^m * delta * 2^e\n        //                    p2 <= 10^m * delta\n        delta *= 10;\n        dist  *= 10;\n        if (p2 <= delta)\n        {\n            break;\n        }\n    }\n\n    // V = buffer * 10^-m, with M- <= V <= M+.\n\n    decimal_exponent -= m;\n\n    // 1 ulp in the decimal representation is now 10^-m.\n    // Since delta and dist are now scaled by 10^m, we need to do the\n    // same with ulp in order to keep the units in sync.\n    //\n    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e\n    //\n    const std::uint64_t ten_m = one.f;\n    grisu2_round(buffer, length, dist, delta, p2, ten_m);\n\n    // By construction this algorithm generates the shortest possible decimal\n    // number (Loitsch, Theorem 6.2) which rounds back to w.\n    // For an input number of precision p, at least\n    //\n    //      N = 1 + ceil(p * log_10(2))\n    //\n    // decimal digits are sufficient to identify all binary floating-point\n    // numbers (Matula, \"In-and-Out conversions\").\n    // This implies that the algorithm does not produce more than N decimal\n    // digits.\n    //\n    //      N = 17 for p = 53 (IEEE double precision)\n    //      N = 9  for p = 24 (IEEE single precision)\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline void grisu2(char* buf, int& len, int& decimal_exponent,\n                   diyfp m_minus, diyfp v, diyfp m_plus)\n{\n    JSON_ASSERT(m_plus.e == m_minus.e);\n    JSON_ASSERT(m_plus.e == v.e);\n\n    //  --------(-----------------------+-----------------------)--------    (A)\n    //          m-                      v                       m+\n    //\n    //  --------------------(-----------+-----------------------)--------    (B)\n    //                      m-          v                       m+\n    //\n    // First scale v (and m- and m+) such that the exponent is in the range\n    // [alpha, gamma].\n\n    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);\n\n    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k\n\n    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]\n    const diyfp w       = diyfp::mul(v,       c_minus_k);\n    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);\n    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);\n\n    //  ----(---+---)---------------(---+---)---------------(---+---)----\n    //          w-                      w                       w+\n    //          = c*m-                  = c*v                   = c*m+\n    //\n    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and\n    // w+ are now off by a small amount.\n    // In fact:\n    //\n    //      w - v * 10^k < 1 ulp\n    //\n    // To account for this inaccuracy, add resp. subtract 1 ulp.\n    //\n    //  --------+---[---------------(---+---)---------------]---+--------\n    //          w-  M-                  w                   M+  w+\n    //\n    // Now any number in [M-, M+] (bounds included) will round to w when input,\n    // regardless of how the input rounding algorithm breaks ties.\n    //\n    // And digit_gen generates the shortest possible such number in [M-, M+].\n    // Note that this does not mean that Grisu2 always generates the shortest\n    // possible number in the interval (m-, m+).\n    const diyfp M_minus(w_minus.f + 1, w_minus.e);\n    const diyfp M_plus (w_plus.f  - 1, w_plus.e );\n\n    decimal_exponent = -cached.k; // = -(-k) = k\n\n    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ntemplate<typename FloatType>\nJSON_HEDLEY_NON_NULL(1)\nvoid grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)\n{\n    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,\n                  \"internal error: not enough precision\");\n\n    JSON_ASSERT(std::isfinite(value));\n    JSON_ASSERT(value > 0);\n\n    // If the neighbors (and boundaries) of 'value' are always computed for double-precision\n    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting\n    // decimal representations are not exactly \"short\".\n    //\n    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)\n    // says \"value is converted to a string as if by std::sprintf in the default (\"C\") locale\"\n    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'\n    // does.\n    // On the other hand, the documentation for 'std::to_chars' requires that \"parsing the\n    // representation using the corresponding std::from_chars function recovers value exactly\". That\n    // indicates that single precision floating-point numbers should be recovered using\n    // 'std::strtof'.\n    //\n    // NB: If the neighbors are computed for single-precision numbers, there is a single float\n    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision\n    //     value is off by 1 ulp.\n#if 0\n    const boundaries w = compute_boundaries(static_cast<double>(value));\n#else\n    const boundaries w = compute_boundaries(value);\n#endif\n\n    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);\n}\n\n/*!\n@brief appends a decimal representation of e to buf\n@return a pointer to the element following the exponent.\n@pre -1000 < e < 1000\n*/\nJSON_HEDLEY_NON_NULL(1)\nJSON_HEDLEY_RETURNS_NON_NULL\ninline char* append_exponent(char* buf, int e)\n{\n    JSON_ASSERT(e > -1000);\n    JSON_ASSERT(e <  1000);\n\n    if (e < 0)\n    {\n        e = -e;\n        *buf++ = '-';\n    }\n    else\n    {\n        *buf++ = '+';\n    }\n\n    auto k = static_cast<std::uint32_t>(e);\n    if (k < 10)\n    {\n        // Always print at least two digits in the exponent.\n        // This is for compatibility with printf(\"%g\").\n        *buf++ = '0';\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else if (k < 100)\n    {\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else\n    {\n        *buf++ = static_cast<char>('0' + k / 100);\n        k %= 100;\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n\n    return buf;\n}\n\n/*!\n@brief prettify v = buf * 10^decimal_exponent\n\nIf v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point\nnotation. Otherwise it will be printed in exponential notation.\n\n@pre min_exp < 0\n@pre max_exp > 0\n*/\nJSON_HEDLEY_NON_NULL(1)\nJSON_HEDLEY_RETURNS_NON_NULL\ninline char* format_buffer(char* buf, int len, int decimal_exponent,\n                           int min_exp, int max_exp)\n{\n    JSON_ASSERT(min_exp < 0);\n    JSON_ASSERT(max_exp > 0);\n\n    const int k = len;\n    const int n = len + decimal_exponent;\n\n    // v = buf * 10^(n-k)\n    // k is the length of the buffer (number of decimal digits)\n    // n is the position of the decimal point relative to the start of the buffer.\n\n    if (k <= n && n <= max_exp)\n    {\n        // digits[000]\n        // len <= max_exp + 2\n\n        std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));\n        // Make it look like a floating-point number (#362, #378)\n        buf[n + 0] = '.';\n        buf[n + 1] = '0';\n        return buf + (static_cast<size_t>(n) + 2);\n    }\n\n    if (0 < n && n <= max_exp)\n    {\n        // dig.its\n        // len <= max_digits10 + 1\n\n        JSON_ASSERT(k > n);\n\n        std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));\n        buf[n] = '.';\n        return buf + (static_cast<size_t>(k) + 1U);\n    }\n\n    if (min_exp < n && n <= 0)\n    {\n        // 0.[000]digits\n        // len <= 2 + (-min_exp - 1) + max_digits10\n\n        std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));\n        buf[0] = '0';\n        buf[1] = '.';\n        std::memset(buf + 2, '0', static_cast<size_t>(-n));\n        return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));\n    }\n\n    if (k == 1)\n    {\n        // dE+123\n        // len <= 1 + 5\n\n        buf += 1;\n    }\n    else\n    {\n        // d.igitsE+123\n        // len <= max_digits10 + 1 + 5\n\n        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);\n        buf[1] = '.';\n        buf += 1 + static_cast<size_t>(k);\n    }\n\n    *buf++ = 'e';\n    return append_exponent(buf, n - 1);\n}\n\n} // namespace dtoa_impl\n\n/*!\n@brief generates a decimal representation of the floating-point number value in [first, last).\n\nThe format of the resulting decimal representation is similar to printf's %g\nformat. Returns an iterator pointing past-the-end of the decimal representation.\n\n@note The input number must be finite, i.e. NaN's and Inf's are not supported.\n@note The buffer must be large enough.\n@note The result is NOT null-terminated.\n*/\ntemplate<typename FloatType>\nJSON_HEDLEY_NON_NULL(1, 2)\nJSON_HEDLEY_RETURNS_NON_NULL\nchar* to_chars(char* first, const char* last, FloatType value)\n{\n    static_cast<void>(last); // maybe unused - fix warning\n    JSON_ASSERT(std::isfinite(value));\n\n    // Use signbit(value) instead of (value < 0) since signbit works for -0.\n    if (std::signbit(value))\n    {\n        value = -value;\n        *first++ = '-';\n    }\n\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n    if (value == 0) // +-0\n    {\n        *first++ = '0';\n        // Make it look like a floating-point number (#362, #378)\n        *first++ = '.';\n        *first++ = '0';\n        return first;\n    }\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n\n    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);\n\n    // Compute v = buffer * 10^decimal_exponent.\n    // The decimal digits are stored in the buffer, which needs to be interpreted\n    // as an unsigned decimal integer.\n    // len is the length of the buffer, i.e. the number of decimal digits.\n    int len = 0;\n    int decimal_exponent = 0;\n    dtoa_impl::grisu2(first, len, decimal_exponent, value);\n\n    JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);\n\n    // Format the buffer like printf(\"%.*g\", prec, value)\n    constexpr int kMinExp = -4;\n    // Use digits10 here to increase compatibility with version 2.\n    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;\n\n    JSON_ASSERT(last - first >= kMaxExp + 2);\n    JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);\n    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);\n\n    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);\n}\n\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// serialization //\n///////////////////\n\n/// how to treat decoding errors\nenum class error_handler_t\n{\n    strict,  ///< throw a type_error exception in case of invalid UTF-8\n    replace, ///< replace invalid UTF-8 sequences with U+FFFD\n    ignore   ///< ignore invalid UTF-8 sequences\n};\n\ntemplate<typename BasicJsonType>\nclass serializer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using binary_char_t = typename BasicJsonType::binary_t::value_type;\n    static constexpr std::uint8_t UTF8_ACCEPT = 0;\n    static constexpr std::uint8_t UTF8_REJECT = 1;\n\n  public:\n    /*!\n    @param[in] s  output stream to serialize to\n    @param[in] ichar  indentation character to use\n    @param[in] error_handler_  how to react on decoding errors\n    */\n    serializer(output_adapter_t<char> s, const char ichar,\n               error_handler_t error_handler_ = error_handler_t::strict)\n        : o(std::move(s))\n        , loc(std::localeconv())\n        , thousands_sep(loc->thousands_sep == nullptr ? '\\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))\n        , decimal_point(loc->decimal_point == nullptr ? '\\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))\n        , indent_char(ichar)\n        , indent_string(512, indent_char)\n        , error_handler(error_handler_)\n    {}\n\n    // delete because of pointer members\n    serializer(const serializer&) = delete;\n    serializer& operator=(const serializer&) = delete;\n    serializer(serializer&&) = delete;\n    serializer& operator=(serializer&&) = delete;\n    ~serializer() = default;\n\n    /*!\n    @brief internal implementation of the serialization function\n\n    This function is called by the public member function dump and organizes\n    the serialization internally. The indentation level is propagated as\n    additional parameter. In case of arrays and objects, the function is\n    called recursively.\n\n    - strings and object keys are escaped using `escape_string()`\n    - integer numbers are converted implicitly via `operator<<`\n    - floating-point numbers are converted to a string using `\"%g\"` format\n    - binary values are serialized as objects containing the subtype and the\n      byte array\n\n    @param[in] val               value to serialize\n    @param[in] pretty_print      whether the output shall be pretty-printed\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] indent_step       the indent level\n    @param[in] current_indent    the current indent level (only used internally)\n    */\n    void dump(const BasicJsonType& val,\n              const bool pretty_print,\n              const bool ensure_ascii,\n              const unsigned int indent_step,\n              const unsigned int current_indent = 0)\n    {\n        switch (val.m_type)\n        {\n            case value_t::object:\n            {\n                if (val.m_value.object->empty())\n                {\n                    o->write_characters(\"{}\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\": \", 3);\n                        dump(i->second, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    JSON_ASSERT(i != val.m_value.object->cend());\n                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\": \", 3);\n                    dump(i->second, true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_character('{');\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\":\", 2);\n                        dump(i->second, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    JSON_ASSERT(i != val.m_value.object->cend());\n                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\":\", 2);\n                    dump(i->second, false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character('}');\n                }\n\n                return;\n            }\n\n            case value_t::array:\n            {\n                if (val.m_value.array->empty())\n                {\n                    o->write_characters(\"[]\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"[\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        dump(*i, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    JSON_ASSERT(!val.m_value.array->empty());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character(']');\n                }\n                else\n                {\n                    o->write_character('[');\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        dump(*i, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    JSON_ASSERT(!val.m_value.array->empty());\n                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character(']');\n                }\n\n                return;\n            }\n\n            case value_t::string:\n            {\n                o->write_character('\\\"');\n                dump_escaped(*val.m_value.string, ensure_ascii);\n                o->write_character('\\\"');\n                return;\n            }\n\n            case value_t::binary:\n            {\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    o->write_characters(indent_string.c_str(), new_indent);\n\n                    o->write_characters(\"\\\"bytes\\\": [\", 10);\n\n                    if (!val.m_value.binary->empty())\n                    {\n                        for (auto i = val.m_value.binary->cbegin();\n                                i != val.m_value.binary->cend() - 1; ++i)\n                        {\n                            dump_integer(*i);\n                            o->write_characters(\", \", 2);\n                        }\n                        dump_integer(val.m_value.binary->back());\n                    }\n\n                    o->write_characters(\"],\\n\", 3);\n                    o->write_characters(indent_string.c_str(), new_indent);\n\n                    o->write_characters(\"\\\"subtype\\\": \", 11);\n                    if (val.m_value.binary->has_subtype())\n                    {\n                        dump_integer(val.m_value.binary->subtype());\n                    }\n                    else\n                    {\n                        o->write_characters(\"null\", 4);\n                    }\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_characters(\"{\\\"bytes\\\":[\", 10);\n\n                    if (!val.m_value.binary->empty())\n                    {\n                        for (auto i = val.m_value.binary->cbegin();\n                                i != val.m_value.binary->cend() - 1; ++i)\n                        {\n                            dump_integer(*i);\n                            o->write_character(',');\n                        }\n                        dump_integer(val.m_value.binary->back());\n                    }\n\n                    o->write_characters(\"],\\\"subtype\\\":\", 12);\n                    if (val.m_value.binary->has_subtype())\n                    {\n                        dump_integer(val.m_value.binary->subtype());\n                        o->write_character('}');\n                    }\n                    else\n                    {\n                        o->write_characters(\"null}\", 5);\n                    }\n                }\n                return;\n            }\n\n            case value_t::boolean:\n            {\n                if (val.m_value.boolean)\n                {\n                    o->write_characters(\"true\", 4);\n                }\n                else\n                {\n                    o->write_characters(\"false\", 5);\n                }\n                return;\n            }\n\n            case value_t::number_integer:\n            {\n                dump_integer(val.m_value.number_integer);\n                return;\n            }\n\n            case value_t::number_unsigned:\n            {\n                dump_integer(val.m_value.number_unsigned);\n                return;\n            }\n\n            case value_t::number_float:\n            {\n                dump_float(val.m_value.number_float);\n                return;\n            }\n\n            case value_t::discarded:\n            {\n                o->write_characters(\"<discarded>\", 11);\n                return;\n            }\n\n            case value_t::null:\n            {\n                o->write_characters(\"null\", 4);\n                return;\n            }\n\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief dump escaped string\n\n    Escape a string by replacing certain special characters by a sequence of an\n    escape character (backslash) and another character and other control\n    characters by a sequence of \"\\u\" followed by a four-digit hex\n    representation. The escaped string is written to output stream @a o.\n\n    @param[in] s  the string to escape\n    @param[in] ensure_ascii  whether to escape non-ASCII characters with\n                             \\uXXXX sequences\n\n    @complexity Linear in the length of string @a s.\n    */\n    void dump_escaped(const string_t& s, const bool ensure_ascii)\n    {\n        std::uint32_t codepoint{};\n        std::uint8_t state = UTF8_ACCEPT;\n        std::size_t bytes = 0;  // number of bytes written to string_buffer\n\n        // number of bytes written at the point of the last valid byte\n        std::size_t bytes_after_last_accept = 0;\n        std::size_t undumped_chars = 0;\n\n        for (std::size_t i = 0; i < s.size(); ++i)\n        {\n            const auto byte = static_cast<std::uint8_t>(s[i]);\n\n            switch (decode(state, codepoint, byte))\n            {\n                case UTF8_ACCEPT:  // decode found a new code point\n                {\n                    switch (codepoint)\n                    {\n                        case 0x08: // backspace\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'b';\n                            break;\n                        }\n\n                        case 0x09: // horizontal tab\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 't';\n                            break;\n                        }\n\n                        case 0x0A: // newline\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'n';\n                            break;\n                        }\n\n                        case 0x0C: // formfeed\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'f';\n                            break;\n                        }\n\n                        case 0x0D: // carriage return\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'r';\n                            break;\n                        }\n\n                        case 0x22: // quotation mark\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\"';\n                            break;\n                        }\n\n                        case 0x5C: // reverse solidus\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\\';\n                            break;\n                        }\n\n                        default:\n                        {\n                            // escape control characters (0x00..0x1F) or, if\n                            // ensure_ascii parameter is used, non-ASCII characters\n                            if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))\n                            {\n                                if (codepoint <= 0xFFFF)\n                                {\n                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                                    (std::snprintf)(string_buffer.data() + bytes, 7, \"\\\\u%04x\",\n                                                    static_cast<std::uint16_t>(codepoint));\n                                    bytes += 6;\n                                }\n                                else\n                                {\n                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                                    (std::snprintf)(string_buffer.data() + bytes, 13, \"\\\\u%04x\\\\u%04x\",\n                                                    static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),\n                                                    static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));\n                                    bytes += 12;\n                                }\n                            }\n                            else\n                            {\n                                // copy byte to buffer (all previous bytes\n                                // been copied have in default case above)\n                                string_buffer[bytes++] = s[i];\n                            }\n                            break;\n                        }\n                    }\n\n                    // write buffer and reset index; there must be 13 bytes\n                    // left, as this is the maximal number of bytes to be\n                    // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                    if (string_buffer.size() - bytes < 13)\n                    {\n                        o->write_characters(string_buffer.data(), bytes);\n                        bytes = 0;\n                    }\n\n                    // remember the byte position of this accept\n                    bytes_after_last_accept = bytes;\n                    undumped_chars = 0;\n                    break;\n                }\n\n                case UTF8_REJECT:  // decode found invalid UTF-8 byte\n                {\n                    switch (error_handler)\n                    {\n                        case error_handler_t::strict:\n                        {\n                            std::string sn(9, '\\0');\n                            // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                            (std::snprintf)(&sn[0], sn.size(), \"%.2X\", byte);\n                            JSON_THROW(type_error::create(316, \"invalid UTF-8 byte at index \" + std::to_string(i) + \": 0x\" + sn, BasicJsonType()));\n                        }\n\n                        case error_handler_t::ignore:\n                        case error_handler_t::replace:\n                        {\n                            // in case we saw this character the first time, we\n                            // would like to read it again, because the byte\n                            // may be OK for itself, but just not OK for the\n                            // previous sequence\n                            if (undumped_chars > 0)\n                            {\n                                --i;\n                            }\n\n                            // reset length buffer to the last accepted index;\n                            // thus removing/ignoring the invalid characters\n                            bytes = bytes_after_last_accept;\n\n                            if (error_handler == error_handler_t::replace)\n                            {\n                                // add a replacement character\n                                if (ensure_ascii)\n                                {\n                                    string_buffer[bytes++] = '\\\\';\n                                    string_buffer[bytes++] = 'u';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'd';\n                                }\n                                else\n                                {\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xEF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBD');\n                                }\n\n                                // write buffer and reset index; there must be 13 bytes\n                                // left, as this is the maximal number of bytes to be\n                                // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                                if (string_buffer.size() - bytes < 13)\n                                {\n                                    o->write_characters(string_buffer.data(), bytes);\n                                    bytes = 0;\n                                }\n\n                                bytes_after_last_accept = bytes;\n                            }\n\n                            undumped_chars = 0;\n\n                            // continue processing the string\n                            state = UTF8_ACCEPT;\n                            break;\n                        }\n\n                        default:            // LCOV_EXCL_LINE\n                            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n\n                default:  // decode found yet incomplete multi-byte code point\n                {\n                    if (!ensure_ascii)\n                    {\n                        // code point will not be escaped - copy byte to buffer\n                        string_buffer[bytes++] = s[i];\n                    }\n                    ++undumped_chars;\n                    break;\n                }\n            }\n        }\n\n        // we finished processing the string\n        if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))\n        {\n            // write buffer\n            if (bytes > 0)\n            {\n                o->write_characters(string_buffer.data(), bytes);\n            }\n        }\n        else\n        {\n            // we finish reading, but do not accept: string was incomplete\n            switch (error_handler)\n            {\n                case error_handler_t::strict:\n                {\n                    std::string sn(9, '\\0');\n                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                    (std::snprintf)(&sn[0], sn.size(), \"%.2X\", static_cast<std::uint8_t>(s.back()));\n                    JSON_THROW(type_error::create(316, \"incomplete UTF-8 string; last byte: 0x\" + sn, BasicJsonType()));\n                }\n\n                case error_handler_t::ignore:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    break;\n                }\n\n                case error_handler_t::replace:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    // add a replacement character\n                    if (ensure_ascii)\n                    {\n                        o->write_characters(\"\\\\ufffd\", 6);\n                    }\n                    else\n                    {\n                        o->write_characters(\"\\xEF\\xBF\\xBD\", 3);\n                    }\n                    break;\n                }\n\n                default:            // LCOV_EXCL_LINE\n                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n            }\n        }\n    }\n\n  private:\n    /*!\n    @brief count digits\n\n    Count the number of decimal (base 10) digits for an input unsigned integer.\n\n    @param[in] x  unsigned integer number to count its digits\n    @return    number of decimal digits\n    */\n    inline unsigned int count_digits(number_unsigned_t x) noexcept\n    {\n        unsigned int n_digits = 1;\n        for (;;)\n        {\n            if (x < 10)\n            {\n                return n_digits;\n            }\n            if (x < 100)\n            {\n                return n_digits + 1;\n            }\n            if (x < 1000)\n            {\n                return n_digits + 2;\n            }\n            if (x < 10000)\n            {\n                return n_digits + 3;\n            }\n            x = x / 10000u;\n            n_digits += 4;\n        }\n    }\n\n    /*!\n    @brief dump an integer\n\n    Dump a given integer to output stream @a o. Works internally with\n    @a number_buffer.\n\n    @param[in] x  integer number (signed or unsigned) to dump\n    @tparam NumberType either @a number_integer_t or @a number_unsigned_t\n    */\n    template < typename NumberType, detail::enable_if_t <\n                   std::is_integral<NumberType>::value ||\n                   std::is_same<NumberType, number_unsigned_t>::value ||\n                   std::is_same<NumberType, number_integer_t>::value ||\n                   std::is_same<NumberType, binary_char_t>::value,\n                   int > = 0 >\n    void dump_integer(NumberType x)\n    {\n        static constexpr std::array<std::array<char, 2>, 100> digits_to_99\n        {\n            {\n                {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},\n                {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},\n                {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},\n                {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},\n                {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},\n                {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},\n                {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},\n                {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},\n                {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},\n                {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},\n            }\n        };\n\n        // special case for \"0\"\n        if (x == 0)\n        {\n            o->write_character('0');\n            return;\n        }\n\n        // use a pointer to fill the buffer\n        auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n\n        const bool is_negative = std::is_signed<NumberType>::value && !(x >= 0); // see issue #755\n        number_unsigned_t abs_value;\n\n        unsigned int n_chars{};\n\n        if (is_negative)\n        {\n            *buffer_ptr = '-';\n            abs_value = remove_sign(static_cast<number_integer_t>(x));\n\n            // account one more byte for the minus sign\n            n_chars = 1 + count_digits(abs_value);\n        }\n        else\n        {\n            abs_value = static_cast<number_unsigned_t>(x);\n            n_chars = count_digits(abs_value);\n        }\n\n        // spare 1 byte for '\\0'\n        JSON_ASSERT(n_chars < number_buffer.size() - 1);\n\n        // jump to the end to generate the string from backward\n        // so we later avoid reversing the result\n        buffer_ptr += n_chars;\n\n        // Fast int2ascii implementation inspired by \"Fastware\" talk by Andrei Alexandrescu\n        // See: https://www.youtube.com/watch?v=o4-CwDo2zpg\n        while (abs_value >= 100)\n        {\n            const auto digits_index = static_cast<unsigned>((abs_value % 100));\n            abs_value /= 100;\n            *(--buffer_ptr) = digits_to_99[digits_index][1];\n            *(--buffer_ptr) = digits_to_99[digits_index][0];\n        }\n\n        if (abs_value >= 10)\n        {\n            const auto digits_index = static_cast<unsigned>(abs_value);\n            *(--buffer_ptr) = digits_to_99[digits_index][1];\n            *(--buffer_ptr) = digits_to_99[digits_index][0];\n        }\n        else\n        {\n            *(--buffer_ptr) = static_cast<char>('0' + abs_value);\n        }\n\n        o->write_characters(number_buffer.data(), n_chars);\n    }\n\n    /*!\n    @brief dump a floating-point number\n\n    Dump a given floating-point number to output stream @a o. Works internally\n    with @a number_buffer.\n\n    @param[in] x  floating-point number to dump\n    */\n    void dump_float(number_float_t x)\n    {\n        // NaN / inf\n        if (!std::isfinite(x))\n        {\n            o->write_characters(\"null\", 4);\n            return;\n        }\n\n        // If number_float_t is an IEEE-754 single or double precision number,\n        // use the Grisu2 algorithm to produce short numbers which are\n        // guaranteed to round-trip, using strtof and strtod, resp.\n        //\n        // NB: The test below works if <long double> == <double>.\n        static constexpr bool is_ieee_single_or_double\n            = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||\n              (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);\n\n        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());\n    }\n\n    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)\n    {\n        auto* begin = number_buffer.data();\n        auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);\n\n        o->write_characters(begin, static_cast<size_t>(end - begin));\n    }\n\n    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)\n    {\n        // get number of digits for a float -> text -> float round-trip\n        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;\n\n        // the actual conversion\n        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), \"%.*g\", d, x);\n\n        // negative value indicates an error\n        JSON_ASSERT(len > 0);\n        // check if buffer was large enough\n        JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());\n\n        // erase thousands separator\n        if (thousands_sep != '\\0')\n        {\n            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081\n            const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);\n            std::fill(end, number_buffer.end(), '\\0');\n            JSON_ASSERT((end - number_buffer.begin()) <= len);\n            len = (end - number_buffer.begin());\n        }\n\n        // convert decimal point to '.'\n        if (decimal_point != '\\0' && decimal_point != '.')\n        {\n            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081\n            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);\n            if (dec_pos != number_buffer.end())\n            {\n                *dec_pos = '.';\n            }\n        }\n\n        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));\n\n        // determine if need to append \".0\"\n        const bool value_is_int_like =\n            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,\n                         [](char c)\n        {\n            return c == '.' || c == 'e';\n        });\n\n        if (value_is_int_like)\n        {\n            o->write_characters(\".0\", 2);\n        }\n    }\n\n    /*!\n    @brief check whether a string is UTF-8 encoded\n\n    The function checks each byte of a string whether it is UTF-8 encoded. The\n    result of the check is stored in the @a state parameter. The function must\n    be called initially with state 0 (accept). State 1 means the string must\n    be rejected, because the current byte is not allowed. If the string is\n    completely processed, but the state is non-zero, the string ended\n    prematurely; that is, the last byte indicated more bytes should have\n    followed.\n\n    @param[in,out] state  the state of the decoding\n    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)\n    @param[in] byte       next byte to decode\n    @return               new state\n\n    @note The function has been edited: a std::array is used.\n\n    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n    */\n    static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept\n    {\n        static const std::array<std::uint8_t, 400> utf8d =\n        {\n            {\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F\n                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF\n                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF\n                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF\n                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF\n                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2\n                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4\n                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6\n                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8\n            }\n        };\n\n        JSON_ASSERT(byte < utf8d.size());\n        const std::uint8_t type = utf8d[byte];\n\n        codep = (state != UTF8_ACCEPT)\n                ? (byte & 0x3fu) | (codep << 6u)\n                : (0xFFu >> type) & (byte);\n\n        std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);\n        JSON_ASSERT(index < 400);\n        state = utf8d[index];\n        return state;\n    }\n\n    /*\n     * Overload to make the compiler happy while it is instantiating\n     * dump_integer for number_unsigned_t.\n     * Must never be called.\n     */\n    number_unsigned_t remove_sign(number_unsigned_t x)\n    {\n        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        return x; // LCOV_EXCL_LINE\n    }\n\n    /*\n     * Helper function for dump_integer\n     *\n     * This function takes a negative signed integer and returns its absolute\n     * value as unsigned integer. The plus/minus shuffling is necessary as we can\n     * not directly remove the sign of an arbitrary signed integer as the\n     * absolute values of INT_MIN and INT_MAX are usually not the same. See\n     * #1708 for details.\n     */\n    inline number_unsigned_t remove_sign(number_integer_t x) noexcept\n    {\n        JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)\n        return static_cast<number_unsigned_t>(-(x + 1)) + 1;\n    }\n\n  private:\n    /// the output of the serializer\n    output_adapter_t<char> o = nullptr;\n\n    /// a (hopefully) large enough character buffer\n    std::array<char, 64> number_buffer{{}};\n\n    /// the locale\n    const std::lconv* loc = nullptr;\n    /// the locale's thousand separator character\n    const char thousands_sep = '\\0';\n    /// the locale's decimal point character\n    const char decimal_point = '\\0';\n\n    /// string buffer\n    std::array<char, 512> string_buffer{{}};\n\n    /// the indentation character\n    const char indent_char;\n    /// the indentation string\n    string_t indent_string;\n\n    /// error_handler how to react on decoding errors\n    const error_handler_t error_handler;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n// #include <nlohmann/json_fwd.hpp>\n\n// #include <nlohmann/ordered_map.hpp>\n\n\n#include <functional> // less\n#include <initializer_list> // initializer_list\n#include <iterator> // input_iterator_tag, iterator_traits\n#include <memory> // allocator\n#include <stdexcept> // for out_of_range\n#include <type_traits> // enable_if, is_convertible\n#include <utility> // pair\n#include <vector> // vector\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\n/// ordered_map: a minimal map-like container that preserves insertion order\n/// for use within nlohmann::basic_json<ordered_map>\ntemplate <class Key, class T, class IgnoredLess = std::less<Key>,\n          class Allocator = std::allocator<std::pair<const Key, T>>>\n                  struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>\n{\n    using key_type = Key;\n    using mapped_type = T;\n    using Container = std::vector<std::pair<const Key, T>, Allocator>;\n    using typename Container::iterator;\n    using typename Container::const_iterator;\n    using typename Container::size_type;\n    using typename Container::value_type;\n\n    // Explicit constructors instead of `using Container::Container`\n    // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)\n    ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {}\n    template <class It>\n    ordered_map(It first, It last, const Allocator& alloc = Allocator())\n        : Container{first, last, alloc} {}\n    ordered_map(std::initializer_list<T> init, const Allocator& alloc = Allocator() )\n        : Container{init, alloc} {}\n\n    std::pair<iterator, bool> emplace(const key_type& key, T&& t)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return {it, false};\n            }\n        }\n        Container::emplace_back(key, t);\n        return {--this->end(), true};\n    }\n\n    T& operator[](const Key& key)\n    {\n        return emplace(key, T{}).first->second;\n    }\n\n    const T& operator[](const Key& key) const\n    {\n        return at(key);\n    }\n\n    T& at(const Key& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    const T& at(const Key& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    size_type erase(const Key& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                // Since we cannot move const Keys, re-construct them in place\n                for (auto next = it; ++next != this->end(); ++it)\n                {\n                    it->~value_type(); // Destroy but keep allocation\n                    new (&*it) value_type{std::move(*next)};\n                }\n                Container::pop_back();\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    iterator erase(iterator pos)\n    {\n        auto it = pos;\n\n        // Since we cannot move const Keys, re-construct them in place\n        for (auto next = it; ++next != this->end(); ++it)\n        {\n            it->~value_type(); // Destroy but keep allocation\n            new (&*it) value_type{std::move(*next)};\n        }\n        Container::pop_back();\n        return pos;\n    }\n\n    size_type count(const Key& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    iterator find(const Key& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    const_iterator find(const Key& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    std::pair<iterator, bool> insert( value_type&& value )\n    {\n        return emplace(value.first, std::move(value.second));\n    }\n\n    std::pair<iterator, bool> insert( const value_type& value )\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == value.first)\n            {\n                return {it, false};\n            }\n        }\n        Container::push_back(value);\n        return {--this->end(), true};\n    }\n\n    template<typename InputIt>\n    using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,\n            std::input_iterator_tag>::value>::type;\n\n    template<typename InputIt, typename = require_input_iter<InputIt>>\n    void insert(InputIt first, InputIt last)\n    {\n        for (auto it = first; it != last; ++it)\n        {\n            insert(*it);\n        }\n    }\n};\n\n}  // namespace nlohmann\n\n\n#if defined(JSON_HAS_CPP_17)\n    #include <string_view>\n#endif\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n\n/*!\n@brief a class to store JSON values\n\n@tparam ObjectType type for JSON objects (`std::map` by default; will be used\nin @ref object_t)\n@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used\nin @ref array_t)\n@tparam StringType type for JSON strings and object keys (`std::string` by\ndefault; will be used in @ref string_t)\n@tparam BooleanType type for JSON booleans (`bool` by default; will be used\nin @ref boolean_t)\n@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by\ndefault; will be used in @ref number_integer_t)\n@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c\n`uint64_t` by default; will be used in @ref number_unsigned_t)\n@tparam NumberFloatType type for JSON floating-point numbers (`double` by\ndefault; will be used in @ref number_float_t)\n@tparam BinaryType type for packed binary data for compatibility with binary\nserialization formats (`std::vector<std::uint8_t>` by default; will be used in\n@ref binary_t)\n@tparam AllocatorType type of the allocator to use (`std::allocator` by\ndefault)\n@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`\nand `from_json()` (@ref adl_serializer by default)\n\n@requirement The class satisfies the following concept requirements:\n- Basic\n - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n   JSON values can be default constructed. The result will be a JSON null\n   value.\n - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):\n   A JSON value can be constructed from an rvalue argument.\n - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):\n   A JSON value can be copy-constructed from an lvalue expression.\n - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):\n   A JSON value van be assigned from an rvalue argument.\n - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):\n   A JSON value can be copy-assigned from an lvalue expression.\n - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):\n   JSON values can be destructed.\n- Layout\n - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):\n   JSON values have\n   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):\n   All non-static data members are private and standard layout types, the\n   class has no virtual functions or (virtual) base classes.\n- Library-wide\n - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):\n   JSON values can be compared with `==`, see @ref\n   operator==(const_reference,const_reference).\n - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n   JSON values can be compared with `<`, see @ref\n   operator<(const_reference,const_reference).\n - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):\n   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of\n   other compatible types, using unqualified function call @ref swap().\n - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):\n   JSON values can be compared against `std::nullptr_t` objects which are used\n   to model the `null` value.\n- Container\n - [Container](https://en.cppreference.com/w/cpp/named_req/Container):\n   JSON values can be used like STL containers and provide iterator access.\n - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);\n   JSON values can be used like STL containers and provide reverse iterator\n   access.\n\n@invariant The member variables @a m_value and @a m_type have the following\nrelationship:\n- If `m_type == value_t::object`, then `m_value.object != nullptr`.\n- If `m_type == value_t::array`, then `m_value.array != nullptr`.\n- If `m_type == value_t::string`, then `m_value.string != nullptr`.\nThe invariants are checked by member function assert_invariant().\n\n@internal\n@note ObjectType trick from https://stackoverflow.com/a/9860911\n@endinternal\n\n@see [RFC 8259: The JavaScript Object Notation (JSON) Data Interchange\nFormat](https://tools.ietf.org/html/rfc8259)\n\n@since version 1.0.0\n\n@nosubgrouping\n*/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nclass basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)\n{\n  private:\n    template<detail::value_t> friend struct detail::external_constructor;\n    friend ::nlohmann::json_pointer<basic_json>;\n\n    template<typename BasicJsonType, typename InputType>\n    friend class ::nlohmann::detail::parser;\n    friend ::nlohmann::detail::serializer<basic_json>;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::iter_impl;\n    template<typename BasicJsonType, typename CharType>\n    friend class ::nlohmann::detail::binary_writer;\n    template<typename BasicJsonType, typename InputType, typename SAX>\n    friend class ::nlohmann::detail::binary_reader;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_parser;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_callback_parser;\n    friend class ::nlohmann::detail::exception;\n\n    /// workaround type for MSVC\n    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    // convenience aliases for types residing in namespace detail;\n    using lexer = ::nlohmann::detail::lexer_base<basic_json>;\n\n    template<typename InputAdapterType>\n    static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(\n        InputAdapterType adapter,\n        detail::parser_callback_t<basic_json>cb = nullptr,\n        const bool allow_exceptions = true,\n        const bool ignore_comments = false\n                                 )\n    {\n        return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),\n                std::move(cb), allow_exceptions, ignore_comments);\n    }\n\n  private:\n    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;\n    template<typename BasicJsonType>\n    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;\n    template<typename BasicJsonType>\n    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;\n    template<typename Iterator>\n    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;\n    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;\n\n    template<typename CharType>\n    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;\n\n    template<typename InputType>\n    using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;\n    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    using serializer = ::nlohmann::detail::serializer<basic_json>;\n\n  public:\n    using value_t = detail::value_t;\n    /// JSON Pointer, see @ref nlohmann::json_pointer\n    using json_pointer = ::nlohmann::json_pointer<basic_json>;\n    template<typename T, typename SFINAE>\n    using json_serializer = JSONSerializer<T, SFINAE>;\n    /// how to treat decoding errors\n    using error_handler_t = detail::error_handler_t;\n    /// how to treat CBOR tags\n    using cbor_tag_handler_t = detail::cbor_tag_handler_t;\n    /// helper type for initializer lists of basic_json values\n    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;\n\n    using input_format_t = detail::input_format_t;\n    /// SAX interface type, see @ref nlohmann::json_sax\n    using json_sax_t = json_sax<basic_json>;\n\n    ////////////////\n    // exceptions //\n    ////////////////\n\n    /// @name exceptions\n    /// Classes to implement user-defined exceptions.\n    /// @{\n\n    /// @copydoc detail::exception\n    using exception = detail::exception;\n    /// @copydoc detail::parse_error\n    using parse_error = detail::parse_error;\n    /// @copydoc detail::invalid_iterator\n    using invalid_iterator = detail::invalid_iterator;\n    /// @copydoc detail::type_error\n    using type_error = detail::type_error;\n    /// @copydoc detail::out_of_range\n    using out_of_range = detail::out_of_range;\n    /// @copydoc detail::other_error\n    using other_error = detail::other_error;\n\n    /// @}\n\n\n    /////////////////////\n    // container types //\n    /////////////////////\n\n    /// @name container types\n    /// The canonic container types to use @ref basic_json like any other STL\n    /// container.\n    /// @{\n\n    /// the type of elements in a basic_json container\n    using value_type = basic_json;\n\n    /// the type of an element reference\n    using reference = value_type&;\n    /// the type of an element const reference\n    using const_reference = const value_type&;\n\n    /// a type to represent differences between iterators\n    using difference_type = std::ptrdiff_t;\n    /// a type to represent container sizes\n    using size_type = std::size_t;\n\n    /// the allocator type\n    using allocator_type = AllocatorType<basic_json>;\n\n    /// the type of an element pointer\n    using pointer = typename std::allocator_traits<allocator_type>::pointer;\n    /// the type of an element const pointer\n    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;\n\n    /// an iterator for a basic_json container\n    using iterator = iter_impl<basic_json>;\n    /// a const iterator for a basic_json container\n    using const_iterator = iter_impl<const basic_json>;\n    /// a reverse iterator for a basic_json container\n    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;\n    /// a const reverse iterator for a basic_json container\n    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;\n\n    /// @}\n\n\n    /*!\n    @brief returns the allocator associated with the container\n    */\n    static allocator_type get_allocator()\n    {\n        return allocator_type();\n    }\n\n    /*!\n    @brief returns version information on the library\n\n    This function returns a JSON object with information about the library,\n    including the version number and information on the platform and compiler.\n\n    @return JSON object holding version information\n    key         | description\n    ----------- | ---------------\n    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).\n    `copyright` | The copyright line for the library as string.\n    `name`      | The name of the library as string.\n    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.\n    `url`       | The URL of the project as string.\n    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).\n\n    @liveexample{The following code shows an example output of the `meta()`\n    function.,meta}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @complexity Constant.\n\n    @since 2.1.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json meta()\n    {\n        basic_json result;\n\n        result[\"copyright\"] = \"(C) 2013-2021 Niels Lohmann\";\n        result[\"name\"] = \"JSON for Modern C++\";\n        result[\"url\"] = \"https://github.com/nlohmann/json\";\n        result[\"version\"][\"string\"] =\n            std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_MINOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_PATCH);\n        result[\"version\"][\"major\"] = NLOHMANN_JSON_VERSION_MAJOR;\n        result[\"version\"][\"minor\"] = NLOHMANN_JSON_VERSION_MINOR;\n        result[\"version\"][\"patch\"] = NLOHMANN_JSON_VERSION_PATCH;\n\n#ifdef _WIN32\n        result[\"platform\"] = \"win32\";\n#elif defined __linux__\n        result[\"platform\"] = \"linux\";\n#elif defined __APPLE__\n        result[\"platform\"] = \"apple\";\n#elif defined __unix__\n        result[\"platform\"] = \"unix\";\n#else\n        result[\"platform\"] = \"unknown\";\n#endif\n\n#if defined(__ICC) || defined(__INTEL_COMPILER)\n        result[\"compiler\"] = {{\"family\", \"icc\"}, {\"version\", __INTEL_COMPILER}};\n#elif defined(__clang__)\n        result[\"compiler\"] = {{\"family\", \"clang\"}, {\"version\", __clang_version__}};\n#elif defined(__GNUC__) || defined(__GNUG__)\n        result[\"compiler\"] = {{\"family\", \"gcc\"}, {\"version\", std::to_string(__GNUC__) + \".\" + std::to_string(__GNUC_MINOR__) + \".\" + std::to_string(__GNUC_PATCHLEVEL__)}};\n#elif defined(__HP_cc) || defined(__HP_aCC)\n        result[\"compiler\"] = \"hp\"\n#elif defined(__IBMCPP__)\n        result[\"compiler\"] = {{\"family\", \"ilecpp\"}, {\"version\", __IBMCPP__}};\n#elif defined(_MSC_VER)\n        result[\"compiler\"] = {{\"family\", \"msvc\"}, {\"version\", _MSC_VER}};\n#elif defined(__PGI)\n        result[\"compiler\"] = {{\"family\", \"pgcpp\"}, {\"version\", __PGI}};\n#elif defined(__SUNPRO_CC)\n        result[\"compiler\"] = {{\"family\", \"sunpro\"}, {\"version\", __SUNPRO_CC}};\n#else\n        result[\"compiler\"] = {{\"family\", \"unknown\"}, {\"version\", \"unknown\"}};\n#endif\n\n#ifdef __cplusplus\n        result[\"compiler\"][\"c++\"] = std::to_string(__cplusplus);\n#else\n        result[\"compiler\"][\"c++\"] = \"unknown\";\n#endif\n        return result;\n    }\n\n\n    ///////////////////////////\n    // JSON value data types //\n    ///////////////////////////\n\n    /// @name JSON value data types\n    /// The data types to store a JSON value. These types are derived from\n    /// the template arguments passed to class @ref basic_json.\n    /// @{\n\n#if defined(JSON_HAS_CPP_14)\n    // Use transparent comparator if possible, combined with perfect forwarding\n    // on find() and count() calls prevents unnecessary string construction.\n    using object_comparator_t = std::less<>;\n#else\n    using object_comparator_t = std::less<StringType>;\n#endif\n\n    /*!\n    @brief a type for an object\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON objects as follows:\n    > An object is an unordered collection of zero or more name/value pairs,\n    > where a name is a string and a value is a string, number, boolean, null,\n    > object, or array.\n\n    To store objects in C++, a type is defined by the template parameters\n    described below.\n\n    @tparam ObjectType  the container to store objects (e.g., `std::map` or\n    `std::unordered_map`)\n    @tparam StringType the type of the keys or names (e.g., `std::string`).\n    The comparison function `std::less<StringType>` is used to order elements\n    inside the container.\n    @tparam AllocatorType the allocator to use for objects (e.g.,\n    `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ObjectType (`std::map`), @a StringType\n    (`std::string`), and @a AllocatorType (`std::allocator`), the default\n    value for @a object_t is:\n\n    @code {.cpp}\n    std::map<\n      std::string, // key_type\n      basic_json, // value_type\n      std::less<std::string>, // key_compare\n      std::allocator<std::pair<const std::string, basic_json>> // allocator_type\n    >\n    @endcode\n\n    #### Behavior\n\n    The choice of @a object_t influences the behavior of the JSON class. With\n    the default type, objects have the following behavior:\n\n    - When all names are unique, objects will be interoperable in the sense\n      that all software implementations receiving that object will agree on\n      the name-value mappings.\n    - When the names within an object are not unique, it is unspecified which\n      one of the values for a given key will be chosen. For instance,\n      `{\"key\": 2, \"key\": 1}` could be equal to either `{\"key\": 1}` or\n      `{\"key\": 2}`.\n    - Internally, name/value pairs are stored in lexicographical order of the\n      names. Objects will also be serialized (see @ref dump) in this order.\n      For instance, `{\"b\": 1, \"a\": 2}` and `{\"a\": 2, \"b\": 1}` will be stored\n      and serialized as `{\"a\": 2, \"b\": 1}`.\n    - When comparing objects, the order of the name/value pairs is irrelevant.\n      This makes objects interoperable in the sense that they will not be\n      affected by these differences. For instance, `{\"b\": 1, \"a\": 2}` and\n      `{\"a\": 2, \"b\": 1}` will be treated as equal.\n\n    #### Limits\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the object's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON object.\n\n    #### Storage\n\n    Objects are stored as pointers in a @ref basic_json type. That is, for any\n    access to object values, a pointer of type `object_t*` must be\n    dereferenced.\n\n    @sa see @ref array_t -- type for an array value\n\n    @since version 1.0.0\n\n    @note The order name/value pairs are added to the object is *not*\n    preserved by the library. Therefore, iterating an object may return\n    name/value pairs in a different order than they were originally stored. In\n    fact, keys will be traversed in alphabetical order as `std::map` with\n    `std::less` is used by default. Please note this behavior conforms to [RFC\n    8259](https://tools.ietf.org/html/rfc8259), because any order implements the\n    specified \"unordered\" nature of JSON objects.\n    */\n    using object_t = ObjectType<StringType,\n          basic_json,\n          object_comparator_t,\n          AllocatorType<std::pair<const StringType,\n          basic_json>>>;\n\n    /*!\n    @brief a type for an array\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON arrays as follows:\n    > An array is an ordered sequence of zero or more values.\n\n    To store objects in C++, a type is defined by the template parameters\n    explained below.\n\n    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or\n    `std::list`)\n    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ArrayType (`std::vector`) and @a\n    AllocatorType (`std::allocator`), the default value for @a array_t is:\n\n    @code {.cpp}\n    std::vector<\n      basic_json, // value_type\n      std::allocator<basic_json> // allocator_type\n    >\n    @endcode\n\n    #### Limits\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the array's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON array.\n\n    #### Storage\n\n    Arrays are stored as pointers in a @ref basic_json type. That is, for any\n    access to array values, a pointer of type `array_t*` must be dereferenced.\n\n    @sa see @ref object_t -- type for an object value\n\n    @since version 1.0.0\n    */\n    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;\n\n    /*!\n    @brief a type for a string\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON strings as follows:\n    > A string is a sequence of zero or more Unicode characters.\n\n    To store objects in C++, a type is defined by the template parameter\n    described below. Unicode values are split by the JSON class into\n    byte-sized characters during deserialization.\n\n    @tparam StringType  the container to store strings (e.g., `std::string`).\n    Note this container is used for keys/names in objects, see @ref object_t.\n\n    #### Default type\n\n    With the default values for @a StringType (`std::string`), the default\n    value for @a string_t is:\n\n    @code {.cpp}\n    std::string\n    @endcode\n\n    #### Encoding\n\n    Strings are stored in UTF-8 encoding. Therefore, functions like\n    `std::string::size()` or `std::string::length()` return the number of\n    bytes in the string rather than the number of characters or glyphs.\n\n    #### String comparison\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) states:\n    > Software implementations are typically required to test names of object\n    > members for equality. Implementations that transform the textual\n    > representation into sequences of Unicode code units and then perform the\n    > comparison numerically, code unit by code unit, are interoperable in the\n    > sense that implementations will agree in all cases on equality or\n    > inequality of two strings. For example, implementations that compare\n    > strings with escaped characters unconverted may incorrectly find that\n    > `\"a\\\\b\"` and `\"a\\u005Cb\"` are not equal.\n\n    This implementation is interoperable as it does compare strings code unit\n    by code unit.\n\n    #### Storage\n\n    String values are stored as pointers in a @ref basic_json type. That is,\n    for any access to string values, a pointer of type `string_t*` must be\n    dereferenced.\n\n    @since version 1.0.0\n    */\n    using string_t = StringType;\n\n    /*!\n    @brief a type for a boolean\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) implicitly describes a boolean as a\n    type which differentiates the two literals `true` and `false`.\n\n    To store objects in C++, a type is defined by the template parameter @a\n    BooleanType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a BooleanType (`bool`), the default value for\n    @a boolean_t is:\n\n    @code {.cpp}\n    bool\n    @endcode\n\n    #### Storage\n\n    Boolean values are stored directly inside a @ref basic_json type.\n\n    @since version 1.0.0\n    */\n    using boolean_t = BooleanType;\n\n    /*!\n    @brief a type for a number (integer)\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store integer numbers in C++, a type is defined by the template\n    parameter @a NumberIntegerType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberIntegerType (`int64_t`), the default\n    value for @a number_integer_t is:\n\n    @code {.cpp}\n    int64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number\n    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers\n    that are out of range will yield over/underflow when used in a\n    constructor. During deserialization, too large or small integer numbers\n    will be automatically be stored as @ref number_unsigned_t or @ref\n    number_float_t.\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange of the exactly supported range [INT64_MIN,\n    INT64_MAX], this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa see @ref number_float_t -- type for number values (floating-point)\n\n    @sa see @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_integer_t = NumberIntegerType;\n\n    /*!\n    @brief a type for a number (unsigned)\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store unsigned integer numbers in C++, a type is defined by the\n    template parameter @a NumberUnsignedType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberUnsignedType (`uint64_t`), the\n    default value for @a number_unsigned_t is:\n\n    @code {.cpp}\n    uint64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer\n    number that can be stored is `0`. Integer numbers that are out of range\n    will yield over/underflow when used in a constructor. During\n    deserialization, too large or small integer numbers will be automatically\n    be stored as @ref number_integer_t or @ref number_float_t.\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange (when considered in conjunction with the\n    number_integer_t type) of the exactly supported range [0, UINT64_MAX],\n    this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa see @ref number_float_t -- type for number values (floating-point)\n    @sa see @ref number_integer_t -- type for number values (integer)\n\n    @since version 2.0.0\n    */\n    using number_unsigned_t = NumberUnsignedType;\n\n    /*!\n    @brief a type for a number (floating-point)\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store floating-point numbers in C++, a type is defined by the template\n    parameter @a NumberFloatType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberFloatType (`double`), the default\n    value for @a number_float_t is:\n\n    @code {.cpp}\n    double\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in floating-point literals will be ignored. Internally,\n      the value will be stored as decimal number. For instance, the C++\n      floating-point literal `01.2` will be serialized to `1.2`. During\n      deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 8259](https://tools.ietf.org/html/rfc8259) states:\n    > This specification allows implementations to set limits on the range and\n    > precision of numbers accepted. Since software that implements IEEE\n    > 754-2008 binary64 (double precision) numbers is generally available and\n    > widely used, good interoperability can be achieved by implementations\n    > that expect no more precision or range than these provide, in the sense\n    > that implementations will approximate JSON numbers within the expected\n    > precision.\n\n    This implementation does exactly follow this approach, as it uses double\n    precision floating-point numbers. Note values smaller than\n    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`\n    will be stored as NaN internally and be serialized to `null`.\n\n    #### Storage\n\n    Floating-point number values are stored directly inside a @ref basic_json\n    type.\n\n    @sa see @ref number_integer_t -- type for number values (integer)\n\n    @sa see @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_float_t = NumberFloatType;\n\n    /*!\n    @brief a type for a packed binary type\n\n    This type is a type designed to carry binary data that appears in various\n    serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and\n    BSON's generic binary subtype. This type is NOT a part of standard JSON and\n    exists solely for compatibility with these binary types. As such, it is\n    simply defined as an ordered sequence of zero or more byte values.\n\n    Additionally, as an implementation detail, the subtype of the binary data is\n    carried around as a `std::uint8_t`, which is compatible with both of the\n    binary data formats that use binary subtyping, (though the specific\n    numbering is incompatible with each other, and it is up to the user to\n    translate between them).\n\n    [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type\n    as:\n    > Major type 2: a byte string. The string's length in bytes is represented\n    > following the rules for positive integers (major type 0).\n\n    [MessagePack's documentation on the bin type\n    family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family)\n    describes this type as:\n    > Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes\n    > in addition to the size of the byte array.\n\n    [BSON's specifications](http://bsonspec.org/spec.html) describe several\n    binary types; however, this type is intended to represent the generic binary\n    type which has the description:\n    > Generic binary subtype - This is the most commonly used binary subtype and\n    > should be the 'default' for drivers and tools.\n\n    None of these impose any limitations on the internal representation other\n    than the basic unit of storage be some type of array whose parts are\n    decomposable into bytes.\n\n    The default representation of this binary format is a\n    `std::vector<std::uint8_t>`, which is a very common way to represent a byte\n    array in modern C++.\n\n    #### Default type\n\n    The default values for @a BinaryType is `std::vector<std::uint8_t>`\n\n    #### Storage\n\n    Binary Arrays are stored as pointers in a @ref basic_json type. That is,\n    for any access to array values, a pointer of the type `binary_t*` must be\n    dereferenced.\n\n    #### Notes on subtypes\n\n    - CBOR\n       - Binary values are represented as byte strings. Subtypes are serialized\n         as tagged values.\n    - MessagePack\n       - If a subtype is given and the binary array contains exactly 1, 2, 4, 8,\n         or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8)\n         is used. For other sizes, the ext family (ext8, ext16, ext32) is used.\n         The subtype is then added as singed 8-bit integer.\n       - If no subtype is given, the bin family (bin8, bin16, bin32) is used.\n    - BSON\n       - If a subtype is given, it is used and added as unsigned 8-bit integer.\n       - If no subtype is given, the generic binary subtype 0x00 is used.\n\n    @sa see @ref binary -- create a binary array\n\n    @since version 3.8.0\n    */\n    using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;\n    /// @}\n\n  private:\n\n    /// helper for exception-safe object creation\n    template<typename T, typename... Args>\n    JSON_HEDLEY_RETURNS_NON_NULL\n    static T* create(Args&& ... args)\n    {\n        AllocatorType<T> alloc;\n        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;\n\n        auto deleter = [&](T * obj)\n        {\n            AllocatorTraits::deallocate(alloc, obj, 1);\n        };\n        std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);\n        AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);\n        JSON_ASSERT(obj != nullptr);\n        return obj.release();\n    }\n\n    ////////////////////////\n    // JSON value storage //\n    ////////////////////////\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief a JSON value\n\n    The actual storage for a JSON value of the @ref basic_json class. This\n    union combines the different storage types for the JSON value types\n    defined in @ref value_t.\n\n    JSON type | value_t type    | used type\n    --------- | --------------- | ------------------------\n    object    | object          | pointer to @ref object_t\n    array     | array           | pointer to @ref array_t\n    string    | string          | pointer to @ref string_t\n    boolean   | boolean         | @ref boolean_t\n    number    | number_integer  | @ref number_integer_t\n    number    | number_unsigned | @ref number_unsigned_t\n    number    | number_float    | @ref number_float_t\n    binary    | binary          | pointer to @ref binary_t\n    null      | null            | *no value is stored*\n\n    @note Variable-length types (objects, arrays, and strings) are stored as\n    pointers. The size of the union should not exceed 64 bits if the default\n    value types are used.\n\n    @since version 1.0.0\n    */\n    union json_value\n    {\n        /// object (stored with pointer to save storage)\n        object_t* object;\n        /// array (stored with pointer to save storage)\n        array_t* array;\n        /// string (stored with pointer to save storage)\n        string_t* string;\n        /// binary (stored with pointer to save storage)\n        binary_t* binary;\n        /// boolean\n        boolean_t boolean;\n        /// number (integer)\n        number_integer_t number_integer;\n        /// number (unsigned integer)\n        number_unsigned_t number_unsigned;\n        /// number (floating-point)\n        number_float_t number_float;\n\n        /// default constructor (for null values)\n        json_value() = default;\n        /// constructor for booleans\n        json_value(boolean_t v) noexcept : boolean(v) {}\n        /// constructor for numbers (integer)\n        json_value(number_integer_t v) noexcept : number_integer(v) {}\n        /// constructor for numbers (unsigned)\n        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}\n        /// constructor for numbers (floating-point)\n        json_value(number_float_t v) noexcept : number_float(v) {}\n        /// constructor for empty values of a given type\n        json_value(value_t t)\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    object = create<object_t>();\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    array = create<array_t>();\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    string = create<string_t>(\"\");\n                    break;\n                }\n\n                case value_t::binary:\n                {\n                    binary = create<binary_t>();\n                    break;\n                }\n\n                case value_t::boolean:\n                {\n                    boolean = boolean_t(false);\n                    break;\n                }\n\n                case value_t::number_integer:\n                {\n                    number_integer = number_integer_t(0);\n                    break;\n                }\n\n                case value_t::number_unsigned:\n                {\n                    number_unsigned = number_unsigned_t(0);\n                    break;\n                }\n\n                case value_t::number_float:\n                {\n                    number_float = number_float_t(0.0);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    break;\n                }\n\n                case value_t::discarded:\n                default:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))\n                    {\n                        JSON_THROW(other_error::create(500, \"961c151d2e87f2686a955a9be24d316f1362bf21 3.10.4\", basic_json())); // LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n            }\n        }\n\n        /// constructor for strings\n        json_value(const string_t& value)\n        {\n            string = create<string_t>(value);\n        }\n\n        /// constructor for rvalue strings\n        json_value(string_t&& value)\n        {\n            string = create<string_t>(std::move(value));\n        }\n\n        /// constructor for objects\n        json_value(const object_t& value)\n        {\n            object = create<object_t>(value);\n        }\n\n        /// constructor for rvalue objects\n        json_value(object_t&& value)\n        {\n            object = create<object_t>(std::move(value));\n        }\n\n        /// constructor for arrays\n        json_value(const array_t& value)\n        {\n            array = create<array_t>(value);\n        }\n\n        /// constructor for rvalue arrays\n        json_value(array_t&& value)\n        {\n            array = create<array_t>(std::move(value));\n        }\n\n        /// constructor for binary arrays\n        json_value(const typename binary_t::container_type& value)\n        {\n            binary = create<binary_t>(value);\n        }\n\n        /// constructor for rvalue binary arrays\n        json_value(typename binary_t::container_type&& value)\n        {\n            binary = create<binary_t>(std::move(value));\n        }\n\n        /// constructor for binary arrays (internal type)\n        json_value(const binary_t& value)\n        {\n            binary = create<binary_t>(value);\n        }\n\n        /// constructor for rvalue binary arrays (internal type)\n        json_value(binary_t&& value)\n        {\n            binary = create<binary_t>(std::move(value));\n        }\n\n        void destroy(value_t t)\n        {\n            if (t == value_t::array || t == value_t::object)\n            {\n                // flatten the current json_value to a heap-allocated stack\n                std::vector<basic_json> stack;\n\n                // move the top-level items to stack\n                if (t == value_t::array)\n                {\n                    stack.reserve(array->size());\n                    std::move(array->begin(), array->end(), std::back_inserter(stack));\n                }\n                else\n                {\n                    stack.reserve(object->size());\n                    for (auto&& it : *object)\n                    {\n                        stack.push_back(std::move(it.second));\n                    }\n                }\n\n                while (!stack.empty())\n                {\n                    // move the last item to local variable to be processed\n                    basic_json current_item(std::move(stack.back()));\n                    stack.pop_back();\n\n                    // if current_item is array/object, move\n                    // its children to the stack to be processed later\n                    if (current_item.is_array())\n                    {\n                        std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack));\n\n                        current_item.m_value.array->clear();\n                    }\n                    else if (current_item.is_object())\n                    {\n                        for (auto&& it : *current_item.m_value.object)\n                        {\n                            stack.push_back(std::move(it.second));\n                        }\n\n                        current_item.m_value.object->clear();\n                    }\n\n                    // it's now safe that current_item get destructed\n                    // since it doesn't have any children\n                }\n            }\n\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    AllocatorType<object_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    AllocatorType<array_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);\n                    break;\n                }\n\n                case value_t::binary:\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);\n                    break;\n                }\n\n                case value_t::null:\n                case value_t::boolean:\n                case value_t::number_integer:\n                case value_t::number_unsigned:\n                case value_t::number_float:\n                case value_t::discarded:\n                default:\n                {\n                    break;\n                }\n            }\n        }\n    };\n\n  private:\n    /*!\n    @brief checks the class invariants\n\n    This function asserts the class invariants. It needs to be called at the\n    end of every constructor to make sure that created objects respect the\n    invariant. Furthermore, it has to be called each time the type of a JSON\n    value is changed, because the invariant expresses a relationship between\n    @a m_type and @a m_value.\n\n    Furthermore, the parent relation is checked for arrays and objects: If\n    @a check_parents true and the value is an array or object, then the\n    container's elements must have the current value as parent.\n\n    @param[in] check_parents  whether the parent relation should be checked.\n               The value is true by default and should only be set to false\n               during destruction of objects when the invariant does not\n               need to hold.\n    */\n    void assert_invariant(bool check_parents = true) const noexcept\n    {\n        JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);\n        JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);\n        JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);\n        JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);\n\n#if JSON_DIAGNOSTICS\n        JSON_TRY\n        {\n            // cppcheck-suppress assertWithSideEffect\n            JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)\n            {\n                return j.m_parent == this;\n            }));\n        }\n        JSON_CATCH(...) {} // LCOV_EXCL_LINE\n#endif\n        static_cast<void>(check_parents);\n    }\n\n    void set_parents()\n    {\n#if JSON_DIAGNOSTICS\n        switch (m_type)\n        {\n            case value_t::array:\n            {\n                for (auto& element : *m_value.array)\n                {\n                    element.m_parent = this;\n                }\n                break;\n            }\n\n            case value_t::object:\n            {\n                for (auto& element : *m_value.object)\n                {\n                    element.second.m_parent = this;\n                }\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                break;\n        }\n#endif\n    }\n\n    iterator set_parents(iterator it, typename iterator::difference_type count)\n    {\n#if JSON_DIAGNOSTICS\n        for (typename iterator::difference_type i = 0; i < count; ++i)\n        {\n            (it + i)->m_parent = this;\n        }\n#else\n        static_cast<void>(count);\n#endif\n        return it;\n    }\n\n    reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1))\n    {\n#if JSON_DIAGNOSTICS\n        if (old_capacity != std::size_t(-1))\n        {\n            // see https://github.com/nlohmann/json/issues/2838\n            JSON_ASSERT(type() == value_t::array);\n            if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))\n            {\n                // capacity has changed: update all parents\n                set_parents();\n                return j;\n            }\n        }\n\n        // ordered_json uses a vector internally, so pointers could have\n        // been invalidated; see https://github.com/nlohmann/json/issues/2962\n#ifdef JSON_HEDLEY_MSVC_VERSION\n#pragma warning(push )\n#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr\n#endif\n        if (detail::is_ordered_map<object_t>::value)\n        {\n            set_parents();\n            return j;\n        }\n#ifdef JSON_HEDLEY_MSVC_VERSION\n#pragma warning( pop )\n#endif\n\n        j.m_parent = this;\n#else\n        static_cast<void>(j);\n        static_cast<void>(old_capacity);\n#endif\n        return j;\n    }\n\n  public:\n    //////////////////////////\n    // JSON parser callback //\n    //////////////////////////\n\n    /*!\n    @brief parser event types\n\n    The parser callback distinguishes the following events:\n    - `object_start`: the parser read `{` and started to process a JSON object\n    - `key`: the parser read a key of a value in an object\n    - `object_end`: the parser read `}` and finished processing a JSON object\n    - `array_start`: the parser read `[` and started to process a JSON array\n    - `array_end`: the parser read `]` and finished processing a JSON array\n    - `value`: the parser finished reading a JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    @sa see @ref parser_callback_t for more information and examples\n    */\n    using parse_event_t = detail::parse_event_t;\n\n    /*!\n    @brief per-element parser callback type\n\n    With a parser callback function, the result of parsing a JSON text can be\n    influenced. When passed to @ref parse, it is called on certain events\n    (passed as @ref parse_event_t via parameter @a event) with a set recursion\n    depth @a depth and context JSON value @a parsed. The return value of the\n    callback function is a boolean indicating whether the element that emitted\n    the callback shall be kept or not.\n\n    We distinguish six scenarios (determined by the event type) in which the\n    callback function can be called. The following table describes the values\n    of the parameters @a depth, @a event, and @a parsed.\n\n    parameter @a event | description | parameter @a depth | parameter @a parsed\n    ------------------ | ----------- | ------------------ | -------------------\n    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded\n    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key\n    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object\n    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded\n    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array\n    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    Discarding a value (i.e., returning `false`) has different effects\n    depending on the context in which function was called:\n\n    - Discarded values in structured types are skipped. That is, the parser\n      will behave as if the discarded value was never read.\n    - In case a value outside a structured type is skipped, it is replaced\n      with `null`. This case happens if the top-level element is skipped.\n\n    @param[in] depth  the depth of the recursion during parsing\n\n    @param[in] event  an event of type parse_event_t indicating the context in\n    the callback function has been called\n\n    @param[in,out] parsed  the current intermediate parse result; note that\n    writing to this value has no effect for parse_event_t::key events\n\n    @return Whether the JSON value which called the function during parsing\n    should be kept (`true`) or not (`false`). In the latter case, it is either\n    skipped completely or replaced by an empty discarded object.\n\n    @sa see @ref parse for examples\n\n    @since version 1.0.0\n    */\n    using parser_callback_t = detail::parser_callback_t<basic_json>;\n\n    //////////////////\n    // constructors //\n    //////////////////\n\n    /// @name constructors and destructors\n    /// Constructors of class @ref basic_json, copy/move constructor, copy\n    /// assignment, static functions creating objects, and the destructor.\n    /// @{\n\n    /*!\n    @brief create an empty value with a given type\n\n    Create an empty JSON value with a given type. The value will be default\n    initialized with an empty value which depends on the type:\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    object      | `{}`\n    array       | `[]`\n    binary      | empty array\n\n    @param[in] v  the type of the value to create\n\n    @complexity Constant.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows the constructor for different @ref\n    value_t values,basic_json__value_t}\n\n    @sa see @ref clear() -- restores the postcondition of this constructor\n\n    @since version 1.0.0\n    */\n    basic_json(const value_t v)\n        : m_type(v), m_value(v)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a null object\n\n    Create a `null` JSON value. It either takes a null pointer as parameter\n    (explicitly creating `null`) or no parameter (implicitly creating `null`).\n    The passed null pointer itself is not read -- it is only used to choose\n    the right constructor.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @liveexample{The following code shows the constructor with and without a\n    null pointer parameter.,basic_json__nullptr_t}\n\n    @since version 1.0.0\n    */\n    basic_json(std::nullptr_t = nullptr) noexcept\n        : basic_json(value_t::null)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value\n\n    This is a \"catch all\" constructor for all compatible JSON types; that is,\n    types for which a `to_json()` method exists. The constructor forwards the\n    parameter @a val to that method (to `json_serializer<U>::to_json` method\n    with `U = uncvref_t<CompatibleType>`, to be exact).\n\n    Template type @a CompatibleType includes, but is not limited to, the\n    following types:\n    - **arrays**: @ref array_t and all kinds of compatible containers such as\n      `std::vector`, `std::deque`, `std::list`, `std::forward_list`,\n      `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,\n      `std::multiset`, and `std::unordered_multiset` with a `value_type` from\n      which a @ref basic_json value can be constructed.\n    - **objects**: @ref object_t and all kinds of compatible associative\n      containers such as `std::map`, `std::unordered_map`, `std::multimap`,\n      and `std::unordered_multimap` with a `key_type` compatible to\n      @ref string_t and a `value_type` from which a @ref basic_json value can\n      be constructed.\n    - **strings**: @ref string_t, string literals, and all compatible string\n      containers can be used.\n    - **numbers**: @ref number_integer_t, @ref number_unsigned_t,\n      @ref number_float_t, and all convertible number types such as `int`,\n      `size_t`, `int64_t`, `float` or `double` can be used.\n    - **boolean**: @ref boolean_t / `bool` can be used.\n    - **binary**: @ref binary_t / `std::vector<std::uint8_t>` may be used,\n      unfortunately because string literals cannot be distinguished from binary\n      character arrays by the C++ type system, all types compatible with `const\n      char*` will be directed to the string constructor instead.  This is both\n      for backwards compatibility, and due to the fact that a binary type is not\n      a standard JSON type.\n\n    See the examples below.\n\n    @tparam CompatibleType a type such that:\n    - @a CompatibleType is not derived from `std::istream`,\n    - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move\n         constructors),\n    - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)\n    - @a CompatibleType is not a @ref basic_json nested type (e.g.,\n         @ref json_pointer, @ref iterator, etc ...)\n    - `json_serializer<U>` has a `to_json(basic_json_t&, CompatibleType&&)` method\n\n    @tparam U = `uncvref_t<CompatibleType>`\n\n    @param[in] val the value to be forwarded to the respective constructor\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @liveexample{The following code shows the constructor with several\n    compatible types.,basic_json__CompatibleType}\n\n    @since version 2.1.0\n    */\n    template < typename CompatibleType,\n               typename U = detail::uncvref_t<CompatibleType>,\n               detail::enable_if_t <\n                   !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >\n    basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)\n                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),\n                                           std::forward<CompatibleType>(val))))\n    {\n        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));\n        set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value from an existing one\n\n    This is a constructor for existing @ref basic_json types.\n    It does not hijack copy/move constructors, since the parameter has different\n    template arguments than the current ones.\n\n    The constructor tries to convert the internal @ref m_value of the parameter.\n\n    @tparam BasicJsonType a type such that:\n    - @a BasicJsonType is a @ref basic_json type.\n    - @a BasicJsonType has different template arguments than @ref basic_json_t.\n\n    @param[in] val the @ref basic_json value to be converted.\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @since version 3.2.0\n    */\n    template < typename BasicJsonType,\n               detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >\n    basic_json(const BasicJsonType& val)\n    {\n        using other_boolean_t = typename BasicJsonType::boolean_t;\n        using other_number_float_t = typename BasicJsonType::number_float_t;\n        using other_number_integer_t = typename BasicJsonType::number_integer_t;\n        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n        using other_string_t = typename BasicJsonType::string_t;\n        using other_object_t = typename BasicJsonType::object_t;\n        using other_array_t = typename BasicJsonType::array_t;\n        using other_binary_t = typename BasicJsonType::binary_t;\n\n        switch (val.type())\n        {\n            case value_t::boolean:\n                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());\n                break;\n            case value_t::number_float:\n                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());\n                break;\n            case value_t::number_integer:\n                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());\n                break;\n            case value_t::number_unsigned:\n                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());\n                break;\n            case value_t::string:\n                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());\n                break;\n            case value_t::object:\n                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());\n                break;\n            case value_t::array:\n                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());\n                break;\n            case value_t::binary:\n                JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());\n                break;\n            case value_t::null:\n                *this = nullptr;\n                break;\n            case value_t::discarded:\n                m_type = value_t::discarded;\n                break;\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n        set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a container (array or object) from an initializer list\n\n    Creates a JSON value of type array or object from the passed initializer\n    list @a d2Init. In case @a type_deduction is `true` (default), the type of\n    the JSON value to be created is deducted from the initializer list @a d2Init\n    according to the following rules:\n\n    1. If the list is empty, an empty JSON object value `{}` is created.\n    2. If the list consists of pairs whose first element is a string, a JSON\n       object value is created where the first elements of the pairs are\n       treated as keys and the second elements are as values.\n    3. In all other cases, an array is created.\n\n    The rules aim to create the best fit between a C++ initializer list and\n    JSON values. The rationale is as follows:\n\n    1. The empty initializer list is written as `{}` which is exactly an empty\n       JSON object.\n    2. C++ has no way of describing mapped types other than to list a list of\n       pairs. As JSON requires that keys must be of type string, rule 2 is the\n       weakest constraint one can pose on initializer lists to interpret them\n       as an object.\n    3. In all other cases, the initializer list could not be interpreted as\n       JSON object type, so interpreting it as JSON array type is safe.\n\n    With the rules described above, the following JSON values cannot be\n    expressed by an initializer list:\n\n    - the empty array (`[]`): use @ref array(initializer_list_t)\n      with an empty initializer list in this case\n    - arrays whose elements satisfy rule 2: use @ref\n      array(initializer_list_t) with the same initializer list\n      in this case\n\n    @note When used without parentheses around an empty initializer list, @ref\n    basic_json() is called instead of this function, yielding the JSON null\n    value.\n\n    @param[in] init  initializer list with JSON values\n\n    @param[in] type_deduction internal parameter; when set to `true`, the type\n    of the JSON value is deducted from the initializer list @a d2Init; when set\n    to `false`, the type provided via @a manual_type is forced. This mode is\n    used by the functions @ref array(initializer_list_t) and\n    @ref object(initializer_list_t).\n\n    @param[in] manual_type internal parameter; when @a type_deduction is set\n    to `false`, the created JSON value will use the provided type (only @ref\n    value_t::array and @ref value_t::object are valid); when @a type_deduction\n    is set to `true`, this parameter has no effect\n\n    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is\n    `value_t::object`, but @a d2Init contains an element which is not a pair\n    whose first element is a string. In this case, the constructor could not\n    create an object. If @a type_deduction would have be `true`, an array\n    would have been created. See @ref object(initializer_list_t)\n    for an example.\n\n    @complexity Linear in the size of the initializer list @a d2Init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows how JSON values are created from\n    initializer lists.,basic_json__list_init_t}\n\n    @sa see @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n    @sa see @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    basic_json(initializer_list_t init,\n               bool type_deduction = true,\n               value_t manual_type = value_t::array)\n    {\n        // check if each element is an array with two elements whose first\n        // element is a string\n        bool is_an_object = std::all_of(init.begin(), init.end(),\n                                        [](const detail::json_ref<basic_json>& element_ref)\n        {\n            return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();\n        });\n\n        // adjust type if type deduction is not wanted\n        if (!type_deduction)\n        {\n            // if array is wanted, do not create an object though possible\n            if (manual_type == value_t::array)\n            {\n                is_an_object = false;\n            }\n\n            // if object is wanted but impossible, throw an exception\n            if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))\n            {\n                JSON_THROW(type_error::create(301, \"cannot create object from initializer list\", basic_json()));\n            }\n        }\n\n        if (is_an_object)\n        {\n            // the initializer list is a list of pairs -> create object\n            m_type = value_t::object;\n            m_value = value_t::object;\n\n            for (auto& element_ref : init)\n            {\n                auto element = element_ref.moved_or_copied();\n                m_value.object->emplace(\n                    std::move(*((*element.m_value.array)[0].m_value.string)),\n                    std::move((*element.m_value.array)[1]));\n            }\n        }\n        else\n        {\n            // the initializer list describes an array -> create array\n            m_type = value_t::array;\n            m_value.array = create<array_t>(init.begin(), init.end());\n        }\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief explicitly create a binary array (without subtype)\n\n    Creates a JSON binary array value from a given binary container. Binary\n    values are part of various binary formats, such as CBOR, MessagePack, and\n    BSON. This constructor is used to create a value for serialization to those\n    formats.\n\n    @note Note, this function exists because of the difficulty in correctly\n    specifying the correct template overload in the standard value ctor, as both\n    JSON arrays and JSON binary arrays are backed with some form of a\n    `std::vector`. Because JSON binary arrays are a non-standard extension it\n    was decided that it would be best to prevent automatic initialization of a\n    binary array type, for backwards compatibility and so it does not happen on\n    accident.\n\n    @param[in] init container containing bytes to use as binary type\n\n    @return JSON binary array value\n\n    @complexity Linear in the size of @a d2Init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @since version 3.8.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(const typename binary_t::container_type& init)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = init;\n        return res;\n    }\n\n    /*!\n    @brief explicitly create a binary array (with subtype)\n\n    Creates a JSON binary array value from a given binary container. Binary\n    values are part of various binary formats, such as CBOR, MessagePack, and\n    BSON. This constructor is used to create a value for serialization to those\n    formats.\n\n    @note Note, this function exists because of the difficulty in correctly\n    specifying the correct template overload in the standard value ctor, as both\n    JSON arrays and JSON binary arrays are backed with some form of a\n    `std::vector`. Because JSON binary arrays are a non-standard extension it\n    was decided that it would be best to prevent automatic initialization of a\n    binary array type, for backwards compatibility and so it does not happen on\n    accident.\n\n    @param[in] init container containing bytes to use as binary type\n    @param[in] subtype subtype to use in MessagePack and BSON\n\n    @return JSON binary array value\n\n    @complexity Linear in the size of @a d2Init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @since version 3.8.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = binary_t(init, subtype);\n        return res;\n    }\n\n    /// @copydoc binary(const typename binary_t::container_type&)\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(typename binary_t::container_type&& init)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = std::move(init);\n        return res;\n    }\n\n    /// @copydoc binary(const typename binary_t::container_type&, typename binary_t::subtype_type)\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = binary_t(std::move(init), subtype);\n        return res;\n    }\n\n    /*!\n    @brief explicitly create an array from an initializer list\n\n    Creates a JSON array value from a given initializer list. That is, given a\n    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the\n    initializer list is empty, the empty array `[]` is created.\n\n    @note This function is only needed to express two edge cases that cannot\n    be realized with the initializer list constructor (@ref\n    basic_json(initializer_list_t, bool, value_t)). These cases\n    are:\n    1. creating an array whose elements are all pairs whose first element is a\n    string -- in this case, the initializer list constructor would create an\n    object, taking the first elements as keys\n    2. creating an empty array -- passing the empty initializer list to the\n    initializer list constructor yields an empty object\n\n    @param[in] init  initializer list with JSON values to create an array from\n    (optional)\n\n    @return JSON array value\n\n    @complexity Linear in the size of @a d2Init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `array`\n    function.,array}\n\n    @sa see @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa see @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json array(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::array);\n    }\n\n    /*!\n    @brief explicitly create an object from an initializer list\n\n    Creates a JSON object value from a given initializer list. The initializer\n    lists elements must be pairs, and their first elements must be strings. If\n    the initializer list is empty, the empty object `{}` is created.\n\n    @note This function is only added for symmetry reasons. In contrast to the\n    related function @ref array(initializer_list_t), there are\n    no cases which can only be expressed by this function. That is, any\n    initializer list @a d2Init can also be passed to the initializer list\n    constructor @ref basic_json(initializer_list_t, bool, value_t).\n\n    @param[in] init  initializer list to create an object from (optional)\n\n    @return JSON object value\n\n    @throw type_error.301 if @a d2Init is not a list of pairs whose first\n    elements are strings. In this case, no object can be created. When such a\n    value is passed to @ref basic_json(initializer_list_t, bool, value_t),\n    an array would have been created from the passed initializer list @a d2Init.\n    See example below.\n\n    @complexity Linear in the size of @a d2Init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `object`\n    function.,object}\n\n    @sa see @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa see @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json object(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::object);\n    }\n\n    /*!\n    @brief construct an array with count copies of given value\n\n    Constructs a JSON array value by creating @a cnt copies of a passed value.\n    In case @a cnt is `0`, an empty array is created.\n\n    @param[in] cnt  the number of JSON copies of @a val to create\n    @param[in] val  the JSON value to copy\n\n    @post `std::distance(begin(),end()) == cnt` holds.\n\n    @complexity Linear in @a cnt.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows examples for the @ref\n    basic_json(size_type\\, const basic_json&)\n    constructor.,basic_json__size_type_basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(size_type cnt, const basic_json& val)\n        : m_type(value_t::array)\n    {\n        m_value.array = create<array_t>(cnt, val);\n        set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief construct a JSON container given an iterator range\n\n    Constructs the JSON value with the contents of the range `[first, last)`.\n    The semantics depends on the different types a JSON value can have:\n    - In case of a null type, invalid_iterator.206 is thrown.\n    - In case of other primitive types (number, boolean, or string), @a first\n      must be `begin()` and @a last must be `end()`. In this case, the value is\n      copied. Otherwise, invalid_iterator.204 is thrown.\n    - In case of structured types (array, object), the constructor behaves as\n      similar versions for `std::vector` or `std::map`; that is, a JSON array\n      or object is constructed from the values in the range.\n\n    @tparam InputIT an input iterator type (@ref iterator or @ref\n    const_iterator)\n\n    @param[in] first begin of the range to copy from (included)\n    @param[in] last end of the range to copy from (excluded)\n\n    @pre Iterators @a first and @a last must be initialized. **This\n         precondition is enforced with an assertion (see warning).** If\n         assertions are switched off, a violation of this precondition yields\n         undefined behavior.\n\n    @pre Range `[first, last)` is valid. Usually, this precondition cannot be\n         checked efficiently. Only certain edge cases are detected; see the\n         description of the exceptions below. A violation of this precondition\n         yields undefined behavior.\n\n    @warning A precondition is enforced with a runtime assertion that will\n             result in calling `std::abort` if this precondition is not met.\n             Assertions can be disabled by defining `NDEBUG` at compile time.\n             See https://en.cppreference.com/w/cpp/error/assert for more\n             information.\n\n    @throw invalid_iterator.201 if iterators @a first and @a last are not\n    compatible (i.e., do not belong to the same JSON value). In this case,\n    the range `[first, last)` is undefined.\n    @throw invalid_iterator.204 if iterators @a first and @a last belong to a\n    primitive type (number, boolean, or string), but @a first does not point\n    to the first element any more. In this case, the range `[first, last)` is\n    undefined. See example code below.\n    @throw invalid_iterator.206 if iterators @a first and @a last belong to a\n    null value. In this case, the range `[first, last)` is undefined.\n\n    @complexity Linear in distance between @a first and @a last.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows several ways to create JSON values by\n    specifying a subrange with iterators.,basic_json__InputIt_InputIt}\n\n    @since version 1.0.0\n    */\n    template < class InputIT, typename std::enable_if <\n                   std::is_same<InputIT, typename basic_json_t::iterator>::value ||\n                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >\n    basic_json(InputIT first, InputIT last)\n    {\n        JSON_ASSERT(first.m_object != nullptr);\n        JSON_ASSERT(last.m_object != nullptr);\n\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(201, \"iterators are not compatible\", basic_json()));\n        }\n\n        // copy type from first iterator\n        m_type = first.m_object->m_type;\n\n        // check if iterator range is complete for primitive values\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()\n                                         || !last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\", *first.m_object));\n                }\n                break;\n            }\n\n            case value_t::null:\n            case value_t::object:\n            case value_t::array:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                break;\n        }\n\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = first.m_object->m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = first.m_object->m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = first.m_object->m_value.number_float;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = first.m_object->m_value.boolean;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *first.m_object->m_value.string;\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object = create<object_t>(first.m_it.object_iterator,\n                                                  last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array = create<array_t>(first.m_it.array_iterator,\n                                                last.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_value = *first.m_object->m_value.binary;\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                JSON_THROW(invalid_iterator::create(206, \"cannot construct with iterators from \" + std::string(first.m_object->type_name()), *first.m_object));\n        }\n\n        set_parents();\n        assert_invariant();\n    }\n\n\n    ///////////////////////////////////////\n    // other constructors and destructor //\n    ///////////////////////////////////////\n\n    template<typename JsonRef,\n             detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,\n                                 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >\n    basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}\n\n    /*!\n    @brief copy constructor\n\n    Creates a copy of a given JSON value.\n\n    @param[in] other  the JSON value to copy\n\n    @post `*this == other`\n\n    @complexity Linear in the size of @a other.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - As postcondition, it holds: `other == basic_json(other)`.\n\n    @liveexample{The following code shows an example for the copy\n    constructor.,basic_json__basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(const basic_json& other)\n        : m_type(other.m_type)\n    {\n        // check of passed value is valid\n        other.assert_invariant();\n\n        switch (m_type)\n        {\n            case value_t::object:\n            {\n                m_value = *other.m_value.object;\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value = *other.m_value.array;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *other.m_value.string;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value = other.m_value.boolean;\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                m_value = other.m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value = other.m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value = other.m_value.number_float;\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_value = *other.m_value.binary;\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                break;\n        }\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief move constructor\n\n    Move constructor. Constructs a JSON value with the contents of the given\n    value @a other using move semantics. It \"steals\" the resources from @a\n    other and leaves it as JSON null value.\n\n    @param[in,out] other  value to move to this object\n\n    @post `*this` has the same value as @a other before the call.\n    @post @a other is a JSON null value.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)\n    requirements.\n\n    @liveexample{The code below shows the move constructor explicitly called\n    via std::move.,basic_json__moveconstructor}\n\n    @since version 1.0.0\n    */\n    basic_json(basic_json&& other) noexcept\n        : m_type(std::move(other.m_type)),\n          m_value(std::move(other.m_value))\n    {\n        // check that passed value is valid\n        other.assert_invariant(false);\n\n        // invalidate payload\n        other.m_type = value_t::null;\n        other.m_value = {};\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief copy assignment\n\n    Copy assignment operator. Copies a JSON value via the \"copy and swap\"\n    strategy: It is expressed in terms of the copy constructor, destructor,\n    and the `swap()` member function.\n\n    @param[in] other  value to copy from\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n\n    @liveexample{The code below shows and example for the copy assignment. It\n    creates a copy of value `a` which is then swapped with `b`. Finally\\, the\n    copy of `a` (which is the null value after the swap) is\n    destroyed.,basic_json__copyassignment}\n\n    @since version 1.0.0\n    */\n    basic_json& operator=(basic_json other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        using std::swap;\n        swap(m_type, other.m_type);\n        swap(m_value, other.m_value);\n\n        set_parents();\n        assert_invariant();\n        return *this;\n    }\n\n    /*!\n    @brief destructor\n\n    Destroys the JSON value and frees all allocated memory.\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - All stored elements are destroyed and all memory is freed.\n\n    @since version 1.0.0\n    */\n    ~basic_json() noexcept\n    {\n        assert_invariant(false);\n        m_value.destroy(m_type);\n    }\n\n    /// @}\n\n  public:\n    ///////////////////////\n    // object inspection //\n    ///////////////////////\n\n    /// @name object inspection\n    /// Functions to inspect the type of a JSON value.\n    /// @{\n\n    /*!\n    @brief serialization\n\n    Serialization function for JSON values. The function tries to mimic\n    Python's `json.dumps()` function, and currently supports its @a indent\n    and @a ensure_ascii parameters.\n\n    @param[in] indent If indent is nonnegative, then array elements and object\n    members will be pretty-printed with that indent level. An indent level of\n    `0` will only insert newlines. `-1` (the default) selects the most compact\n    representation.\n    @param[in] indent_char The character to use for indentation if @a indent is\n    greater than `0`. The default is ` ` (space).\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] error_handler  how to react on decoding errors; there are three\n    possible values: `strict` (throws and exception in case a decoding error\n    occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),\n    and `ignore` (ignore invalid UTF-8 sequences during serialization; all\n    bytes are copied to the output unchanged).\n\n    @return string containing the serialization of the JSON value\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded and @a error_handler is set to strict\n\n    @note Binary values are serialized as object containing two keys:\n      - \"bytes\": an array of bytes as integers\n      - \"subtype\": the subtype as integer or \"null\" if the binary has no subtype\n\n    @complexity Linear.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @liveexample{The following example shows the effect of different @a indent\\,\n    @a indent_char\\, and @a ensure_ascii parameters to the result of the\n    serialization.,dump}\n\n    @see https://docs.python.org/2/library/json.html#json.dump\n\n    @since version 1.0.0; indentation character @a indent_char, option\n           @a ensure_ascii and exceptions added in version 3.0.0; error\n           handlers added in version 3.4.0; serialization of binary values added\n           in version 3.8.0.\n    */\n    string_t dump(const int indent = -1,\n                  const char indent_char = ' ',\n                  const bool ensure_ascii = false,\n                  const error_handler_t error_handler = error_handler_t::strict) const\n    {\n        string_t result;\n        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);\n\n        if (indent >= 0)\n        {\n            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));\n        }\n        else\n        {\n            s.dump(*this, false, ensure_ascii, 0);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief return the type of the JSON value (explicit)\n\n    Return the type of the JSON value as a value from the @ref value_t\n    enumeration.\n\n    @return the type of the JSON value\n            Value type                | return value\n            ------------------------- | -------------------------\n            null                      | value_t::null\n            boolean                   | value_t::boolean\n            string                    | value_t::string\n            number (integer)          | value_t::number_integer\n            number (unsigned integer) | value_t::number_unsigned\n            number (floating-point)   | value_t::number_float\n            object                    | value_t::object\n            array                     | value_t::array\n            binary                    | value_t::binary\n            discarded                 | value_t::discarded\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `type()` for all JSON\n    types.,type}\n\n    @sa see @ref operator value_t() -- return the type of the JSON value (implicit)\n    @sa see @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr value_t type() const noexcept\n    {\n        return m_type;\n    }\n\n    /*!\n    @brief return whether type is primitive\n\n    This function returns true if and only if the JSON type is primitive\n    (string, number, boolean, or null).\n\n    @return `true` if type is primitive (string, number, boolean, or null),\n    `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_primitive()` for all JSON\n    types.,is_primitive}\n\n    @sa see @ref is_structured() -- returns whether JSON value is structured\n    @sa see @ref is_null() -- returns whether JSON value is `null`\n    @sa see @ref is_string() -- returns whether JSON value is a string\n    @sa see @ref is_boolean() -- returns whether JSON value is a boolean\n    @sa see @ref is_number() -- returns whether JSON value is a number\n    @sa see @ref is_binary() -- returns whether JSON value is a binary array\n\n    @since version 1.0.0\n    */\n    constexpr bool is_primitive() const noexcept\n    {\n        return is_null() || is_string() || is_boolean() || is_number() || is_binary();\n    }\n\n    /*!\n    @brief return whether type is structured\n\n    This function returns true if and only if the JSON type is structured\n    (array or object).\n\n    @return `true` if type is structured (array or object), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_structured()` for all JSON\n    types.,is_structured}\n\n    @sa see @ref is_primitive() -- returns whether value is primitive\n    @sa see @ref is_array() -- returns whether value is an array\n    @sa see @ref is_object() -- returns whether value is an object\n\n    @since version 1.0.0\n    */\n    constexpr bool is_structured() const noexcept\n    {\n        return is_array() || is_object();\n    }\n\n    /*!\n    @brief return whether value is null\n\n    This function returns true if and only if the JSON value is null.\n\n    @return `true` if type is null, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_null()` for all JSON\n    types.,is_null}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_null() const noexcept\n    {\n        return m_type == value_t::null;\n    }\n\n    /*!\n    @brief return whether value is a boolean\n\n    This function returns true if and only if the JSON value is a boolean.\n\n    @return `true` if type is boolean, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_boolean()` for all JSON\n    types.,is_boolean}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_boolean() const noexcept\n    {\n        return m_type == value_t::boolean;\n    }\n\n    /*!\n    @brief return whether value is a number\n\n    This function returns true if and only if the JSON value is a number. This\n    includes both integer (signed and unsigned) and floating-point values.\n\n    @return `true` if type is number (regardless whether integer, unsigned\n    integer or floating-type), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number()` for all JSON\n    types.,is_number}\n\n    @sa see @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa see @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa see @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number() const noexcept\n    {\n        return is_number_integer() || is_number_float();\n    }\n\n    /*!\n    @brief return whether value is an integer number\n\n    This function returns true if and only if the JSON value is a signed or\n    unsigned integer number. This excludes floating-point values.\n\n    @return `true` if type is an integer or unsigned integer number, `false`\n    otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_integer()` for all\n    JSON types.,is_number_integer}\n\n    @sa see @ref is_number() -- check if value is a number\n    @sa see @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa see @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_integer() const noexcept\n    {\n        return m_type == value_t::number_integer || m_type == value_t::number_unsigned;\n    }\n\n    /*!\n    @brief return whether value is an unsigned integer number\n\n    This function returns true if and only if the JSON value is an unsigned\n    integer number. This excludes floating-point and signed integer values.\n\n    @return `true` if type is an unsigned integer number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_unsigned()` for all\n    JSON types.,is_number_unsigned}\n\n    @sa see @ref is_number() -- check if value is a number\n    @sa see @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa see @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 2.0.0\n    */\n    constexpr bool is_number_unsigned() const noexcept\n    {\n        return m_type == value_t::number_unsigned;\n    }\n\n    /*!\n    @brief return whether value is a floating-point number\n\n    This function returns true if and only if the JSON value is a\n    floating-point number. This excludes signed and unsigned integer values.\n\n    @return `true` if type is a floating-point number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_float()` for all\n    JSON types.,is_number_float}\n\n    @sa see @ref is_number() -- check if value is number\n    @sa see @ref is_number_integer() -- check if value is an integer number\n    @sa see @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_float() const noexcept\n    {\n        return m_type == value_t::number_float;\n    }\n\n    /*!\n    @brief return whether value is an object\n\n    This function returns true if and only if the JSON value is an object.\n\n    @return `true` if type is object, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_object()` for all JSON\n    types.,is_object}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_object() const noexcept\n    {\n        return m_type == value_t::object;\n    }\n\n    /*!\n    @brief return whether value is an array\n\n    This function returns true if and only if the JSON value is an array.\n\n    @return `true` if type is array, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_array()` for all JSON\n    types.,is_array}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_array() const noexcept\n    {\n        return m_type == value_t::array;\n    }\n\n    /*!\n    @brief return whether value is a string\n\n    This function returns true if and only if the JSON value is a string.\n\n    @return `true` if type is string, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_string()` for all JSON\n    types.,is_string}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_string() const noexcept\n    {\n        return m_type == value_t::string;\n    }\n\n    /*!\n    @brief return whether value is a binary array\n\n    This function returns true if and only if the JSON value is a binary array.\n\n    @return `true` if type is binary array, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_binary()` for all JSON\n    types.,is_binary}\n\n    @since version 3.8.0\n    */\n    constexpr bool is_binary() const noexcept\n    {\n        return m_type == value_t::binary;\n    }\n\n    /*!\n    @brief return whether value is discarded\n\n    This function returns true if and only if the JSON value was discarded\n    during parsing with a callback function (see @ref parser_callback_t).\n\n    @note This function will always be `false` for JSON values after parsing.\n    That is, discarded values can only occur during parsing, but will be\n    removed when inside a structured value or replaced by null in other cases.\n\n    @return `true` if type is discarded, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_discarded()` for all JSON\n    types.,is_discarded}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_discarded() const noexcept\n    {\n        return m_type == value_t::discarded;\n    }\n\n    /*!\n    @brief return the type of the JSON value (implicit)\n\n    Implicitly return the type of the JSON value as a value from the @ref\n    value_t enumeration.\n\n    @return the type of the JSON value\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies the @ref value_t operator for\n    all JSON types.,operator__value_t}\n\n    @sa see @ref type() -- return the type of the JSON value (explicit)\n    @sa see @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr operator value_t() const noexcept\n    {\n        return m_type;\n    }\n\n    /// @}\n\n  private:\n    //////////////////\n    // value access //\n    //////////////////\n\n    /// get a boolean (explicit)\n    boolean_t get_impl(boolean_t* /*unused*/) const\n    {\n        if (JSON_HEDLEY_LIKELY(is_boolean()))\n        {\n            return m_value.boolean;\n        }\n\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(type_name()), *this));\n    }\n\n    /// get a pointer to the value (object)\n    object_t* get_impl_ptr(object_t* /*unused*/) noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (object)\n    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    array_t* get_impl_ptr(array_t* /*unused*/) noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    string_t* get_impl_ptr(string_t* /*unused*/) noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (binary)\n    binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept\n    {\n        return is_binary() ? m_value.binary : nullptr;\n    }\n\n    /// get a pointer to the value (binary)\n    constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept\n    {\n        return is_binary() ? m_value.binary : nullptr;\n    }\n\n    /*!\n    @brief helper function to implement get_ref()\n\n    This function helps to implement get_ref() without code duplication for\n    const and non-const overloads\n\n    @tparam ThisType will be deduced as `basic_json` or `const basic_json`\n\n    @throw type_error.303 if ReferenceType does not match underlying value\n    type of the current JSON\n    */\n    template<typename ReferenceType, typename ThisType>\n    static ReferenceType get_ref_impl(ThisType& obj)\n    {\n        // delegate the call to get_ptr<>()\n        auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();\n\n        if (JSON_HEDLEY_LIKELY(ptr != nullptr))\n        {\n            return *ptr;\n        }\n\n        JSON_THROW(type_error::create(303, \"incompatible ReferenceType for get_ref, actual type is \" + std::string(obj.type_name()), obj));\n    }\n\n  public:\n    /// @name value access\n    /// Direct access to the stored value of a JSON value.\n    /// @{\n\n    /*!\n    @brief get a pointer value (implicit)\n\n    Implicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning Writing data to the pointee of the result yields an undefined\n    state.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static\n    assertion.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get_ptr}\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>()\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (implicit)\n    @copydoc get_ptr()\n    */\n    template < typename PointerType, typename std::enable_if <\n                   std::is_pointer<PointerType>::value&&\n                   std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >\n    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>() const\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n  private:\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType ret;\n    JSONSerializer<ValueType>::from_json(*this, ret);\n    return ret;\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n    - @ref json_serializer<ValueType> does not have a `from_json()` method of\n      the form `ValueType from_json(const basic_json&)`\n\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get__ValueType_const}\n\n    @since version 2.1.0\n    */\n    template < typename ValueType,\n               detail::enable_if_t <\n                   detail::is_default_constructible<ValueType>::value&&\n                   detail::has_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(\n                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))\n    {\n        auto ret = ValueType();\n        JSONSerializer<ValueType>::from_json(*this, ret);\n        return ret;\n    }\n\n    /*!\n    @brief get a value (explicit); special case\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    return JSONSerializer<ValueType>::from_json(*this);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json and\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `ValueType from_json(const basic_json&)`\n\n    @note If @ref json_serializer<ValueType> has both overloads of\n    `from_json()`, this one is chosen.\n\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @since version 2.1.0\n    */\n    template < typename ValueType,\n               detail::enable_if_t <\n                   detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(\n                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))\n    {\n        return JSONSerializer<ValueType>::from_json(*this);\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads converts the current @ref basic_json in a different\n    @ref basic_json type\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this, converted into @a BasicJsonType\n\n    @complexity Depending on the implementation of the called `from_json()`\n                method.\n\n    @since version 3.2.0\n    */\n    template < typename BasicJsonType,\n               detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value,\n                   int > = 0 >\n    BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads avoids a lot of template boilerplate, it can be seen as the\n    identity method\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this\n\n    @complexity Constant.\n\n    @since version 2.1.0\n    */\n    template<typename BasicJsonType,\n             detail::enable_if_t<\n                 std::is_same<BasicJsonType, basic_json_t>::value,\n                 int> = 0>\n    basic_json get_impl(detail::priority_tag<3> /*unused*/) const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n    @copydoc get()\n    */\n    template<typename PointerType,\n             detail::enable_if_t<\n                 std::is_pointer<PointerType>::value,\n                 int> = 0>\n    constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept\n    -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n  public:\n    /*!\n    @brief get a (pointer) value (explicit)\n\n    Performs explicit type conversion between the JSON value and a compatible value if required.\n\n    - If the requested type is a pointer to the internally stored JSON value that pointer is returned.\n    No copies are made.\n\n    - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible\n    from the current @ref basic_json.\n\n    - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`\n    method.\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @tparam ValueType if necessary\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required\n\n    @since version 2.1.0\n    */\n    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>\n#if defined(JSON_HAS_CPP_14)\n    constexpr\n#endif\n    auto get() const noexcept(\n    noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))\n    -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))\n    {\n        // we cannot static_assert on ValueTypeCV being non-const, because\n        // there is support for get<const basic_json_t>(), which is why we\n        // still need the uncvref\n        static_assert(!std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        return get_impl<ValueType>(detail::priority_tag<4> {});\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n\n    Explicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning The pointer becomes invalid if the underlying JSON object\n    changes.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get__PointerType}\n\n    @sa see @ref get_ptr() for explicit pointer-member access\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value.\n    The value is filled into the input parameter by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType v;\n    JSONSerializer<ValueType>::from_json(*this, v);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n\n    @tparam ValueType the input parameter type.\n\n    @return the input parameter, allowing chaining calls.\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get_to}\n\n    @since version 3.3.0\n    */\n    template < typename ValueType,\n               detail::enable_if_t <\n                   !detail::is_basic_json<ValueType>::value&&\n                   detail::has_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType & get_to(ValueType& v) const noexcept(noexcept(\n                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<ValueType>::from_json(*this, v);\n        return v;\n    }\n\n    // specialization to allow to call get_to with a basic_json value\n    // see https://github.com/nlohmann/json/issues/2175\n    template<typename ValueType,\n             detail::enable_if_t <\n                 detail::is_basic_json<ValueType>::value,\n                 int> = 0>\n    ValueType & get_to(ValueType& v) const\n    {\n        v = *this;\n        return v;\n    }\n\n    template <\n        typename T, std::size_t N,\n        typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n        detail::enable_if_t <\n            detail::has_from_json<basic_json_t, Array>::value, int > = 0 >\n    Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n    noexcept(noexcept(JSONSerializer<Array>::from_json(\n                          std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<Array>::from_json(*this, v);\n        return v;\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n\n    Implicit reference access to the internally stored JSON value. No copies\n    are made.\n\n    @warning Writing data to the referee of the result yields an undefined\n    state.\n\n    @tparam ReferenceType reference type; must be a reference to @ref array_t,\n    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or\n    @ref number_float_t. Enforced by static assertion.\n\n    @return reference to the internally stored JSON value if the requested\n    reference type @a ReferenceType fits to the JSON value; throws\n    type_error.303 otherwise\n\n    @throw type_error.303 in case passed type @a ReferenceType is incompatible\n    with the stored JSON value; see example below\n\n    @complexity Constant.\n\n    @liveexample{The example shows several calls to `get_ref()`.,get_ref}\n\n    @since version 1.1.0\n    */\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value, int>::type = 0>\n    ReferenceType get_ref()\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n    @copydoc get_ref()\n    */\n    template < typename ReferenceType, typename std::enable_if <\n                   std::is_reference<ReferenceType>::value&&\n                   std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >\n    ReferenceType get_ref() const\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a value (implicit)\n\n    Implicit type conversion between the JSON value and a compatible value.\n    The call is realized by calling @ref get() const.\n\n    @tparam ValueType non-pointer type compatible to the JSON value, for\n    instance `int` for JSON integer numbers, `bool` for JSON booleans, or\n    `std::vector` types for JSON arrays. The character type of @ref string_t\n    as well as an initializer list of this type is excluded to avoid\n    ambiguities as these types implicitly convert to `std::string`.\n\n    @return copy of the JSON value, converted to type @a ValueType\n\n    @throw type_error.302 in case passed type @a ValueType is incompatible\n    to the JSON value type (e.g., the JSON value is of type boolean, but a\n    string is requested); see example below\n\n    @complexity Linear in the size of the JSON value.\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,operator__ValueType}\n\n    @since version 1.0.0\n    */\n    template < typename ValueType, typename std::enable_if <\n                   detail::conjunction <\n                       detail::negation<std::is_pointer<ValueType>>,\n                       detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,\n                                        detail::negation<std::is_same<ValueType, typename string_t::value_type>>,\n                                        detail::negation<detail::is_basic_json<ValueType>>,\n                                        detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,\n\n#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))\n                                                detail::negation<std::is_same<ValueType, std::string_view>>,\n#endif\n                                                detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>\n                                                >::value, int >::type = 0 >\n                                        JSON_EXPLICIT operator ValueType() const\n    {\n        // delegate the call to get<>() const\n        return get<ValueType>();\n    }\n\n    /*!\n    @return reference to the binary value\n\n    @throw type_error.302 if the value is not binary\n\n    @sa see @ref is_binary() to check if the value is binary\n\n    @since version 3.8.0\n    */\n    binary_t& get_binary()\n    {\n        if (!is_binary())\n        {\n            JSON_THROW(type_error::create(302, \"type must be binary, but is \" + std::string(type_name()), *this));\n        }\n\n        return *get_ptr<binary_t*>();\n    }\n\n    /// @copydoc get_binary()\n    const binary_t& get_binary() const\n    {\n        if (!is_binary())\n        {\n            JSON_THROW(type_error::create(302, \"type must be binary, but is \" + std::string(type_name()), *this));\n        }\n\n        return *get_ptr<const binary_t*>();\n    }\n\n    /// @}\n\n\n    ////////////////////\n    // element access //\n    ////////////////////\n\n    /// @name element access\n    /// Access to the JSON value.\n    /// @{\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a reference to the element at specified location @a idx, with\n    bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__size_type}\n    */\n    reference at(size_type idx)\n    {\n        // at only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return set_parent(m_value.array->at(idx));\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\", *this));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a const reference to the element at specified location @a idx,\n    with bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__size_type_const}\n    */\n    const_reference at(size_type idx) const\n    {\n        // at only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\", *this));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a reference to the element at with specified key @a key, with\n    bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa see @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa see @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__object_t_key_type}\n    */\n    reference at(const typename object_t::key_type& key)\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return set_parent(m_value.object->at(key));\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\", *this));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a const reference to the element at with specified key @a key,\n    with bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa see @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa see @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__object_t_key_type_const}\n    */\n    const_reference at(const typename object_t::key_type& key) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\", *this));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a reference to the element at specified location @a idx.\n\n    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),\n    then the array is silently filled up with `null` values to make `idx` a\n    valid reference to the last stored element.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array or null; in that\n    cases, using the [] operator with an index makes no sense.\n\n    @complexity Constant if @a idx is in the range of the array. Otherwise\n    linear in `idx - size()`.\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `[]` operator. Note the addition of `null`\n    values.,operatorarray__size_type}\n\n    @since version 1.0.0\n    */\n    reference operator[](size_type idx)\n    {\n        // implicitly convert null value to an empty array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value.array = create<array_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // fill up array with null values if given idx is outside range\n            if (idx >= m_value.array->size())\n            {\n#if JSON_DIAGNOSTICS\n                // remember array size & capacity before resizing\n                const auto old_size = m_value.array->size();\n                const auto old_capacity = m_value.array->capacity();\n#endif\n                m_value.array->resize(idx + 1);\n\n#if JSON_DIAGNOSTICS\n                if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))\n                {\n                    // capacity has changed: update all parents\n                    set_parents();\n                }\n                else\n                {\n                    // set parent for values added above\n                    set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));\n                }\n#endif\n                assert_invariant();\n            }\n\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a const reference to the element at specified location @a idx.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array; in that case,\n    using the [] operator with an index makes no sense.\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how array elements can be read using\n    the `[]` operator.,operatorarray__size_type_const}\n\n    @since version 1.0.0\n    */\n    const_reference operator[](size_type idx) const\n    {\n        // const operator[] only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa see @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa see @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    reference operator[](const typename object_t::key_type& key)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            return set_parent(m_value.object->operator[](key));\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa see @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa see @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    const_reference operator[](const typename object_t::key_type& key) const\n    {\n        // const operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_ASSERT(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa see @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa see @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    JSON_HEDLEY_NON_NULL(2)\n    reference operator[](T* key)\n    {\n        // implicitly convert null to object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            return set_parent(m_value.object->operator[](key));\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa see @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa see @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    JSON_HEDLEY_NON_NULL(2)\n    const_reference operator[](T* key) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_ASSERT(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief access specified object element with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(key);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const typename object_t::key_type&), this function\n    does not throw if the given key @a key was not found.\n\n    @note Unlike @ref operator[](const typename object_t::key_type& key), this\n    function does not implicitly add an element to the position defined by @a\n    key. This function is furthermore also applicable to const objects.\n\n    @param[in] key  key of the element to access\n    @param[in] default_value  the value to return if @a key is not found\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.302 if @a default_value does not match the type of the\n    value at @a key\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value}\n\n    @sa see @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa see @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n\n    @since version 1.0.0\n    */\n    // using std::is_convertible in a std::enable_if will fail when using explicit conversions\n    template < class ValueType, typename std::enable_if <\n                   detail::is_getable<basic_json_t, ValueType>::value\n                   && !std::is_same<value_t, ValueType>::value, int >::type = 0 >\n    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(key);\n            if (it != end())\n            {\n                return it->template get<ValueType>();\n            }\n\n            return default_value;\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const\n    */\n    string_t value(const typename object_t::key_type& key, const char* default_value) const\n    {\n        return value(key, string_t(default_value));\n    }\n\n    /*!\n    @brief access specified object element via JSON Pointer with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(ptr);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const json_pointer&), this function does not throw\n    if the given key @a key was not found.\n\n    @param[in] ptr  a JSON pointer to the element to access\n    @param[in] default_value  the value to return if @a ptr found no value\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.302 if @a default_value does not match the type of the\n    value at @a ptr\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value_ptr}\n\n    @sa see @ref operator[](const json_pointer&) for unchecked access by reference\n\n    @since version 2.0.2\n    */\n    template<class ValueType, typename std::enable_if<\n                 detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>\n    ValueType value(const json_pointer& ptr, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if pointer resolves a value, return it or use default value\n            JSON_TRY\n            {\n                return ptr.get_checked(this).template get<ValueType>();\n            }\n            JSON_INTERNAL_CATCH (out_of_range&)\n            {\n                return default_value;\n            }\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const json_pointer&, ValueType) const\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    string_t value(const json_pointer& ptr, const char* default_value) const\n    {\n        return value(ptr, string_t(default_value));\n    }\n\n    /*!\n    @brief access the first element\n\n    Returns a reference to the first element in the container. For a JSON\n    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.\n\n    @return In case of a structured type (array or object), a reference to the\n    first element is returned. In case of number, string, boolean, or binary\n    values, a reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on `null` value\n\n    @liveexample{The following code shows an example for `front()`.,front}\n\n    @sa see @ref back() -- access the last element\n\n    @since version 1.0.0\n    */\n    reference front()\n    {\n        return *begin();\n    }\n\n    /*!\n    @copydoc basic_json::front()\n    */\n    const_reference front() const\n    {\n        return *cbegin();\n    }\n\n    /*!\n    @brief access the last element\n\n    Returns a reference to the last element in the container. For a JSON\n    container `c`, the expression `c.back()` is equivalent to\n    @code {.cpp}\n    auto tmp = c.end();\n    --tmp;\n    return *tmp;\n    @endcode\n\n    @return In case of a structured type (array or object), a reference to the\n    last element is returned. In case of number, string, boolean, or binary\n    values, a reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on a `null` value. See example\n    below.\n\n    @liveexample{The following code shows an example for `back()`.,back}\n\n    @sa see @ref front() -- access the first element\n\n    @since version 1.0.0\n    */\n    reference back()\n    {\n        auto tmp = end();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @copydoc basic_json::back()\n    */\n    const_reference back() const\n    {\n        auto tmp = cend();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @brief remove element given an iterator\n\n    Removes the element specified by iterator @a pos. The iterator @a pos must\n    be valid and dereferenceable. Thus the `end()` iterator (which is valid,\n    but is not dereferenceable) cannot be used as a value for @a pos.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] pos iterator to the element to remove\n    @return Iterator following the last removed element. If the iterator @a\n    pos refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.202 if called on an iterator which does not belong\n    to the current JSON value; example: `\"iterator does not fit current\n    value\"`\n    @throw invalid_iterator.205 if called on a primitive type with invalid\n    iterator (i.e., any iterator which is not `begin()`); example: `\"iterator\n    out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: amortized constant\n    - arrays: linear in distance between @a pos and the end of the container\n    - strings and binary: linear in the length of the member\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType}\n\n    @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa see @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa see @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template < class IteratorType, typename std::enable_if <\n                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||\n                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type\n               = 0 >\n    IteratorType erase(IteratorType pos)\n    {\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", *this));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            case value_t::binary:\n            {\n                if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))\n                {\n                    JSON_THROW(invalid_iterator::create(205, \"iterator out of range\", *this));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n                else if (is_binary())\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);\n                    m_value.binary = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name()), *this));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove elements given an iterator range\n\n    Removes the element specified by the range `[first; last)`. The iterator\n    @a first does not need to be dereferenceable if `first == last`: erasing\n    an empty range is a no-op.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] first iterator to the beginning of the range to remove\n    @param[in] last iterator past the end of the range to remove\n    @return Iterator following the last removed element. If the iterator @a\n    second refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.203 if called on iterators which does not belong\n    to the current JSON value; example: `\"iterators do not fit current value\"`\n    @throw invalid_iterator.204 if called on a primitive type with invalid\n    iterators (i.e., if `first != begin()` and `last != end()`); example:\n    `\"iterators out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: `log(size()) + std::distance(first, last)`\n    - arrays: linear in the distance between @a first and @a last, plus linear\n      in the distance between @a last and end of the container\n    - strings and binary: linear in the length of the member\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType_IteratorType}\n\n    @sa see @ref erase(IteratorType) -- removes the element at a given position\n    @sa see @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa see @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template < class IteratorType, typename std::enable_if <\n                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||\n                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type\n               = 0 >\n    IteratorType erase(IteratorType first, IteratorType last)\n    {\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(203, \"iterators do not fit current value\", *this));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            case value_t::binary:\n            {\n                if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()\n                                       || !last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\", *this));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n                else if (is_binary())\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);\n                    m_value.binary = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,\n                                              last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,\n                                             last.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name()), *this));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove element from a JSON object given a key\n\n    Removes elements from a JSON object with the key value @a key.\n\n    @param[in] key value of the elements to remove\n\n    @return Number of elements removed. If @a ObjectType is the default\n    `std::map` type, the return value will always be `0` (@a key was not\n    found) or `1` (@a key was found).\n\n    @post References and iterators to the erased elements are invalidated.\n    Other references and iterators are not affected.\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n\n    @complexity `log(size()) + count(key)`\n\n    @liveexample{The example shows the effect of `erase()`.,erase__key_type}\n\n    @sa see @ref erase(IteratorType) -- removes the element at a given position\n    @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa see @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    size_type erase(const typename object_t::key_type& key)\n    {\n        // this erase only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            return m_value.object->erase(key);\n        }\n\n        JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief remove element from a JSON array given an index\n\n    Removes element from a JSON array at the index @a idx.\n\n    @param[in] idx index of the element to remove\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n    @throw out_of_range.401 when `idx >= size()`; example: `\"array index 17\n    is out of range\"`\n\n    @complexity Linear in distance between @a idx and the end of the container.\n\n    @liveexample{The example shows the effect of `erase()`.,erase__size_type}\n\n    @sa see @ref erase(IteratorType) -- removes the element at a given position\n    @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa see @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n\n    @since version 1.0.0\n    */\n    void erase(const size_type idx)\n    {\n        // this erase only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            if (JSON_HEDLEY_UNLIKELY(idx >= size()))\n            {\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\", *this));\n            }\n\n            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));\n        }\n        else\n        {\n            JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /// @}\n\n\n    ////////////\n    // lookup //\n    ////////////\n\n    /// @name lookup\n    /// @{\n\n    /*!\n    @brief find an element in a JSON object\n\n    Finds an element in a JSON object with key equivalent to @a key. If the\n    element is not found or the JSON value is not an object, end() is\n    returned.\n\n    @note This method always returns @ref end() when executed on a JSON type\n          that is not an object.\n\n    @param[in] key key value of the element to search for.\n\n    @return Iterator to an element with key equivalent to @a key. If no such\n    element is found or the JSON value is not an object, past-the-end (see\n    @ref end()) iterator is returned.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `find()` is used.,find__key_type}\n\n    @sa see @ref contains(KeyT&&) const -- checks whether a key exists\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    iterator find(KeyT&& key)\n    {\n        auto result = end();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief find an element in a JSON object\n    @copydoc find(KeyT&&)\n    */\n    template<typename KeyT>\n    const_iterator find(KeyT&& key) const\n    {\n        auto result = cend();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief returns the number of occurrences of a key in a JSON object\n\n    Returns the number of elements with key @a key. If ObjectType is the\n    default `std::map` type, the return value will always be `0` (@a key was\n    not found) or `1` (@a key was found).\n\n    @note This method always returns `0` when executed on a JSON type that is\n          not an object.\n\n    @param[in] key key value of the element to count\n\n    @return Number of elements with key @a key. If the JSON value is not an\n    object, the return value will be `0`.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `count()` is used.,count}\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    size_type count(KeyT&& key) const\n    {\n        // return 0 for all nonobject types\n        return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;\n    }\n\n    /*!\n    @brief check the existence of an element in a JSON object\n\n    Check whether an element exists in a JSON object with key equivalent to\n    @a key. If the element is not found or the JSON value is not an object,\n    false is returned.\n\n    @note This method always returns false when executed on a JSON type\n          that is not an object.\n\n    @param[in] key key value to check its existence.\n\n    @return true if an element with specified @a key exists. If no such\n    element with such key is found or the JSON value is not an object,\n    false is returned.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The following code shows an example for `contains()`.,contains}\n\n    @sa see @ref find(KeyT&&) -- returns an iterator to an object element\n    @sa see @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer\n\n    @since version 3.6.0\n    */\n    template < typename KeyT, typename std::enable_if <\n                   !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int >::type = 0 >\n    bool contains(KeyT && key) const\n    {\n        return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();\n    }\n\n    /*!\n    @brief check the existence of an element in a JSON object given a JSON pointer\n\n    Check whether the given JSON pointer @a ptr can be resolved in the current\n    JSON value.\n\n    @note This method can be executed on any JSON value type.\n\n    @param[in] ptr JSON pointer to check its existence.\n\n    @return true if the JSON pointer can be resolved to a stored value, false\n    otherwise.\n\n    @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The following code shows an example for `contains()`.,contains_json_pointer}\n\n    @sa see @ref contains(KeyT &&) const -- checks the existence of a key\n\n    @since version 3.7.0\n    */\n    bool contains(const json_pointer& ptr) const\n    {\n        return ptr.contains(this);\n    }\n\n    /// @}\n\n\n    ///////////////\n    // iterators //\n    ///////////////\n\n    /// @name iterators\n    /// @{\n\n    /*!\n    @brief returns an iterator to the first element\n\n    Returns an iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `begin()`.,begin}\n\n    @sa see @ref cbegin() -- returns a const iterator to the beginning\n    @sa see @ref end() -- returns an iterator to the end\n    @sa see @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    iterator begin() noexcept\n    {\n        iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cbegin()\n    */\n    const_iterator begin() const noexcept\n    {\n        return cbegin();\n    }\n\n    /*!\n    @brief returns a const iterator to the first element\n\n    Returns a const iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.\n\n    @liveexample{The following code shows an example for `cbegin()`.,cbegin}\n\n    @sa see @ref begin() -- returns an iterator to the beginning\n    @sa see @ref end() -- returns an iterator to the end\n    @sa see @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    const_iterator cbegin() const noexcept\n    {\n        const_iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to one past the last element\n\n    Returns an iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `end()`.,end}\n\n    @sa see @ref cend() -- returns a const iterator to the end\n    @sa see @ref begin() -- returns an iterator to the beginning\n    @sa see @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    iterator end() noexcept\n    {\n        iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cend()\n    */\n    const_iterator end() const noexcept\n    {\n        return cend();\n    }\n\n    /*!\n    @brief returns a const iterator to one past the last element\n\n    Returns a const iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.\n\n    @liveexample{The following code shows an example for `cend()`.,cend}\n\n    @sa see @ref end() -- returns an iterator to the end\n    @sa see @ref begin() -- returns an iterator to the beginning\n    @sa see @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_iterator cend() const noexcept\n    {\n        const_iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-beginning\n\n    Returns an iterator to the reverse-beginning; that is, the last element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(end())`.\n\n    @liveexample{The following code shows an example for `rbegin()`.,rbegin}\n\n    @sa see @ref crbegin() -- returns a const reverse iterator to the beginning\n    @sa see @ref rend() -- returns a reverse iterator to the end\n    @sa see @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    reverse_iterator rbegin() noexcept\n    {\n        return reverse_iterator(end());\n    }\n\n    /*!\n    @copydoc basic_json::crbegin()\n    */\n    const_reverse_iterator rbegin() const noexcept\n    {\n        return crbegin();\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-end\n\n    Returns an iterator to the reverse-end; that is, one before the first\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(begin())`.\n\n    @liveexample{The following code shows an example for `rend()`.,rend}\n\n    @sa see @ref crend() -- returns a const reverse iterator to the end\n    @sa see @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa see @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    reverse_iterator rend() noexcept\n    {\n        return reverse_iterator(begin());\n    }\n\n    /*!\n    @copydoc basic_json::crend()\n    */\n    const_reverse_iterator rend() const noexcept\n    {\n        return crend();\n    }\n\n    /*!\n    @brief returns a const reverse iterator to the last element\n\n    Returns a const iterator to the reverse-beginning; that is, the last\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.\n\n    @liveexample{The following code shows an example for `crbegin()`.,crbegin}\n\n    @sa see @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa see @ref rend() -- returns a reverse iterator to the end\n    @sa see @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crbegin() const noexcept\n    {\n        return const_reverse_iterator(cend());\n    }\n\n    /*!\n    @brief returns a const reverse iterator to one before the first\n\n    Returns a const reverse iterator to the reverse-end; that is, one before\n    the first element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.\n\n    @liveexample{The following code shows an example for `crend()`.,crend}\n\n    @sa see @ref rend() -- returns a reverse iterator to the end\n    @sa see @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa see @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crend() const noexcept\n    {\n        return const_reverse_iterator(cbegin());\n    }\n\n  public:\n    /*!\n    @brief wrapper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without iterator_wrapper:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without iterator proxy:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with iterator proxy:\n\n    @code{cpp}\n    for (auto it : json::iterator_wrapper(j_object))\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example).\n\n    @param[in] ref  reference to a JSON value\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the wrapper is used,iterator_wrapper}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @note The name of this function is not yet final and may change in the\n    future.\n\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use @ref items() instead;\n                that is, replace `json::iterator_wrapper(j)` with `j.items()`.\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())\n    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @copydoc iterator_wrapper(reference)\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())\n    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @brief helper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without `items()` function:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without `items()` function:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with `items()` function:\n\n    @code{cpp}\n    for (auto& el : j_object.items())\n    {\n        std::cout << \"key: \" << el.key() << \", value:\" << el.value() << '\\n';\n    }\n    @endcode\n\n    The `items()` function also allows to use\n    [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)\n    (C++17):\n\n    @code{cpp}\n    for (auto& [key, val] : j_object.items())\n    {\n        std::cout << \"key: \" << key << \", value:\" << val << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example). For primitive types (e.g., numbers),\n          `key()` returns an empty string.\n\n    @warning Using `items()` on temporary objects is dangerous. Make sure the\n             object's lifetime exeeds the iteration. See\n             <https://github.com/nlohmann/json/issues/2040> for more\n             information.\n\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the function is used.,items}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 3.1.0, structured bindings support since 3.5.0.\n    */\n    iteration_proxy<iterator> items() noexcept\n    {\n        return iteration_proxy<iterator>(*this);\n    }\n\n    /*!\n    @copydoc items()\n    */\n    iteration_proxy<const_iterator> items() const noexcept\n    {\n        return iteration_proxy<const_iterator>(*this);\n    }\n\n    /// @}\n\n\n    //////////////\n    // capacity //\n    //////////////\n\n    /// @name capacity\n    /// @{\n\n    /*!\n    @brief checks whether the container is empty.\n\n    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `true`\n            boolean     | `false`\n            string      | `false`\n            number      | `false`\n            binary      | `false`\n            object      | result of function `object_t::empty()`\n            array       | result of function `array_t::empty()`\n\n    @liveexample{The following code uses `empty()` to check if a JSON\n    object contains any elements.,empty}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `empty()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return whether a string stored as JSON value\n    is empty - it returns whether the JSON container itself is empty which is\n    false in the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `begin() == end()`.\n\n    @sa see @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    bool empty() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return true;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::empty()\n                return m_value.array->empty();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::empty()\n                return m_value.object->empty();\n            }\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // all other types are nonempty\n                return false;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the number of elements\n\n    Returns the number of elements in a JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0`\n            boolean     | `1`\n            string      | `1`\n            number      | `1`\n            binary      | `1`\n            object      | result of function object_t::size()\n            array       | result of function array_t::size()\n\n    @liveexample{The following code calls `size()` on the different value\n    types.,size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their size() functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return the length of a string stored as JSON\n    value - it returns the number of elements in the JSON value which is 1 in\n    the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `std::distance(begin(), end())`.\n\n    @sa see @ref empty() -- checks whether the container is empty\n    @sa see @ref max_size() -- returns the maximal number of elements\n\n    @since version 1.0.0\n    */\n    size_type size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return 0;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::size()\n                return m_value.array->size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::size()\n                return m_value.object->size();\n            }\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // all other types have size 1\n                return 1;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the maximum possible number of elements\n\n    Returns the maximum number of elements a JSON value is able to hold due to\n    system or library implementation limitations, i.e. `std::distance(begin(),\n    end())` for the JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0` (same as `size()`)\n            boolean     | `1` (same as `size()`)\n            string      | `1` (same as `size()`)\n            number      | `1` (same as `size()`)\n            binary      | `1` (same as `size()`)\n            object      | result of function `object_t::max_size()`\n            array       | result of function `array_t::max_size()`\n\n    @liveexample{The following code calls `max_size()` on the different value\n    types. Note the output is implementation specific.,max_size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `max_size()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of returning `b.size()` where `b` is the largest\n      possible JSON value.\n\n    @sa see @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    size_type max_size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::array:\n            {\n                // delegate call to array_t::max_size()\n                return m_value.array->max_size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::max_size()\n                return m_value.object->max_size();\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // all other types have max_size() == size()\n                return size();\n            }\n        }\n    }\n\n    /// @}\n\n\n    ///////////////\n    // modifiers //\n    ///////////////\n\n    /// @name modifiers\n    /// @{\n\n    /*!\n    @brief clears the contents\n\n    Clears the content of a JSON value and resets it to the default value as\n    if @ref basic_json(value_t) would have been called with the current value\n    type from @ref type():\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    binary      | An empty byte vector\n    object      | `{}`\n    array       | `[]`\n\n    @post Has the same effect as calling\n    @code {.cpp}\n    *this = basic_json(type());\n    @endcode\n\n    @liveexample{The example below shows the effect of `clear()` to different\n    JSON types.,clear}\n\n    @complexity Linear in the size of the JSON value.\n\n    @iterators All iterators, pointers and references related to this container\n               are invalidated.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @sa see @ref basic_json(value_t) -- constructor that creates an object with the\n        same value than calling `clear()`\n\n    @since version 1.0.0\n    */\n    void clear() noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = 0;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = 0;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = 0.0;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = false;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value.string->clear();\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_value.binary->clear();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array->clear();\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object->clear();\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Appends the given element @a val to the end of the JSON value. If the\n    function is called on a JSON null value, an empty array is created before\n    appending @a val.\n\n    @param[in] val the value to add to the JSON array\n\n    @throw type_error.308 when called on a type other than JSON array or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON array. Note how the `null` value was silently\n    converted to a JSON array.,push_back}\n\n    @since version 1.0.0\n    */\n    void push_back(basic_json&& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name()), *this));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (move semantics)\n        const auto old_capacity = m_value.array->capacity();\n        m_value.array->push_back(std::move(val));\n        set_parent(m_value.array->back(), old_capacity);\n        // if val is moved from, basic_json move constructor marks it null so we do not call the destructor\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(basic_json&& val)\n    {\n        push_back(std::move(val));\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    void push_back(const basic_json& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name()), *this));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array\n        const auto old_capacity = m_value.array->capacity();\n        m_value.array->push_back(val);\n        set_parent(m_value.array->back(), old_capacity);\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(const basic_json& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    Inserts the given element @a val to the JSON object. If the function is\n    called on a JSON null value, an empty object is created before inserting\n    @a val.\n\n    @param[in] val the value to add to the JSON object\n\n    @throw type_error.308 when called on a type other than JSON object or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON object. Note how the `null` value was silently\n    converted to a JSON object.,push_back__object_t__value}\n\n    @since version 1.0.0\n    */\n    void push_back(const typename object_t::value_type& val)\n    {\n        // push_back only works for null objects or objects\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name()), *this));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to object\n        auto res = m_value.object->insert(val);\n        set_parent(res.first->second);\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(const typename object_t::value_type&)\n    */\n    reference operator+=(const typename object_t::value_type& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    This function allows to use `push_back` with an initializer list. In case\n\n    1. the current value is an object,\n    2. the initializer list @a d2Init contains only two elements, and\n    3. the first element of @a d2Init is a string,\n\n    @a d2Init is converted into an object element and added using\n    @ref push_back(const typename object_t::value_type&). Otherwise, @a d2Init\n    is converted to a JSON value and added using @ref push_back(basic_json&&).\n\n    @param[in] init  an initializer list\n\n    @complexity Linear in the size of the initializer list @a d2Init.\n\n    @note This function is required to resolve an ambiguous overload error,\n          because pairs like `{\"key\", \"value\"}` can be both interpreted as\n          `object_t::value_type` or `std::initializer_list<basic_json>`, see\n          https://github.com/nlohmann/json/issues/235 for more information.\n\n    @liveexample{The example shows how initializer lists are treated as\n    objects when possible.,push_back__initializer_list}\n    */\n    void push_back(initializer_list_t init)\n    {\n        if (is_object() && init.size() == 2 && (*init.begin())->is_string())\n        {\n            basic_json&& key = init.begin()->moved_or_copied();\n            push_back(typename object_t::value_type(\n                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));\n        }\n        else\n        {\n            push_back(basic_json(init));\n        }\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(initializer_list_t)\n    */\n    reference operator+=(initializer_list_t init)\n    {\n        push_back(init);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Creates a JSON value from the passed parameters @a args to the end of the\n    JSON value. If the function is called on a JSON null value, an empty array\n    is created before appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @return reference to the inserted element\n\n    @throw type_error.311 when called on a type other than JSON array or\n    null; example: `\"cannot use emplace_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` can be used to add\n    elements to a JSON array. Note how the `null` value was silently converted\n    to a JSON array.,emplace_back}\n\n    @since version 2.0.8, returns reference since 3.7.0\n    */\n    template<class... Args>\n    reference emplace_back(Args&& ... args)\n    {\n        // emplace_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace_back() with \" + std::string(type_name()), *this));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        const auto old_capacity = m_value.array->capacity();\n        m_value.array->emplace_back(std::forward<Args>(args)...);\n        return set_parent(m_value.array->back(), old_capacity);\n    }\n\n    /*!\n    @brief add an object to an object if key does not exist\n\n    Inserts a new element into a JSON object constructed in-place with the\n    given @a args if there is no element with the key in the container. If the\n    function is called on a JSON null value, an empty object is created before\n    appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @return a pair consisting of an iterator to the inserted element, or the\n            already-existing element if no insertion happened, and a bool\n            denoting whether the insertion took place.\n\n    @throw type_error.311 when called on a type other than JSON object or\n    null; example: `\"cannot use emplace() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `emplace()` can be used to add elements\n    to a JSON object. Note how the `null` value was silently converted to a\n    JSON object. Further note how no value is added if there was already one\n    value stored with the same key.,emplace}\n\n    @since version 2.0.8\n    */\n    template<class... Args>\n    std::pair<iterator, bool> emplace(Args&& ... args)\n    {\n        // emplace only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace() with \" + std::string(type_name()), *this));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        auto res = m_value.object->emplace(std::forward<Args>(args)...);\n        set_parent(res.first->second);\n\n        // create result iterator and set iterator to the result of emplace\n        auto it = begin();\n        it.m_it.object_iterator = res.first;\n\n        // return pair of iterator and boolean\n        return {it, res.second};\n    }\n\n    /// Helper for insertion of an iterator\n    /// @note: This uses std::distance to support GCC 4.8,\n    ///        see https://github.com/nlohmann/json/pull/1257\n    template<typename... Args>\n    iterator insert_iterator(const_iterator pos, Args&& ... args)\n    {\n        iterator result(this);\n        JSON_ASSERT(m_value.array != nullptr);\n\n        auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);\n        m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);\n        result.m_it.array_iterator = m_value.array->begin() + insert_pos;\n\n        // This could have been written as:\n        // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);\n        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.\n\n        set_parents();\n        return result;\n    }\n\n    /*!\n    @brief inserts element\n\n    Inserts element @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] val element to insert\n    @return iterator pointing to the inserted @a val.\n\n    @throw type_error.309 if called on JSON values other than arrays;\n    example: `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Constant plus linear in the distance between @a pos and end of\n    the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", *this));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief inserts element\n    @copydoc insert(const_iterator, const basic_json&)\n    */\n    iterator insert(const_iterator pos, basic_json&& val)\n    {\n        return insert(pos, val);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts @a cnt copies of @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] cnt number of copies of @a val to insert\n    @param[in] val element to insert\n    @return iterator pointing to the first element inserted, or @a pos if\n    `cnt==0`\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Linear in @a cnt plus linear in the distance between @a pos\n    and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__count}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", *this));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, cnt, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name()), *this));\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)` before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n    @throw invalid_iterator.211 if @a first or @a last are iterators into\n    container for which insert is called; example: `\"passed iterators may not\n    belong to container\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `first==last`\n\n    @complexity Linear in `std::distance(first, last)` plus linear in the\n    distance between @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const_iterator first, const_iterator last)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_UNLIKELY(!is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name()), *this));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", *this));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\", *this));\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(first.m_object == this))\n        {\n            JSON_THROW(invalid_iterator::create(211, \"passed iterators may not belong to container\", *this));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from initializer list @a ilist before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] ilist initializer list to insert the values from\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `ilist` is empty\n\n    @complexity Linear in `ilist.size()` plus linear in the distance between\n    @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__ilist}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, initializer_list_t ilist)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_UNLIKELY(!is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name()), *this));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", *this));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, ilist.begin(), ilist.end());\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)`.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than objects; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number\n    of elements to insert.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range_object}\n\n    @since version 3.0.0\n    */\n    void insert(const_iterator first, const_iterator last)\n    {\n        // insert only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name()), *this));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\", *this));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\", *this));\n        }\n\n        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from JSON object @a j and overwrites existing keys.\n\n    @param[in] j  JSON object to read values from\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_reference j)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name()), *this));\n        }\n        if (JSON_HEDLEY_UNLIKELY(!j.is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(j.type_name()), *this));\n        }\n\n        for (auto it = j.cbegin(); it != j.cend(); ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n#if JSON_DIAGNOSTICS\n            m_value.object->operator[](it.key()).m_parent = this;\n#endif\n        }\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from from range `[first, last)` and overwrites existing\n    keys.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used__range.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_iterator first, const_iterator last)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name()), *this));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\", *this));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()\n                                 || !last.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\", *this));\n        }\n\n        for (auto it = first; it != last; ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n#if JSON_DIAGNOSTICS\n            m_value.object->operator[](it.key()).m_parent = this;\n#endif\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of the JSON value with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other JSON value to exchange the contents with\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how JSON values can be swapped with\n    `swap()`.,swap__reference}\n\n    @since version 1.0.0\n    */\n    void swap(reference other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        std::swap(m_type, other.m_type);\n        std::swap(m_value, other.m_value);\n\n        set_parents();\n        other.set_parents();\n        assert_invariant();\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of the JSON value from @a left with those of @a right. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated. implemented as a friend function callable via ADL.\n\n    @param[in,out] left JSON value to exchange the contents with\n    @param[in,out] right JSON value to exchange the contents with\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how JSON values can be swapped with\n    `swap()`.,swap__reference}\n\n    @since version 1.0.0\n    */\n    friend void swap(reference left, reference right) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        left.swap(right);\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON array with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other array to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an array; example: `\"cannot\n    use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how arrays can be swapped with\n    `swap()`.,swap__array_t}\n\n    @since version 1.0.0\n    */\n    void swap(array_t& other) // NOLINT(bugprone-exception-escape)\n    {\n        // swap only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            std::swap(*(m_value.array), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON object with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other object to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an object; example:\n    `\"cannot use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how objects can be swapped with\n    `swap()`.,swap__object_t}\n\n    @since version 1.0.0\n    */\n    void swap(object_t& other) // NOLINT(bugprone-exception-escape)\n    {\n        // swap only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            std::swap(*(m_value.object), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON string with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other string to exchange the contents with\n\n    @throw type_error.310 when JSON value is not a string; example: `\"cannot\n    use swap() with boolean\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how strings can be swapped with\n    `swap()`.,swap__string_t}\n\n    @since version 1.0.0\n    */\n    void swap(string_t& other) // NOLINT(bugprone-exception-escape)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_string()))\n        {\n            std::swap(*(m_value.string), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON string with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other binary to exchange the contents with\n\n    @throw type_error.310 when JSON value is not a string; example: `\"cannot\n    use swap() with boolean\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how strings can be swapped with\n    `swap()`.,swap__binary_t}\n\n    @since version 3.8.0\n    */\n    void swap(binary_t& other) // NOLINT(bugprone-exception-escape)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_binary()))\n        {\n            std::swap(*(m_value.binary), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /// @copydoc swap(binary_t&)\n    void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_binary()))\n        {\n            std::swap(*(m_value.binary), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name()), *this));\n        }\n    }\n\n    /// @}\n\n  public:\n    //////////////////////////////////////////\n    // lexicographical comparison operators //\n    //////////////////////////////////////////\n\n    /// @name lexicographical comparison operators\n    /// @{\n\n    /*!\n    @brief comparison: equal\n\n    Compares two JSON values for equality according to the following rules:\n    - Two JSON values are equal if (1) they are from the same type and (2)\n      their stored values are the same according to their respective\n      `operator==`.\n    - Integer and floating-point numbers are automatically converted before\n      comparison. Note that two NaN values are always treated as unequal.\n    - Two JSON null values are equal.\n\n    @note Floating-point inside JSON values numbers are compared with\n    `json::number_float_t::operator==` which is `double::operator==` by\n    default. To compare floating-point while respecting an epsilon, an alternative\n    [comparison function](https://github.com/mariokonrad/marnav/blob/master/include/marnav/math/floatingpoint.hpp#L34-#L39)\n    could be used, for instance\n    @code {.cpp}\n    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>\n    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept\n    {\n        return std::abs(a - b) <= epsilon;\n    }\n    @endcode\n    Or you can self-defined operator equal function like this:\n    @code {.cpp}\n    bool my_equal(const_reference lhs, const_reference rhs) {\n    const auto lhs_type lhs.type();\n    const auto rhs_type rhs.type();\n    if (lhs_type == rhs_type) {\n        switch(lhs_type)\n            // self_defined case\n            case value_t::number_float:\n                return std::abs(lhs - rhs) <= std::numeric_limits<float>::epsilon();\n            // other cases remain the same with the original\n            ...\n    }\n    ...\n    }\n    @endcode\n\n    @note NaN values never compare equal to themselves or to other NaN values.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are equal\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Linear.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__equal}\n\n    @since version 1.0.0\n    */\n    friend bool operator==(const_reference lhs, const_reference rhs) noexcept\n    {\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    return *lhs.m_value.array == *rhs.m_value.array;\n\n                case value_t::object:\n                    return *lhs.m_value.object == *rhs.m_value.object;\n\n                case value_t::null:\n                    return true;\n\n                case value_t::string:\n                    return *lhs.m_value.string == *rhs.m_value.string;\n\n                case value_t::boolean:\n                    return lhs.m_value.boolean == rhs.m_value.boolean;\n\n                case value_t::number_integer:\n                    return lhs.m_value.number_integer == rhs.m_value.number_integer;\n\n                case value_t::number_unsigned:\n                    return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;\n\n                case value_t::number_float:\n                    return lhs.m_value.number_float == rhs.m_value.number_float;\n\n                case value_t::binary:\n                    return *lhs.m_value.binary == *rhs.m_value.binary;\n\n                case value_t::discarded:\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)\n        {\n            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)\n        {\n            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n        }\n\n        return false;\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs == basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) == rhs;\n    }\n\n    /*!\n    @brief comparison: not equal\n\n    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are not equal\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__notequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(lhs == rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs != basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) != rhs;\n    }\n\n    /*!\n    @brief comparison: less than\n\n    Compares whether one JSON value @a lhs is less than another JSON value @a\n    rhs according to the following rules:\n    - If @a lhs and @a rhs have the same type, the values are compared using\n      the default `<` operator.\n    - Integer and floating-point numbers are automatically converted before\n      comparison\n    - In case @a lhs and @a rhs have different types, the values are ignored\n      and the order of the types is considered, see\n      @ref operator<(const value_t, const value_t).\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__less}\n\n    @since version 1.0.0\n    */\n    friend bool operator<(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    // note parentheses are necessary, see\n                    // https://github.com/nlohmann/json/issues/1530\n                    return (*lhs.m_value.array) < (*rhs.m_value.array);\n\n                case value_t::object:\n                    return (*lhs.m_value.object) < (*rhs.m_value.object);\n\n                case value_t::null:\n                    return false;\n\n                case value_t::string:\n                    return (*lhs.m_value.string) < (*rhs.m_value.string);\n\n                case value_t::boolean:\n                    return (lhs.m_value.boolean) < (rhs.m_value.boolean);\n\n                case value_t::number_integer:\n                    return (lhs.m_value.number_integer) < (rhs.m_value.number_integer);\n\n                case value_t::number_unsigned:\n                    return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned);\n\n                case value_t::number_float:\n                    return (lhs.m_value.number_float) < (rhs.m_value.number_float);\n\n                case value_t::binary:\n                    return (*lhs.m_value.binary) < (*rhs.m_value.binary);\n\n                case value_t::discarded:\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)\n        {\n            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;\n        }\n\n        // We only reach this line if we cannot compare values. In that case,\n        // we compare types. Note we have to call the operator explicitly,\n        // because MSVC has problems otherwise.\n        return operator<(lhs_type, rhs_type);\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs < basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) < rhs;\n    }\n\n    /*!\n    @brief comparison: less than or equal\n\n    Compares whether one JSON value @a lhs is less than or equal to another\n    JSON value by calculating `not (rhs < lhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greater}\n\n    @since version 1.0.0\n    */\n    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(rhs < lhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs <= basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) <= rhs;\n    }\n\n    /*!\n    @brief comparison: greater than\n\n    Compares whether one JSON value @a lhs is greater than another\n    JSON value by calculating `not (lhs <= rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__lessequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(lhs <= rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs > basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) > rhs;\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n\n    Compares whether one JSON value @a lhs is greater than or equal to another\n    JSON value by calculating `not (lhs < rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greaterequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(lhs < rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs >= basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) >= rhs;\n    }\n\n    /// @}\n\n    ///////////////////\n    // serialization //\n    ///////////////////\n\n    /// @name serialization\n    /// @{\n#ifndef JSON_NO_IO\n    /*!\n    @brief serialize to stream\n\n    Serialize the given JSON value @a j to the output stream @a o. The JSON\n    value will be serialized using the @ref dump member function.\n\n    - The indentation of the output can be controlled with the member variable\n      `width` of the output stream @a o. For instance, using the manipulator\n      `std::setw(4)` on @a o sets the indentation level to `4` and the\n      serialization result is the same as calling `dump(4)`.\n\n    - The indentation character can be controlled with the member variable\n      `fill` of the output stream @a o. For instance, the manipulator\n      `std::setfill('\\\\t')` sets indentation to use a tab character rather than\n      the default space character.\n\n    @param[in,out] o  stream to serialize to\n    @param[in] j  JSON value to serialize\n\n    @return the stream @a o\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded\n\n    @complexity Linear.\n\n    @liveexample{The example below shows the serialization with different\n    parameters to `width` to adjust the indentation level.,operator_serialize}\n\n    @since version 1.0.0; indentation character added in version 3.0.0\n    */\n    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)\n    {\n        // read width member and use it as indentation parameter if nonzero\n        const bool pretty_print = o.width() > 0;\n        const auto indentation = pretty_print ? o.width() : 0;\n\n        // reset width to 0 for subsequent calls to this stream\n        o.width(0);\n\n        // do the actual serialization\n        serializer s(detail::output_adapter<char>(o), o.fill());\n        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));\n        return o;\n    }\n\n    /*!\n    @brief serialize to stream\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use\n                @ref operator<<(std::ostream&, const basic_json&)\n                instead; that is, replace calls like `j >> o;` with `o << j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))\n    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)\n    {\n        return o << j;\n    }\n#endif  // JSON_NO_IO\n    /// @}\n\n\n    /////////////////////\n    // deserialization //\n    /////////////////////\n\n    /// @name deserialization\n    /// @{\n\n    /*!\n    @brief deserialize from a compatible input\n\n    @tparam InputType A compatible input, for instance\n    - an std::istream object\n    - a FILE pointer\n    - a C-style array of characters\n    - a pointer to a null-terminated string of single byte characters\n    - an object obj for which begin(obj) and end(obj) produces a valid pair of\n      iterators.\n\n    @param[in] i  input to read from\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the parser callback function\n    @a cb or reading from the input @a i has a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from an array.,parse__array__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__string__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__istream__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}\n\n    @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to\n    ignore comments.\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json parse(InputType&& i,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);\n        return result;\n    }\n\n    /*!\n    @brief deserialize from a pair of character iterators\n\n    The value_type of the iterator must be a integral type with size of 1, 2 or\n    4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32.\n\n    @param[in] first iterator to start of character range\n    @param[in] last  iterator to end of character range\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json parse(IteratorType first,\n                            IteratorType last,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);\n        return result;\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))\n    static basic_json parse(detail::span_input_adapter&& i,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);\n        return result;\n    }\n\n    /*!\n    @brief check if the input is valid JSON\n\n    Unlike the @ref parse(InputType&&, const parser_callback_t,const bool)\n    function, this function neither throws an exception in case of invalid JSON\n    input (i.e., a parse error) nor creates diagnostic information.\n\n    @tparam InputType A compatible input, for instance\n    - an std::istream object\n    - a FILE pointer\n    - a C-style array of characters\n    - a pointer to a null-terminated string of single byte characters\n    - an object obj for which begin(obj) and end(obj) produces a valid pair of\n      iterators.\n\n    @param[in] i input to read from\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default)\n\n    @return Whether the input read from @a i is valid JSON.\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `accept()` function reading\n    from a string.,accept__string}\n    */\n    template<typename InputType>\n    static bool accept(InputType&& i,\n                       const bool ignore_comments = false)\n    {\n        return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);\n    }\n\n    template<typename IteratorType>\n    static bool accept(IteratorType first, IteratorType last,\n                       const bool ignore_comments = false)\n    {\n        return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))\n    static bool accept(detail::span_input_adapter&& i,\n                       const bool ignore_comments = false)\n    {\n        return parser(i.get(), nullptr, false, ignore_comments).accept(true);\n    }\n\n    /*!\n    @brief generate SAX events\n\n    The SAX event lister must follow the interface of @ref json_sax.\n\n    This function reads from a compatible input. Examples are:\n    - an std::istream object\n    - a FILE pointer\n    - a C-style array of characters\n    - a pointer to a null-terminated string of single byte characters\n    - an object obj for which begin(obj) and end(obj) produces a valid pair of\n      iterators.\n\n    @param[in] i  input to read from\n    @param[in,out] sax  SAX event listener\n    @param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)\n    @param[in] strict  whether the input has to be consumed completely\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default); only applies to the JSON file format.\n\n    @return return value of the last processed SAX event\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the SAX consumer @a sax has\n    a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `sax_parse()` function\n    reading from string and processing the events with a user-defined SAX\n    event consumer.,sax_parse}\n\n    @since version 3.2.0\n    */\n    template <typename InputType, typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    static bool sax_parse(InputType&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);\n    }\n\n    template<class IteratorType, class SAX>\n    JSON_HEDLEY_NON_NULL(3)\n    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);\n    }\n\n    template <typename SAX>\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))\n    JSON_HEDLEY_NON_NULL(2)\n    static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = i.get();\n        return format == input_format_t::json\n               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);\n    }\n#ifndef JSON_NO_IO\n    /*!\n    @brief deserialize from stream\n    @deprecated This stream operator is deprecated and will be removed in\n                version 4.0.0 of the library. Please use\n                @ref operator>>(std::istream&, basic_json&)\n                instead; that is, replace calls like `j << i;` with `i >> j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))\n    friend std::istream& operator<<(basic_json& j, std::istream& i)\n    {\n        return operator>>(i, j);\n    }\n\n    /*!\n    @brief deserialize from stream\n\n    Deserializes an input stream to a JSON value.\n\n    @param[in,out] i  input stream to read a serialized JSON value from\n    @param[in,out] j  JSON value to write the deserialized input to\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below shows how a JSON value is constructed by\n    reading a serialization from a stream.,operator_deserialize}\n\n    @sa parse(std::istream&, const parser_callback_t) for a variant with a\n    parser callback function to filter values while parsing\n\n    @since version 1.0.0\n    */\n    friend std::istream& operator>>(std::istream& i, basic_json& j)\n    {\n        parser(detail::input_adapter(i)).parse(false, j);\n        return i;\n    }\n#endif  // JSON_NO_IO\n    /// @}\n\n    ///////////////////////////\n    // convenience functions //\n    ///////////////////////////\n\n    /*!\n    @brief return the type as string\n\n    Returns the type name as string to be used in error messages - usually to\n    indicate that a function was called on a wrong JSON type.\n\n    @return a string representation of a the @a m_type member:\n            Value type  | return value\n            ----------- | -------------\n            null        | `\"null\"`\n            boolean     | `\"boolean\"`\n            string      | `\"string\"`\n            number      | `\"number\"` (for all number types)\n            object      | `\"object\"`\n            array       | `\"array\"`\n            binary      | `\"binary\"`\n            discarded   | `\"discarded\"`\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Constant.\n\n    @liveexample{The following code exemplifies `type_name()` for all JSON\n    types.,type_name}\n\n    @sa see @ref type() -- return the type of the JSON value\n    @sa see @ref operator value_t() -- return the type of the JSON value (implicit)\n\n    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`\n    since 3.0.0\n    */\n    JSON_HEDLEY_RETURNS_NON_NULL\n    const char* type_name() const noexcept\n    {\n        {\n            switch (m_type)\n            {\n                case value_t::null:\n                    return \"null\";\n                case value_t::object:\n                    return \"object\";\n                case value_t::array:\n                    return \"array\";\n                case value_t::string:\n                    return \"string\";\n                case value_t::boolean:\n                    return \"boolean\";\n                case value_t::binary:\n                    return \"binary\";\n                case value_t::discarded:\n                    return \"discarded\";\n                case value_t::number_integer:\n                case value_t::number_unsigned:\n                case value_t::number_float:\n                default:\n                    return \"number\";\n            }\n        }\n    }\n\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    //////////////////////\n    // member variables //\n    //////////////////////\n\n    /// the type of the current element\n    value_t m_type = value_t::null;\n\n    /// the value of the current element\n    json_value m_value = {};\n\n#if JSON_DIAGNOSTICS\n    /// a pointer to a parent value (for debugging purposes)\n    basic_json* m_parent = nullptr;\n#endif\n\n    //////////////////////////////////////////\n    // binary serialization/deserialization //\n    //////////////////////////////////////////\n\n    /// @name binary serialization/deserialization support\n    /// @{\n\n  public:\n    /*!\n    @brief create a CBOR serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise\n    Binary Object Representation) serialization format. CBOR is a binary\n    serialization format which aims to be more compact than JSON itself, yet\n    more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    CBOR types according to the CBOR specification (RFC 7049):\n\n    JSON value type | value/range                                | CBOR type                          | first byte\n    --------------- | ------------------------------------------ | ---------------------------------- | ---------------\n    null            | `null`                                     | Null                               | 0xF6\n    boolean         | `true`                                     | True                               | 0xF5\n    boolean         | `false`                                    | False                              | 0xF4\n    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B\n    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A\n    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39\n    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38\n    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37\n    number_integer  | 0..23                                      | Integer                            | 0x00..0x17\n    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17\n    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_float    | *any value representable by a float*       | Single-Precision Float             | 0xFA\n    number_float    | *any value NOT representable by a float*   | Double-Precision Float             | 0xFB\n    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77\n    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78\n    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79\n    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A\n    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B\n    array           | *size*: 0..23                              | array                              | 0x80..0x97\n    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98\n    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99\n    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A\n    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B\n    object          | *size*: 0..23                              | map                                | 0xA0..0xB7\n    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8\n    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9\n    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA\n    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB\n    binary          | *size*: 0..23                              | byte string                        | 0x40..0x57\n    binary          | *size*: 23..255                            | byte string (1 byte follow)        | 0x58\n    binary          | *size*: 256..65535                         | byte string (2 bytes follow)       | 0x59\n    binary          | *size*: 65536..4294967295                  | byte string (4 bytes follow)       | 0x5A\n    binary          | *size*: 4294967296..18446744073709551615   | byte string (8 bytes follow)       | 0x5B\n\n    Binary values with subtype are mapped to tagged values (0xD8..0xDB)\n    depending on the subtype, followed by a byte string, see \"binary\" cells\n    in the table above.\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a CBOR value.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The following CBOR types are not used in the conversion:\n          - UTF-8 strings terminated by \"break\" (0x7F)\n          - arrays terminated by \"break\" (0x9F)\n          - maps terminated by \"break\" (0xBF)\n          - byte strings terminated by \"break\" (0x5F)\n          - date/time (0xC0..0xC1)\n          - bignum (0xC2..0xC3)\n          - decimal fraction (0xC4)\n          - bigfloat (0xC5)\n          - expected conversions (0xD5..0xD7)\n          - simple values (0xE0..0xF3, 0xF8)\n          - undefined (0xF7)\n          - half-precision floats (0xF9)\n          - break (0xFF)\n\n    @param[in] j  JSON value to serialize\n    @return CBOR serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in CBOR format.,to_cbor}\n\n    @sa http://cbor.io\n    @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the\n        analogous deserialization\n    @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format\n    @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9; compact representation of floating-point numbers\n           since version 3.8.0\n    */\n    static std::vector<std::uint8_t> to_cbor(const basic_json& j)\n    {\n        std::vector<std::uint8_t> result;\n        to_cbor(j, result);\n        return result;\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)\n    {\n        binary_writer<std::uint8_t>(o).write_cbor(j);\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_cbor(j);\n    }\n\n    /*!\n    @brief create a MessagePack serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the MessagePack\n    serialization format. MessagePack is a binary serialization format which\n    aims to be more compact than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    MessagePack types according to the MessagePack specification:\n\n    JSON value type | value/range                       | MessagePack type | first byte\n    --------------- | --------------------------------- | ---------------- | ----------\n    null            | `null`                            | nil              | 0xC0\n    boolean         | `true`                            | true             | 0xC3\n    boolean         | `false`                           | false            | 0xC2\n    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3\n    number_integer  | -2147483648..-32769               | int32            | 0xD2\n    number_integer  | -32768..-129                      | int16            | 0xD1\n    number_integer  | -128..-33                         | int8             | 0xD0\n    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF\n    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F\n    number_integer  | 128..255                          | uint 8           | 0xCC\n    number_integer  | 256..65535                        | uint 16          | 0xCD\n    number_integer  | 65536..4294967295                 | uint 32          | 0xCE\n    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F\n    number_unsigned | 128..255                          | uint 8           | 0xCC\n    number_unsigned | 256..65535                        | uint 16          | 0xCD\n    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE\n    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_float    | *any value representable by a float*     | float 32 | 0xCA\n    number_float    | *any value NOT representable by a float* | float 64 | 0xCB\n    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF\n    string          | *length*: 32..255                 | str 8            | 0xD9\n    string          | *length*: 256..65535              | str 16           | 0xDA\n    string          | *length*: 65536..4294967295       | str 32           | 0xDB\n    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F\n    array           | *size*: 16..65535                 | array 16         | 0xDC\n    array           | *size*: 65536..4294967295         | array 32         | 0xDD\n    object          | *size*: 0..15                     | fix map          | 0x80..0x8F\n    object          | *size*: 16..65535                 | map 16           | 0xDE\n    object          | *size*: 65536..4294967295         | map 32           | 0xDF\n    binary          | *size*: 0..255                    | bin 8            | 0xC4\n    binary          | *size*: 256..65535                | bin 16           | 0xC5\n    binary          | *size*: 65536..4294967295         | bin 32           | 0xC6\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a MessagePack value.\n\n    @note The following values can **not** be converted to a MessagePack value:\n          - strings with more than 4294967295 bytes\n          - byte strings with more than 4294967295 bytes\n          - arrays with more than 4294967295 elements\n          - objects with more than 4294967295 elements\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @param[in] j  JSON value to serialize\n    @return MessagePack serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in MessagePack format.,to_msgpack}\n\n    @sa http://msgpack.org\n    @sa see @ref from_msgpack for the analogous deserialization\n    @sa see @ref to_cbor(const basic_json& for the related CBOR format\n    @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9\n    */\n    static std::vector<std::uint8_t> to_msgpack(const basic_json& j)\n    {\n        std::vector<std::uint8_t> result;\n        to_msgpack(j, result);\n        return result;\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)\n    {\n        binary_writer<std::uint8_t>(o).write_msgpack(j);\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_msgpack(j);\n    }\n\n    /*!\n    @brief create a UBJSON serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the UBJSON\n    (Universal Binary JSON) serialization format. UBJSON aims to be more compact\n    than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    UBJSON types according to the UBJSON specification:\n\n    JSON value type | value/range                       | UBJSON type | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | `Z`\n    boolean         | `true`                            | true        | `T`\n    boolean         | `false`                           | false       | `F`\n    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`\n    number_integer  | -2147483648..-32769               | int32       | `l`\n    number_integer  | -32768..-129                      | int16       | `I`\n    number_integer  | -128..127                         | int8        | `i`\n    number_integer  | 128..255                          | uint8       | `U`\n    number_integer  | 256..32767                        | int16       | `I`\n    number_integer  | 32768..2147483647                 | int32       | `l`\n    number_integer  | 2147483648..9223372036854775807   | int64       | `L`\n    number_unsigned | 0..127                            | int8        | `i`\n    number_unsigned | 128..255                          | uint8       | `U`\n    number_unsigned | 256..32767                        | int16       | `I`\n    number_unsigned | 32768..2147483647                 | int32       | `l`\n    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`\n    number_unsigned | 2147483649..18446744073709551615  | high-precision | `H`\n    number_float    | *any value*                       | float64     | `D`\n    string          | *with shortest length indicator*  | string      | `S`\n    array           | *see notes on optimized format*   | array       | `[`\n    object          | *see notes on optimized format*   | map         | `{`\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a UBJSON value.\n\n    @note The following values can **not** be converted to a UBJSON value:\n          - strings with more than 9223372036854775807 bytes (theoretical)\n\n    @note The following markers are not used in the conversion:\n          - `Z`: no-op values are not created.\n          - `C`: single-byte strings are serialized with `S` markers.\n\n    @note Any UBJSON output created @ref to_ubjson can be successfully parsed\n          by @ref from_ubjson.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The optimized formats for containers are supported: Parameter\n          @a use_size adds size information to the beginning of a container and\n          removes the closing marker. Parameter @a use_type further checks\n          whether all elements of a container have the same type and adds the\n          type marker to the beginning of the container. The @a use_type\n          parameter must only be used together with @a use_size = true. Note\n          that @a use_size = true alone may result in larger representations -\n          the benefit of this parameter is that the receiving side is\n          immediately informed on the number of elements of the container.\n\n    @note If the JSON data contains the binary type, the value stored is a list\n          of integers, as suggested by the UBJSON documentation.  In particular,\n          this means that serialization and the deserialization of a JSON\n          containing binary values into UBJSON and back will result in a\n          different JSON object.\n\n    @param[in] j  JSON value to serialize\n    @param[in] use_size  whether to add size annotations to container types\n    @param[in] use_type  whether to add type annotations to container types\n                         (must be combined with @a use_size = true)\n    @return UBJSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in UBJSON format.,to_ubjson}\n\n    @sa http://ubjson.org\n    @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the\n        analogous deserialization\n    @sa see @ref to_cbor(const basic_json& for the related CBOR format\n    @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format\n\n    @since version 3.1.0\n    */\n    static std::vector<std::uint8_t> to_ubjson(const basic_json& j,\n            const bool use_size = false,\n            const bool use_type = false)\n    {\n        std::vector<std::uint8_t> result;\n        to_ubjson(j, result, use_size, use_type);\n        return result;\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<char>(o).write_ubjson(j, use_size, use_type);\n    }\n\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and returns a vector\n           containing the corresponding BSON-representation.\n\n    BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are\n    stored as a single entity (a so-called document).\n\n    The library uses the following mapping from JSON values types to BSON types:\n\n    JSON value type | value/range                       | BSON type   | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | 0x0A\n    boolean         | `true`, `false`                   | boolean     | 0x08\n    number_integer  | -9223372036854775808..-2147483649 | int64       | 0x12\n    number_integer  | -2147483648..2147483647           | int32       | 0x10\n    number_integer  | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 0..2147483647                     | int32       | 0x10\n    number_unsigned | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 9223372036854775808..18446744073709551615| --   | --\n    number_float    | *any value*                       | double      | 0x01\n    string          | *any value*                       | string      | 0x02\n    array           | *any value*                       | document    | 0x04\n    object          | *any value*                       | document    | 0x03\n    binary          | *any value*                       | binary      | 0x05\n\n    @warning The mapping is **incomplete**, since only JSON-objects (and things\n    contained therein) can be serialized to BSON.\n    Also, integers larger than 9223372036854775807 cannot be serialized to BSON,\n    and the keys may not contain U+0000, since they are serialized a\n    zero-terminated c-strings.\n\n    @throw out_of_range.407  if `j.is_number_unsigned() && j.get<std::uint64_t>() > 9223372036854775807`\n    @throw out_of_range.409  if a key in `j` contains a NULL (U+0000)\n    @throw type_error.317    if `!j.is_object()`\n\n    @pre The input `j` is required to be an object: `j.is_object() == true`.\n\n    @note Any BSON output created via @ref to_bson can be successfully parsed\n          by @ref from_bson.\n\n    @param[in] j  JSON value to serialize\n    @return BSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in BSON format.,to_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa see @ref from_bson(detail::input_adapter&&, const bool strict) for the\n        analogous deserialization\n    @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n    @sa see @ref to_cbor(const basic_json&) for the related CBOR format\n    @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format\n    */\n    static std::vector<std::uint8_t> to_bson(const basic_json& j)\n    {\n        std::vector<std::uint8_t> result;\n        to_bson(j, result);\n        return result;\n    }\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and forwards the\n           corresponding BSON-representation to the given output_adapter `o`.\n    @param j The JSON object to convert to BSON.\n    @param o The output adapter that receives the binary BSON representation.\n    @pre The input `j` shall be an object: `j.is_object() == true`\n    @sa see @ref to_bson(const basic_json&)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)\n    {\n        binary_writer<std::uint8_t>(o).write_bson(j);\n    }\n\n    /*!\n    @copydoc to_bson(const basic_json&, detail::output_adapter<std::uint8_t>)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_bson(j);\n    }\n\n\n    /*!\n    @brief create a JSON value from an input in CBOR format\n\n    Deserializes a given input @a i to a JSON value using the CBOR (Concise\n    Binary Object Representation) serialization format.\n\n    The library maps CBOR types to JSON value types as follows:\n\n    CBOR type              | JSON value type | first byte\n    ---------------------- | --------------- | ----------\n    Integer                | number_unsigned | 0x00..0x17\n    Unsigned integer       | number_unsigned | 0x18\n    Unsigned integer       | number_unsigned | 0x19\n    Unsigned integer       | number_unsigned | 0x1A\n    Unsigned integer       | number_unsigned | 0x1B\n    Negative integer       | number_integer  | 0x20..0x37\n    Negative integer       | number_integer  | 0x38\n    Negative integer       | number_integer  | 0x39\n    Negative integer       | number_integer  | 0x3A\n    Negative integer       | number_integer  | 0x3B\n    Byte string            | binary          | 0x40..0x57\n    Byte string            | binary          | 0x58\n    Byte string            | binary          | 0x59\n    Byte string            | binary          | 0x5A\n    Byte string            | binary          | 0x5B\n    UTF-8 string           | string          | 0x60..0x77\n    UTF-8 string           | string          | 0x78\n    UTF-8 string           | string          | 0x79\n    UTF-8 string           | string          | 0x7A\n    UTF-8 string           | string          | 0x7B\n    UTF-8 string           | string          | 0x7F\n    array                  | array           | 0x80..0x97\n    array                  | array           | 0x98\n    array                  | array           | 0x99\n    array                  | array           | 0x9A\n    array                  | array           | 0x9B\n    array                  | array           | 0x9F\n    map                    | object          | 0xA0..0xB7\n    map                    | object          | 0xB8\n    map                    | object          | 0xB9\n    map                    | object          | 0xBA\n    map                    | object          | 0xBB\n    map                    | object          | 0xBF\n    False                  | `false`         | 0xF4\n    True                   | `true`          | 0xF5\n    Null                   | `null`          | 0xF6\n    Half-Precision Float   | number_float    | 0xF9\n    Single-Precision Float | number_float    | 0xFA\n    Double-Precision Float | number_float    | 0xFB\n\n    @warning The mapping is **incomplete** in the sense that not all CBOR\n             types can be converted to a JSON value. The following CBOR types\n             are not supported and will yield parse errors (parse_error.112):\n             - date/time (0xC0..0xC1)\n             - bignum (0xC2..0xC3)\n             - decimal fraction (0xC4)\n             - bigfloat (0xC5)\n             - expected conversions (0xD5..0xD7)\n             - simple values (0xE0..0xF3, 0xF8)\n             - undefined (0xF7)\n\n    @warning CBOR allows map keys of any type, whereas JSON only allows\n             strings as keys in object values. Therefore, CBOR maps with keys\n             other than UTF-8 strings are rejected (parse_error.113).\n\n    @note Any CBOR output created @ref to_cbor can be successfully parsed by\n          @ref from_cbor.\n\n    @param[in] i  an input in CBOR format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n    @param[in] tag_handler how to treat CBOR tags (optional, error by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from CBOR were\n    used in the given input @a v or if the input is not valid CBOR\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in CBOR\n    format to a JSON value.,from_cbor}\n\n    @sa http://cbor.io\n    @sa see @ref to_cbor(const basic_json&) for the analogous serialization\n    @sa see @ref from_msgpack(InputType&&, const bool, const bool) for the\n        related MessagePack format\n    @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the\n        related UBJSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0; added @a tag_handler parameter since 3.9.0.\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_cbor(InputType&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_cbor(IteratorType first, IteratorType last,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))\n    static basic_json from_cbor(const T* ptr, std::size_t len,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);\n    }\n\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))\n    static basic_json from_cbor(detail::span_input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief create a JSON value from an input in MessagePack format\n\n    Deserializes a given input @a i to a JSON value using the MessagePack\n    serialization format.\n\n    The library maps MessagePack types to JSON value types as follows:\n\n    MessagePack type | JSON value type | first byte\n    ---------------- | --------------- | ----------\n    positive fixint  | number_unsigned | 0x00..0x7F\n    fixmap           | object          | 0x80..0x8F\n    fixarray         | array           | 0x90..0x9F\n    fixstr           | string          | 0xA0..0xBF\n    nil              | `null`          | 0xC0\n    false            | `false`         | 0xC2\n    true             | `true`          | 0xC3\n    float 32         | number_float    | 0xCA\n    float 64         | number_float    | 0xCB\n    uint 8           | number_unsigned | 0xCC\n    uint 16          | number_unsigned | 0xCD\n    uint 32          | number_unsigned | 0xCE\n    uint 64          | number_unsigned | 0xCF\n    int 8            | number_integer  | 0xD0\n    int 16           | number_integer  | 0xD1\n    int 32           | number_integer  | 0xD2\n    int 64           | number_integer  | 0xD3\n    str 8            | string          | 0xD9\n    str 16           | string          | 0xDA\n    str 32           | string          | 0xDB\n    array 16         | array           | 0xDC\n    array 32         | array           | 0xDD\n    map 16           | object          | 0xDE\n    map 32           | object          | 0xDF\n    bin 8            | binary          | 0xC4\n    bin 16           | binary          | 0xC5\n    bin 32           | binary          | 0xC6\n    ext 8            | binary          | 0xC7\n    ext 16           | binary          | 0xC8\n    ext 32           | binary          | 0xC9\n    fixext 1         | binary          | 0xD4\n    fixext 2         | binary          | 0xD5\n    fixext 4         | binary          | 0xD6\n    fixext 8         | binary          | 0xD7\n    fixext 16        | binary          | 0xD8\n    negative fixint  | number_integer  | 0xE0-0xFF\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @param[in] i  an input in MessagePack format convertible to an input\n                  adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from MessagePack were\n    used in the given input @a i or if the input is not valid MessagePack\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    MessagePack format to a JSON value.,from_msgpack}\n\n    @sa http://msgpack.org\n    @sa see @ref to_msgpack(const basic_json&) for the analogous serialization\n    @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the\n        related CBOR format\n    @sa see @ref from_ubjson(InputType&&, const bool, const bool) for\n        the related UBJSON format\n    @sa see @ref from_bson(InputType&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_msgpack(InputType&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_msgpack(InputType&&, const bool, const bool)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_msgpack(IteratorType first, IteratorType last,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))\n    static basic_json from_msgpack(const T* ptr, std::size_t len,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        return from_msgpack(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))\n    static basic_json from_msgpack(detail::span_input_adapter&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n    /*!\n    @brief create a JSON value from an input in UBJSON format\n\n    Deserializes a given input @a i to a JSON value using the UBJSON (Universal\n    Binary JSON) serialization format.\n\n    The library maps UBJSON types to JSON value types as follows:\n\n    UBJSON type | JSON value type                         | marker\n    ----------- | --------------------------------------- | ------\n    no-op       | *no value, next value is read*          | `N`\n    null        | `null`                                  | `Z`\n    false       | `false`                                 | `F`\n    true        | `true`                                  | `T`\n    float32     | number_float                            | `d`\n    float64     | number_float                            | `D`\n    uint8       | number_unsigned                         | `U`\n    int8        | number_integer                          | `i`\n    int16       | number_integer                          | `I`\n    int32       | number_integer                          | `l`\n    int64       | number_integer                          | `L`\n    high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H'\n    string      | string                                  | `S`\n    char        | string                                  | `C`\n    array       | array (optimized values are supported)  | `[`\n    object      | object (optimized values are supported) | `{`\n\n    @note The mapping is **complete** in the sense that any UBJSON value can\n          be converted to a JSON value.\n\n    @param[in] i  an input in UBJSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if a parse error occurs\n    @throw parse_error.113 if a string could not be parsed successfully\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    UBJSON format to a JSON value.,from_ubjson}\n\n    @sa http://ubjson.org\n    @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             analogous serialization\n    @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the\n        related CBOR format\n    @sa see @ref from_msgpack(InputType&&, const bool, const bool) for\n        the related MessagePack format\n    @sa see @ref from_bson(InputType&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_ubjson(InputType&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_ubjson(InputType&&, const bool, const bool)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_ubjson(IteratorType first, IteratorType last,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))\n    static basic_json from_ubjson(const T* ptr, std::size_t len,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        return from_ubjson(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))\n    static basic_json from_ubjson(detail::span_input_adapter&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n    /*!\n    @brief Create a JSON value from an input in BSON format\n\n    Deserializes a given input @a i to a JSON value using the BSON (Binary JSON)\n    serialization format.\n\n    The library maps BSON record types to JSON value types as follows:\n\n    BSON type       | BSON marker byte | JSON value type\n    --------------- | ---------------- | ---------------------------\n    double          | 0x01             | number_float\n    string          | 0x02             | string\n    document        | 0x03             | object\n    array           | 0x04             | array\n    binary          | 0x05             | binary\n    undefined       | 0x06             | still unsupported\n    ObjectId        | 0x07             | still unsupported\n    boolean         | 0x08             | boolean\n    UTC Date-Time   | 0x09             | still unsupported\n    null            | 0x0A             | null\n    Regular Expr.   | 0x0B             | still unsupported\n    DB Pointer      | 0x0C             | still unsupported\n    JavaScript Code | 0x0D             | still unsupported\n    Symbol          | 0x0E             | still unsupported\n    JavaScript Code | 0x0F             | still unsupported\n    int32           | 0x10             | number_integer\n    Timestamp       | 0x11             | still unsupported\n    128-bit decimal float | 0x13       | still unsupported\n    Max Key         | 0x7F             | still unsupported\n    Min Key         | 0xFF             | still unsupported\n\n    @warning The mapping is **incomplete**. The unsupported mappings\n             are indicated in the table above.\n\n    @param[in] i  an input in BSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.114 if an unsupported BSON record type is encountered\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    BSON format to a JSON value.,from_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa see @ref to_bson(const basic_json&) for the analogous serialization\n    @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the\n        related CBOR format\n    @sa see @ref from_msgpack(InputType&&, const bool, const bool) for\n        the related MessagePack format\n    @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the\n        related UBJSON format\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bson(InputType&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_bson(InputType&&, const bool, const bool)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bson(IteratorType first, IteratorType last,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))\n    static basic_json from_bson(const T* ptr, std::size_t len,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        return from_bson(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))\n    static basic_json from_bson(detail::span_input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n    /// @}\n\n    //////////////////////////\n    // JSON Pointer support //\n    //////////////////////////\n\n    /// @name JSON Pointer functions\n    /// @{\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. Similar to @ref operator[](const typename\n    object_t::key_type&), `null` values are created in arrays and objects if\n    necessary.\n\n    In particular:\n    - If the JSON pointer points to an object key that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned.\n    - If the JSON pointer points to an array index that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned. All indices between the current maximum and the given\n      index are also filled with `null`.\n    - The special value `-` is treated as a synonym for the index past the\n      end.\n\n    @param[in] ptr  a JSON pointer\n\n    @return reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer}\n\n    @since version 2.0.0\n    */\n    reference operator[](const json_pointer& ptr)\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. The function does not change the JSON\n    value; no `null` values are created. In particular, the special value\n    `-` yields an exception.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return const reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}\n\n    @since version 2.0.0\n    */\n    const_reference operator[](const json_pointer& ptr) const\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a reference to the element at with specified JSON pointer @a ptr,\n    with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer}\n    */\n    reference at(const json_pointer& ptr)\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a const reference to the element at with specified JSON pointer @a\n    ptr, with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer_const}\n    */\n    const_reference at(const json_pointer& ptr) const\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief return flattened JSON value\n\n    The function creates a JSON object whose keys are JSON pointers (see [RFC\n    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all\n    primitive. The original JSON value can be restored using the @ref\n    unflatten() function.\n\n    @return an object that maps JSON pointers to primitive values\n\n    @note Empty objects and arrays are flattened to `null` and will not be\n          reconstructed correctly by the @ref unflatten() function.\n\n    @complexity Linear in the size the JSON value.\n\n    @liveexample{The following code shows how a JSON object is flattened to an\n    object whose keys consist of JSON pointers.,flatten}\n\n    @sa see @ref unflatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json flatten() const\n    {\n        basic_json result(value_t::object);\n        json_pointer::flatten(\"\", *this, result);\n        return result;\n    }\n\n    /*!\n    @brief unflatten a previously flattened JSON value\n\n    The function restores the arbitrary nesting of a JSON value that has been\n    flattened before using the @ref flatten() function. The JSON value must\n    meet certain constraints:\n    1. The value must be an object.\n    2. The keys must be JSON pointers (see\n       [RFC 6901](https://tools.ietf.org/html/rfc6901))\n    3. The mapped values must be primitive JSON types.\n\n    @return the original JSON from a flattened version\n\n    @note Empty objects and arrays are flattened by @ref flatten() to `null`\n          values and can not unflattened to their original type. Apart from\n          this example, for a JSON value `j`, the following is always true:\n          `j == j.flatten().unflatten()`.\n\n    @complexity Linear in the size the JSON value.\n\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n\n    @liveexample{The following code shows how a flattened JSON object is\n    unflattened into the original nested JSON object.,unflatten}\n\n    @sa see @ref flatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json unflatten() const\n    {\n        return json_pointer::unflatten(*this);\n    }\n\n    /// @}\n\n    //////////////////////////\n    // JSON Patch functions //\n    //////////////////////////\n\n    /// @name JSON Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON patch\n\n    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for\n    expressing a sequence of operations to apply to a JSON) document. With\n    this function, a JSON Patch is applied to the current JSON value by\n    executing all operations from the patch.\n\n    @param[in] json_patch  JSON patch document\n    @return patched document\n\n    @note The application of a patch is atomic: Either all operations succeed\n          and the patched document is returned or an exception is thrown. In\n          any case, the original value is not changed: the patch is applied\n          to a copy of the value.\n\n    @throw parse_error.104 if the JSON patch does not consist of an array of\n    objects\n\n    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory\n    attributes are missing); example: `\"operation add must have member path\"`\n\n    @throw out_of_range.401 if an array index is out of range.\n\n    @throw out_of_range.403 if a JSON pointer inside the patch could not be\n    resolved successfully in the current JSON value; example: `\"key baz not\n    found\"`\n\n    @throw out_of_range.405 if JSON pointer has no parent (\"add\", \"remove\",\n    \"move\")\n\n    @throw other_error.501 if \"test\" operation was unsuccessful\n\n    @complexity Linear in the size of the JSON value and the length of the\n    JSON patch. As usually only a fraction of the JSON value is affected by\n    the patch, the complexity can usually be neglected.\n\n    @liveexample{The following code shows how a JSON patch is applied to a\n    value.,patch}\n\n    @sa see @ref diff -- create a JSON patch by comparing two JSON values\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)\n\n    @since version 2.0.0\n    */\n    basic_json patch(const basic_json& json_patch) const\n    {\n        // make a working copy to apply the patch to\n        basic_json result = *this;\n\n        // the valid JSON Patch operations\n        enum class patch_operations {add, remove, replace, move, copy, test, invalid};\n\n        const auto get_op = [](const std::string & op)\n        {\n            if (op == \"add\")\n            {\n                return patch_operations::add;\n            }\n            if (op == \"remove\")\n            {\n                return patch_operations::remove;\n            }\n            if (op == \"replace\")\n            {\n                return patch_operations::replace;\n            }\n            if (op == \"move\")\n            {\n                return patch_operations::move;\n            }\n            if (op == \"copy\")\n            {\n                return patch_operations::copy;\n            }\n            if (op == \"test\")\n            {\n                return patch_operations::test;\n            }\n\n            return patch_operations::invalid;\n        };\n\n        // wrapper for \"add\" operation; add value at ptr\n        const auto operation_add = [&result](json_pointer & ptr, basic_json val)\n        {\n            // adding to the root of the target document means replacing it\n            if (ptr.empty())\n            {\n                result = val;\n                return;\n            }\n\n            // make sure the top element of the pointer exists\n            json_pointer top_pointer = ptr.top();\n            if (top_pointer != ptr)\n            {\n                result.at(top_pointer);\n            }\n\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.back();\n            ptr.pop_back();\n            basic_json& parent = result[ptr];\n\n            switch (parent.m_type)\n            {\n                case value_t::null:\n                case value_t::object:\n                {\n                    // use operator[] to add value\n                    parent[last_path] = val;\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    if (last_path == \"-\")\n                    {\n                        // special case: append to back\n                        parent.push_back(val);\n                    }\n                    else\n                    {\n                        const auto idx = json_pointer::array_index(last_path);\n                        if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))\n                        {\n                            // avoid undefined behavior\n                            JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\", parent));\n                        }\n\n                        // default case: insert add offset\n                        parent.insert(parent.begin() + static_cast<difference_type>(idx), val);\n                    }\n                    break;\n                }\n\n                // if there exists a parent it cannot be primitive\n                case value_t::string: // LCOV_EXCL_LINE\n                case value_t::boolean: // LCOV_EXCL_LINE\n                case value_t::number_integer: // LCOV_EXCL_LINE\n                case value_t::number_unsigned: // LCOV_EXCL_LINE\n                case value_t::number_float: // LCOV_EXCL_LINE\n                case value_t::binary: // LCOV_EXCL_LINE\n                case value_t::discarded: // LCOV_EXCL_LINE\n                default:            // LCOV_EXCL_LINE\n                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n            }\n        };\n\n        // wrapper for \"remove\" operation; remove value at ptr\n        const auto operation_remove = [this, &result](json_pointer & ptr)\n        {\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.back();\n            ptr.pop_back();\n            basic_json& parent = result.at(ptr);\n\n            // remove child\n            if (parent.is_object())\n            {\n                // perform range check\n                auto it = parent.find(last_path);\n                if (JSON_HEDLEY_LIKELY(it != parent.end()))\n                {\n                    parent.erase(it);\n                }\n                else\n                {\n                    JSON_THROW(out_of_range::create(403, \"key '\" + last_path + \"' not found\", *this));\n                }\n            }\n            else if (parent.is_array())\n            {\n                // note erase performs range check\n                parent.erase(json_pointer::array_index(last_path));\n            }\n        };\n\n        // type check: top level value must be an array\n        if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))\n        {\n            JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\", json_patch));\n        }\n\n        // iterate and apply the operations\n        for (const auto& val : json_patch)\n        {\n            // wrapper to get a value for an operation\n            const auto get_value = [&val](const std::string & op,\n                                          const std::string & member,\n                                          bool string_type) -> basic_json &\n            {\n                // find value\n                auto it = val.m_value.object->find(member);\n\n                // context-sensitive error message\n                const auto error_msg = (op == \"op\") ? \"operation\" : \"operation '\" + op + \"'\";\n\n                // check if desired value is present\n                if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end()))\n                {\n                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have member '\" + member + \"'\", val));\n                }\n\n                // check if result is of type string\n                if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))\n                {\n                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have string member '\" + member + \"'\", val));\n                }\n\n                // no error: return value\n                return it->second;\n            };\n\n            // type check: every element of the array must be an object\n            if (JSON_HEDLEY_UNLIKELY(!val.is_object()))\n            {\n                JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\", val));\n            }\n\n            // collect mandatory members\n            const auto op = get_value(\"op\", \"op\", true).template get<std::string>();\n            const auto path = get_value(op, \"path\", true).template get<std::string>();\n            json_pointer ptr(path);\n\n            switch (get_op(op))\n            {\n                case patch_operations::add:\n                {\n                    operation_add(ptr, get_value(\"add\", \"value\", false));\n                    break;\n                }\n\n                case patch_operations::remove:\n                {\n                    operation_remove(ptr);\n                    break;\n                }\n\n                case patch_operations::replace:\n                {\n                    // the \"path\" location must exist - use at()\n                    result.at(ptr) = get_value(\"replace\", \"value\", false);\n                    break;\n                }\n\n                case patch_operations::move:\n                {\n                    const auto from_path = get_value(\"move\", \"from\", true).template get<std::string>();\n                    json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The move operation is functionally identical to a\n                    // \"remove\" operation on the \"from\" location, followed\n                    // immediately by an \"add\" operation at the target\n                    // location with the value that was just removed.\n                    operation_remove(from_ptr);\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::copy:\n                {\n                    const auto from_path = get_value(\"copy\", \"from\", true).template get<std::string>();\n                    const json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The copy is functionally identical to an \"add\"\n                    // operation at the target location using the value\n                    // specified in the \"from\" member.\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::test:\n                {\n                    bool success = false;\n                    JSON_TRY\n                    {\n                        // check if \"value\" matches the one at \"path\"\n                        // the \"path\" location must exist - use at()\n                        success = (result.at(ptr) == get_value(\"test\", \"value\", false));\n                    }\n                    JSON_INTERNAL_CATCH (out_of_range&)\n                    {\n                        // ignore out of range errors: success remains false\n                    }\n\n                    // throw an exception if test fails\n                    if (JSON_HEDLEY_UNLIKELY(!success))\n                    {\n                        JSON_THROW(other_error::create(501, \"unsuccessful: \" + val.dump(), val));\n                    }\n\n                    break;\n                }\n\n                case patch_operations::invalid:\n                default:\n                {\n                    // op must be \"add\", \"remove\", \"replace\", \"move\", \"copy\", or\n                    // \"test\"\n                    JSON_THROW(parse_error::create(105, 0, \"operation value '\" + op + \"' is invalid\", val));\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief creates a diff as a JSON patch\n\n    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can\n    be changed into the value @a target by calling @ref patch function.\n\n    @invariant For two JSON values @a source and @a target, the following code\n    yields always `true`:\n    @code {.cpp}\n    source.patch(diff(source, target)) == target;\n    @endcode\n\n    @note Currently, only `remove`, `add`, and `replace` operations are\n          generated.\n\n    @param[in] source  JSON value to compare from\n    @param[in] target  JSON value to compare against\n    @param[in] path    helper value to create JSON pointers\n\n    @return a JSON patch to convert the @a source to @a target\n\n    @complexity Linear in the lengths of @a source and @a target.\n\n    @liveexample{The following code shows how a JSON patch is created as a\n    diff for two JSON values.,diff}\n\n    @sa see @ref patch -- apply a JSON patch\n    @sa see @ref merge_patch -- apply a JSON Merge Patch\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n\n    @since version 2.0.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json diff(const basic_json& source, const basic_json& target,\n                           const std::string& path = \"\")\n    {\n        // the patch\n        basic_json result(value_t::array);\n\n        // if the values are the same, return empty patch\n        if (source == target)\n        {\n            return result;\n        }\n\n        if (source.type() != target.type())\n        {\n            // different types: replace value\n            result.push_back(\n            {\n                {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n            });\n            return result;\n        }\n\n        switch (source.type())\n        {\n            case value_t::array:\n            {\n                // first pass: traverse common elements\n                std::size_t i = 0;\n                while (i < source.size() && i < target.size())\n                {\n                    // recursive call to compare array values at index i\n                    auto temp_diff = diff(source[i], target[i], path + \"/\" + std::to_string(i));\n                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                    ++i;\n                }\n\n                // i now reached the end of at least one array\n                // in a second pass, traverse the remaining elements\n\n                // remove my remaining elements\n                const auto end_index = static_cast<difference_type>(result.size());\n                while (i < source.size())\n                {\n                    // add operations in reverse order to avoid invalid\n                    // indices\n                    result.insert(result.begin() + end_index, object(\n                    {\n                        {\"op\", \"remove\"},\n                        {\"path\", path + \"/\" + std::to_string(i)}\n                    }));\n                    ++i;\n                }\n\n                // add other remaining elements\n                while (i < target.size())\n                {\n                    result.push_back(\n                    {\n                        {\"op\", \"add\"},\n                        {\"path\", path + \"/-\"},\n                        {\"value\", target[i]}\n                    });\n                    ++i;\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // first pass: traverse this object's elements\n                for (auto it = source.cbegin(); it != source.cend(); ++it)\n                {\n                    // escape the key name to be used in a JSON patch\n                    const auto path_key = path + \"/\" + detail::escape(it.key());\n\n                    if (target.find(it.key()) != target.end())\n                    {\n                        // recursive call to compare object values at key it\n                        auto temp_diff = diff(it.value(), target[it.key()], path_key);\n                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                    }\n                    else\n                    {\n                        // found a key that is not in o -> remove it\n                        result.push_back(object(\n                        {\n                            {\"op\", \"remove\"}, {\"path\", path_key}\n                        }));\n                    }\n                }\n\n                // second pass: traverse other object's elements\n                for (auto it = target.cbegin(); it != target.cend(); ++it)\n                {\n                    if (source.find(it.key()) == source.end())\n                    {\n                        // found a key that is not in this -> add it\n                        const auto path_key = path + \"/\" + detail::escape(it.key());\n                        result.push_back(\n                        {\n                            {\"op\", \"add\"}, {\"path\", path_key},\n                            {\"value\", it.value()}\n                        });\n                    }\n                }\n\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // both primitive type: replace value\n                result.push_back(\n                {\n                    {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n                });\n                break;\n            }\n        }\n\n        return result;\n    }\n\n    /// @}\n\n    ////////////////////////////////\n    // JSON Merge Patch functions //\n    ////////////////////////////////\n\n    /// @name JSON Merge Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON Merge Patch\n\n    The merge patch format is primarily intended for use with the HTTP PATCH\n    method as a means of describing a set of modifications to a target\n    resource's content. This function applies a merge patch to the current\n    JSON value.\n\n    The function implements the following algorithm from Section 2 of\n    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):\n\n    ```\n    define MergePatch(Target, Patch):\n      if Patch is an Object:\n        if Target is not an Object:\n          Target = {} // Ignore the contents and set it to an empty Object\n        for each Name/Value pair in Patch:\n          if Value is null:\n            if Name exists in Target:\n              remove the Name/Value pair from Target\n          else:\n            Target[Name] = MergePatch(Target[Name], Value)\n        return Target\n      else:\n        return Patch\n    ```\n\n    Thereby, `Target` is the current object; that is, the patch is applied to\n    the current value.\n\n    @param[in] apply_patch  the patch to apply\n\n    @complexity Linear in the lengths of @a patch.\n\n    @liveexample{The following code shows how a JSON Merge Patch is applied to\n    a JSON document.,merge_patch}\n\n    @sa see @ref patch -- apply a JSON patch\n    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)\n\n    @since version 3.0.0\n    */\n    void merge_patch(const basic_json& apply_patch)\n    {\n        if (apply_patch.is_object())\n        {\n            if (!is_object())\n            {\n                *this = object();\n            }\n            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)\n            {\n                if (it.value().is_null())\n                {\n                    erase(it.key());\n                }\n                else\n                {\n                    operator[](it.key()).merge_patch(it.value());\n                }\n            }\n        }\n        else\n        {\n            *this = apply_patch;\n        }\n    }\n\n    /// @}\n};\n\n/*!\n@brief user-defined to_string function for JSON values\n\nThis function implements a user-defined to_string  for JSON objects.\n\n@param[in] j  a JSON object\n@return a std::string object\n*/\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstd::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)\n{\n    return j.dump();\n}\n} // namespace nlohmann\n\n///////////////////////\n// nonmember support //\n///////////////////////\n\n// specialization of std::swap, and std::hash\nnamespace std\n{\n\n/// hash value for JSON objects\ntemplate<>\nstruct hash<nlohmann::json>\n{\n    /*!\n    @brief return a hash value for a JSON object\n\n    @since version 1.0.0\n    */\n    std::size_t operator()(const nlohmann::json& j) const\n    {\n        return nlohmann::detail::hash(j);\n    }\n};\n\n/// specialization for std::less<value_t>\n/// @note: do not remove the space after '<',\n///        see https://github.com/nlohmann/json/pull/679\ntemplate<>\nstruct less<::nlohmann::detail::value_t>\n{\n    /*!\n    @brief compare two value_t enum values\n    @since version 3.0.0\n    */\n    bool operator()(nlohmann::detail::value_t lhs,\n                    nlohmann::detail::value_t rhs) const noexcept\n    {\n        return nlohmann::detail::operator<(lhs, rhs);\n    }\n};\n\n// C++20 prohibit function specialization in the std namespace.\n#ifndef JSON_HAS_CPP_20\n\n/*!\n@brief exchanges the values of two JSON objects\n\n@since version 1.0.0\n*/\ntemplate<>\ninline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)\n    is_nothrow_move_constructible<nlohmann::json>::value&&  // NOLINT(misc-redundant-expression)\n    is_nothrow_move_assignable<nlohmann::json>::value\n                              )\n{\n    j1.swap(j2);\n}\n\n#endif\n\n} // namespace std\n\n/*!\n@brief user-defined string literal for JSON values\n\nThis operator implements a user-defined string literal for JSON objects. It\ncan be used by adding `\"_json\"` to a string literal and returns a JSON object\nif no parse error occurred.\n\n@param[in] s  a string representation of a JSON object\n@param[in] n  the length of string @a s\n@return a JSON object\n\n@since version 1.0.0\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline nlohmann::json operator \"\" _json(const char* s, std::size_t n)\n{\n    return nlohmann::json::parse(s, s + n);\n}\n\n/*!\n@brief user-defined string literal for JSON pointer\n\nThis operator implements a user-defined string literal for JSON Pointers. It\ncan be used by adding `\"_json_pointer\"` to a string literal and returns a JSON pointer\nobject if no parse error occurred.\n\n@param[in] s  a string representation of a JSON Pointer\n@param[in] n  the length of string @a s\n@return a JSON pointer object\n\n@since version 2.0.0\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline nlohmann::json::json_pointer operator \"\" _json_pointer(const char* s, std::size_t n)\n{\n    return nlohmann::json::json_pointer(std::string(s, n));\n}\n\n// #include <nlohmann/detail/macro_unscope.hpp>\n\n\n// restore clang diagnostic settings\n#if defined(__clang__)\n    #pragma clang diagnostic pop\n#endif\n\n// clean up\n#undef JSON_ASSERT\n#undef JSON_INTERNAL_CATCH\n#undef JSON_CATCH\n#undef JSON_THROW\n#undef JSON_TRY\n#undef JSON_PRIVATE_UNLESS_TESTED\n#undef JSON_HAS_CPP_11\n#undef JSON_HAS_CPP_14\n#undef JSON_HAS_CPP_17\n#undef JSON_HAS_CPP_20\n#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION\n#undef NLOHMANN_BASIC_JSON_TPL\n#undef JSON_EXPLICIT\n#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL\n\n// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>\n\n\n#undef JSON_HEDLEY_ALWAYS_INLINE\n#undef JSON_HEDLEY_ARM_VERSION\n#undef JSON_HEDLEY_ARM_VERSION_CHECK\n#undef JSON_HEDLEY_ARRAY_PARAM\n#undef JSON_HEDLEY_ASSUME\n#undef JSON_HEDLEY_BEGIN_C_DECLS\n#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_BUILTIN\n#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_EXTENSION\n#undef JSON_HEDLEY_CLANG_HAS_FEATURE\n#undef JSON_HEDLEY_CLANG_HAS_WARNING\n#undef JSON_HEDLEY_COMPCERT_VERSION\n#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK\n#undef JSON_HEDLEY_CONCAT\n#undef JSON_HEDLEY_CONCAT3\n#undef JSON_HEDLEY_CONCAT3_EX\n#undef JSON_HEDLEY_CONCAT_EX\n#undef JSON_HEDLEY_CONST\n#undef JSON_HEDLEY_CONSTEXPR\n#undef JSON_HEDLEY_CONST_CAST\n#undef JSON_HEDLEY_CPP_CAST\n#undef JSON_HEDLEY_CRAY_VERSION\n#undef JSON_HEDLEY_CRAY_VERSION_CHECK\n#undef JSON_HEDLEY_C_DECL\n#undef JSON_HEDLEY_DEPRECATED\n#undef JSON_HEDLEY_DEPRECATED_FOR\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION\n#undef JSON_HEDLEY_DIAGNOSTIC_POP\n#undef JSON_HEDLEY_DIAGNOSTIC_PUSH\n#undef JSON_HEDLEY_DMC_VERSION\n#undef JSON_HEDLEY_DMC_VERSION_CHECK\n#undef JSON_HEDLEY_EMPTY_BASES\n#undef JSON_HEDLEY_EMSCRIPTEN_VERSION\n#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#undef JSON_HEDLEY_END_C_DECLS\n#undef JSON_HEDLEY_FLAGS\n#undef JSON_HEDLEY_FLAGS_CAST\n#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_BUILTIN\n#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_EXTENSION\n#undef JSON_HEDLEY_GCC_HAS_FEATURE\n#undef JSON_HEDLEY_GCC_HAS_WARNING\n#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#undef JSON_HEDLEY_GCC_VERSION\n#undef JSON_HEDLEY_GCC_VERSION_CHECK\n#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_BUILTIN\n#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_EXTENSION\n#undef JSON_HEDLEY_GNUC_HAS_FEATURE\n#undef JSON_HEDLEY_GNUC_HAS_WARNING\n#undef JSON_HEDLEY_GNUC_VERSION\n#undef JSON_HEDLEY_GNUC_VERSION_CHECK\n#undef JSON_HEDLEY_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_BUILTIN\n#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS\n#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_EXTENSION\n#undef JSON_HEDLEY_HAS_FEATURE\n#undef JSON_HEDLEY_HAS_WARNING\n#undef JSON_HEDLEY_IAR_VERSION\n#undef JSON_HEDLEY_IAR_VERSION_CHECK\n#undef JSON_HEDLEY_IBM_VERSION\n#undef JSON_HEDLEY_IBM_VERSION_CHECK\n#undef JSON_HEDLEY_IMPORT\n#undef JSON_HEDLEY_INLINE\n#undef JSON_HEDLEY_INTEL_CL_VERSION\n#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK\n#undef JSON_HEDLEY_INTEL_VERSION\n#undef JSON_HEDLEY_INTEL_VERSION_CHECK\n#undef JSON_HEDLEY_IS_CONSTANT\n#undef JSON_HEDLEY_IS_CONSTEXPR_\n#undef JSON_HEDLEY_LIKELY\n#undef JSON_HEDLEY_MALLOC\n#undef JSON_HEDLEY_MCST_LCC_VERSION\n#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK\n#undef JSON_HEDLEY_MESSAGE\n#undef JSON_HEDLEY_MSVC_VERSION\n#undef JSON_HEDLEY_MSVC_VERSION_CHECK\n#undef JSON_HEDLEY_NEVER_INLINE\n#undef JSON_HEDLEY_NON_NULL\n#undef JSON_HEDLEY_NO_ESCAPE\n#undef JSON_HEDLEY_NO_RETURN\n#undef JSON_HEDLEY_NO_THROW\n#undef JSON_HEDLEY_NULL\n#undef JSON_HEDLEY_PELLES_VERSION\n#undef JSON_HEDLEY_PELLES_VERSION_CHECK\n#undef JSON_HEDLEY_PGI_VERSION\n#undef JSON_HEDLEY_PGI_VERSION_CHECK\n#undef JSON_HEDLEY_PREDICT\n#undef JSON_HEDLEY_PRINTF_FORMAT\n#undef JSON_HEDLEY_PRIVATE\n#undef JSON_HEDLEY_PUBLIC\n#undef JSON_HEDLEY_PURE\n#undef JSON_HEDLEY_REINTERPRET_CAST\n#undef JSON_HEDLEY_REQUIRE\n#undef JSON_HEDLEY_REQUIRE_CONSTEXPR\n#undef JSON_HEDLEY_REQUIRE_MSG\n#undef JSON_HEDLEY_RESTRICT\n#undef JSON_HEDLEY_RETURNS_NON_NULL\n#undef JSON_HEDLEY_SENTINEL\n#undef JSON_HEDLEY_STATIC_ASSERT\n#undef JSON_HEDLEY_STATIC_CAST\n#undef JSON_HEDLEY_STRINGIFY\n#undef JSON_HEDLEY_STRINGIFY_EX\n#undef JSON_HEDLEY_SUNPRO_VERSION\n#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK\n#undef JSON_HEDLEY_TINYC_VERSION\n#undef JSON_HEDLEY_TINYC_VERSION_CHECK\n#undef JSON_HEDLEY_TI_ARMCL_VERSION\n#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL2000_VERSION\n#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL430_VERSION\n#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL6X_VERSION\n#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL7X_VERSION\n#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CLPRU_VERSION\n#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK\n#undef JSON_HEDLEY_TI_VERSION\n#undef JSON_HEDLEY_TI_VERSION_CHECK\n#undef JSON_HEDLEY_UNAVAILABLE\n#undef JSON_HEDLEY_UNLIKELY\n#undef JSON_HEDLEY_UNPREDICTABLE\n#undef JSON_HEDLEY_UNREACHABLE\n#undef JSON_HEDLEY_UNREACHABLE_RETURN\n#undef JSON_HEDLEY_VERSION\n#undef JSON_HEDLEY_VERSION_DECODE_MAJOR\n#undef JSON_HEDLEY_VERSION_DECODE_MINOR\n#undef JSON_HEDLEY_VERSION_DECODE_REVISION\n#undef JSON_HEDLEY_VERSION_ENCODE\n#undef JSON_HEDLEY_WARNING\n#undef JSON_HEDLEY_WARN_UNUSED_RESULT\n#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG\n#undef JSON_HEDLEY_FALL_THROUGH\n\n\n\n#endif  // INCLUDE_NLOHMANN_JSON_HPP_\n"
  },
  {
    "path": "d2mapapi/mapdata.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"mapdata.h\"\n\n#include \"offset.h\"\n#include \"d2map.h\"\n#include \"d2ptrs.h\"\n\n#include <algorithm>\n#include <vector>\n#include <tuple>\n\nnamespace d2mapapi {\n\nconstexpr int unit_type_npc = 1;\nconstexpr int unit_type_object = 2;\nconstexpr int unit_type_tile = 5;\n\nMapData::MapData(Act *act, unsigned int areaId, bool generatePathData) : CollisionMap(areaId) {\n    auto d2Ver = getD2Version();\n    Level *pLevel = getLevel(act, areaId);\n\n    if (!pLevel) { return; }\n\n    unsigned int currLevelNo;\n    unsigned int currPosX;\n    unsigned int currPosY;\n    unsigned int width, height;\n    if (!pLevel->pRoom2First(d2Ver)) {\n        D2COMMON_InitLevel(pLevel);\n    }\n    built = true;\n    if (!pLevel->pRoom2First(d2Ver)) { return; }\n    currLevelNo = pLevel->dwLevelNo(d2Ver);\n    currPosX = pLevel->dwPosX(d2Ver);\n    currPosY = pLevel->dwPosY(d2Ver);\n    width = pLevel->dwSizeX(d2Ver) * 5;\n    height = pLevel->dwSizeY(d2Ver) * 5;\n    offset.x = currPosX * 5;\n    offset.y = currPosY * 5;\n\n    auto map = std::vector<int16_t>(width * height, -1);\n    size.width = width;\n    size.height = height;\n\n    std::vector<std::tuple<uint32_t, int, int, int>> sides;\n    for (Room2 *pRoom2 = pLevel->pRoom2First(d2Ver); pRoom2; pRoom2 = pRoom2->pRoom2Next(d2Ver)) {\n        bool bAdded = false;\n        auto roomPosX = pRoom2->dwPosX(d2Ver);\n        auto roomPosY = pRoom2->dwPosY(d2Ver);\n\n        if (!pRoom2->pRoom1(d2Ver)) {\n            bAdded = true;\n            D2COMMON_AddRoomData(act, pLevel->dwLevelNo(d2Ver), roomPosX, roomPosY, nullptr);\n        }\n\n        /* Check near levels' walkable rect (we check 2 pixels from edge)\n         * side: 0-left 1-right 2-top 3-bottom\n         */\n        for (uint32_t i = 0; i < pRoom2->dwRoomsNear(d2Ver); i++) {\n            int side = -1;\n            auto *pRoom2Near = pRoom2->pRoom2Near(d2Ver)[i];\n            auto nearLevelNo = pRoom2Near->pLevel(d2Ver)->dwLevelNo(d2Ver);\n            if (currLevelNo == nearLevelNo) { continue; }\n            auto nearPosX = pRoom2Near->dwPosX(d2Ver);\n            auto nearPosY = pRoom2Near->dwPosY(d2Ver);\n            auto nearSizeX = pRoom2Near->dwSizeX(d2Ver);\n            auto nearSizeY = pRoom2Near->dwSizeY(d2Ver);\n            auto roomSizeX = pRoom2->dwSizeX(d2Ver);\n            auto roomSizeY = pRoom2->dwSizeY(d2Ver);\n            if (nearPosX + nearSizeX == roomPosX && nearPosY == roomPosY) {\n                side = 0;\n            } else if (nearPosX == roomPosX + roomSizeX && nearPosY == roomPosY) {\n                side = 1;\n            } else if (nearPosY + nearSizeY == roomPosY && nearPosX == roomPosX) {\n                side = 2;\n            } else if (nearPosY == roomPosY + roomSizeY && nearPosX == roomPosX) {\n                side = 3;\n            }\n            if (side < 0) { continue; }\n            bool bAddedNear = false;\n            if (!pRoom2Near->pRoom1(d2Ver)) {\n                D2COMMON_AddRoomData(act, nearLevelNo, nearPosX, nearPosY, nullptr);\n                bAddedNear = true;\n            }\n            int sideStart = -1;\n            Room1 *room1;\n            CollMap *coll;\n            if ((room1 = pRoom2Near->pRoom1(d2Ver)) && (coll = room1->Coll(d2Ver))) {\n                uint16_t *p = coll->pMapStart;\n                auto w = coll->dwSizeGameX, h = coll->dwSizeGameY;\n                switch (side) {\n                case 0:\n                    p += w - 1;\n                    for (int z = 0; z < h; z++) {\n                        if ((*p & 1) || (*(p-1) & 1)) {\n                            if (sideStart >= 0) {\n                                sides.emplace_back(nearLevelNo, side, coll->dwPosGameY + sideStart, coll->dwPosGameY + z);\n                                sideStart = -1;\n                            }\n                        } else {\n                            if (sideStart < 0) {\n                                sideStart = z;\n                            }\n                        }\n                        p += w;\n                    }\n                    break;\n                case 1:\n                    for (int z = 0; z < h; z++) {\n                        if ((*p & 1) || (*(p+1) & 1)) {\n                            if (sideStart >= 0) {\n                                sides.emplace_back(nearLevelNo, side, coll->dwPosGameY + sideStart, coll->dwPosGameY + z);\n                                sideStart = -1;\n                            }\n                        } else {\n                            if (sideStart < 0) {\n                                sideStart = z;\n                            }\n                        }\n                        p += w;\n                    }\n                    break;\n                case 2:\n                    p += w * (h - 1);\n                    for (int z = 0; z < w; z++) {\n                        if ((*p & 1) || (*(p-w) & 1)) {\n                            if (sideStart >= 0) {\n                                sides.emplace_back(nearLevelNo, side, coll->dwPosGameX + sideStart, coll->dwPosGameX + z);\n                                sideStart = -1;\n                            }\n                        } else {\n                            if (sideStart < 0) {\n                                sideStart = z;\n                            }\n                        }\n                        p++;\n                    }\n                    break;\n                case 3:\n                    for (int z = 0; z < w; z++) {\n                        if ((*p & 1) || (*(p+w) & 1)) {\n                            if (sideStart >= 0) {\n                                sides.emplace_back(nearLevelNo, side, coll->dwPosGameX + sideStart, coll->dwPosGameX + z);\n                                sideStart = -1;\n                            }\n                        } else {\n                            if (sideStart < 0) {\n                                sideStart = z;\n                            }\n                        }\n                        p++;\n                    }\n                    break;\n                default: break;\n                }\n                if (sideStart >= 0) {\n                    if (side == 2 || side == 3) {\n                        sides.emplace_back(nearLevelNo, side, coll->dwPosGameX + sideStart, coll->dwPosGameX + w);\n                    } else {\n                        sides.emplace_back(nearLevelNo, side, coll->dwPosGameY + sideStart, coll->dwPosGameY + h);\n                    }\n                }\n            }\n            if (bAddedNear) {\n                D2COMMON_RemoveRoomData(act, nearLevelNo, nearPosX, nearPosY, nullptr);\n            }\n        }\n\n        // add collision data\n        Room1 *room1;\n        CollMap *coll;\n        if ((room1 = pRoom2->pRoom1(d2Ver)) && (coll = room1->Coll(d2Ver))) {\n            const int x = coll->dwPosGameX - offset.x;\n            const int y = coll->dwPosGameY - offset.y;\n            const int cx = coll->dwSizeGameX;\n            const int cy = coll->dwSizeGameY;\n            const int nLimitX = x + cx;\n            const int nLimitY = y + cy;\n\n            uint16_t *p = coll->pMapStart;\n            if (crop.x0 < 0 || x < crop.x0) crop.x0 = x;\n            if (crop.y0 < 0 || y < crop.y0) crop.y0 = y;\n            if (crop.x1 < 0 || nLimitX > crop.x1) crop.x1 = nLimitX;\n            if (crop.y1 < 0 || nLimitY > crop.y1) crop.y1 = nLimitY;\n            for (int j = y; j < nLimitY; j++) {\n                int index = j * width + x;\n                for (int i = x; i < nLimitX; i++) {\n                    map[index++] = *p++;\n                }\n            }\n        }\n\n        // add unit data\n        for (PresetUnit *pPresetUnit = pRoom2->pPreset(d2Ver); pPresetUnit; pPresetUnit = pPresetUnit->pPresetNext(d2Ver)) {\n            // npcs\n            auto type = pPresetUnit->dwType(d2Ver);\n            if (type == unit_type_npc) {\n                const auto npcX = static_cast<int>(roomPosX * 5 + pPresetUnit->dwPosX(d2Ver));\n                const auto npcY = static_cast<int>(roomPosY * 5 + pPresetUnit->dwPosY(d2Ver));\n                npcs[pPresetUnit->dwTxtFileNo(d2Ver)].push_back(Point{npcX, npcY});\n            }\n\n            // objects\n            if (type == unit_type_object) {\n                const auto objectX = static_cast<int>(roomPosX * 5 + pPresetUnit->dwPosX(d2Ver));\n                const auto objectY = static_cast<int>(roomPosY * 5 + pPresetUnit->dwPosY(d2Ver));\n                objects[pPresetUnit->dwTxtFileNo(d2Ver)].push_back(Point{objectX, objectY});\n            }\n\n            // level exits\n            if (type == unit_type_tile) {\n                auto txtFileNo = pPresetUnit->dwTxtFileNo(d2Ver);\n                auto presetPosX = pPresetUnit->dwPosX(d2Ver);\n                auto presetPosY = pPresetUnit->dwPosY(d2Ver);\n                for (RoomTile *pRoomTile = pRoom2->pRoomTiles(d2Ver); pRoomTile; pRoomTile = pRoomTile->pNext(d2Ver)) {\n                    if (*pRoomTile->nNum(d2Ver) == txtFileNo) {\n                        const auto exitX = static_cast<int>(roomPosX * 5 + presetPosX);\n                        const auto exitY = static_cast<int>(roomPosY * 5 + presetPosY);\n\n                        auto &al = exits[pRoomTile->pRoom2(d2Ver)->pLevel(d2Ver)->dwLevelNo(d2Ver)];\n                        al.isPortal = true;\n                        al.offsets.emplace_back(Point{exitX, exitY});\n                    }\n                }\n            }\n        }\n\n        if (bAdded) {\n            D2COMMON_RemoveRoomData(act, currLevelNo, roomPosX, roomPosY, nullptr);\n        }\n    }\n\n    std::sort(sides.begin(), sides.end());\n    std::vector<std::tuple<uint32_t, int, int, int>> realSides;\n    uint32_t lastNearLevelNo = 0;\n    int lastSide = -1, start = -1, end = -1;\n    for (auto [nearLevelNo, side, sideStart, sideEnd]: sides) {\n        if (lastNearLevelNo != nearLevelNo || lastSide != side) {\n            if (start >= 0) {\n                realSides.emplace_back(lastNearLevelNo, lastSide, start, end);\n            }\n            lastSide = side;\n            lastNearLevelNo = nearLevelNo;\n            start = -1;\n            end = -1;\n        }\n        if (start == -1) {\n            start = sideStart;\n            end = sideEnd;\n        } else if (sideStart == end) {\n            end = sideEnd;\n        } else {\n            realSides.emplace_back(lastNearLevelNo, lastSide, start, end);\n            start = sideStart;\n            end = sideEnd;\n        }\n    }\n    if (start >= 0) {\n        realSides.emplace_back(lastNearLevelNo, lastSide, start, end);\n    }\n    sides.clear();\n    for (auto [nearLevelNo, side, sideStart, sideEnd]: realSides) {\n        int sStart = -1;\n        switch (side) {\n        case 0: {\n            sideStart -= offset.y;\n            if (sideStart < crop.y0) sideStart = crop.y0;\n            sideEnd -= offset.y;\n            if (sideEnd > crop.y1) sideEnd = crop.y1;\n            if (sideStart == sideEnd) break;\n            auto w = crop.x1 - crop.x0;\n            auto *p = map.data() + (sideStart - crop.y0) * w;\n            for (auto z = sideStart; z < sideEnd; ++z) {\n                if ((*p & 1) || (*(p+1) & 1)) {\n                    if (sStart >= 0) {\n                        sides.emplace_back(nearLevelNo, side, sStart, z);\n                        sStart = -1;\n                    }\n                } else {\n                    if (sStart < 0) {\n                        sStart = z;\n                    }\n                }\n                p += w;\n            }\n            break;\n        }\n        case 1: {\n            sideStart -= offset.y;\n            if (sideStart < crop.y0) sideStart = crop.y0;\n            sideEnd -= offset.y;\n            if (sideEnd > crop.y1) sideEnd = crop.y1;\n            if (sideStart == sideEnd) break;\n            auto w = crop.x1 - crop.x0;\n            auto *p = map.data() + (sideStart - crop.y0) * w + (w - 1);\n            for (auto z = sideStart; z < sideEnd; ++z) {\n                if ((*p & 1) || (*(p-1) & 1)) {\n                    if (sStart >= 0) {\n                        sides.emplace_back(nearLevelNo, side, sStart, z);\n                        sStart = -1;\n                    }\n                } else {\n                    if (sStart < 0) {\n                        sStart = z;\n                    }\n                }\n                p += w;\n            }\n            break;\n        }\n        case 2: {\n            sideStart -= offset.x;\n            if (sideStart < crop.x0) sideStart = crop.x0;\n            sideEnd -= offset.x;\n            if (sideEnd > crop.x1) sideEnd = crop.x1;\n            if (sideStart == sideEnd) break;\n            auto w = crop.x1 - crop.x0;\n            auto *p = map.data() + (sideStart - crop.x0);\n            for (auto z = sideStart; z < sideEnd; ++z) {\n                if ((*p & 1) || (*(p+w) & 1)) {\n                    if (sStart >= 0) {\n                        sides.emplace_back(nearLevelNo, side, sStart, z);\n                        sStart = -1;\n                    }\n                } else {\n                    if (sStart < 0) {\n                        sStart = z;\n                    }\n                }\n                p++;\n            }\n            break;\n        }\n        case 3: {\n            sideStart -= offset.x;\n            if (sideStart < crop.x0) sideStart = crop.x0;\n            sideEnd -= offset.x;\n            if (sideEnd > crop.x1) sideEnd = crop.x1;\n            if (sideStart == sideEnd) break;\n            auto w = crop.x1 - crop.x0;\n            auto *p = map.data() + w * (crop.y1 - crop.y0 - 1) + (sideStart - crop.x0);\n            for (auto z = sideStart; z < sideEnd; ++z) {\n                if ((*p & 1) || (*(p-w) & 1)) {\n                    if (sStart >= 0) {\n                        sides.emplace_back(nearLevelNo, side, sStart, z);\n                        sStart = -1;\n                    }\n                } else {\n                    if (sStart < 0) {\n                        sStart = z;\n                    }\n                }\n                p++;\n            }\n            break;\n        }\n        default:\n            break;\n        }\n        if (sStart >= 0) {\n            sides.emplace_back(nearLevelNo, side, sStart, sideEnd);\n        }\n    }\n    for (auto [nearLevelNo, side, sideStart, sideEnd]: sides) {\n        if (sideStart + 2 >= sideEnd) { continue; }\n        switch (side) {\n        case 0:\n            exits[nearLevelNo].offsets.emplace_back(Point{offset.x + crop.x0, offset.y + (sideStart + sideEnd) / 2});\n            break;\n        case 1:\n            exits[nearLevelNo].offsets.emplace_back(Point{offset.x + crop.x1 - 1, offset.y + (sideStart + sideEnd) / 2});\n            break;\n        case 2:\n            exits[nearLevelNo].offsets.emplace_back(Point{offset.x + (sideStart + sideEnd) / 2, offset.y + crop.y0});\n            break;\n        case 3:\n            exits[nearLevelNo].offsets.emplace_back(Point{offset.x + (sideStart + sideEnd) / 2, offset.y + crop.y1 - 1});\n            break;\n        default:\n            break;\n        }\n    }\n    /* run length encoding map data */\n    mapData.clear();\n    for (int j = crop.y0; j < crop.y1; ++j) {\n        int index = j * width + crop.x0;\n        bool lastIsWalkable = false;\n        int count = 0;\n        for (int i = crop.x0; i < crop.x1; ++i) {\n            bool walkable = !(map[index++] & 1);\n            if (walkable == lastIsWalkable) {\n                ++count;\n                continue;\n            }\n            mapData.emplace_back(count);\n            count = 1;\n            lastIsWalkable = walkable;\n        }\n        mapData.emplace_back(count);\n        mapData.emplace_back(-1);\n    }\n    /* generate path data */\n    if (generatePathData) {\n        genPathData(map.data());\n    } else {\n        pathData.clear();\n    }\n}\n\nvoid MapData::genPathData(const int16_t *map) {\n    pathData.clear();\n    auto w = (crop.x1 - crop.x0) / 5;\n    auto h = (crop.y1 - crop.y0) / 5;\n    path.resize(w * h, 0);\n    int pathIndex = 0;\n    auto width = size.width;\n    for (int j = crop.y0; j < crop.y1; j += 5) {\n        int index = j * width + crop.x0;\n        for (int i = crop.x0; i < crop.x1; i += 5, index += 5, pathIndex++) {\n            if (i + 5 < crop.x1) {\n                for (int p = 1; p < 4; ++p) {\n                    for (int q = 3; q < 7; ++q) {\n                        if (map[index + p * width + q] & 1) {\n                            goto out;\n                        }\n                    }\n                    path[pathIndex] |= 2;\n                    path[pathIndex + 1] |= 1;\n                    break;\nout:;\n                }\n            }\n            if (j + 5 < crop.y1) {\n                for (int p = 1; p < 4; ++p) {\n                    for (int q = 3; q < 7; ++q) {\n                        if (map[index + q * width + p] & 1) {\n                            goto out2;\n                        }\n                    }\n                    path[pathIndex] |= 8;\n                    path[pathIndex + w] |= 4;\n                    break;\nout2:;\n                }\n            }\n        }\n    }\n    /* run length encoding path data */\n    pathData.clear();\n    uint32_t count = 0;\n    uint8_t lastByte = path[0];\n    for (auto v: path) {\n        if (v != lastByte) {\n            while (count > 255) {\n                pathData.emplace_back(lastByte); pathData.emplace_back(255);\n                count -= 255;\n            }\n            pathData.emplace_back(lastByte); pathData.emplace_back(count);\n            lastByte = v;\n            count = 1;\n        } else {\n            ++count;\n        }\n    }\n    while (count > 255) {\n        pathData.emplace_back(lastByte); pathData.emplace_back(255);\n        count -= 255;\n    }\n    pathData.emplace_back(lastByte); pathData.emplace_back(count);\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/mapdata.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"collisionmap.h\"\n#include \"d2structs.h\"\n\nnamespace d2mapapi {\n\nclass MapData: public CollisionMap {\npublic:\n    MapData(Act *act, unsigned int areaId, bool generatePathData = false);\n    void genPathData(const int16_t *map);\n};\n\n}\n"
  },
  {
    "path": "d2mapapi/offset.cpp",
    "content": "#include \"offset.h\"\n\n#define _DEFINE_VARS\n#include \"d2ptrs.h\"\n#include \"crc32.h\"\n\n#include <iostream>\n#include <windows.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\nnamespace d2mapapi {\n\nstatic D2Version d2version = D2_113c;\n\nD2Version getD2Version() {\n    return d2version;\n}\n\nbool defineOffsets() {\n    const struct DllOffset {\n        const char *dll;\n        void *data;\n        int32_t ordinal;\n    } offsets_111a[] = {\n        {\"STORM.DLL\", &p_STORM_MPQHashTable, 0x52B00},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_1, 0x5AF10},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_2, 0x5ABD0},\n        {\"D2CLIENT.DLL\", &D2CLIENT_InitGameMisc_I, 0x8901B},\n        {\"D2COMMON.DLL\", &D2COMMON_AddRoomData, -10432},\n        {\"D2COMMON.DLL\", &D2COMMON_RemoveRoomData, -10716},\n        {\"D2COMMON.DLL\", &D2COMMON_GetLevel, -10204},\n\n        {\"D2COMMON.DLL\", &D2COMMON_InitLevel, -10972},\n        {\"D2COMMON.DLL\", &D2COMMON_LoadAct, 0x137F0}, /* -10141 */\n        {\"D2COMMON.DLL\", &D2COMMON_UnloadAct, -10155},\n\n        {\"FOG.DLL\", &FOG_10021, -10021},\n        {\"FOG.DLL\", &FOG_10101, -10101},\n        {\"FOG.DLL\", &FOG_10089, -10089},\n        {\"FOG.DLL\", &FOG_10218, -10218},\n\n        {\"D2WIN.DLL\", &D2WIN_10086, -10176},\n        {\"D2WIN.DLL\", &D2WIN_10005, -10063},\n\n        {\"D2LANG.DLL\", &D2LANG_Init, -10001},\n        {\"D2COMMON.DLL\", &D2COMMON_InitDataTables, -10149},\n        {nullptr},\n    }, offsets_111b[] = {\n        {\"STORM.DLL\", &p_STORM_MPQHashTable, 0x54D30},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_1, 0x52F40},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_2, 0x52C00},\n        {\"D2CLIENT.DLL\", &D2CLIENT_InitGameMisc_I, 0x32E5B},\n        {\"D2COMMON.DLL\", &D2COMMON_AddRoomData, -10787},\n        {\"D2COMMON.DLL\", &D2COMMON_RemoveRoomData, -10672},\n        {\"D2COMMON.DLL\", &D2COMMON_GetLevel, -11058},\n\n        {\"D2COMMON.DLL\", &D2COMMON_InitLevel, -10741},\n        {\"D2COMMON.DLL\", &D2COMMON_LoadAct, 0x264A0}, /* -10669 */\n        {\"D2COMMON.DLL\", &D2COMMON_UnloadAct, -10651},\n\n        {\"FOG.DLL\", &FOG_10021, -10021},\n        {\"FOG.DLL\", &FOG_10101, -10101},\n        {\"FOG.DLL\", &FOG_10089, -10089},\n        {\"FOG.DLL\", &FOG_10218, -10218},\n\n        {\"D2WIN.DLL\", &D2WIN_10086, -10030},\n        {\"D2WIN.DLL\", &D2WIN_10005, -10051},\n\n        {\"D2LANG.DLL\", &D2LANG_Init, -10009},\n        {\"D2COMMON.DLL\", &D2COMMON_InitDataTables, -10506},\n        {nullptr},\n    }, offsets_112a[] = {\n        {\"STORM.DLL\", &p_STORM_MPQHashTable, 0x55358},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_1, 0x409E0},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_2, 0x406A0},\n        {\"D2CLIENT.DLL\", &D2CLIENT_InitGameMisc_I, 0x7CD2B},\n        {\"D2COMMON.DLL\", &D2COMMON_AddRoomData, -10184},\n        {\"D2COMMON.DLL\", &D2COMMON_RemoveRoomData, -11009},\n        {\"D2COMMON.DLL\", &D2COMMON_GetLevel, -11020},\n\n        {\"D2COMMON.DLL\", &D2COMMON_InitLevel, -10721},\n        {\"D2COMMON.DLL\", &D2COMMON_LoadAct, 0x56780}, /* -10588 */\n        {\"D2COMMON.DLL\", &D2COMMON_UnloadAct, -10710},\n\n        {\"FOG.DLL\", &FOG_10021, -10021},\n        {\"FOG.DLL\", &FOG_10101, -10101},\n        {\"FOG.DLL\", &FOG_10089, -10089},\n        {\"FOG.DLL\", &FOG_10218, -10218},\n\n        {\"D2WIN.DLL\", &D2WIN_10086, -10059},\n        {\"D2WIN.DLL\", &D2WIN_10005, -10073},\n\n        {\"D2LANG.DLL\", &D2LANG_Init, -10003},\n        {\"D2COMMON.DLL\", &D2COMMON_InitDataTables, -10797},\n        {nullptr},\n    }, offsets_113c[] = {\n        {\"STORM.DLL\", &p_STORM_MPQHashTable, 0x53120},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_1, 0x62AA0},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_2, 0x62760},\n        {\"D2CLIENT.DLL\", &D2CLIENT_InitGameMisc_I, 0x4454B},\n        {\"D2COMMON.DLL\", &D2COMMON_AddRoomData, -10401},\n        {\"D2COMMON.DLL\", &D2COMMON_RemoveRoomData, -11099},\n        {\"D2COMMON.DLL\", &D2COMMON_GetLevel, -10207},\n\n        {\"D2COMMON.DLL\", &D2COMMON_InitLevel, -10322},\n        {\"D2COMMON.DLL\", &D2COMMON_LoadAct, 0x3CB30},\n        {\"D2COMMON.DLL\", &D2COMMON_UnloadAct, -10868},\n\n        {\"FOG.DLL\", &FOG_10021, -10021},\n        {\"FOG.DLL\", &FOG_10101, -10101},\n        {\"FOG.DLL\", &FOG_10089, -10089},\n        {\"FOG.DLL\", &FOG_10218, -10218},\n\n        {\"D2WIN.DLL\", &D2WIN_10086, -10086},\n        {\"D2WIN.DLL\", &D2WIN_10005, -10005},\n\n        {\"D2LANG.DLL\", &D2LANG_Init, -10008},\n        {\"D2COMMON.DLL\", &D2COMMON_InitDataTables, -10943},\n        {nullptr},\n    }, offsets_113d[] = {\n        {\"STORM.DLL\", &p_STORM_MPQHashTable, 0x52A60},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_1, 0x737F0},\n        {\"D2CLIENT.DLL\", &D2CLIENT_LoadAct_2, 0x2B420},\n        {\"D2CLIENT.DLL\", &D2CLIENT_InitGameMisc_I, 0x4559B},\n        {\"D2COMMON.DLL\", &D2COMMON_AddRoomData, 0x24990},\n        {\"D2COMMON.DLL\", &D2COMMON_RemoveRoomData, 0x24930},\n        {\"D2COMMON.DLL\", &D2COMMON_GetLevel, 0x6D440},\n\n        {\"D2COMMON.DLL\", &D2COMMON_InitLevel, 0x6DDF0},\n        {\"D2COMMON.DLL\", &D2COMMON_LoadAct, 0x24810},\n        {\"D2COMMON.DLL\", &D2COMMON_UnloadAct, 0x24590},\n\n        {\"FOG.DLL\", &FOG_10021, -10021},\n        {\"FOG.DLL\", &FOG_10101, -10101},\n        {\"FOG.DLL\", &FOG_10089, -10089},\n        {\"FOG.DLL\", &FOG_10218, -10218},\n\n        {\"D2WIN.DLL\", &D2WIN_10086, -10174},\n        {\"D2WIN.DLL\", &D2WIN_10005, -10072},\n\n        {\"D2LANG.DLL\", &D2LANG_Init, -10009},\n        {\"D2COMMON.DLL\", &D2COMMON_InitDataTables, -10081},\n        {nullptr},\n    }, *offsets = nullptr;\n    const struct DllSizeToVersion {\n        uint32_t gameCrc32;\n        uint32_t stormCrc32;\n        const DllOffset *offsets;\n        D2Version version;\n    } sizeMap[] = {\n        { 0xf44cd0cf, 0x9f06891d, offsets_111a, D2_111a },\n        { 0x8fd3f392, 0xb6390775, offsets_111b, D2_111b },\n        { 0xab566eaa, 0xe5b0f351, offsets_112a, D2_112a },\n        { 0xea2f0e6e, 0x5711a8b4, offsets_113c, D2_113c },\n        { 0xb3d69c47, 0xbdb6784e, offsets_113d, D2_113d },\n    };\n    uint32_t gameCrc32, stormCrc32;\n    auto crc32File = [](const wchar_t *filename)->uint32_t {\n        auto file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);\n        if (file == INVALID_HANDLE_VALUE) {\n            return 0;\n        }\n        std::string data;\n        auto size = GetFileSize(file, nullptr);\n        data.resize(size);\n        DWORD bytesRead;\n        ReadFile(file, data.data(), size, &bytesRead, nullptr);\n        CloseHandle(file);\n        return crc::crc32(data.data(), size);\n    };\n    /* Do CRC check for game.exe first, fallback to Storm.dll */\n    gameCrc32 = crc32File(L\"Game.exe\");\n    stormCrc32 = gameCrc32 ? 0 : crc32File(L\"Storm.dll\");\n    for (auto &sm: sizeMap) {\n        if (gameCrc32 == sm.gameCrc32 || stormCrc32 == sm.stormCrc32) {\n            offsets = sm.offsets;\n            d2version = sm.version;\n            break;\n        }\n    }\n    if (!offsets) {\n        return false;\n    }\n    for (const auto *off = offsets; off->dll; off++) {\n        HMODULE hMod = GetModuleHandle(off->dll);\n        if (!hMod) {\n            hMod = LoadLibrary(off->dll);\n        }\n        if (!hMod) {\n            return false;\n        }\n        uintptr_t addr;\n        if (off->ordinal < 0) {\n            addr = (uintptr_t)GetProcAddress(hMod, (const char *)-off->ordinal);\n        } else {\n            addr = (uintptr_t)hMod + off->ordinal;\n        }\n        if (!addr) {\n            return false;\n        }\n        *(uintptr_t*)off->data = addr;\n    }\n    return true;\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/offset.h",
    "content": "#pragma once\n\n#include <cstdint>\n\nnamespace d2mapapi {\n\nenum D2Version {\n    D2_111a,\n    D2_111b,\n    D2_112a,\n    D2_113c,\n    D2_113d,\n};\nD2Version getD2Version();\nbool defineOffsets();\n\n}\n"
  },
  {
    "path": "d2mapapi/pathfinder.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"pathfinder.h\"\n\n#include <queue>\n#include <cmath>\n\nnamespace d2mapapi {\n\nstd::vector<std::pair<int, int>> pathFindBFS(int startX, int startY, int targetX, int targetY,\n                const uint8_t *mapData, int mapWidth, int mapHeight, bool merge) {\n    const int n = mapWidth * mapHeight;\n    if (startX >= mapWidth || startY >= mapHeight || targetX >= mapWidth || targetY >= mapHeight) {\n        return {};\n    }\n    const int startPos = startX + startY * mapWidth, targetPos = targetX + targetY * mapWidth;\n    std::vector<std::pair<int, int>> p(n, {-1, -1});\n    p[startPos].second = 0;\n    std::queue<int> q;\n    q.push(startPos);\n    int offset[] = {0, -1, +1, 0, -mapWidth, 0, 0, 0, +mapWidth};\n    while (!q.empty()) {\n        int u = q.front();\n        q.pop();\n        for (auto e: {1, 2, 4, 8}) {\n            if (!(mapData[u] & e)) { continue; }\n            int off = offset[e];\n            int v = u + off;\n            if ((off == 1 && (v % mapWidth == 0)) || (off == -1 && (u % mapWidth == 0)))\n                continue;\n            if (0 <= v && v < n && p[v].second == -1 && mapData[v]) {\n                p[v] = { u, p[u].second + 1 };\n                if (v == targetPos)\n                    goto end;\n                q.push(v);\n            }\n        }\n    }\nend:\n    if (p[targetPos].second == -1) {\n        return {};\n    }\n    std::vector<std::pair<int, int>> result;\n    result.reserve(p[targetPos].second);\n    if (merge) {\n        int curr = targetPos;\n        if (curr == -1) { return {}; }\n        int prevX = curr % mapWidth, prevY = curr / mapWidth;\n        int lastX = prevX, lastY = prevY;\n        result.emplace_back(lastX, lastY);\n        curr = p[curr].first;\n        while (curr != -1) {\n            int currX = curr % mapWidth, currY = curr / mapWidth;\n            bool blocked = false;\n            /* Check if line is blocked here */\n            if (currX == prevX) {\n                int delta = prevY < currY ? 1 : -1;\n                int indexDelta = delta * mapWidth;\n                int checkBit = delta == 1 ? 8 : 4;\n                int index = prevY * mapWidth + prevX;\n                for (int y = prevY; y != currY; y += delta, index += indexDelta) {\n                    if (!(mapData[index] & checkBit)) {\n                        blocked = true;\n                        break;\n                    }\n                }\n            } else if (currY == prevY) {\n                int delta = prevX < currX ? 1 : -1;\n                int checkBit = delta == 1 ? 2 : 1;\n                int index = prevY * mapWidth + prevX;\n                for (int x = prevX; x != currX; x += delta, index += delta) {\n                    if (!(mapData[index] & checkBit)) {\n                        blocked = true;\n                        break;\n                    }\n                }\n            } else {\n                int dx = std::abs(currX - prevX);\n                int dy = std::abs(currY - prevY);\n                if (dx < dy) {\n                    int delta = prevY < currY ? 1 : -1;\n                    int indexDelta = delta * mapWidth;\n                    int delta2 = prevX < currX ? 1 : -1;\n                    int checkBit = delta == 1 ? 8 : 4;\n                    int checkBit2 = delta2 == 1 ? 2 : 1;\n                    int index = prevY * mapWidth + prevX;\n                    int total = dy / 2;\n                    for (int y = prevY; y != currY; y += delta, index += indexDelta) {\n                        total += dx;\n                        if (total >= dy) {\n                            total -= dy;\n                            auto val0 = dx - total;\n                            if (val0 >= total) {\n                                if (!(mapData[index] & checkBit) || !(mapData[index + indexDelta] & checkBit2)) {\n                                    blocked = true;\n                                    break;\n                                }\n                            } else {\n                                if (!(mapData[index] & checkBit2) || !(mapData[index + delta2] & checkBit)) {\n                                    blocked = true;\n                                    break;\n                                }\n                            }\n                            index += delta2;\n                        } else {\n                            if (!(mapData[index] & checkBit)) {\n                                blocked = true;\n                                break;\n                            }\n                        }\n                    }\n                } else {\n                    int delta = prevX < currX ? 1 : -1;\n                    int delta2 = prevY < currY ? 1 : -1;\n                    int indexDelta2 = delta2 * mapWidth;\n                    int checkBit = delta == 1 ? 2 : 1;\n                    int checkBit2 = delta2 == 1 ? 8 : 4;\n                    int index = prevY * mapWidth + prevX;\n                    int total = dx / 2;\n                    for (int x = prevX; x != currX; x += delta, index += delta) {\n                        total += dy;\n                        if (total >= dx) {\n                            total -= dx;\n                            auto val0 = dy - total;\n                            if (val0 >= total) {\n                                if (!(mapData[index] & checkBit) || !(mapData[index + delta] & checkBit2)) {\n                                    blocked = true;\n                                    break;\n                                }\n                            } else {\n                                if (!(mapData[index] & checkBit2) || !(mapData[index + indexDelta2] & checkBit)) {\n                                    blocked = true;\n                                    break;\n                                }\n                            }\n                            index += indexDelta2;\n                        } else {\n                            if (!(mapData[index] & checkBit)) {\n                                blocked = true;\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n            if (blocked) {\n                result.emplace_back(lastX, lastY);\n                prevX = lastX; prevY = lastY;\n                continue;\n            }\n            lastX = currX; lastY = currY;\n            curr = p[curr].first;\n        }\n        result.emplace_back(lastX, lastY);\n        return result;\n    }\n    int curr = targetPos;\n    while (curr != -1) {\n        int currX = curr % mapWidth, currY = curr / mapWidth;\n        result.emplace_back(currX, currY);\n        curr = p[curr].first;\n    }\n    return std::move(result);\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/pathfinder.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <vector>\n#include <utility>\n#include <cstdint>\n\nnamespace d2mapapi {\n\nstd::vector<std::pair<int, int>> pathFindBFS(int startX, int startY, int targetX, int targetY,\n                                             const uint8_t *mapData, int mapWidth, int mapHeight, bool merge = false);\n\n}\n"
  },
  {
    "path": "d2mapapi/piped.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"d2map.h\"\n#include \"session.h\"\n\n#include <json.hpp>\n\n#include <windows.h>\n#include <unordered_map>\n#include <string>\n#include <cstdint>\n\nenum {\n    SessionsCacheSize = 8,\n};\n\nint wmain(int argc, wchar_t *argv[]) {\n    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);\n    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);\n    if ((hStdout == INVALID_HANDLE_VALUE) || (hStdin == INVALID_HANDLE_VALUE)) {\n        ExitProcess(1);\n    }\n\n    int ret = 0;\n    const auto *errstr = argc > 1 ? d2mapapi::d2Init(argv[1]) : \"Usage: d2mapapi_piped <D2 Game Path>\";\n    if (errstr) {\n        do {\n            HKEY key;\n            if (RegOpenKeyExW(HKEY_CURRENT_USER, L\"SOFTWARE\\\\Blizzard Entertainment\\\\Diablo II\", 0, KEY_READ, &key)\n                == ERROR_SUCCESS) {\n                wchar_t path[MAX_PATH];\n                DWORD pathSize = sizeof(path);\n                if (RegQueryValueExW(key, L\"InstallPath\", nullptr, nullptr, LPBYTE(path), &pathSize) == ERROR_SUCCESS) {\n                    errstr = d2mapapi::d2Init(path);\n                    if (!errstr) {\n                        RegCloseKey(key);\n                        break;\n                    }\n                }\n                RegCloseKey(key);\n            }\n            ret = -1;\n            DWORD written;\n            WriteFile(hStdout, &ret, sizeof(int), &written, nullptr);\n            nlohmann::json j;\n            j[\"error\"] = std::string(\"[d2mapapi_mod v\" D2MAPAPI_VERSION \"] \") + errstr;\n            auto str = j.dump();\n            auto sz = uint32_t(str.size());\n            WriteFile(hStdout, &sz, sizeof(uint32_t), &written, nullptr);\n            WriteFile(hStdout, str.c_str(), sz, &written, nullptr);\n            return -1;\n        } while (false);\n    }\n\n    DWORD written;\n    WriteFile(hStdout, &ret, sizeof(int), &written, nullptr);\n    std::unordered_map<uint64_t, std::unique_ptr<d2mapapi::Session>> sessions;\n    std::vector<uint64_t> sessionsOrder;\n    for (;;) {\n        struct Req {\n            uint32_t seed;\n            uint32_t difficulty;\n            uint32_t levelId;\n        };\n        Req req = {};\n        DWORD bytesRead;\n        if (!ReadFile(hStdin, &req, sizeof(uint32_t) * 3, &bytesRead, nullptr)) {\n            break;\n        }\n        auto key = uint64_t(req.seed) | (uint64_t(req.difficulty) << 32);\n        auto &session = sessions[key];\n        if (!session) {\n            sessionsOrder.emplace_back(key);\n            session = std::make_unique<d2mapapi::Session>();\n            session->update(req.seed, req.difficulty);\n            if (sessionsOrder.size() > SessionsCacheSize) {\n                auto oldKey = sessionsOrder[0];\n                sessionsOrder.erase(sessionsOrder.begin());\n                sessions.erase(oldKey);\n            }\n        }\n        auto levelId = req.levelId & 0xFFFFu;\n        auto option = req.levelId >> 16;\n        const auto *map = session->getMap(levelId, (option & 1u) != 0);\n        std::string str;\n        if (map) {\n            str = map->encode((option & 1u) != 0);\n        } else {\n            str = R\"({\"error\":\"[d2mapapi_mod v)\" D2MAPAPI_VERSION R\"(] Invalid map id!\"})\";\n        }\n        auto sz = uint32_t(str.size());\n        if (!WriteFile(hStdout, &sz, sizeof(uint32_t), &written, nullptr) ||\n            !WriteFile(hStdout, str.c_str(), sz, &written, nullptr)) {\n            break;\n        }\n    }\n    return 0;\n}\n"
  },
  {
    "path": "d2mapapi/pipehost.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"pipehost.h\"\n\n#include <json.hpp>\n\n#include <windows.h>\n#include <string>\n#include <cstdio>\n\nnamespace d2mapapi {\n\nPipedChildProcess::~PipedChildProcess() {\n    if (process) {\n        CloseHandle(HANDLE(process));\n        CloseHandle(HANDLE(childStdoutRd));\n        CloseHandle(HANDLE(childStdinWr));\n    }\n}\n\nbool PipedChildProcess::start(const wchar_t *filename, const wchar_t *parameters) {\n    SECURITY_ATTRIBUTES saAttr = {\n        .nLength = sizeof(SECURITY_ATTRIBUTES),\n        .lpSecurityDescriptor = nullptr,\n        .bInheritHandle = TRUE,\n    };\n    if (!CreatePipe((HANDLE*)&childStdoutRd, (HANDLE*)&childStdoutWr, &saAttr, 0) ||\n        !CreatePipe((HANDLE*)&childStdinRd, (HANDLE*)&childStdinWr, &saAttr, 0)) {\n        return false;\n    }\n\n    SetHandleInformation(HANDLE(childStdoutRd), HANDLE_FLAG_INHERIT, 0);\n    SetHandleInformation(HANDLE(childStdinWr), HANDLE_FLAG_INHERIT, 0);\n    PROCESS_INFORMATION piProcInfo = {};\n    STARTUPINFOW siStartInfo = {.cb = sizeof(STARTUPINFOW), .dwFlags = STARTF_USESTDHANDLES, .hStdInput = childStdinRd, .hStdOutput = childStdoutWr, .hStdError = childStdoutWr};\n    BOOL bSuccess = FALSE;\n\n    wchar_t cmdLine[1024];\n    wsprintfW(cmdLine, L\"\\\"%s\\\" \\\"%s\\\"\", filename, parameters);\n    bSuccess = CreateProcessW(nullptr, cmdLine, nullptr, nullptr, TRUE, 0, nullptr, nullptr, &siStartInfo, &piProcInfo);\n    process = piProcInfo.hProcess;\n\n    if (!bSuccess) {\n        return false;\n    }\n    CloseHandle(piProcInfo.hThread);\n    CloseHandle(HANDLE(childStdoutWr));\n    CloseHandle(HANDLE(childStdinRd));\n    int ret;\n    if (!readPipe(&ret, 4)) {\n        errMsg_ = \"failed to read from child process!\";\n        return false;\n    }\n    if (ret == 0) { return true; }\n    uint32_t len;\n    readPipe(&len, 4);\n    std::string str;\n    str.resize(len);\n    readPipe(str.data(), len);\n    try {\n        auto j = nlohmann::json::parse(str);\n        errMsg_ = j[\"error\"];\n    } catch(const std::exception &e) {\n        errMsg_ = e.what();\n    }\n    return false;\n}\n\nbool PipedChildProcess::writePipe(const void *data, size_t size) {\n    DWORD dwWritten;\n    return WriteFile(HANDLE(childStdinWr), data, DWORD(size), &dwWritten, nullptr);\n}\n\nbool PipedChildProcess::readPipe(void *data, size_t size) {\n    DWORD dwRead;\n    return ReadFile(HANDLE(childStdoutRd), data, DWORD(size), &dwRead, nullptr);\n}\n\nstd::string PipedChildProcess::queryMapRaw(uint32_t seed, uint8_t difficulty, uint32_t levelId, bool generatePathData) {\n    struct Req {\n        uint32_t seed;\n        uint32_t difficulty;\n        uint32_t levelId;\n    };\n    Req req = {.seed = seed, .difficulty = difficulty, .levelId = levelId | ((generatePathData ? 1u : 0u) << 16)};\n    uint32_t size;\n    if (!writePipe(&req, sizeof(uint32_t) * 3)) { return \"\"; }\n    if (!readPipe(&size, sizeof(size))) { return \"\"; }\n    std::string str;\n    str.resize(size);\n    if (!readPipe(str.data(), str.length())) { return \"\"; }\n    return std::move(str);\n}\n\nCollisionMap *PipedChildProcess::queryMap(uint32_t seed, uint8_t difficulty, uint32_t levelId, bool generatePathData) {\n    auto str = queryMapRaw(seed, difficulty, levelId, generatePathData);\n    if (str.empty()) { return nullptr; }\n    try {\n        return new CollisionMap(str);\n    } catch(...) {\n        return nullptr;\n    }\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/pipehost.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"collisionmap.h\"\n\n#include <string>\n#include <cstdint>\n\nnamespace d2mapapi {\n\nclass PipedChildProcess final {\npublic:\n    ~PipedChildProcess();\n    bool start(const wchar_t *filename, const wchar_t *parameters);\n\n    bool writePipe(const void *data, size_t size);\n    bool readPipe(void *data, size_t size);\n\n    [[nodiscard]] inline const std::string &errMsg() const { return errMsg_; }\n\n    std::string queryMapRaw(uint32_t seed, uint8_t difficulty, uint32_t levelId, bool generatePathData = false);\n    CollisionMap *queryMap(uint32_t seed, uint8_t difficulty, uint32_t levelId, bool generatePathData = false);\n\nprivate:\n    void *childStdinRd = nullptr;\n    void *childStdinWr = nullptr;\n    void *childStdoutRd = nullptr;\n    void *childStdoutWr = nullptr;\n    void *process = nullptr;\n    std::string errMsg_;\n};\n\n}\n"
  },
  {
    "path": "d2mapapi/session.cpp",
    "content": "#include \"session.h\"\n\n#include \"d2ptrs.h\"\n\nnamespace d2mapapi {\n\nstatic const unsigned int ActLevels[] = {1, 40, 75, 103, 109, 137};\n\nnamespace Helpers {\nint getAct(unsigned int areaid) {\n    for (int i = 0; i < 6; i++) {\n        if (areaid < ActLevels[i]) {\n            return i - 1;\n        }\n    }\n\n    return -1;\n}\n}\n\nSession::~Session() {\n    unloadAll();\n}\n\nbool Session::update(unsigned int seed, unsigned char difficulty) {\n    if (difficulty > 2) difficulty = 2;\n    if (seed_ == seed && difficulty == difficulty_) { return false; }\n    seed_ = seed;\n    difficulty_ = difficulty;\n    unloadAll();\n    return true;\n}\n\nconst CollisionMap *Session::getMap(unsigned int areaid, bool generatePathData) {\n    auto ite = maps_.find(areaid);\n    if (ite != maps_.end()) {\n        if (generatePathData && ite->second->pathData.empty()) {\n            auto w = ite->second->size.width;\n            auto h = ite->second->size.height;\n            std::vector<int16_t> map(w, h);\n            if (ite->second->extractCellData<int16_t>(map.data(), w, h, 0, 0, 1, 0)) {\n                ite->second->genPathData(map.data());\n            }\n        }\n        return ite->second.get();\n    }\n    auto actId = Helpers::getAct(areaid);\n    if (actId < 0) {\n        return nullptr;\n    }\n    if (!acts_[actId]) {\n        acts_[actId] = D2COMMON_LoadAct(actId, seed_, 1 /*TRUE*/, nullptr, difficulty_, nullptr,\n                                        ActLevels[actId], D2CLIENT_LoadAct_1, D2CLIENT_LoadAct_2);\n    }\n    auto map = std::make_unique<MapData>(acts_[actId], areaid, generatePathData);\n    if (!map->built) { return nullptr; }\n    auto &output = maps_[areaid];\n    output = std::move(map);\n    return output.get();\n}\n\nvoid Session::unloadAll() {\n    maps_.clear();\n    for (auto *&act: acts_) {\n        if (act) {\n            D2COMMON_UnloadAct(act);\n            act = nullptr;\n        }\n    }\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/session.h",
    "content": "#pragma once\n\n#include \"mapdata.h\"\n\n#include <map>\n#include <memory>\n\nnamespace d2mapapi {\n\nclass Session {\npublic:\n    ~Session();\n\n    bool update(unsigned int seed, unsigned char difficulty);\n\n    const CollisionMap *getMap(unsigned int areaid, bool generatePathData = false);\n\nprivate:\n    void unloadAll();\n\nprivate:\n    std::map<int, std::unique_ptr<MapData>> maps_;\n    unsigned int seed_ = 0;\n    unsigned char difficulty_ = 0;\n    Act *acts_[5] = {};\n};\n\n}\n"
  },
  {
    "path": "d2mapapi/simphttp/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\n\nproject(simphttp)\n\nlist(APPEND CMAKE_MODULE_PATH \"${PROJECT_SOURCE_DIR}/cmake\")\n\nfind_package(Git QUIET REQUIRED)\ninclude(ExternalProject)\nfind_package(LibUV QUIET)\nif(LIBUV_FOUND)\n    message(STATUS \"Using system libuv\")\n    add_library(libuv_external INTERFACE)\n    target_include_directories(libuv_external INTERFACE ${LIBUV_INCLUDE_DIRS})\n    target_link_libraries(libuv_external INTERFACE ${LIBUV_LIBRARIES})\n    add_library(uv::libuv ALIAS libuv_external)\nelse()\n    ExternalProject_Add(libuv\n        PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libuv\n        STEP_TARGETS update\n        GIT_REPOSITORY https://github.com/libuv/libuv.git\n        GIT_TAG v1.x\n        GIT_SHALLOW ON\n        UPDATE_DISCONNECTED ON\n        STEP_TARGETS update\n        CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}\n                   -DCMAKE_INSTALL_LIBDIR=lib -DLIBUV_BUILD_TESTS=OFF -DLIBUV_BUILD_BENCH=OFF\n        )\n    add_library(uv-static INTERFACE)\n    add_dependencies(uv-static libuv)\n    target_include_directories(uv-static INTERFACE ${CMAKE_BINARY_DIR}/include)\n    target_link_directories(uv-static INTERFACE ${CMAKE_BINARY_DIR}/lib)\n    find_package(Threads)\n    target_link_libraries(uv-static INTERFACE uv_a Threads::Threads ${CMAKE_DL_LIBS})\n    if(WIN32)\n        target_link_libraries(uv-static INTERFACE ws2_32 iphlpapi userenv)\n    endif()\n    add_library(uv::libuv ALIAS uv-static)\nendif()\n\nadd_subdirectory(llhttp)\n\nadd_library(${PROJECT_NAME} STATIC EXCLUDE_FROM_ALL simphttp.cpp simphttp.h)\ntarget_include_directories(${PROJECT_NAME} PUBLIC .)\ntarget_link_libraries(${PROJECT_NAME} llhttp uv::libuv)\n"
  },
  {
    "path": "d2mapapi/simphttp/cmake/FindLibUV.cmake",
    "content": "# - Try to find libuv\n# Once done, this will define\n#\n#  LIBUV_FOUND - system has libuv\n#  LIBUV_INCLUDE_DIRS - the libuv include directories\n#  LIBUV_LIBRARIES - link these to use libuv\n\nif(UNIX)\n    find_package(PkgConfig)\n    if (PKG_CONFIG_FOUND)\n        pkg_check_modules(PC_LIBUV QUIET libuv)\n    endif()\nendif()\n\nfind_path(LIBUV_INCLUDE_DIR uv.h\n    HINTS ${PC_LIBUV_INCLUDEDIR} ${PC_LIBUV_INCLUDE_DIRS})\n\nlist(APPEND LIBUV_NAMES uv)\n\nfind_library(LIBUV_LIBRARY NAMES ${LIBUV_NAMES}\n    HINTS ${PC_LIBUV_LIBDIR} ${PC_LIBUV_LIBRARY_DIRS})\n\nmark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY)\n\nif(PC_LIBUV_LIBRARIES)\n    list(REMOVE_ITEM PC_LIBUV_LIBRARIES uv)\nendif()\n\nset(LIBUV_LIBRARIES ${LIBUV_LIBRARY} ${PC_LIBUV_LIBRARIES})\nset(LIBUV_INCLUDE_DIRS ${LIBUV_INCLUDE_DIR})\n\n# Deal with the fact that libuv.pc is missing important dependency information.\n\ninclude(CheckLibraryExists)\n\ncheck_library_exists(dl dlopen \"dlfcn.h\" HAVE_LIBDL)\nif(HAVE_LIBDL)\n    list(APPEND LIBUV_LIBRARIES dl)\nendif()\n\ncheck_library_exists(kstat kstat_lookup \"kstat.h\" HAVE_LIBKSTAT)\nif(HAVE_LIBKSTAT)\n    list(APPEND LIBUV_LIBRARIES kstat)\nendif()\n\ncheck_library_exists(kvm kvm_open \"kvm.h\" HAVE_LIBKVM)\nif(HAVE_LIBKVM AND NOT CMAKE_SYSTEM_NAME STREQUAL \"OpenBSD\")\n    list(APPEND LIBUV_LIBRARIES kvm)\nendif()\n\ncheck_library_exists(nsl gethostbyname \"nsl.h\" HAVE_LIBNSL)\nif(HAVE_LIBNSL)\n    list(APPEND LIBUV_LIBRARIES nsl)\nendif()\n\ncheck_library_exists(perfstat perfstat_cpu \"libperfstat.h\" HAVE_LIBPERFSTAT)\nif(HAVE_LIBPERFSTAT)\n    list(APPEND LIBUV_LIBRARIES perfstat)\nendif()\n\ncheck_library_exists(rt clock_gettime \"time.h\" HAVE_LIBRT)\nif(HAVE_LIBRT)\n    list(APPEND LIBUV_LIBRARIES rt)\nendif()\n\ncheck_library_exists(sendfile sendfile \"\" HAVE_LIBSENDFILE)\nif(HAVE_LIBSENDFILE)\n    list(APPEND LIBUV_LIBRARIES sendfile)\nendif()\n\nif(WIN32)\n    # check_library_exists() does not work for Win32 API calls in X86 due to name\n    # mangling calling conventions\n    list(APPEND LIBUV_LIBRARIES iphlpapi)\n    list(APPEND LIBUV_LIBRARIES psapi)\n    list(APPEND LIBUV_LIBRARIES userenv)\n    list(APPEND LIBUV_LIBRARIES ws2_32)\nendif()\n\ninclude(FindPackageHandleStandardArgs)\n\n# handle the QUIETLY and REQUIRED arguments and set LIBUV_FOUND to TRUE\n# if all listed variables are TRUE\nfind_package_handle_standard_args(LibUV DEFAULT_MSG\n    LIBUV_LIBRARY LIBUV_INCLUDE_DIR)\n\nmark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY)\n"
  },
  {
    "path": "d2mapapi/simphttp/llhttp/CMakeLists.txt",
    "content": "project(llhttp)\nadd_library(${PROJECT_NAME} STATIC EXCLUDE_FROM_ALL api.c api.h http.c llhttp.c llhttp.h)\ntarget_include_directories(${PROJECT_NAME} PUBLIC .)\n"
  },
  {
    "path": "d2mapapi/simphttp/llhttp/api.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"llhttp.h\"\n\n#define CALLBACK_MAYBE(PARSER, NAME)                                          \\\n  do {                                                                        \\\n    const llhttp_settings_t* settings;                                        \\\n    settings = (const llhttp_settings_t*) (PARSER)->settings;                 \\\n    if (settings == NULL || settings->NAME == NULL) {                         \\\n      err = 0;                                                                \\\n      break;                                                                  \\\n    }                                                                         \\\n    err = settings->NAME((PARSER));                                           \\\n  } while (0)\n\n#define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN)                         \\\n  do {                                                                        \\\n    const llhttp_settings_t* settings;                                        \\\n    settings = (const llhttp_settings_t*) (PARSER)->settings;                 \\\n    if (settings == NULL || settings->NAME == NULL) {                         \\\n      err = 0;                                                                \\\n      break;                                                                  \\\n    }                                                                         \\\n    err = settings->NAME((PARSER), (START), (LEN));                           \\\n    if (err == -1) {                                                          \\\n      err = HPE_USER;                                                         \\\n      llhttp_set_error_reason((PARSER), \"Span callback error in \" #NAME);     \\\n    }                                                                         \\\n  } while (0)\n\nvoid llhttp_init(llhttp_t* parser, llhttp_type_t type,\n                 const llhttp_settings_t* settings) {\n  llhttp__internal_init(parser);\n\n  parser->type = type;\n  parser->settings = (void*) settings;\n}\n\n\n#if defined(__wasm__)\n\nextern int wasm_on_message_begin(llhttp_t * p);\nextern int wasm_on_url(llhttp_t* p, const char* at, size_t length);\nextern int wasm_on_status(llhttp_t* p, const char* at, size_t length);\nextern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length);\nextern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length);\nextern int wasm_on_headers_complete(llhttp_t * p, int status_code,\n                                    uint8_t upgrade, int should_keep_alive);\nextern int wasm_on_body(llhttp_t* p, const char* at, size_t length);\nextern int wasm_on_message_complete(llhttp_t * p);\n\nstatic int wasm_on_headers_complete_wrap(llhttp_t* p) {\n  return wasm_on_headers_complete(p, p->status_code, p->upgrade,\n                                  llhttp_should_keep_alive(p));\n}\n\nconst llhttp_settings_t wasm_settings = {\n  wasm_on_message_begin,\n  wasm_on_url,\n  wasm_on_status,\n  wasm_on_header_field,\n  wasm_on_header_value,\n  wasm_on_headers_complete_wrap,\n  wasm_on_body,\n  wasm_on_message_complete,\n  NULL,\n  NULL,\n};\n\n\nllhttp_t* llhttp_alloc(llhttp_type_t type) {\n  llhttp_t* parser = malloc(sizeof(llhttp_t));\n  llhttp_init(parser, type, &wasm_settings);\n  return parser;\n}\n\nvoid llhttp_free(llhttp_t* parser) {\n  free(parser);\n}\n\n/* Some getters required to get stuff from the parser */\n\nuint8_t llhttp_get_type(llhttp_t* parser) {\n  return parser->type;\n}\n\nuint8_t llhttp_get_http_major(llhttp_t* parser) {\n  return parser->http_major;\n}\n\nuint8_t llhttp_get_http_minor(llhttp_t* parser) {\n  return parser->http_minor;\n}\n\nuint8_t llhttp_get_method(llhttp_t* parser) {\n  return parser->method;\n}\n\nint llhttp_get_status_code(llhttp_t* parser) {\n  return parser->status_code;\n}\n\nuint8_t llhttp_get_upgrade(llhttp_t* parser) {\n  return parser->upgrade;\n}\n\n#endif  // defined(__wasm__)\n\n\nvoid llhttp_reset(llhttp_t* parser) {\n  llhttp_type_t type = parser->type;\n  const llhttp_settings_t* settings = parser->settings;\n  void* data = parser->data;\n  uint8_t lenient_flags = parser->lenient_flags;\n\n  llhttp__internal_init(parser);\n\n  parser->type = type;\n  parser->settings = (void*) settings;\n  parser->data = data;\n  parser->lenient_flags = lenient_flags;\n}\n\n\nllhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) {\n  return llhttp__internal_execute(parser, data, data + len);\n}\n\n\nvoid llhttp_settings_init(llhttp_settings_t* settings) {\n  memset(settings, 0, sizeof(*settings));\n}\n\n\nllhttp_errno_t llhttp_finish(llhttp_t* parser) {\n  int err;\n\n  /* We're in an error state. Don't bother doing anything. */\n  if (parser->error != 0) {\n    return 0;\n  }\n\n  switch (parser->finish) {\n    case HTTP_FINISH_SAFE_WITH_CB:\n      CALLBACK_MAYBE(parser, on_message_complete);\n      if (err != HPE_OK) return err;\n\n    /* FALLTHROUGH */\n    case HTTP_FINISH_SAFE:\n      return HPE_OK;\n    case HTTP_FINISH_UNSAFE:\n      parser->reason = \"Invalid EOF state\";\n      return HPE_INVALID_EOF_STATE;\n    default:\n      abort();\n  }\n}\n\n\nvoid llhttp_pause(llhttp_t* parser) {\n  if (parser->error != HPE_OK) {\n    return;\n  }\n\n  parser->error = HPE_PAUSED;\n  parser->reason = \"Paused\";\n}\n\n\nvoid llhttp_resume(llhttp_t* parser) {\n  if (parser->error != HPE_PAUSED) {\n    return;\n  }\n\n  parser->error = 0;\n}\n\n\nvoid llhttp_resume_after_upgrade(llhttp_t* parser) {\n  if (parser->error != HPE_PAUSED_UPGRADE) {\n    return;\n  }\n\n  parser->error = 0;\n}\n\n\nllhttp_errno_t llhttp_get_errno(const llhttp_t* parser) {\n  return parser->error;\n}\n\n\nconst char* llhttp_get_error_reason(const llhttp_t* parser) {\n  return parser->reason;\n}\n\n\nvoid llhttp_set_error_reason(llhttp_t* parser, const char* reason) {\n  parser->reason = reason;\n}\n\n\nconst char* llhttp_get_error_pos(const llhttp_t* parser) {\n  return parser->error_pos;\n}\n\n\nconst char* llhttp_errno_name(llhttp_errno_t err) {\n#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return \"HPE_\" #NAME;\n  switch (err) {\n    HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)\n    default: abort();\n  }\n#undef HTTP_ERRNO_GEN\n}\n\n\nconst char* llhttp_method_name(llhttp_method_t method) {\n#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING;\n  switch (method) {\n    HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN)\n    default: abort();\n  }\n#undef HTTP_METHOD_GEN\n}\n\n\nvoid llhttp_set_lenient_headers(llhttp_t* parser, int enabled) {\n  if (enabled) {\n    parser->lenient_flags |= LENIENT_HEADERS;\n  } else {\n    parser->lenient_flags &= ~LENIENT_HEADERS;\n  }\n}\n\n\nvoid llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) {\n  if (enabled) {\n    parser->lenient_flags |= LENIENT_CHUNKED_LENGTH;\n  } else {\n    parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH;\n  }\n}\n\n\nvoid llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) {\n  if (enabled) {\n    parser->lenient_flags |= LENIENT_KEEP_ALIVE;\n  } else {\n    parser->lenient_flags &= ~LENIENT_KEEP_ALIVE;\n  }\n}\n\n/* Callbacks */\n\n\nint llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_message_begin);\n  return err;\n}\n\n\nint llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_url_complete);\n  return err;\n}\n\n\nint llhttp__on_status(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_status_complete);\n  return err;\n}\n\n\nint llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_header_field_complete);\n  return err;\n}\n\n\nint llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_header_value_complete);\n  return err;\n}\n\n\nint llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_headers_complete);\n  return err;\n}\n\n\nint llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_message_complete);\n  return err;\n}\n\n\nint llhttp__on_body(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_chunk_header);\n  return err;\n}\n\n\nint llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_chunk_complete);\n  return err;\n}\n\n\n/* Private */\n\n\nvoid llhttp__debug(llhttp_t* s, const char* p, const char* endp,\n                   const char* msg) {\n  if (p == endp) {\n    fprintf(stderr, \"p=%p type=%d flags=%02x next=null debug=%s\\n\", s, s->type,\n            s->flags, msg);\n  } else {\n    fprintf(stderr, \"p=%p type=%d flags=%02x next=%02x   debug=%s\\n\", s,\n            s->type, s->flags, *p, msg);\n  }\n}\n"
  },
  {
    "path": "d2mapapi/simphttp/llhttp/api.h",
    "content": "#ifndef INCLUDE_LLHTTP_API_H_\n#define INCLUDE_LLHTTP_API_H_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include <stddef.h>\n\n#if defined(__wasm__)\n#define LLHTTP_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define LLHTTP_EXPORT\n#endif\n\ntypedef llhttp__internal_t llhttp_t;\ntypedef struct llhttp_settings_s llhttp_settings_t;\n\ntypedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);\ntypedef int (*llhttp_cb)(llhttp_t*);\n\nstruct llhttp_settings_s {\n  /* Possible return values 0, -1, `HPE_PAUSED` */\n  llhttp_cb      on_message_begin;\n\n  /* Possible return values 0, -1, HPE_USER */\n  llhttp_data_cb on_url;\n  llhttp_data_cb on_status;\n  llhttp_data_cb on_header_field;\n  llhttp_data_cb on_header_value;\n\n  /* Possible return values:\n   * 0  - Proceed normally\n   * 1  - Assume that request/response has no body, and proceed to parsing the\n   *      next message\n   * 2  - Assume absence of body (as above) and make `llhttp_execute()` return\n   *      `HPE_PAUSED_UPGRADE`\n   * -1 - Error\n   * `HPE_PAUSED`\n   */\n  llhttp_cb      on_headers_complete;\n\n  /* Possible return values 0, -1, HPE_USER */\n  llhttp_data_cb on_body;\n\n  /* Possible return values 0, -1, `HPE_PAUSED` */\n  llhttp_cb      on_message_complete;\n\n  /* When on_chunk_header is called, the current chunk length is stored\n   * in parser->content_length.\n   * Possible return values 0, -1, `HPE_PAUSED`\n   */\n  llhttp_cb      on_chunk_header;\n  llhttp_cb      on_chunk_complete;\n\n  /* Information-only callbacks, return value is ignored */\n  llhttp_cb      on_url_complete;\n  llhttp_cb      on_status_complete;\n  llhttp_cb      on_header_field_complete;\n  llhttp_cb      on_header_value_complete;\n};\n\n/* Initialize the parser with specific type and user settings.\n *\n * NOTE: lifetime of `settings` has to be at least the same as the lifetime of\n * the `parser` here. In practice, `settings` has to be either a static\n * variable or be allocated with `malloc`, `new`, etc.\n */\nLLHTTP_EXPORT\nvoid llhttp_init(llhttp_t* parser, llhttp_type_t type,\n                 const llhttp_settings_t* settings);\n\n#if defined(__wasm__)\n\nLLHTTP_EXPORT\nllhttp_t* llhttp_alloc(llhttp_type_t type);\n\nLLHTTP_EXPORT\nvoid llhttp_free(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_type(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_http_major(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_http_minor(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_method(llhttp_t* parser);\n\nLLHTTP_EXPORT\nint llhttp_get_status_code(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_upgrade(llhttp_t* parser);\n\n#endif  // defined(__wasm__)\n\n/* Reset an already initialized parser back to the start state, preserving the\n * existing parser type, callback settings, user data, and lenient flags.\n */\nLLHTTP_EXPORT\nvoid llhttp_reset(llhttp_t* parser);\n\n/* Initialize the settings object */\nLLHTTP_EXPORT\nvoid llhttp_settings_init(llhttp_settings_t* settings);\n\n/* Parse full or partial request/response, invoking user callbacks along the\n * way.\n *\n * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing\n * interrupts, and such errno is returned from `llhttp_execute()`. If\n * `HPE_PAUSED` was used as a errno, the execution can be resumed with\n * `llhttp_resume()` call.\n *\n * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`\n * is returned after fully parsing the request/response. If the user wishes to\n * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.\n *\n * NOTE: if this function ever returns a non-pause type error, it will continue\n * to return the same error upon each successive call up until `llhttp_init()`\n * is called.\n */\nLLHTTP_EXPORT\nllhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);\n\n/* This method should be called when the other side has no further bytes to\n * send (e.g. shutdown of readable side of the TCP connection.)\n *\n * Requests without `Content-Length` and other messages might require treating\n * all incoming bytes as the part of the body, up to the last byte of the\n * connection. This method will invoke `on_message_complete()` callback if the\n * request was terminated safely. Otherwise a error code would be returned.\n */\nLLHTTP_EXPORT\nllhttp_errno_t llhttp_finish(llhttp_t* parser);\n\n/* Returns `1` if the incoming message is parsed until the last byte, and has\n * to be completed by calling `llhttp_finish()` on EOF\n */\nLLHTTP_EXPORT\nint llhttp_message_needs_eof(const llhttp_t* parser);\n\n/* Returns `1` if there might be any other messages following the last that was\n * successfully parsed.\n */\nLLHTTP_EXPORT\nint llhttp_should_keep_alive(const llhttp_t* parser);\n\n/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set\n * appropriate error reason.\n *\n * Important: do not call this from user callbacks! User callbacks must return\n * `HPE_PAUSED` if pausing is required.\n */\nLLHTTP_EXPORT\nvoid llhttp_pause(llhttp_t* parser);\n\n/* Might be called to resume the execution after the pause in user's callback.\n * See `llhttp_execute()` above for details.\n *\n * Call this only if `llhttp_execute()` returns `HPE_PAUSED`.\n */\nLLHTTP_EXPORT\nvoid llhttp_resume(llhttp_t* parser);\n\n/* Might be called to resume the execution after the pause in user's callback.\n * See `llhttp_execute()` above for details.\n *\n * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`\n */\nLLHTTP_EXPORT\nvoid llhttp_resume_after_upgrade(llhttp_t* parser);\n\n/* Returns the latest return error */\nLLHTTP_EXPORT\nllhttp_errno_t llhttp_get_errno(const llhttp_t* parser);\n\n/* Returns the verbal explanation of the latest returned error.\n *\n * Note: User callback should set error reason when returning the error. See\n * `llhttp_set_error_reason()` for details.\n */\nLLHTTP_EXPORT\nconst char* llhttp_get_error_reason(const llhttp_t* parser);\n\n/* Assign verbal description to the returned error. Must be called in user\n * callbacks right before returning the errno.\n *\n * Note: `HPE_USER` error code might be useful in user callbacks.\n */\nLLHTTP_EXPORT\nvoid llhttp_set_error_reason(llhttp_t* parser, const char* reason);\n\n/* Returns the pointer to the last parsed byte before the returned error. The\n * pointer is relative to the `data` argument of `llhttp_execute()`.\n *\n * Note: this method might be useful for counting the number of parsed bytes.\n */\nLLHTTP_EXPORT\nconst char* llhttp_get_error_pos(const llhttp_t* parser);\n\n/* Returns textual name of error code */\nLLHTTP_EXPORT\nconst char* llhttp_errno_name(llhttp_errno_t err);\n\n/* Returns textual name of HTTP method */\nLLHTTP_EXPORT\nconst char* llhttp_method_name(llhttp_method_t method);\n\n\n/* Enables/disables lenient header value parsing (disabled by default).\n *\n * Lenient parsing disables header value token checks, extending llhttp's\n * protocol support to highly non-compliant clients/server. No\n * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when\n * lenient parsing is \"on\".\n *\n * **(USE AT YOUR OWN RISK)**\n */\nLLHTTP_EXPORT\nvoid llhttp_set_lenient_headers(llhttp_t* parser, int enabled);\n\n\n/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and\n * `Content-Length` headers (disabled by default).\n *\n * Normally `llhttp` would error when `Transfer-Encoding` is present in\n * conjunction with `Content-Length`. This error is important to prevent HTTP\n * request smuggling, but may be less desirable for small number of cases\n * involving legacy servers.\n *\n * **(USE AT YOUR OWN RISK)**\n */\nLLHTTP_EXPORT\nvoid llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);\n\n\n/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0\n * requests responses.\n *\n * Normally `llhttp` would error on (in strict mode) or discard (in loose mode)\n * the HTTP request/response after the request/response with `Connection: close`\n * and `Content-Length`. This is important to prevent cache poisoning attacks,\n * but might interact badly with outdated and insecure clients. With this flag\n * the extra request/response will be parsed normally.\n *\n * **(USE AT YOUR OWN RISK)**\n */\nvoid llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* INCLUDE_LLHTTP_API_H_ */\n"
  },
  {
    "path": "d2mapapi/simphttp/llhttp/http.c",
    "content": "#include <stdio.h>\n#ifndef LLHTTP__TEST\n# include \"llhttp.h\"\n#else\n# define llhttp_t llparse_t\n#endif  /* */\n\nint llhttp_message_needs_eof(const llhttp_t* parser);\nint llhttp_should_keep_alive(const llhttp_t* parser);\n\nint llhttp__before_headers_complete(llhttp_t* parser, const char* p,\n                                    const char* endp) {\n  /* Set this here so that on_headers_complete() callbacks can see it */\n  if ((parser->flags & F_UPGRADE) &&\n      (parser->flags & F_CONNECTION_UPGRADE)) {\n    /* For responses, \"Upgrade: foo\" and \"Connection: upgrade\" are\n     * mandatory only when it is a 101 Switching Protocols response,\n     * otherwise it is purely informational, to announce support.\n     */\n    parser->upgrade =\n        (parser->type == HTTP_REQUEST || parser->status_code == 101);\n  } else {\n    parser->upgrade = (parser->method == HTTP_CONNECT);\n  }\n  return 0;\n}\n\n\n/* Return values:\n * 0 - No body, `restart`, message_complete\n * 1 - CONNECT request, `restart`, message_complete, and pause\n * 2 - chunk_size_start\n * 3 - body_identity\n * 4 - body_identity_eof\n * 5 - invalid transfer-encoding for request\n */\nint llhttp__after_headers_complete(llhttp_t* parser, const char* p,\n                                   const char* endp) {\n  int hasBody;\n\n  hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;\n  if (parser->upgrade && (parser->method == HTTP_CONNECT ||\n                          (parser->flags & F_SKIPBODY) || !hasBody)) {\n    /* Exit, the rest of the message is in a different protocol. */\n    return 1;\n  }\n\n  if (parser->flags & F_SKIPBODY) {\n    return 0;\n  } else if (parser->flags & F_CHUNKED) {\n    /* chunked encoding - ignore Content-Length header, prepare for a chunk */\n    return 2;\n  } else if (parser->flags & F_TRANSFER_ENCODING) {\n    if (parser->type == HTTP_REQUEST &&\n        (parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0) {\n      /* RFC 7230 3.3.3 */\n\n      /* If a Transfer-Encoding header field\n       * is present in a request and the chunked transfer coding is not\n       * the final encoding, the message body length cannot be determined\n       * reliably; the server MUST respond with the 400 (Bad Request)\n       * status code and then close the connection.\n       */\n      return 5;\n    } else {\n      /* RFC 7230 3.3.3 */\n\n      /* If a Transfer-Encoding header field is present in a response and\n       * the chunked transfer coding is not the final encoding, the\n       * message body length is determined by reading the connection until\n       * it is closed by the server.\n       */\n      return 4;\n    }\n  } else {\n    if (!(parser->flags & F_CONTENT_LENGTH)) {\n      if (!llhttp_message_needs_eof(parser)) {\n        /* Assume content-length 0 - read the next */\n        return 0;\n      } else {\n        /* Read body until EOF */\n        return 4;\n      }\n    } else if (parser->content_length == 0) {\n      /* Content-Length header given but zero: Content-Length: 0\\r\\n */\n      return 0;\n    } else {\n      /* Content-Length header given and non-zero */\n      return 3;\n    }\n  }\n}\n\n\nint llhttp__after_message_complete(llhttp_t* parser, const char* p,\n                                   const char* endp) {\n  int should_keep_alive;\n\n  should_keep_alive = llhttp_should_keep_alive(parser);\n  parser->finish = HTTP_FINISH_SAFE;\n  parser->flags = 0;\n\n  /* NOTE: this is ignored in loose parsing mode */\n  return should_keep_alive;\n}\n\n\nint llhttp_message_needs_eof(const llhttp_t* parser) {\n  if (parser->type == HTTP_REQUEST) {\n    return 0;\n  }\n\n  /* See RFC 2616 section 4.4 */\n  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */\n      parser->status_code == 204 ||     /* No Content */\n      parser->status_code == 304 ||     /* Not Modified */\n      (parser->flags & F_SKIPBODY)) {     /* response to a HEAD request */\n    return 0;\n  }\n\n  /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */\n  if ((parser->flags & F_TRANSFER_ENCODING) &&\n      (parser->flags & F_CHUNKED) == 0) {\n    return 1;\n  }\n\n  if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {\n    return 0;\n  }\n\n  return 1;\n}\n\n\nint llhttp_should_keep_alive(const llhttp_t* parser) {\n  if (parser->http_major > 0 && parser->http_minor > 0) {\n    /* HTTP/1.1 */\n    if (parser->flags & F_CONNECTION_CLOSE) {\n      return 0;\n    }\n  } else {\n    /* HTTP/1.0 or earlier */\n    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {\n      return 0;\n    }\n  }\n\n  return !llhttp_message_needs_eof(parser);\n}\n"
  },
  {
    "path": "d2mapapi/simphttp/llhttp/llhttp.c",
    "content": "#if LLHTTP_STRICT_MODE\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __SSE4_2__\n #ifdef _MSC_VER\n  #include <nmmintrin.h>\n #else  /* !_MSC_VER */\n  #include <x86intrin.h>\n #endif  /* _MSC_VER */\n#endif  /* __SSE4_2__ */\n\n#ifdef _MSC_VER\n #define ALIGN(n) _declspec(align(n))\n#else  /* !_MSC_VER */\n #define ALIGN(n) __attribute__((aligned(n)))\n#endif  /* _MSC_VER */\n\n#include \"llhttp.h\"\n\ntypedef int (*llhttp__internal__span_cb)(\n             llhttp__internal_t*, const char*, const char*);\n\nstatic const unsigned char llparse_blob0[] = {\n  0xd, 0xa\n};\nstatic const unsigned char llparse_blob1[] = {\n  'o', 'n'\n};\nstatic const unsigned char llparse_blob2[] = {\n  'e', 'c', 't', 'i', 'o', 'n'\n};\nstatic const unsigned char llparse_blob3[] = {\n  'l', 'o', 's', 'e'\n};\nstatic const unsigned char llparse_blob4[] = {\n  'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e'\n};\nstatic const unsigned char llparse_blob5[] = {\n  'p', 'g', 'r', 'a', 'd', 'e'\n};\nstatic const unsigned char llparse_blob6[] = {\n  'c', 'h', 'u', 'n', 'k', 'e', 'd'\n};\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob7[] = {\n  0x9, 0x9, ' ', '~', 0x80, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,\n  0x0, 0x0, 0x0, 0x0, 0x0\n};\n#endif  /* __SSE4_2__ */\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob8[] = {\n  '!', '!', '#', '\\'', '*', '+', '-', '.', '0', '9', 'A',\n  'Z', '^', 'z', '|', '|'\n};\n#endif  /* __SSE4_2__ */\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob9[] = {\n  '~', '~', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n  0x0, 0x0, 0x0, 0x0, 0x0\n};\n#endif  /* __SSE4_2__ */\nstatic const unsigned char llparse_blob10[] = {\n  'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h'\n};\nstatic const unsigned char llparse_blob11[] = {\n  'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c',\n  't', 'i', 'o', 'n'\n};\nstatic const unsigned char llparse_blob12[] = {\n  'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c',\n  'o', 'd', 'i', 'n', 'g'\n};\nstatic const unsigned char llparse_blob13[] = {\n  'p', 'g', 'r', 'a', 'd', 'e'\n};\nstatic const unsigned char llparse_blob14[] = {\n  'T', 'T', 'P', '/'\n};\nstatic const unsigned char llparse_blob15[] = {\n  0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa\n};\nstatic const unsigned char llparse_blob16[] = {\n  'C', 'E', '/'\n};\nstatic const unsigned char llparse_blob17[] = {\n  'T', 'S', 'P', '/'\n};\nstatic const unsigned char llparse_blob18[] = {\n  'N', 'O', 'U', 'N', 'C', 'E'\n};\nstatic const unsigned char llparse_blob19[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob20[] = {\n  'E', 'C', 'K', 'O', 'U', 'T'\n};\nstatic const unsigned char llparse_blob21[] = {\n  'N', 'E', 'C', 'T'\n};\nstatic const unsigned char llparse_blob22[] = {\n  'E', 'T', 'E'\n};\nstatic const unsigned char llparse_blob23[] = {\n  'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob24[] = {\n  'L', 'U', 'S', 'H'\n};\nstatic const unsigned char llparse_blob25[] = {\n  'E', 'T'\n};\nstatic const unsigned char llparse_blob26[] = {\n  'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R'\n};\nstatic const unsigned char llparse_blob27[] = {\n  'E', 'A', 'D'\n};\nstatic const unsigned char llparse_blob28[] = {\n  'N', 'K'\n};\nstatic const unsigned char llparse_blob29[] = {\n  'C', 'K'\n};\nstatic const unsigned char llparse_blob30[] = {\n  'S', 'E', 'A', 'R', 'C', 'H'\n};\nstatic const unsigned char llparse_blob31[] = {\n  'R', 'G', 'E'\n};\nstatic const unsigned char llparse_blob32[] = {\n  'C', 'T', 'I', 'V', 'I', 'T', 'Y'\n};\nstatic const unsigned char llparse_blob33[] = {\n  'L', 'E', 'N', 'D', 'A', 'R'\n};\nstatic const unsigned char llparse_blob34[] = {\n  'V', 'E'\n};\nstatic const unsigned char llparse_blob35[] = {\n  'O', 'T', 'I', 'F', 'Y'\n};\nstatic const unsigned char llparse_blob36[] = {\n  'P', 'T', 'I', 'O', 'N', 'S'\n};\nstatic const unsigned char llparse_blob37[] = {\n  'C', 'H'\n};\nstatic const unsigned char llparse_blob38[] = {\n  'S', 'E'\n};\nstatic const unsigned char llparse_blob39[] = {\n  'A', 'Y'\n};\nstatic const unsigned char llparse_blob40[] = {\n  'S', 'T'\n};\nstatic const unsigned char llparse_blob41[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob42[] = {\n  'A', 'T', 'C', 'H'\n};\nstatic const unsigned char llparse_blob43[] = {\n  'G', 'E'\n};\nstatic const unsigned char llparse_blob44[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob45[] = {\n  'O', 'R', 'D'\n};\nstatic const unsigned char llparse_blob46[] = {\n  'I', 'R', 'E', 'C', 'T'\n};\nstatic const unsigned char llparse_blob47[] = {\n  'O', 'R', 'T'\n};\nstatic const unsigned char llparse_blob48[] = {\n  'R', 'C', 'H'\n};\nstatic const unsigned char llparse_blob49[] = {\n  'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R'\n};\nstatic const unsigned char llparse_blob50[] = {\n  'U', 'R', 'C', 'E'\n};\nstatic const unsigned char llparse_blob51[] = {\n  'B', 'S', 'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob52[] = {\n  'A', 'R', 'D', 'O', 'W', 'N'\n};\nstatic const unsigned char llparse_blob53[] = {\n  'A', 'C', 'E'\n};\nstatic const unsigned char llparse_blob54[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob55[] = {\n  'N', 'K'\n};\nstatic const unsigned char llparse_blob56[] = {\n  'C', 'K'\n};\nstatic const unsigned char llparse_blob57[] = {\n  'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob58[] = {\n  'H', 'T', 'T', 'P', '/'\n};\nstatic const unsigned char llparse_blob59[] = {\n  'A', 'D'\n};\nstatic const unsigned char llparse_blob60[] = {\n  'T', 'P', '/'\n};\n\nenum llparse_match_status_e {\n  kMatchComplete,\n  kMatchPause,\n  kMatchMismatch\n};\ntypedef enum llparse_match_status_e llparse_match_status_t;\n\nstruct llparse_match_s {\n  llparse_match_status_t status;\n  const unsigned char* current;\n};\ntypedef struct llparse_match_s llparse_match_t;\n\nstatic llparse_match_t llparse__match_sequence_id(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = *p;\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nstatic llparse_match_t llparse__match_sequence_to_lower(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = ((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p));\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nstatic llparse_match_t llparse__match_sequence_to_lower_unsafe(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = ((*p) | 0x20);\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nenum llparse_state_e {\n  s_error,\n  s_n_llhttp__internal__n_closed,\n  s_n_llhttp__internal__n_invoke_llhttp__after_message_complete,\n  s_n_llhttp__internal__n_pause_1,\n  s_n_llhttp__internal__n_invoke_is_equal_upgrade,\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2,\n  s_n_llhttp__internal__n_chunk_data_almost_done,\n  s_n_llhttp__internal__n_consume_content_length,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body,\n  s_n_llhttp__internal__n_invoke_is_equal_content_length,\n  s_n_llhttp__internal__n_chunk_size_almost_done,\n  s_n_llhttp__internal__n_chunk_parameters,\n  s_n_llhttp__internal__n_chunk_size_otherwise,\n  s_n_llhttp__internal__n_chunk_size,\n  s_n_llhttp__internal__n_chunk_size_digit,\n  s_n_llhttp__internal__n_invoke_update_content_length,\n  s_n_llhttp__internal__n_consume_content_length_1,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body_1,\n  s_n_llhttp__internal__n_eof,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body_2,\n  s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete,\n  s_n_llhttp__internal__n_headers_almost_done,\n  s_n_llhttp__internal__n_header_field_colon_discard_ws,\n  s_n_llhttp__internal__n_error_19,\n  s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_value,\n  s_n_llhttp__internal__n_header_value_discard_lws,\n  s_n_llhttp__internal__n_header_value_discard_ws_almost_done,\n  s_n_llhttp__internal__n_header_value_lws,\n  s_n_llhttp__internal__n_header_value_almost_done,\n  s_n_llhttp__internal__n_header_value_lenient,\n  s_n_llhttp__internal__n_header_value_otherwise,\n  s_n_llhttp__internal__n_header_value_connection_token,\n  s_n_llhttp__internal__n_header_value_connection_ws,\n  s_n_llhttp__internal__n_header_value_connection_1,\n  s_n_llhttp__internal__n_header_value_connection_2,\n  s_n_llhttp__internal__n_header_value_connection_3,\n  s_n_llhttp__internal__n_header_value_connection,\n  s_n_llhttp__internal__n_error_25,\n  s_n_llhttp__internal__n_error_26,\n  s_n_llhttp__internal__n_header_value_content_length_ws,\n  s_n_llhttp__internal__n_header_value_content_length,\n  s_n_llhttp__internal__n_header_value_te_chunked_last,\n  s_n_llhttp__internal__n_header_value_te_token_ows,\n  s_n_llhttp__internal__n_header_value,\n  s_n_llhttp__internal__n_header_value_te_token,\n  s_n_llhttp__internal__n_header_value_te_chunked,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1,\n  s_n_llhttp__internal__n_header_value_discard_ws,\n  s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete,\n  s_n_llhttp__internal__n_header_field_general_otherwise,\n  s_n_llhttp__internal__n_header_field_general,\n  s_n_llhttp__internal__n_header_field_colon,\n  s_n_llhttp__internal__n_header_field_3,\n  s_n_llhttp__internal__n_header_field_4,\n  s_n_llhttp__internal__n_header_field_2,\n  s_n_llhttp__internal__n_header_field_1,\n  s_n_llhttp__internal__n_header_field_5,\n  s_n_llhttp__internal__n_header_field_6,\n  s_n_llhttp__internal__n_header_field_7,\n  s_n_llhttp__internal__n_header_field,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_field,\n  s_n_llhttp__internal__n_header_field_start,\n  s_n_llhttp__internal__n_url_to_http_09,\n  s_n_llhttp__internal__n_url_skip_to_http09,\n  s_n_llhttp__internal__n_url_skip_lf_to_http09_1,\n  s_n_llhttp__internal__n_url_skip_lf_to_http09,\n  s_n_llhttp__internal__n_req_pri_upgrade,\n  s_n_llhttp__internal__n_req_http_complete_1,\n  s_n_llhttp__internal__n_req_http_complete,\n  s_n_llhttp__internal__n_req_http_minor,\n  s_n_llhttp__internal__n_req_http_dot,\n  s_n_llhttp__internal__n_req_http_major,\n  s_n_llhttp__internal__n_req_http_start_1,\n  s_n_llhttp__internal__n_req_http_start_2,\n  s_n_llhttp__internal__n_req_http_start_3,\n  s_n_llhttp__internal__n_req_http_start,\n  s_n_llhttp__internal__n_url_to_http,\n  s_n_llhttp__internal__n_url_skip_to_http,\n  s_n_llhttp__internal__n_url_fragment,\n  s_n_llhttp__internal__n_span_end_stub_query_3,\n  s_n_llhttp__internal__n_url_query,\n  s_n_llhttp__internal__n_url_query_or_fragment,\n  s_n_llhttp__internal__n_url_path,\n  s_n_llhttp__internal__n_span_start_stub_path_2,\n  s_n_llhttp__internal__n_span_start_stub_path,\n  s_n_llhttp__internal__n_span_start_stub_path_1,\n  s_n_llhttp__internal__n_url_server_with_at,\n  s_n_llhttp__internal__n_url_server,\n  s_n_llhttp__internal__n_url_schema_delim_1,\n  s_n_llhttp__internal__n_url_schema_delim,\n  s_n_llhttp__internal__n_span_end_stub_schema,\n  s_n_llhttp__internal__n_url_schema,\n  s_n_llhttp__internal__n_url_start,\n  s_n_llhttp__internal__n_span_start_llhttp__on_url_1,\n  s_n_llhttp__internal__n_url_entry_normal,\n  s_n_llhttp__internal__n_span_start_llhttp__on_url,\n  s_n_llhttp__internal__n_url_entry_connect,\n  s_n_llhttp__internal__n_req_spaces_before_url,\n  s_n_llhttp__internal__n_req_first_space_before_url,\n  s_n_llhttp__internal__n_start_req_2,\n  s_n_llhttp__internal__n_start_req_3,\n  s_n_llhttp__internal__n_start_req_1,\n  s_n_llhttp__internal__n_start_req_4,\n  s_n_llhttp__internal__n_start_req_6,\n  s_n_llhttp__internal__n_start_req_8,\n  s_n_llhttp__internal__n_start_req_9,\n  s_n_llhttp__internal__n_start_req_7,\n  s_n_llhttp__internal__n_start_req_5,\n  s_n_llhttp__internal__n_start_req_12,\n  s_n_llhttp__internal__n_start_req_13,\n  s_n_llhttp__internal__n_start_req_11,\n  s_n_llhttp__internal__n_start_req_10,\n  s_n_llhttp__internal__n_start_req_14,\n  s_n_llhttp__internal__n_start_req_17,\n  s_n_llhttp__internal__n_start_req_16,\n  s_n_llhttp__internal__n_start_req_15,\n  s_n_llhttp__internal__n_start_req_18,\n  s_n_llhttp__internal__n_start_req_20,\n  s_n_llhttp__internal__n_start_req_21,\n  s_n_llhttp__internal__n_start_req_19,\n  s_n_llhttp__internal__n_start_req_23,\n  s_n_llhttp__internal__n_start_req_24,\n  s_n_llhttp__internal__n_start_req_26,\n  s_n_llhttp__internal__n_start_req_28,\n  s_n_llhttp__internal__n_start_req_29,\n  s_n_llhttp__internal__n_start_req_27,\n  s_n_llhttp__internal__n_start_req_25,\n  s_n_llhttp__internal__n_start_req_30,\n  s_n_llhttp__internal__n_start_req_22,\n  s_n_llhttp__internal__n_start_req_31,\n  s_n_llhttp__internal__n_start_req_32,\n  s_n_llhttp__internal__n_start_req_35,\n  s_n_llhttp__internal__n_start_req_36,\n  s_n_llhttp__internal__n_start_req_34,\n  s_n_llhttp__internal__n_start_req_37,\n  s_n_llhttp__internal__n_start_req_38,\n  s_n_llhttp__internal__n_start_req_42,\n  s_n_llhttp__internal__n_start_req_43,\n  s_n_llhttp__internal__n_start_req_41,\n  s_n_llhttp__internal__n_start_req_40,\n  s_n_llhttp__internal__n_start_req_39,\n  s_n_llhttp__internal__n_start_req_45,\n  s_n_llhttp__internal__n_start_req_44,\n  s_n_llhttp__internal__n_start_req_33,\n  s_n_llhttp__internal__n_start_req_48,\n  s_n_llhttp__internal__n_start_req_49,\n  s_n_llhttp__internal__n_start_req_50,\n  s_n_llhttp__internal__n_start_req_51,\n  s_n_llhttp__internal__n_start_req_47,\n  s_n_llhttp__internal__n_start_req_46,\n  s_n_llhttp__internal__n_start_req_54,\n  s_n_llhttp__internal__n_start_req_56,\n  s_n_llhttp__internal__n_start_req_57,\n  s_n_llhttp__internal__n_start_req_55,\n  s_n_llhttp__internal__n_start_req_53,\n  s_n_llhttp__internal__n_start_req_58,\n  s_n_llhttp__internal__n_start_req_59,\n  s_n_llhttp__internal__n_start_req_52,\n  s_n_llhttp__internal__n_start_req_61,\n  s_n_llhttp__internal__n_start_req_62,\n  s_n_llhttp__internal__n_start_req_60,\n  s_n_llhttp__internal__n_start_req_65,\n  s_n_llhttp__internal__n_start_req_67,\n  s_n_llhttp__internal__n_start_req_68,\n  s_n_llhttp__internal__n_start_req_66,\n  s_n_llhttp__internal__n_start_req_69,\n  s_n_llhttp__internal__n_start_req_64,\n  s_n_llhttp__internal__n_start_req_63,\n  s_n_llhttp__internal__n_start_req,\n  s_n_llhttp__internal__n_invoke_llhttp__on_status_complete,\n  s_n_llhttp__internal__n_res_line_almost_done,\n  s_n_llhttp__internal__n_res_status,\n  s_n_llhttp__internal__n_span_start_llhttp__on_status,\n  s_n_llhttp__internal__n_res_status_start,\n  s_n_llhttp__internal__n_res_status_code_otherwise,\n  s_n_llhttp__internal__n_res_status_code,\n  s_n_llhttp__internal__n_res_http_end,\n  s_n_llhttp__internal__n_res_http_minor,\n  s_n_llhttp__internal__n_res_http_dot,\n  s_n_llhttp__internal__n_res_http_major,\n  s_n_llhttp__internal__n_start_res,\n  s_n_llhttp__internal__n_req_or_res_method_2,\n  s_n_llhttp__internal__n_req_or_res_method_3,\n  s_n_llhttp__internal__n_req_or_res_method_1,\n  s_n_llhttp__internal__n_req_or_res_method,\n  s_n_llhttp__internal__n_start_req_or_res,\n  s_n_llhttp__internal__n_invoke_load_type,\n  s_n_llhttp__internal__n_start,\n};\ntypedef enum llparse_state_e llparse_state_t;\n\nint llhttp__on_url(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_header_field(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_header_value(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_body(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_status(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_finish(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 2;\n  return 0;\n}\n\nint llhttp__on_message_begin(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_load_type(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->type;\n}\n\nint llhttp__internal__c_store_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->method = match;\n  return 0;\n}\n\nint llhttp__internal__c_is_equal_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->method == 5;\n}\n\nint llhttp__internal__c_update_http_major(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->http_major = 0;\n  return 0;\n}\n\nint llhttp__internal__c_update_http_minor(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->http_minor = 9;\n  return 0;\n}\n\nint llhttp__on_url_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_test_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 128) == 128;\n}\n\nint llhttp__on_chunk_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_message_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_is_equal_upgrade(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->upgrade == 1;\n}\n\nint llhttp__after_message_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_finish_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 0;\n  return 0;\n}\n\nint llhttp__internal__c_test_lenient_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->lenient_flags & 4) == 4;\n}\n\nint llhttp__internal__c_test_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 544) == 544;\n}\n\nint llhttp__internal__c_test_lenient_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->lenient_flags & 2) == 2;\n}\n\nint llhttp__before_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__after_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->content_length = 0;\n  return 0;\n}\n\nint llhttp__internal__c_mul_add_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->content_length > 0xffffffffffffffffULL / 16) {\n    return 1;\n  }\n  \n  state->content_length *= 16;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->content_length > 0xffffffffffffffffULL - match) {\n      return 1;\n    }\n  } else {\n    if (state->content_length < 0ULL - match) {\n      return 1;\n    }\n  }\n  state->content_length += match;\n  return 0;\n}\n\nint llhttp__on_chunk_header(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_is_equal_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->content_length == 0;\n}\n\nint llhttp__internal__c_or_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 128;\n  return 0;\n}\n\nint llhttp__internal__c_update_finish_3(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 1;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 64;\n  return 0;\n}\n\nint llhttp__internal__c_update_upgrade(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->upgrade = 1;\n  return 0;\n}\n\nint llhttp__internal__c_store_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->header_state = match;\n  return 0;\n}\n\nint llhttp__internal__c_test_lenient_flags_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->lenient_flags & 1) == 1;\n}\n\nint llhttp__on_header_field_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_load_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->header_state;\n}\n\nint llhttp__internal__c_or_flags_3(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 1;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 1;\n  return 0;\n}\n\nint llhttp__on_header_value_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_or_flags_4(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 2;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_5(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 4;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_6(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 8;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 6;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_4(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 0;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_5(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 5;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_6(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 7;\n  return 0;\n}\n\nint llhttp__internal__c_test_flags_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 32) == 32;\n}\n\nint llhttp__internal__c_mul_add_content_length_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->content_length > 0xffffffffffffffffULL / 10) {\n    return 1;\n  }\n  \n  state->content_length *= 10;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->content_length > 0xffffffffffffffffULL - match) {\n      return 1;\n    }\n  } else {\n    if (state->content_length < 0ULL - match) {\n      return 1;\n    }\n  }\n  state->content_length += match;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_15(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 32;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_16(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 512;\n  return 0;\n}\n\nint llhttp__internal__c_and_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags &= -9;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_7(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 8;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_17(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 16;\n  return 0;\n}\n\nint llhttp__internal__c_load_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->method;\n}\n\nint llhttp__internal__c_store_http_major(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->http_major = match;\n  return 0;\n}\n\nint llhttp__internal__c_store_http_minor(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->http_minor = match;\n  return 0;\n}\n\nint llhttp__internal__c_update_status_code(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->status_code = 0;\n  return 0;\n}\n\nint llhttp__internal__c_mul_add_status_code(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->status_code > 0xffff / 10) {\n    return 1;\n  }\n  \n  state->status_code *= 10;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->status_code > 0xffff - match) {\n      return 1;\n    }\n  } else {\n    if (state->status_code < 0 - match) {\n      return 1;\n    }\n  }\n  state->status_code += match;\n  \n  /* Enforce maximum */\n  if (state->status_code > 999) {\n    return 1;\n  }\n  return 0;\n}\n\nint llhttp__on_status_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_type(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->type = 1;\n  return 0;\n}\n\nint llhttp__internal__c_update_type_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->type = 2;\n  return 0;\n}\n\nint llhttp__internal_init(llhttp__internal_t* state) {\n  memset(state, 0, sizeof(*state));\n  state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start;\n  return 0;\n}\n\nstatic llparse_state_t llhttp__internal__run(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  int match;\n  switch ((llparse_state_t) (intptr_t) state->_current) {\n    case s_n_llhttp__internal__n_closed:\n    s_n_llhttp__internal__n_closed: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_closed;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_closed;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_closed;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_error_4;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: {\n      switch (llhttp__after_message_complete(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_invoke_update_finish_2;\n        default:\n          goto s_n_llhttp__internal__n_invoke_update_finish_1;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_pause_1:\n    s_n_llhttp__internal__n_pause_1: {\n      state->error = 0x16;\n      state->reason = \"Pause on CONNECT/Upgrade\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_is_equal_upgrade:\n    s_n_llhttp__internal__n_invoke_is_equal_upgrade: {\n      switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n        default:\n          goto s_n_llhttp__internal__n_pause_1;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2:\n    s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: {\n      switch (llhttp__on_message_complete(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_invoke_is_equal_upgrade;\n        case 21:\n          goto s_n_llhttp__internal__n_pause_5;\n        default:\n          goto s_n_llhttp__internal__n_error_14;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_data_almost_done:\n    s_n_llhttp__internal__n_chunk_data_almost_done: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_data_almost_done;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob0, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_chunk_data_almost_done;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_8;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_consume_content_length:\n    s_n_llhttp__internal__n_consume_content_length: {\n      size_t avail;\n      uint64_t need;\n      \n      avail = endp - p;\n      need = state->content_length;\n      if (avail >= need) {\n        p += need;\n        state->content_length = 0;\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_body;\n      }\n      \n      state->content_length -= avail;\n      return s_n_llhttp__internal__n_consume_content_length;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_consume_content_length;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_is_equal_content_length:\n    s_n_llhttp__internal__n_invoke_is_equal_content_length: {\n      switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_body;\n        default:\n          goto s_n_llhttp__internal__n_invoke_or_flags;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_almost_done:\n    s_n_llhttp__internal__n_chunk_size_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_9;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_parameters:\n    s_n_llhttp__internal__n_chunk_parameters: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_parameters;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_size_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_otherwise:\n    s_n_llhttp__internal__n_chunk_size_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_otherwise;\n      }\n      switch (*p) {\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_size_almost_done;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        case ';': {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_11;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size:\n    s_n_llhttp__internal__n_chunk_size: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'A': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'B': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'C': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'D': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'E': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'F': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'a': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'b': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'c': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'd': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'e': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'f': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_chunk_size_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_digit:\n    s_n_llhttp__internal__n_chunk_size_digit: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_digit;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'A': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'B': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'C': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'D': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'E': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'F': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'a': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'b': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'c': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'd': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'e': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'f': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_13;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_update_content_length:\n    s_n_llhttp__internal__n_invoke_update_content_length: {\n      switch (llhttp__internal__c_update_content_length(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_chunk_size_digit;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_consume_content_length_1:\n    s_n_llhttp__internal__n_consume_content_length_1: {\n      size_t avail;\n      uint64_t need;\n      \n      avail = endp - p;\n      need = state->content_length;\n      if (avail >= need) {\n        p += need;\n        state->content_length = 0;\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1;\n      }\n      \n      state->content_length -= avail;\n      return s_n_llhttp__internal__n_consume_content_length_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_consume_content_length_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_eof:\n    s_n_llhttp__internal__n_eof: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_eof;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_eof;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body_2:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body_2;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_eof;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: {\n      switch (llhttp__after_headers_complete(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1;\n        case 2:\n          goto s_n_llhttp__internal__n_invoke_update_content_length;\n        case 3:\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1;\n        case 4:\n          goto s_n_llhttp__internal__n_invoke_update_finish_3;\n        case 5:\n          goto s_n_llhttp__internal__n_error_15;\n        default:\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_headers_almost_done:\n    s_n_llhttp__internal__n_headers_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_headers_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_test_flags;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_18;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_colon_discard_ws:\n    s_n_llhttp__internal__n_header_field_colon_discard_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_colon_discard_ws;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_colon_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_field_colon;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_19:\n    s_n_llhttp__internal__n_error_19: {\n      state->error = 0xa;\n      state->reason = \"Invalid header field char\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: {\n      switch (llhttp__on_header_value_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_header_field_start;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_value:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_value: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_value;\n      goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_lws:\n    s_n_llhttp__internal__n_header_value_discard_lws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_lws;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_load_header_state;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_ws_almost_done:\n    s_n_llhttp__internal__n_header_value_discard_ws_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_ws_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_lws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_21;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_lws:\n    s_n_llhttp__internal__n_header_value_lws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_lws;\n      }\n      switch (*p) {\n        case 9: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_load_header_state_3;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_almost_done:\n    s_n_llhttp__internal__n_header_value_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_lws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_22;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_lenient:\n    s_n_llhttp__internal__n_header_value_lenient: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_lenient;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_lenient;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_otherwise:\n    s_n_llhttp__internal__n_header_value_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_otherwise;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_token:\n    s_n_llhttp__internal__n_header_value_connection_token: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_token;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_ws:\n    s_n_llhttp__internal__n_header_value_connection_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_ws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_ws;\n        }\n        case ',': {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_header_state_4;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_4;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_1:\n    s_n_llhttp__internal__n_header_value_connection_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_1;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob3, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_2:\n    s_n_llhttp__internal__n_header_value_connection_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_2;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob4, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_5;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_3:\n    s_n_llhttp__internal__n_header_value_connection_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_3;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob5, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_6;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection:\n    s_n_llhttp__internal__n_header_value_connection: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection;\n      }\n      switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_1;\n        }\n        case 'k': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_2;\n        }\n        case 'u': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_25:\n    s_n_llhttp__internal__n_error_25: {\n      state->error = 0xb;\n      state->reason = \"Content-Length overflow\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_26:\n    s_n_llhttp__internal__n_error_26: {\n      state->error = 0xb;\n      state->reason = \"Invalid character in Content-Length\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_content_length_ws:\n    s_n_llhttp__internal__n_header_value_content_length_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_content_length_ws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_invoke_or_flags_15;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_invoke_or_flags_15;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_content_length_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_content_length:\n    s_n_llhttp__internal__n_header_value_content_length: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_content_length;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_content_length_ws;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_chunked_last:\n    s_n_llhttp__internal__n_header_value_te_chunked_last: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_chunked_last;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_chunked_last;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_te_chunked;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_token_ows:\n    s_n_llhttp__internal__n_header_value_te_token_ows: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_token_ows;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token_ows;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token_ows;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_te_chunked;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value:\n    s_n_llhttp__internal__n_header_value: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob7);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 6,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_value;\n        }\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_token:\n    s_n_llhttp__internal__n_header_value_te_token: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_token;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token_ows;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_8;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_chunked:\n    s_n_llhttp__internal__n_header_value_te_chunked: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_chunked;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_chunked_last;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_te_chunked;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_te_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_value;\n      goto s_n_llhttp__internal__n_invoke_load_header_state_2;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_ws:\n    s_n_llhttp__internal__n_header_value_discard_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_ws;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_lws;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: {\n      switch (llhttp__on_header_field_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_general_otherwise:\n    s_n_llhttp__internal__n_header_field_general_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_general_otherwise;\n      }\n      switch (*p) {\n        case ':': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_27;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_general:\n    s_n_llhttp__internal__n_header_field_general: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n        0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_general;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob8);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 16,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob9);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 2,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        goto s_n_llhttp__internal__n_header_field_general_otherwise;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_field_general_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_colon:\n    s_n_llhttp__internal__n_header_field_colon: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_colon;\n      }\n      switch (*p) {\n        case ' ': {\n          goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2;\n        }\n        case ':': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_9;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_3:\n    s_n_llhttp__internal__n_header_field_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_3;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob2, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_4:\n    s_n_llhttp__internal__n_header_field_4: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_4;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob10, 10);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_4;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_2:\n    s_n_llhttp__internal__n_header_field_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_2;\n      }\n      switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) {\n        case 'n': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_3;\n        }\n        case 't': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_4;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_1:\n    s_n_llhttp__internal__n_header_field_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_1;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob1, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_5:\n    s_n_llhttp__internal__n_header_field_5: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_5;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob11, 15);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_5;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_6:\n    s_n_llhttp__internal__n_header_field_6: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_6;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob12, 16);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_6;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_7:\n    s_n_llhttp__internal__n_header_field_7: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_7;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob13, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_7;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field:\n    s_n_llhttp__internal__n_header_field: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field;\n      }\n      switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) {\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_1;\n        }\n        case 'p': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_5;\n        }\n        case 't': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_6;\n        }\n        case 'u': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_7;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_field:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_field: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_field;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_field;\n      goto s_n_llhttp__internal__n_header_field;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_start:\n    s_n_llhttp__internal__n_header_field_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_start;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_headers_almost_done;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_headers_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_to_http_09:\n    s_n_llhttp__internal__n_url_to_http_09: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_to_http_09;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_http_major;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_to_http09:\n    s_n_llhttp__internal__n_url_skip_to_http09: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_to_http09;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_url_to_http_09;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_lf_to_http09_1:\n    s_n_llhttp__internal__n_url_skip_lf_to_http09_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_lf_to_http09_1;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_url_to_http_09;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_28;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_lf_to_http09:\n    s_n_llhttp__internal__n_url_skip_lf_to_http09: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_url_skip_lf_to_http09_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_28;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_pri_upgrade:\n    s_n_llhttp__internal__n_req_pri_upgrade: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_pri_upgrade;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 10);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_error_31;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_pri_upgrade;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_complete_1:\n    s_n_llhttp__internal__n_req_http_complete_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_complete_1;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_30;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_complete:\n    s_n_llhttp__internal__n_req_http_complete: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_complete;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_complete_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_30;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_minor:\n    s_n_llhttp__internal__n_req_http_minor: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_minor;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_33;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_dot:\n    s_n_llhttp__internal__n_req_http_dot: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_dot;\n      }\n      switch (*p) {\n        case '.': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_34;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_major:\n    s_n_llhttp__internal__n_req_http_major: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_major;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_35;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_1:\n    s_n_llhttp__internal__n_req_http_start_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_1;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_method;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_38;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_2:\n    s_n_llhttp__internal__n_req_http_start_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_method_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_38;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_3:\n    s_n_llhttp__internal__n_req_http_start_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_method_3;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_38;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start:\n    s_n_llhttp__internal__n_req_http_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start;\n        }\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_1;\n        }\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_2;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_38;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_to_http:\n    s_n_llhttp__internal__n_url_to_http: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_to_http;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_to_http:\n    s_n_llhttp__internal__n_url_skip_to_http: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_to_http;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_url_to_http;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_fragment:\n    s_n_llhttp__internal__n_url_fragment: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_fragment;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8;\n        }\n        case 5: {\n          p++;\n          goto s_n_llhttp__internal__n_url_fragment;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_39;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_end_stub_query_3:\n    s_n_llhttp__internal__n_span_end_stub_query_3: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_end_stub_query_3;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_fragment;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_query:\n    s_n_llhttp__internal__n_url_query: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_query;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11;\n        }\n        case 5: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 6: {\n          goto s_n_llhttp__internal__n_span_end_stub_query_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_40;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_query_or_fragment:\n    s_n_llhttp__internal__n_url_query_or_fragment: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_query_or_fragment;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5;\n        }\n        case '#': {\n          p++;\n          goto s_n_llhttp__internal__n_url_fragment;\n        }\n        case '?': {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_41;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_path:\n    s_n_llhttp__internal__n_url_path: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,\n        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_path;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_url_path;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_url_query_or_fragment;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path_2:\n    s_n_llhttp__internal__n_span_start_stub_path_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path_2;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path:\n    s_n_llhttp__internal__n_span_start_stub_path: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path_1:\n    s_n_llhttp__internal__n_span_start_stub_path_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path_1;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_server_with_at:\n    s_n_llhttp__internal__n_url_server_with_at: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7,\n        8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5,\n        0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_server_with_at;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14;\n        }\n        case 5: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        case 6: {\n          goto s_n_llhttp__internal__n_span_start_stub_path_1;\n        }\n        case 7: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 8: {\n          p++;\n          goto s_n_llhttp__internal__n_error_42;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_server:\n    s_n_llhttp__internal__n_url_server: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7,\n        8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5,\n        0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_server;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2;\n        }\n        case 5: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        case 6: {\n          goto s_n_llhttp__internal__n_span_start_stub_path;\n        }\n        case 7: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 8: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server_with_at;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_44;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema_delim_1:\n    s_n_llhttp__internal__n_url_schema_delim_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema_delim_1;\n      }\n      switch (*p) {\n        case '/': {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_46;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema_delim:\n    s_n_llhttp__internal__n_url_schema_delim: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema_delim;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_error_45;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_error_45;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_error_45;\n        }\n        case '/': {\n          p++;\n          goto s_n_llhttp__internal__n_url_schema_delim_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_46;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_end_stub_schema:\n    s_n_llhttp__internal__n_span_end_stub_schema: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_end_stub_schema;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_schema_delim;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema:\n    s_n_llhttp__internal__n_url_schema: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_error_45;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_stub_schema;\n        }\n        case 4: {\n          p++;\n          goto s_n_llhttp__internal__n_url_schema;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_47;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_start:\n    s_n_llhttp__internal__n_url_start: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_start;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_error_45;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_start_stub_path_2;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_url_schema;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_48;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_url_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_url_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_url_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_url;\n      goto s_n_llhttp__internal__n_url_start;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_entry_normal:\n    s_n_llhttp__internal__n_url_entry_normal: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_entry_normal;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_url:\n    s_n_llhttp__internal__n_span_start_llhttp__on_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_url;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_url;\n      goto s_n_llhttp__internal__n_url_server;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_entry_connect:\n    s_n_llhttp__internal__n_url_entry_connect: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_entry_connect;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        case 12: {\n          p++;\n          goto s_n_llhttp__internal__n_error_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_url;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_spaces_before_url:\n    s_n_llhttp__internal__n_req_spaces_before_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_spaces_before_url;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_spaces_before_url;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_is_equal_method;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_first_space_before_url:\n    s_n_llhttp__internal__n_req_first_space_before_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_first_space_before_url;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_spaces_before_url;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_49;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_2:\n    s_n_llhttp__internal__n_start_req_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_2;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          match = 19;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_3:\n    s_n_llhttp__internal__n_start_req_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 36;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_1:\n    s_n_llhttp__internal__n_start_req_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_1;\n      }\n      switch (*p) {\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_2;\n        }\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_4:\n    s_n_llhttp__internal__n_start_req_4: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_4;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 16;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_4;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_6:\n    s_n_llhttp__internal__n_start_req_6: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_6;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 22;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_6;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_8:\n    s_n_llhttp__internal__n_start_req_8: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_8;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_8;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_9:\n    s_n_llhttp__internal__n_start_req_9: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_9;\n      }\n      switch (*p) {\n        case 'Y': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_7:\n    s_n_llhttp__internal__n_start_req_7: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_7;\n      }\n      switch (*p) {\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_8;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_9;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_5:\n    s_n_llhttp__internal__n_start_req_5: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_5;\n      }\n      switch (*p) {\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_6;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_7;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_12:\n    s_n_llhttp__internal__n_start_req_12: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_12;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_12;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_13:\n    s_n_llhttp__internal__n_start_req_13: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_13;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 35;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_13;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_11:\n    s_n_llhttp__internal__n_start_req_11: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_11;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_12;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_13;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_10:\n    s_n_llhttp__internal__n_start_req_10: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_10;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_11;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_14:\n    s_n_llhttp__internal__n_start_req_14: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_14;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 45;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_14;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_17:\n    s_n_llhttp__internal__n_start_req_17: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_17;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 41;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_17;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_16:\n    s_n_llhttp__internal__n_start_req_16: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_16;\n      }\n      switch (*p) {\n        case '_': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_17;\n        }\n        default: {\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_15:\n    s_n_llhttp__internal__n_start_req_15: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_15;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_16;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_15;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_18:\n    s_n_llhttp__internal__n_start_req_18: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_18;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_18;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_20:\n    s_n_llhttp__internal__n_start_req_20: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_20;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 31;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_20;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_21:\n    s_n_llhttp__internal__n_start_req_21: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_21;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_21;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_19:\n    s_n_llhttp__internal__n_start_req_19: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_19;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_20;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_21;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_23:\n    s_n_llhttp__internal__n_start_req_23: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_23;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 24;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_23;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_24:\n    s_n_llhttp__internal__n_start_req_24: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_24;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 23;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_24;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_26:\n    s_n_llhttp__internal__n_start_req_26: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_26;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 21;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_26;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_28:\n    s_n_llhttp__internal__n_start_req_28: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_28;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 30;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_28;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_29:\n    s_n_llhttp__internal__n_start_req_29: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_29;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_27:\n    s_n_llhttp__internal__n_start_req_27: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_27;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_28;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_29;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_25:\n    s_n_llhttp__internal__n_start_req_25: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_25;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_26;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_27;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_30:\n    s_n_llhttp__internal__n_start_req_30: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_30;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_30;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_22:\n    s_n_llhttp__internal__n_start_req_22: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_22;\n      }\n      switch (*p) {\n        case '-': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_23;\n        }\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_24;\n        }\n        case 'K': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_25;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_30;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_31:\n    s_n_llhttp__internal__n_start_req_31: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_31;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 25;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_31;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_32:\n    s_n_llhttp__internal__n_start_req_32: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_32;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_32;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_35:\n    s_n_llhttp__internal__n_start_req_35: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_35;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 28;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_35;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_36:\n    s_n_llhttp__internal__n_start_req_36: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_36;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 39;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_36;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_34:\n    s_n_llhttp__internal__n_start_req_34: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_34;\n      }\n      switch (*p) {\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_35;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_36;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_37:\n    s_n_llhttp__internal__n_start_req_37: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_37;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 38;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_37;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_38:\n    s_n_llhttp__internal__n_start_req_38: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_38;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_38;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_42:\n    s_n_llhttp__internal__n_start_req_42: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_42;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_42;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_43:\n    s_n_llhttp__internal__n_start_req_43: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_43;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_43;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_41:\n    s_n_llhttp__internal__n_start_req_41: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_41;\n      }\n      switch (*p) {\n        case 'F': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_42;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_43;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_40:\n    s_n_llhttp__internal__n_start_req_40: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_40;\n      }\n      switch (*p) {\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_41;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_39:\n    s_n_llhttp__internal__n_start_req_39: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_39;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          match = 34;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_40;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_45:\n    s_n_llhttp__internal__n_start_req_45: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_45;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 29;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_45;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_44:\n    s_n_llhttp__internal__n_start_req_44: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_44;\n      }\n      switch (*p) {\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_45;\n        }\n        case 'T': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_33:\n    s_n_llhttp__internal__n_start_req_33: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_33;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_34;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_37;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_38;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_39;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_44;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_48:\n    s_n_llhttp__internal__n_start_req_48: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_48;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 17;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_48;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_49:\n    s_n_llhttp__internal__n_start_req_49: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_49;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 44;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_49;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_50:\n    s_n_llhttp__internal__n_start_req_50: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_50;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 43;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_50;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_51:\n    s_n_llhttp__internal__n_start_req_51: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_51;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 20;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_51;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_47:\n    s_n_llhttp__internal__n_start_req_47: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_47;\n      }\n      switch (*p) {\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_48;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_49;\n        }\n        case 'D': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_50;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_51;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_46:\n    s_n_llhttp__internal__n_start_req_46: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_46;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_47;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_54:\n    s_n_llhttp__internal__n_start_req_54: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_54;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_54;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_56:\n    s_n_llhttp__internal__n_start_req_56: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_56;\n      }\n      switch (*p) {\n        case 'P': {\n          p++;\n          match = 37;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_57:\n    s_n_llhttp__internal__n_start_req_57: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_57;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 42;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_57;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_55:\n    s_n_llhttp__internal__n_start_req_55: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_55;\n      }\n      switch (*p) {\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_56;\n        }\n        case '_': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_57;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_53:\n    s_n_llhttp__internal__n_start_req_53: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_53;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_54;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_55;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_58:\n    s_n_llhttp__internal__n_start_req_58: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_58;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 33;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_58;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_59:\n    s_n_llhttp__internal__n_start_req_59: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_59;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 26;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_59;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_52:\n    s_n_llhttp__internal__n_start_req_52: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_52;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_53;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_58;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_59;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_61:\n    s_n_llhttp__internal__n_start_req_61: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_61;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob52, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 40;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_61;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_62:\n    s_n_llhttp__internal__n_start_req_62: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_62;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob53, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_62;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_60:\n    s_n_llhttp__internal__n_start_req_60: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_60;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_61;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_62;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_65:\n    s_n_llhttp__internal__n_start_req_65: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_65;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob54, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 18;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_65;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_67:\n    s_n_llhttp__internal__n_start_req_67: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_67;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob55, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 32;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_67;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_68:\n    s_n_llhttp__internal__n_start_req_68: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_68;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob56, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_68;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_66:\n    s_n_llhttp__internal__n_start_req_66: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_66;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_67;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_68;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_69:\n    s_n_llhttp__internal__n_start_req_69: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_69;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob57, 8);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 27;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_69;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_64:\n    s_n_llhttp__internal__n_start_req_64: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_64;\n      }\n      switch (*p) {\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_65;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_66;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_69;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_63:\n    s_n_llhttp__internal__n_start_req_63: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_63;\n      }\n      switch (*p) {\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_64;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req:\n    s_n_llhttp__internal__n_start_req: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_1;\n        }\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_4;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_5;\n        }\n        case 'D': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_10;\n        }\n        case 'F': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_14;\n        }\n        case 'G': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_15;\n        }\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_18;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_19;\n        }\n        case 'M': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_22;\n        }\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_31;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_32;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_33;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_46;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_52;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_60;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_63;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_58;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_status_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: {\n      switch (llhttp__on_status_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_header_field_start;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_line_almost_done:\n    s_n_llhttp__internal__n_res_line_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_line_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status:\n    s_n_llhttp__internal__n_res_status: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_status;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_res_status;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_status:\n    s_n_llhttp__internal__n_span_start_llhttp__on_status: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_status;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_status;\n      goto s_n_llhttp__internal__n_res_status;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_start:\n    s_n_llhttp__internal__n_res_status_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_start;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_res_line_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_status;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_code_otherwise:\n    s_n_llhttp__internal__n_res_status_code_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_code_otherwise;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_52;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_code:\n    s_n_llhttp__internal__n_res_status_code: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_code;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_res_status_code_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_end:\n    s_n_llhttp__internal__n_res_http_end: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_end;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_status_code;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_53;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_minor:\n    s_n_llhttp__internal__n_res_http_minor: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_minor;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_54;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_dot:\n    s_n_llhttp__internal__n_res_http_dot: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_dot;\n      }\n      switch (*p) {\n        case '.': {\n          p++;\n          goto s_n_llhttp__internal__n_res_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_55;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_major:\n    s_n_llhttp__internal__n_res_http_major: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_major;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_56;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_res:\n    s_n_llhttp__internal__n_start_res: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_res;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_res_http_major;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_res;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_59;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_2:\n    s_n_llhttp__internal__n_req_or_res_method_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_method;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_or_res_method_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_57;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_3:\n    s_n_llhttp__internal__n_req_or_res_method_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_type_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_or_res_method_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_57;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_1:\n    s_n_llhttp__internal__n_req_or_res_method_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_1;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_2;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_57;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method:\n    s_n_llhttp__internal__n_req_or_res_method: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method;\n      }\n      switch (*p) {\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_57;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_or_res:\n    s_n_llhttp__internal__n_start_req_or_res: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_or_res;\n      }\n      switch (*p) {\n        case 'H': {\n          goto s_n_llhttp__internal__n_req_or_res_method;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_type_2;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_load_type:\n    s_n_llhttp__internal__n_invoke_load_type: {\n      switch (llhttp__internal__c_load_type(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_start_req;\n        case 2:\n          goto s_n_llhttp__internal__n_start_res;\n        default:\n          goto s_n_llhttp__internal__n_start_req_or_res;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start:\n    s_n_llhttp__internal__n_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_finish;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    default:\n      /* UNREACHABLE */\n      abort();\n  }\n  s_n_llhttp__internal__n_error_1: {\n    state->error = 0x7;\n    state->reason = \"Invalid characters in url (strict mode)\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_45: {\n    state->error = 0x7;\n    state->reason = \"Invalid characters in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_2: {\n    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_4: {\n    state->error = 0x5;\n    state->reason = \"Data after `Connection: close`\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags: {\n    switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_update_finish_2;\n      default:\n        goto s_n_llhttp__internal__n_closed;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_1: {\n    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_test_lenient_flags;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_5: {\n    state->error = 0x15;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_14: {\n    state->error = 0x12;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_7: {\n    state->error = 0x15;\n    state->reason = \"on_chunk_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_17: {\n    state->error = 0x14;\n    state->reason = \"`on_chunk_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: {\n    switch (llhttp__on_chunk_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_7;\n      default:\n        goto s_n_llhttp__internal__n_error_17;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_16: {\n    state->error = 0x4;\n    state->reason = \"Content-Length can't be present with Transfer-Encoding\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_2: {\n    state->error = 0x15;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_5: {\n    state->error = 0x12;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: {\n    switch (llhttp__on_message_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_pause_1;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_2;\n      default:\n        goto s_n_llhttp__internal__n_error_5;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_12: {\n    state->error = 0xc;\n    state->reason = \"Chunk size overflow\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_3: {\n    state->error = 0x15;\n    state->reason = \"on_chunk_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_7: {\n    state->error = 0x14;\n    state->reason = \"`on_chunk_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: {\n    switch (llhttp__on_chunk_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_update_content_length;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_3;\n      default:\n        goto s_n_llhttp__internal__n_error_7;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_8: {\n    state->error = 0x2;\n    state->reason = \"Expected CRLF after chunk\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_body: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_body(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_chunk_data_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags: {\n    switch (llhttp__internal__c_or_flags(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_4: {\n    state->error = 0x15;\n    state->reason = \"on_chunk_header pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_6: {\n    state->error = 0x13;\n    state->reason = \"`on_chunk_header` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: {\n    switch (llhttp__on_chunk_header(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_is_equal_content_length;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_4;\n      default:\n        goto s_n_llhttp__internal__n_error_6;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_9: {\n    state->error = 0x2;\n    state->reason = \"Expected LF after chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_10: {\n    state->error = 0x2;\n    state->reason = \"Invalid character in chunk parameters\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_11: {\n    state->error = 0xc;\n    state->reason = \"Invalid character in chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_content_length: {\n    switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_12;\n      default:\n        goto s_n_llhttp__internal__n_chunk_size;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_13: {\n    state->error = 0xc;\n    state->reason = \"Invalid character in chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_body_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_body(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_3: {\n    switch (llhttp__internal__c_update_finish_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_15: {\n    state->error = 0xf;\n    state->reason = \"Request has invalid `Transfer-Encoding`\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause: {\n    state->error = 0x15;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_3: {\n    state->error = 0x12;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: {\n    switch (llhttp__on_message_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n      case 21:\n        goto s_n_llhttp__internal__n_pause;\n      default:\n        goto s_n_llhttp__internal__n_error_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_1: {\n    switch (llhttp__internal__c_or_flags_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_2: {\n    switch (llhttp__internal__c_or_flags_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_upgrade: {\n    switch (llhttp__internal__c_update_upgrade(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_or_flags_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_6: {\n    state->error = 0x15;\n    state->reason = \"Paused by on_headers_complete\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_2: {\n    state->error = 0x11;\n    state->reason = \"User callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: {\n    switch (llhttp__on_headers_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_or_flags_1;\n      case 2:\n        goto s_n_llhttp__internal__n_invoke_update_upgrade;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_6;\n      default:\n        goto s_n_llhttp__internal__n_error_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: {\n    switch (llhttp__before_headers_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags_1: {\n    switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_error_16;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_1: {\n    switch (llhttp__internal__c_test_flags_1(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_test_lenient_flags_1;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags: {\n    switch (llhttp__internal__c_test_flags(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1;\n      default:\n        goto s_n_llhttp__internal__n_invoke_test_flags_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_18: {\n    state->error = 0x2;\n    state->reason = \"Expected LF after headers\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_19;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_error_19;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags_2: {\n    switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_field_colon_discard_ws;\n      default:\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_20: {\n    state->error = 0xb;\n    state->reason = \"Empty Content-Length\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_3: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_4: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_5: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_6: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_1: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_3;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_4;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_5;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_6;\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 2:\n        goto s_n_llhttp__internal__n_error_20;\n      default:\n        goto s_n_llhttp__internal__n_invoke_load_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_21: {\n    state->error = 0x2;\n    state->reason = \"Expected LF after CR\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_1: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_7: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_8: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_9: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_10: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_3: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_7;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_8;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_9;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_10;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_22: {\n    state->error = 0x3;\n    state->reason = \"Missing expected LF after header value\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_23: {\n    state->error = 0xa;\n    state->reason = \"Invalid header value char\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags_3: {\n    switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_value_lenient;\n      default:\n        goto s_n_llhttp__internal__n_error_23;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_3: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_11: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_12: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_13: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_14: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_4: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_11;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_12;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_13;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_14;\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_4: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_token;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_2: {\n    switch (llhttp__internal__c_update_header_state_2(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_5: {\n    switch (llhttp__internal__c_update_header_state_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_6: {\n    switch (llhttp__internal__c_update_header_state_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_25;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_error_25;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_content_length_1: {\n    switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4;\n      default:\n        goto s_n_llhttp__internal__n_header_value_content_length;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_15: {\n    switch (llhttp__internal__c_or_flags_15(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_26;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_error_26;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_24: {\n    state->error = 0x4;\n    state->reason = \"Duplicate Content-Length\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_2: {\n    switch (llhttp__internal__c_test_flags_2(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_header_value_content_length;\n      default:\n        goto s_n_llhttp__internal__n_error_24;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_7: {\n    switch (llhttp__internal__c_update_header_state_7(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_8: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_and_flags: {\n    switch (llhttp__internal__c_and_flags(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_te_chunked;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_16: {\n    switch (llhttp__internal__c_or_flags_16(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_and_flags;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_17: {\n    switch (llhttp__internal__c_or_flags_17(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_8;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_2: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_value_connection;\n      case 2:\n        goto s_n_llhttp__internal__n_invoke_test_flags_2;\n      case 3:\n        goto s_n_llhttp__internal__n_invoke_or_flags_16;\n      case 4:\n        goto s_n_llhttp__internal__n_invoke_or_flags_17;\n      default:\n        goto s_n_llhttp__internal__n_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_27: {\n    state->error = 0xa;\n    state->reason = \"Invalid header token\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_9: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_general;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_header_state: {\n    switch (llhttp__internal__c_store_header_state(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_colon;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_10: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_general;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: {\n    switch (llhttp__on_url_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_http_minor: {\n    switch (llhttp__internal__c_update_http_minor(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_http_major: {\n    switch (llhttp__internal__c_update_http_major(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_http_minor;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_3: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_28: {\n    state->error = 0x7;\n    state->reason = \"Expected CRLF\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_4: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_31: {\n    state->error = 0x17;\n    state->reason = \"Pause on PRI/Upgrade\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_32: {\n    state->error = 0x9;\n    state->reason = \"Expected HTTP/2 Connection Preface\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_30: {\n    state->error = 0x9;\n    state->reason = \"Expected CRLF after version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method_1: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 34:\n        goto s_n_llhttp__internal__n_req_pri_upgrade;\n      default:\n        goto s_n_llhttp__internal__n_req_http_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_minor: {\n    switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_load_method_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_33: {\n    state->error = 0x9;\n    state->reason = \"Invalid minor version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_34: {\n    state->error = 0x9;\n    state->reason = \"Expected dot\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_major: {\n    switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_http_dot;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_35: {\n    state->error = 0x9;\n    state->reason = \"Invalid major version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_29: {\n    state->error = 0x8;\n    state->reason = \"Invalid method for HTTP/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 1:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 2:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 3:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 4:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 5:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 6:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 7:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 8:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 9:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 10:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 11:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 12:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 13:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 14:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 15:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 16:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 17:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 18:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 19:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 20:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 21:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 22:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 23:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 24:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 25:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 26:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 27:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 28:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 29:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 30:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 31:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 32:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 33:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 34:\n        goto s_n_llhttp__internal__n_req_http_major;\n      default:\n        goto s_n_llhttp__internal__n_error_29;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_38: {\n    state->error = 0x8;\n    state->reason = \"Expected HTTP/\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_36: {\n    state->error = 0x8;\n    state->reason = \"Expected SOURCE method for ICE/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method_2: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 33:\n        goto s_n_llhttp__internal__n_req_http_major;\n      default:\n        goto s_n_llhttp__internal__n_error_36;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_37: {\n    state->error = 0x8;\n    state->reason = \"Invalid method for RTSP/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method_3: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 3:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 6:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 35:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 36:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 37:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 38:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 39:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 40:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 41:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 42:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 43:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 44:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 45:\n        goto s_n_llhttp__internal__n_req_http_major;\n      default:\n        goto s_n_llhttp__internal__n_error_37;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: {\n    switch (llhttp__on_url_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_req_http_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_5: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_6: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_7: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_8: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_39: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url fragment start\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_9: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_10: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_11: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_40: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url query\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_41: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url path\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_12: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_13: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_14: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_42: {\n    state->error = 0x7;\n    state->reason = \"Double @ in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_43: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url server\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_44: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url server\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_46: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url schema\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_47: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url schema\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_48: {\n    state->error = 0x7;\n    state->reason = \"Unexpected start char in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_is_equal_method: {\n    switch (llhttp__internal__c_is_equal_method(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_url_entry_normal;\n      default:\n        goto s_n_llhttp__internal__n_url_entry_connect;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_49: {\n    state->error = 0x6;\n    state->reason = \"Expected space after method\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_method_1: {\n    switch (llhttp__internal__c_store_method(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_first_space_before_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_58: {\n    state->error = 0x6;\n    state->reason = \"Invalid method encountered\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_50: {\n    state->error = 0xd;\n    state->reason = \"Response overflow\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_status_code: {\n    switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_50;\n      default:\n        goto s_n_llhttp__internal__n_res_status_code;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_51: {\n    state->error = 0x2;\n    state->reason = \"Expected LF after CR\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_status: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_status(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_status_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_status(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_res_line_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_52: {\n    state->error = 0xd;\n    state->reason = \"Invalid response status\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_status_code: {\n    switch (llhttp__internal__c_update_status_code(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_res_status_code;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_53: {\n    state->error = 0x9;\n    state->reason = \"Expected space after version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_minor_1: {\n    switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_end;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_54: {\n    state->error = 0x9;\n    state->reason = \"Invalid minor version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_55: {\n    state->error = 0x9;\n    state->reason = \"Expected dot\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_major_1: {\n    switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_dot;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_56: {\n    state->error = 0x9;\n    state->reason = \"Invalid major version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_59: {\n    state->error = 0x8;\n    state->reason = \"Expected HTTP/\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type: {\n    switch (llhttp__internal__c_update_type(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_req_first_space_before_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_method: {\n    switch (llhttp__internal__c_store_method(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_type;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_57: {\n    state->error = 0x8;\n    state->reason = \"Invalid word encountered\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type_1: {\n    switch (llhttp__internal__c_update_type_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_major;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type_2: {\n    switch (llhttp__internal__c_update_type(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_start_req;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_8: {\n    state->error = 0x15;\n    state->reason = \"on_message_begin pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error: {\n    state->error = 0x10;\n    state->reason = \"`on_message_begin` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: {\n    switch (llhttp__on_message_begin(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_load_type;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_8;\n      default:\n        goto s_n_llhttp__internal__n_error;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish: {\n    switch (llhttp__internal__c_update_finish(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n}\n\nint llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) {\n  llparse_state_t next;\n\n  /* check lingering errors */\n  if (state->error != 0) {\n    return state->error;\n  }\n\n  /* restart spans */\n  if (state->_span_pos0 != NULL) {\n    state->_span_pos0 = (void*) p;\n  }\n  \n  next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp);\n  if (next == s_error) {\n    return state->error;\n  }\n  state->_current = (void*) (intptr_t) next;\n\n  /* execute spans */\n  if (state->_span_pos0 != NULL) {\n    int error;\n  \n    error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp);\n    if (error != 0) {\n      state->error = error;\n      state->error_pos = endp;\n      return error;\n    }\n  }\n  \n  return 0;\n}\n\n#else  /* !LLHTTP_STRICT_MODE */\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __SSE4_2__\n #ifdef _MSC_VER\n  #include <nmmintrin.h>\n #else  /* !_MSC_VER */\n  #include <x86intrin.h>\n #endif  /* _MSC_VER */\n#endif  /* __SSE4_2__ */\n\n#ifdef _MSC_VER\n #define ALIGN(n) _declspec(align(n))\n#else  /* !_MSC_VER */\n #define ALIGN(n) __attribute__((aligned(n)))\n#endif  /* _MSC_VER */\n\n#include \"llhttp.h\"\n\ntypedef int (*llhttp__internal__span_cb)(\n             llhttp__internal_t*, const char*, const char*);\n\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob0[] = {\n  0x9, 0x9, 0xc, 0xc, '!', '\"', '$', '>', '@', '~', 0x80,\n  0xff, 0x0, 0x0, 0x0, 0x0\n};\n#endif  /* __SSE4_2__ */\nstatic const unsigned char llparse_blob1[] = {\n  'o', 'n'\n};\nstatic const unsigned char llparse_blob2[] = {\n  'e', 'c', 't', 'i', 'o', 'n'\n};\nstatic const unsigned char llparse_blob3[] = {\n  'l', 'o', 's', 'e'\n};\nstatic const unsigned char llparse_blob4[] = {\n  'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e'\n};\nstatic const unsigned char llparse_blob5[] = {\n  'p', 'g', 'r', 'a', 'd', 'e'\n};\nstatic const unsigned char llparse_blob6[] = {\n  'c', 'h', 'u', 'n', 'k', 'e', 'd'\n};\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob7[] = {\n  0x9, 0x9, ' ', '~', 0x80, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,\n  0x0, 0x0, 0x0, 0x0, 0x0\n};\n#endif  /* __SSE4_2__ */\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob8[] = {\n  ' ', '!', '#', '\\'', '*', '+', '-', '.', '0', '9', 'A',\n  'Z', '^', 'z', '|', '|'\n};\n#endif  /* __SSE4_2__ */\n#ifdef __SSE4_2__\nstatic const unsigned char ALIGN(16) llparse_blob9[] = {\n  '~', '~', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n  0x0, 0x0, 0x0, 0x0, 0x0\n};\n#endif  /* __SSE4_2__ */\nstatic const unsigned char llparse_blob10[] = {\n  'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h'\n};\nstatic const unsigned char llparse_blob11[] = {\n  'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c',\n  't', 'i', 'o', 'n'\n};\nstatic const unsigned char llparse_blob12[] = {\n  'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c',\n  'o', 'd', 'i', 'n', 'g'\n};\nstatic const unsigned char llparse_blob13[] = {\n  'p', 'g', 'r', 'a', 'd', 'e'\n};\nstatic const unsigned char llparse_blob14[] = {\n  0xd, 0xa\n};\nstatic const unsigned char llparse_blob15[] = {\n  'T', 'T', 'P', '/'\n};\nstatic const unsigned char llparse_blob16[] = {\n  0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa\n};\nstatic const unsigned char llparse_blob17[] = {\n  'C', 'E', '/'\n};\nstatic const unsigned char llparse_blob18[] = {\n  'T', 'S', 'P', '/'\n};\nstatic const unsigned char llparse_blob19[] = {\n  'N', 'O', 'U', 'N', 'C', 'E'\n};\nstatic const unsigned char llparse_blob20[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob21[] = {\n  'E', 'C', 'K', 'O', 'U', 'T'\n};\nstatic const unsigned char llparse_blob22[] = {\n  'N', 'E', 'C', 'T'\n};\nstatic const unsigned char llparse_blob23[] = {\n  'E', 'T', 'E'\n};\nstatic const unsigned char llparse_blob24[] = {\n  'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob25[] = {\n  'L', 'U', 'S', 'H'\n};\nstatic const unsigned char llparse_blob26[] = {\n  'E', 'T'\n};\nstatic const unsigned char llparse_blob27[] = {\n  'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R'\n};\nstatic const unsigned char llparse_blob28[] = {\n  'E', 'A', 'D'\n};\nstatic const unsigned char llparse_blob29[] = {\n  'N', 'K'\n};\nstatic const unsigned char llparse_blob30[] = {\n  'C', 'K'\n};\nstatic const unsigned char llparse_blob31[] = {\n  'S', 'E', 'A', 'R', 'C', 'H'\n};\nstatic const unsigned char llparse_blob32[] = {\n  'R', 'G', 'E'\n};\nstatic const unsigned char llparse_blob33[] = {\n  'C', 'T', 'I', 'V', 'I', 'T', 'Y'\n};\nstatic const unsigned char llparse_blob34[] = {\n  'L', 'E', 'N', 'D', 'A', 'R'\n};\nstatic const unsigned char llparse_blob35[] = {\n  'V', 'E'\n};\nstatic const unsigned char llparse_blob36[] = {\n  'O', 'T', 'I', 'F', 'Y'\n};\nstatic const unsigned char llparse_blob37[] = {\n  'P', 'T', 'I', 'O', 'N', 'S'\n};\nstatic const unsigned char llparse_blob38[] = {\n  'C', 'H'\n};\nstatic const unsigned char llparse_blob39[] = {\n  'S', 'E'\n};\nstatic const unsigned char llparse_blob40[] = {\n  'A', 'Y'\n};\nstatic const unsigned char llparse_blob41[] = {\n  'S', 'T'\n};\nstatic const unsigned char llparse_blob42[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob43[] = {\n  'A', 'T', 'C', 'H'\n};\nstatic const unsigned char llparse_blob44[] = {\n  'G', 'E'\n};\nstatic const unsigned char llparse_blob45[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob46[] = {\n  'O', 'R', 'D'\n};\nstatic const unsigned char llparse_blob47[] = {\n  'I', 'R', 'E', 'C', 'T'\n};\nstatic const unsigned char llparse_blob48[] = {\n  'O', 'R', 'T'\n};\nstatic const unsigned char llparse_blob49[] = {\n  'R', 'C', 'H'\n};\nstatic const unsigned char llparse_blob50[] = {\n  'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R'\n};\nstatic const unsigned char llparse_blob51[] = {\n  'U', 'R', 'C', 'E'\n};\nstatic const unsigned char llparse_blob52[] = {\n  'B', 'S', 'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob53[] = {\n  'A', 'R', 'D', 'O', 'W', 'N'\n};\nstatic const unsigned char llparse_blob54[] = {\n  'A', 'C', 'E'\n};\nstatic const unsigned char llparse_blob55[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob56[] = {\n  'N', 'K'\n};\nstatic const unsigned char llparse_blob57[] = {\n  'C', 'K'\n};\nstatic const unsigned char llparse_blob58[] = {\n  'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob59[] = {\n  'H', 'T', 'T', 'P', '/'\n};\nstatic const unsigned char llparse_blob60[] = {\n  'A', 'D'\n};\nstatic const unsigned char llparse_blob61[] = {\n  'T', 'P', '/'\n};\n\nenum llparse_match_status_e {\n  kMatchComplete,\n  kMatchPause,\n  kMatchMismatch\n};\ntypedef enum llparse_match_status_e llparse_match_status_t;\n\nstruct llparse_match_s {\n  llparse_match_status_t status;\n  const unsigned char* current;\n};\ntypedef struct llparse_match_s llparse_match_t;\n\nstatic llparse_match_t llparse__match_sequence_to_lower(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = ((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p));\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nstatic llparse_match_t llparse__match_sequence_to_lower_unsafe(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = ((*p) | 0x20);\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nstatic llparse_match_t llparse__match_sequence_id(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = *p;\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nenum llparse_state_e {\n  s_error,\n  s_n_llhttp__internal__n_closed,\n  s_n_llhttp__internal__n_invoke_llhttp__after_message_complete,\n  s_n_llhttp__internal__n_pause_1,\n  s_n_llhttp__internal__n_invoke_is_equal_upgrade,\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2,\n  s_n_llhttp__internal__n_chunk_data_almost_done_skip,\n  s_n_llhttp__internal__n_chunk_data_almost_done,\n  s_n_llhttp__internal__n_consume_content_length,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body,\n  s_n_llhttp__internal__n_invoke_is_equal_content_length,\n  s_n_llhttp__internal__n_chunk_size_almost_done,\n  s_n_llhttp__internal__n_chunk_parameters,\n  s_n_llhttp__internal__n_chunk_size_otherwise,\n  s_n_llhttp__internal__n_chunk_size,\n  s_n_llhttp__internal__n_chunk_size_digit,\n  s_n_llhttp__internal__n_invoke_update_content_length,\n  s_n_llhttp__internal__n_consume_content_length_1,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body_1,\n  s_n_llhttp__internal__n_eof,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body_2,\n  s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete,\n  s_n_llhttp__internal__n_headers_almost_done,\n  s_n_llhttp__internal__n_header_field_colon_discard_ws,\n  s_n_llhttp__internal__n_error_14,\n  s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_value,\n  s_n_llhttp__internal__n_header_value_discard_lws,\n  s_n_llhttp__internal__n_header_value_discard_ws_almost_done,\n  s_n_llhttp__internal__n_header_value_lws,\n  s_n_llhttp__internal__n_header_value_almost_done,\n  s_n_llhttp__internal__n_header_value_lenient,\n  s_n_llhttp__internal__n_header_value_otherwise,\n  s_n_llhttp__internal__n_header_value_connection_token,\n  s_n_llhttp__internal__n_header_value_connection_ws,\n  s_n_llhttp__internal__n_header_value_connection_1,\n  s_n_llhttp__internal__n_header_value_connection_2,\n  s_n_llhttp__internal__n_header_value_connection_3,\n  s_n_llhttp__internal__n_header_value_connection,\n  s_n_llhttp__internal__n_error_19,\n  s_n_llhttp__internal__n_error_20,\n  s_n_llhttp__internal__n_header_value_content_length_ws,\n  s_n_llhttp__internal__n_header_value_content_length,\n  s_n_llhttp__internal__n_header_value_te_chunked_last,\n  s_n_llhttp__internal__n_header_value_te_token_ows,\n  s_n_llhttp__internal__n_header_value,\n  s_n_llhttp__internal__n_header_value_te_token,\n  s_n_llhttp__internal__n_header_value_te_chunked,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1,\n  s_n_llhttp__internal__n_header_value_discard_ws,\n  s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete,\n  s_n_llhttp__internal__n_header_field_general_otherwise,\n  s_n_llhttp__internal__n_header_field_general,\n  s_n_llhttp__internal__n_header_field_colon,\n  s_n_llhttp__internal__n_header_field_3,\n  s_n_llhttp__internal__n_header_field_4,\n  s_n_llhttp__internal__n_header_field_2,\n  s_n_llhttp__internal__n_header_field_1,\n  s_n_llhttp__internal__n_header_field_5,\n  s_n_llhttp__internal__n_header_field_6,\n  s_n_llhttp__internal__n_header_field_7,\n  s_n_llhttp__internal__n_header_field,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_field,\n  s_n_llhttp__internal__n_header_field_start,\n  s_n_llhttp__internal__n_url_skip_to_http09,\n  s_n_llhttp__internal__n_url_skip_lf_to_http09,\n  s_n_llhttp__internal__n_req_pri_upgrade,\n  s_n_llhttp__internal__n_req_http_complete_1,\n  s_n_llhttp__internal__n_req_http_complete,\n  s_n_llhttp__internal__n_req_http_minor,\n  s_n_llhttp__internal__n_req_http_dot,\n  s_n_llhttp__internal__n_req_http_major,\n  s_n_llhttp__internal__n_req_http_start_1,\n  s_n_llhttp__internal__n_req_http_start_2,\n  s_n_llhttp__internal__n_req_http_start_3,\n  s_n_llhttp__internal__n_req_http_start,\n  s_n_llhttp__internal__n_url_skip_to_http,\n  s_n_llhttp__internal__n_url_fragment,\n  s_n_llhttp__internal__n_span_end_stub_query_3,\n  s_n_llhttp__internal__n_url_query,\n  s_n_llhttp__internal__n_url_query_or_fragment,\n  s_n_llhttp__internal__n_url_path,\n  s_n_llhttp__internal__n_span_start_stub_path_2,\n  s_n_llhttp__internal__n_span_start_stub_path,\n  s_n_llhttp__internal__n_span_start_stub_path_1,\n  s_n_llhttp__internal__n_url_server_with_at,\n  s_n_llhttp__internal__n_url_server,\n  s_n_llhttp__internal__n_url_schema_delim_1,\n  s_n_llhttp__internal__n_url_schema_delim,\n  s_n_llhttp__internal__n_span_end_stub_schema,\n  s_n_llhttp__internal__n_url_schema,\n  s_n_llhttp__internal__n_url_start,\n  s_n_llhttp__internal__n_span_start_llhttp__on_url_1,\n  s_n_llhttp__internal__n_span_start_llhttp__on_url,\n  s_n_llhttp__internal__n_req_spaces_before_url,\n  s_n_llhttp__internal__n_req_first_space_before_url,\n  s_n_llhttp__internal__n_start_req_2,\n  s_n_llhttp__internal__n_start_req_3,\n  s_n_llhttp__internal__n_start_req_1,\n  s_n_llhttp__internal__n_start_req_4,\n  s_n_llhttp__internal__n_start_req_6,\n  s_n_llhttp__internal__n_start_req_8,\n  s_n_llhttp__internal__n_start_req_9,\n  s_n_llhttp__internal__n_start_req_7,\n  s_n_llhttp__internal__n_start_req_5,\n  s_n_llhttp__internal__n_start_req_12,\n  s_n_llhttp__internal__n_start_req_13,\n  s_n_llhttp__internal__n_start_req_11,\n  s_n_llhttp__internal__n_start_req_10,\n  s_n_llhttp__internal__n_start_req_14,\n  s_n_llhttp__internal__n_start_req_17,\n  s_n_llhttp__internal__n_start_req_16,\n  s_n_llhttp__internal__n_start_req_15,\n  s_n_llhttp__internal__n_start_req_18,\n  s_n_llhttp__internal__n_start_req_20,\n  s_n_llhttp__internal__n_start_req_21,\n  s_n_llhttp__internal__n_start_req_19,\n  s_n_llhttp__internal__n_start_req_23,\n  s_n_llhttp__internal__n_start_req_24,\n  s_n_llhttp__internal__n_start_req_26,\n  s_n_llhttp__internal__n_start_req_28,\n  s_n_llhttp__internal__n_start_req_29,\n  s_n_llhttp__internal__n_start_req_27,\n  s_n_llhttp__internal__n_start_req_25,\n  s_n_llhttp__internal__n_start_req_30,\n  s_n_llhttp__internal__n_start_req_22,\n  s_n_llhttp__internal__n_start_req_31,\n  s_n_llhttp__internal__n_start_req_32,\n  s_n_llhttp__internal__n_start_req_35,\n  s_n_llhttp__internal__n_start_req_36,\n  s_n_llhttp__internal__n_start_req_34,\n  s_n_llhttp__internal__n_start_req_37,\n  s_n_llhttp__internal__n_start_req_38,\n  s_n_llhttp__internal__n_start_req_42,\n  s_n_llhttp__internal__n_start_req_43,\n  s_n_llhttp__internal__n_start_req_41,\n  s_n_llhttp__internal__n_start_req_40,\n  s_n_llhttp__internal__n_start_req_39,\n  s_n_llhttp__internal__n_start_req_45,\n  s_n_llhttp__internal__n_start_req_44,\n  s_n_llhttp__internal__n_start_req_33,\n  s_n_llhttp__internal__n_start_req_48,\n  s_n_llhttp__internal__n_start_req_49,\n  s_n_llhttp__internal__n_start_req_50,\n  s_n_llhttp__internal__n_start_req_51,\n  s_n_llhttp__internal__n_start_req_47,\n  s_n_llhttp__internal__n_start_req_46,\n  s_n_llhttp__internal__n_start_req_54,\n  s_n_llhttp__internal__n_start_req_56,\n  s_n_llhttp__internal__n_start_req_57,\n  s_n_llhttp__internal__n_start_req_55,\n  s_n_llhttp__internal__n_start_req_53,\n  s_n_llhttp__internal__n_start_req_58,\n  s_n_llhttp__internal__n_start_req_59,\n  s_n_llhttp__internal__n_start_req_52,\n  s_n_llhttp__internal__n_start_req_61,\n  s_n_llhttp__internal__n_start_req_62,\n  s_n_llhttp__internal__n_start_req_60,\n  s_n_llhttp__internal__n_start_req_65,\n  s_n_llhttp__internal__n_start_req_67,\n  s_n_llhttp__internal__n_start_req_68,\n  s_n_llhttp__internal__n_start_req_66,\n  s_n_llhttp__internal__n_start_req_69,\n  s_n_llhttp__internal__n_start_req_64,\n  s_n_llhttp__internal__n_start_req_63,\n  s_n_llhttp__internal__n_start_req,\n  s_n_llhttp__internal__n_invoke_llhttp__on_status_complete,\n  s_n_llhttp__internal__n_res_line_almost_done,\n  s_n_llhttp__internal__n_res_status,\n  s_n_llhttp__internal__n_span_start_llhttp__on_status,\n  s_n_llhttp__internal__n_res_status_start,\n  s_n_llhttp__internal__n_res_status_code_otherwise,\n  s_n_llhttp__internal__n_res_status_code,\n  s_n_llhttp__internal__n_res_http_end,\n  s_n_llhttp__internal__n_res_http_minor,\n  s_n_llhttp__internal__n_res_http_dot,\n  s_n_llhttp__internal__n_res_http_major,\n  s_n_llhttp__internal__n_start_res,\n  s_n_llhttp__internal__n_req_or_res_method_2,\n  s_n_llhttp__internal__n_req_or_res_method_3,\n  s_n_llhttp__internal__n_req_or_res_method_1,\n  s_n_llhttp__internal__n_req_or_res_method,\n  s_n_llhttp__internal__n_start_req_or_res,\n  s_n_llhttp__internal__n_invoke_load_type,\n  s_n_llhttp__internal__n_start,\n};\ntypedef enum llparse_state_e llparse_state_t;\n\nint llhttp__on_url(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_header_field(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_header_value(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_body(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_status(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_finish(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 2;\n  return 0;\n}\n\nint llhttp__on_message_begin(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_load_type(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->type;\n}\n\nint llhttp__internal__c_store_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->method = match;\n  return 0;\n}\n\nint llhttp__internal__c_is_equal_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->method == 5;\n}\n\nint llhttp__internal__c_update_http_major(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->http_major = 0;\n  return 0;\n}\n\nint llhttp__internal__c_update_http_minor(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->http_minor = 9;\n  return 0;\n}\n\nint llhttp__on_url_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_test_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 128) == 128;\n}\n\nint llhttp__on_chunk_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_message_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_is_equal_upgrade(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->upgrade == 1;\n}\n\nint llhttp__after_message_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_finish_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 0;\n  return 0;\n}\n\nint llhttp__internal__c_test_lenient_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->lenient_flags & 4) == 4;\n}\n\nint llhttp__internal__c_test_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 544) == 544;\n}\n\nint llhttp__internal__c_test_lenient_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->lenient_flags & 2) == 2;\n}\n\nint llhttp__before_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__after_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->content_length = 0;\n  return 0;\n}\n\nint llhttp__internal__c_mul_add_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->content_length > 0xffffffffffffffffULL / 16) {\n    return 1;\n  }\n  \n  state->content_length *= 16;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->content_length > 0xffffffffffffffffULL - match) {\n      return 1;\n    }\n  } else {\n    if (state->content_length < 0ULL - match) {\n      return 1;\n    }\n  }\n  state->content_length += match;\n  return 0;\n}\n\nint llhttp__on_chunk_header(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_is_equal_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->content_length == 0;\n}\n\nint llhttp__internal__c_or_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 128;\n  return 0;\n}\n\nint llhttp__internal__c_update_finish_3(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 1;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 64;\n  return 0;\n}\n\nint llhttp__internal__c_update_upgrade(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->upgrade = 1;\n  return 0;\n}\n\nint llhttp__internal__c_store_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->header_state = match;\n  return 0;\n}\n\nint llhttp__internal__c_test_lenient_flags_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->lenient_flags & 1) == 1;\n}\n\nint llhttp__on_header_field_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_load_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->header_state;\n}\n\nint llhttp__internal__c_or_flags_3(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 1;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 1;\n  return 0;\n}\n\nint llhttp__on_header_value_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_or_flags_4(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 2;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_5(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 4;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_6(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 8;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 6;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_4(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 0;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_5(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 5;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_6(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 7;\n  return 0;\n}\n\nint llhttp__internal__c_test_flags_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 32) == 32;\n}\n\nint llhttp__internal__c_mul_add_content_length_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->content_length > 0xffffffffffffffffULL / 10) {\n    return 1;\n  }\n  \n  state->content_length *= 10;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->content_length > 0xffffffffffffffffULL - match) {\n      return 1;\n    }\n  } else {\n    if (state->content_length < 0ULL - match) {\n      return 1;\n    }\n  }\n  state->content_length += match;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_15(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 32;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_16(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 512;\n  return 0;\n}\n\nint llhttp__internal__c_and_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags &= -9;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_7(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 8;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_17(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 16;\n  return 0;\n}\n\nint llhttp__internal__c_load_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->method;\n}\n\nint llhttp__internal__c_store_http_major(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->http_major = match;\n  return 0;\n}\n\nint llhttp__internal__c_store_http_minor(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->http_minor = match;\n  return 0;\n}\n\nint llhttp__internal__c_update_status_code(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->status_code = 0;\n  return 0;\n}\n\nint llhttp__internal__c_mul_add_status_code(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->status_code > 0xffff / 10) {\n    return 1;\n  }\n  \n  state->status_code *= 10;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->status_code > 0xffff - match) {\n      return 1;\n    }\n  } else {\n    if (state->status_code < 0 - match) {\n      return 1;\n    }\n  }\n  state->status_code += match;\n  \n  /* Enforce maximum */\n  if (state->status_code > 999) {\n    return 1;\n  }\n  return 0;\n}\n\nint llhttp__on_status_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_type(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->type = 1;\n  return 0;\n}\n\nint llhttp__internal__c_update_type_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->type = 2;\n  return 0;\n}\n\nint llhttp__internal_init(llhttp__internal_t* state) {\n  memset(state, 0, sizeof(*state));\n  state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start;\n  return 0;\n}\n\nstatic llparse_state_t llhttp__internal__run(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  int match;\n  switch ((llparse_state_t) (intptr_t) state->_current) {\n    case s_n_llhttp__internal__n_closed:\n    s_n_llhttp__internal__n_closed: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_closed;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_closed;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: {\n      switch (llhttp__after_message_complete(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_invoke_update_finish_2;\n        default:\n          goto s_n_llhttp__internal__n_invoke_update_finish_1;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_pause_1:\n    s_n_llhttp__internal__n_pause_1: {\n      state->error = 0x16;\n      state->reason = \"Pause on CONNECT/Upgrade\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_is_equal_upgrade:\n    s_n_llhttp__internal__n_invoke_is_equal_upgrade: {\n      switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n        default:\n          goto s_n_llhttp__internal__n_pause_1;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2:\n    s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: {\n      switch (llhttp__on_message_complete(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_invoke_is_equal_upgrade;\n        case 21:\n          goto s_n_llhttp__internal__n_pause_5;\n        default:\n          goto s_n_llhttp__internal__n_error_10;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_data_almost_done_skip:\n    s_n_llhttp__internal__n_chunk_data_almost_done_skip: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_data_almost_done_skip;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_data_almost_done:\n    s_n_llhttp__internal__n_chunk_data_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_data_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_chunk_data_almost_done_skip;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_consume_content_length:\n    s_n_llhttp__internal__n_consume_content_length: {\n      size_t avail;\n      uint64_t need;\n      \n      avail = endp - p;\n      need = state->content_length;\n      if (avail >= need) {\n        p += need;\n        state->content_length = 0;\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_body;\n      }\n      \n      state->content_length -= avail;\n      return s_n_llhttp__internal__n_consume_content_length;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_consume_content_length;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_is_equal_content_length:\n    s_n_llhttp__internal__n_invoke_is_equal_content_length: {\n      switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_body;\n        default:\n          goto s_n_llhttp__internal__n_invoke_or_flags;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_almost_done:\n    s_n_llhttp__internal__n_chunk_size_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_parameters:\n    s_n_llhttp__internal__n_chunk_parameters: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_parameters;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_size_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_6;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_otherwise:\n    s_n_llhttp__internal__n_chunk_size_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_otherwise;\n      }\n      switch (*p) {\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_size_almost_done;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        case ';': {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_7;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size:\n    s_n_llhttp__internal__n_chunk_size: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'A': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'B': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'C': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'D': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'E': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'F': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'a': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'b': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'c': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'd': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'e': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'f': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_chunk_size_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_digit:\n    s_n_llhttp__internal__n_chunk_size_digit: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_digit;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'A': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'B': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'C': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'D': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'E': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'F': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'a': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'b': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'c': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'd': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'e': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'f': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_9;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_update_content_length:\n    s_n_llhttp__internal__n_invoke_update_content_length: {\n      switch (llhttp__internal__c_update_content_length(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_chunk_size_digit;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_consume_content_length_1:\n    s_n_llhttp__internal__n_consume_content_length_1: {\n      size_t avail;\n      uint64_t need;\n      \n      avail = endp - p;\n      need = state->content_length;\n      if (avail >= need) {\n        p += need;\n        state->content_length = 0;\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1;\n      }\n      \n      state->content_length -= avail;\n      return s_n_llhttp__internal__n_consume_content_length_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_consume_content_length_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_eof:\n    s_n_llhttp__internal__n_eof: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_eof;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_eof;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body_2:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body_2;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_eof;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: {\n      switch (llhttp__after_headers_complete(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1;\n        case 2:\n          goto s_n_llhttp__internal__n_invoke_update_content_length;\n        case 3:\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1;\n        case 4:\n          goto s_n_llhttp__internal__n_invoke_update_finish_3;\n        case 5:\n          goto s_n_llhttp__internal__n_error_11;\n        default:\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_headers_almost_done:\n    s_n_llhttp__internal__n_headers_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_headers_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_test_flags;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_colon_discard_ws:\n    s_n_llhttp__internal__n_header_field_colon_discard_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_colon_discard_ws;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_colon_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_field_colon;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_14:\n    s_n_llhttp__internal__n_error_14: {\n      state->error = 0xa;\n      state->reason = \"Invalid header field char\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: {\n      switch (llhttp__on_header_value_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_header_field_start;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_value:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_value: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_value;\n      goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_lws:\n    s_n_llhttp__internal__n_header_value_discard_lws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_lws;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_load_header_state;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_ws_almost_done:\n    s_n_llhttp__internal__n_header_value_discard_ws_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_ws_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_header_value_discard_lws;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_lws:\n    s_n_llhttp__internal__n_header_value_lws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_lws;\n      }\n      switch (*p) {\n        case 9: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_load_header_state_3;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_almost_done:\n    s_n_llhttp__internal__n_header_value_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_lws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_16;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_lenient:\n    s_n_llhttp__internal__n_header_value_lenient: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_lenient;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_lenient;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_otherwise:\n    s_n_llhttp__internal__n_header_value_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_otherwise;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_token:\n    s_n_llhttp__internal__n_header_value_connection_token: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_token;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_ws:\n    s_n_llhttp__internal__n_header_value_connection_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_ws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_ws;\n        }\n        case ',': {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_header_state_4;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_4;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_1:\n    s_n_llhttp__internal__n_header_value_connection_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_1;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob3, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_2:\n    s_n_llhttp__internal__n_header_value_connection_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_2;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob4, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_5;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_3:\n    s_n_llhttp__internal__n_header_value_connection_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_3;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob5, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_6;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection:\n    s_n_llhttp__internal__n_header_value_connection: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection;\n      }\n      switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_1;\n        }\n        case 'k': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_2;\n        }\n        case 'u': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_19:\n    s_n_llhttp__internal__n_error_19: {\n      state->error = 0xb;\n      state->reason = \"Content-Length overflow\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_20:\n    s_n_llhttp__internal__n_error_20: {\n      state->error = 0xb;\n      state->reason = \"Invalid character in Content-Length\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_content_length_ws:\n    s_n_llhttp__internal__n_header_value_content_length_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_content_length_ws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_invoke_or_flags_15;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_invoke_or_flags_15;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_content_length_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_content_length:\n    s_n_llhttp__internal__n_header_value_content_length: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_content_length;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_content_length_ws;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_chunked_last:\n    s_n_llhttp__internal__n_header_value_te_chunked_last: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_chunked_last;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_chunked_last;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_te_chunked;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_token_ows:\n    s_n_llhttp__internal__n_header_value_te_token_ows: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_token_ows;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token_ows;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token_ows;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_te_chunked;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value:\n    s_n_llhttp__internal__n_header_value: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob7);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 6,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_value;\n        }\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_token:\n    s_n_llhttp__internal__n_header_value_te_token: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_token;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_token_ows;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_8;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_chunked:\n    s_n_llhttp__internal__n_header_value_te_chunked: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_chunked;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_chunked_last;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_te_chunked;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_te_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_value;\n      goto s_n_llhttp__internal__n_invoke_load_header_state_2;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_ws:\n    s_n_llhttp__internal__n_header_value_discard_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_ws;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_lws;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: {\n      switch (llhttp__on_header_field_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_general_otherwise:\n    s_n_llhttp__internal__n_header_field_general_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_general_otherwise;\n      }\n      switch (*p) {\n        case ':': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_21;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_general:\n    s_n_llhttp__internal__n_header_field_general: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n        0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_general;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob8);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 16,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob9);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 2,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        goto s_n_llhttp__internal__n_header_field_general_otherwise;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_field_general_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_colon:\n    s_n_llhttp__internal__n_header_field_colon: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_colon;\n      }\n      switch (*p) {\n        case ' ': {\n          goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2;\n        }\n        case ':': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_9;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_3:\n    s_n_llhttp__internal__n_header_field_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_3;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob2, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_4:\n    s_n_llhttp__internal__n_header_field_4: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_4;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob10, 10);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_4;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_2:\n    s_n_llhttp__internal__n_header_field_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_2;\n      }\n      switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) {\n        case 'n': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_3;\n        }\n        case 't': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_4;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_1:\n    s_n_llhttp__internal__n_header_field_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_1;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob1, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_5:\n    s_n_llhttp__internal__n_header_field_5: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_5;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob11, 15);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_5;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_6:\n    s_n_llhttp__internal__n_header_field_6: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_6;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob12, 16);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_6;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_7:\n    s_n_llhttp__internal__n_header_field_7: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_7;\n      }\n      match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob13, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_7;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field:\n    s_n_llhttp__internal__n_header_field: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field;\n      }\n      switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) {\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_1;\n        }\n        case 'p': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_5;\n        }\n        case 't': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_6;\n        }\n        case 'u': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_7;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_field:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_field: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_field;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_field;\n      goto s_n_llhttp__internal__n_header_field;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_start:\n    s_n_llhttp__internal__n_header_field_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_start;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_headers_almost_done;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_headers_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_to_http09:\n    s_n_llhttp__internal__n_url_skip_to_http09: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_to_http09;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_update_http_major;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_lf_to_http09:\n    s_n_llhttp__internal__n_url_skip_lf_to_http09: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_http_major;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_url_skip_lf_to_http09;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_22;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_pri_upgrade:\n    s_n_llhttp__internal__n_req_pri_upgrade: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_pri_upgrade;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 10);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_error_25;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_pri_upgrade;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_26;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_complete_1:\n    s_n_llhttp__internal__n_req_http_complete_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_complete_1;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_24;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_complete:\n    s_n_llhttp__internal__n_req_http_complete: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_complete;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_complete_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_24;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_minor:\n    s_n_llhttp__internal__n_req_http_minor: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_minor;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_27;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_dot:\n    s_n_llhttp__internal__n_req_http_dot: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_dot;\n      }\n      switch (*p) {\n        case '.': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_28;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_major:\n    s_n_llhttp__internal__n_req_http_major: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_major;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_29;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_1:\n    s_n_llhttp__internal__n_req_http_start_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_1;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_method;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_2:\n    s_n_llhttp__internal__n_req_http_start_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_method_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_3:\n    s_n_llhttp__internal__n_req_http_start_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_method_3;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start:\n    s_n_llhttp__internal__n_req_http_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start;\n        }\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_1;\n        }\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_2;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_to_http:\n    s_n_llhttp__internal__n_url_skip_to_http: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_to_http;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_fragment:\n    s_n_llhttp__internal__n_url_fragment: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_fragment;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_url_fragment;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_33;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_end_stub_query_3:\n    s_n_llhttp__internal__n_span_end_stub_query_3: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_end_stub_query_3;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_fragment;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_query:\n    s_n_llhttp__internal__n_url_query: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_query;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11;\n        }\n        case 5: {\n          goto s_n_llhttp__internal__n_span_end_stub_query_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_34;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_query_or_fragment:\n    s_n_llhttp__internal__n_url_query_or_fragment: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_query_or_fragment;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5;\n        }\n        case '#': {\n          p++;\n          goto s_n_llhttp__internal__n_url_fragment;\n        }\n        case '?': {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_35;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_path:\n    s_n_llhttp__internal__n_url_path: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_path;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob0);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 12,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_url_path;\n        }\n        goto s_n_llhttp__internal__n_url_query_or_fragment;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_url_path;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_url_query_or_fragment;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path_2:\n    s_n_llhttp__internal__n_span_start_stub_path_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path_2;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path:\n    s_n_llhttp__internal__n_span_start_stub_path: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path_1:\n    s_n_llhttp__internal__n_span_start_stub_path_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path_1;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_server_with_at:\n    s_n_llhttp__internal__n_url_server_with_at: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6,\n        7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_server_with_at;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14;\n        }\n        case 4: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        case 5: {\n          goto s_n_llhttp__internal__n_span_start_stub_path_1;\n        }\n        case 6: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 7: {\n          p++;\n          goto s_n_llhttp__internal__n_error_36;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_37;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_server:\n    s_n_llhttp__internal__n_url_server: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6,\n        7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_server;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2;\n        }\n        case 4: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        case 5: {\n          goto s_n_llhttp__internal__n_span_start_stub_path;\n        }\n        case 6: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 7: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server_with_at;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_38;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema_delim_1:\n    s_n_llhttp__internal__n_url_schema_delim_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema_delim_1;\n      }\n      switch (*p) {\n        case '/': {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_40;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema_delim:\n    s_n_llhttp__internal__n_url_schema_delim: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema_delim;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_error_39;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_error_39;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_error_39;\n        }\n        case '/': {\n          p++;\n          goto s_n_llhttp__internal__n_url_schema_delim_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_40;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_end_stub_schema:\n    s_n_llhttp__internal__n_span_end_stub_schema: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_end_stub_schema;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_schema_delim;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema:\n    s_n_llhttp__internal__n_url_schema: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_39;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_stub_schema;\n        }\n        case 3: {\n          p++;\n          goto s_n_llhttp__internal__n_url_schema;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_41;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_start:\n    s_n_llhttp__internal__n_url_start: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_start;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_39;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_start_stub_path_2;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_url_schema;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_42;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_url_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_url_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_url_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_url;\n      goto s_n_llhttp__internal__n_url_start;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_url:\n    s_n_llhttp__internal__n_span_start_llhttp__on_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_url;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_url;\n      goto s_n_llhttp__internal__n_url_server;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_spaces_before_url:\n    s_n_llhttp__internal__n_req_spaces_before_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_spaces_before_url;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_spaces_before_url;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_is_equal_method;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_first_space_before_url:\n    s_n_llhttp__internal__n_req_first_space_before_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_first_space_before_url;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_spaces_before_url;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_2:\n    s_n_llhttp__internal__n_start_req_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_2;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          match = 19;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_3:\n    s_n_llhttp__internal__n_start_req_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 36;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_1:\n    s_n_llhttp__internal__n_start_req_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_1;\n      }\n      switch (*p) {\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_2;\n        }\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_4:\n    s_n_llhttp__internal__n_start_req_4: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_4;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 16;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_4;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_6:\n    s_n_llhttp__internal__n_start_req_6: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_6;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 22;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_6;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_8:\n    s_n_llhttp__internal__n_start_req_8: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_8;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_8;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_9:\n    s_n_llhttp__internal__n_start_req_9: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_9;\n      }\n      switch (*p) {\n        case 'Y': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_7:\n    s_n_llhttp__internal__n_start_req_7: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_7;\n      }\n      switch (*p) {\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_8;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_9;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_5:\n    s_n_llhttp__internal__n_start_req_5: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_5;\n      }\n      switch (*p) {\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_6;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_7;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_12:\n    s_n_llhttp__internal__n_start_req_12: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_12;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_12;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_13:\n    s_n_llhttp__internal__n_start_req_13: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_13;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 35;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_13;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_11:\n    s_n_llhttp__internal__n_start_req_11: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_11;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_12;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_13;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_10:\n    s_n_llhttp__internal__n_start_req_10: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_10;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_11;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_14:\n    s_n_llhttp__internal__n_start_req_14: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_14;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 45;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_14;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_17:\n    s_n_llhttp__internal__n_start_req_17: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_17;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 41;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_17;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_16:\n    s_n_llhttp__internal__n_start_req_16: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_16;\n      }\n      switch (*p) {\n        case '_': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_17;\n        }\n        default: {\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_15:\n    s_n_llhttp__internal__n_start_req_15: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_15;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_16;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_15;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_18:\n    s_n_llhttp__internal__n_start_req_18: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_18;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_18;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_20:\n    s_n_llhttp__internal__n_start_req_20: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_20;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 31;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_20;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_21:\n    s_n_llhttp__internal__n_start_req_21: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_21;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_21;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_19:\n    s_n_llhttp__internal__n_start_req_19: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_19;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_20;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_21;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_23:\n    s_n_llhttp__internal__n_start_req_23: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_23;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 24;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_23;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_24:\n    s_n_llhttp__internal__n_start_req_24: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_24;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 23;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_24;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_26:\n    s_n_llhttp__internal__n_start_req_26: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_26;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 21;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_26;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_28:\n    s_n_llhttp__internal__n_start_req_28: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_28;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 30;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_28;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_29:\n    s_n_llhttp__internal__n_start_req_29: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_29;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_27:\n    s_n_llhttp__internal__n_start_req_27: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_27;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_28;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_29;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_25:\n    s_n_llhttp__internal__n_start_req_25: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_25;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_26;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_27;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_30:\n    s_n_llhttp__internal__n_start_req_30: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_30;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_30;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_22:\n    s_n_llhttp__internal__n_start_req_22: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_22;\n      }\n      switch (*p) {\n        case '-': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_23;\n        }\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_24;\n        }\n        case 'K': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_25;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_30;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_31:\n    s_n_llhttp__internal__n_start_req_31: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_31;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 25;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_31;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_32:\n    s_n_llhttp__internal__n_start_req_32: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_32;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_32;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_35:\n    s_n_llhttp__internal__n_start_req_35: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_35;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 28;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_35;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_36:\n    s_n_llhttp__internal__n_start_req_36: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_36;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 39;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_36;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_34:\n    s_n_llhttp__internal__n_start_req_34: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_34;\n      }\n      switch (*p) {\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_35;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_36;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_37:\n    s_n_llhttp__internal__n_start_req_37: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_37;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 38;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_37;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_38:\n    s_n_llhttp__internal__n_start_req_38: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_38;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_38;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_42:\n    s_n_llhttp__internal__n_start_req_42: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_42;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_42;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_43:\n    s_n_llhttp__internal__n_start_req_43: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_43;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_43;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_41:\n    s_n_llhttp__internal__n_start_req_41: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_41;\n      }\n      switch (*p) {\n        case 'F': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_42;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_43;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_40:\n    s_n_llhttp__internal__n_start_req_40: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_40;\n      }\n      switch (*p) {\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_41;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_39:\n    s_n_llhttp__internal__n_start_req_39: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_39;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          match = 34;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_40;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_45:\n    s_n_llhttp__internal__n_start_req_45: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_45;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 29;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_45;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_44:\n    s_n_llhttp__internal__n_start_req_44: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_44;\n      }\n      switch (*p) {\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_45;\n        }\n        case 'T': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_33:\n    s_n_llhttp__internal__n_start_req_33: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_33;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_34;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_37;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_38;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_39;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_44;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_48:\n    s_n_llhttp__internal__n_start_req_48: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_48;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 17;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_48;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_49:\n    s_n_llhttp__internal__n_start_req_49: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_49;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 44;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_49;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_50:\n    s_n_llhttp__internal__n_start_req_50: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_50;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 43;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_50;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_51:\n    s_n_llhttp__internal__n_start_req_51: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_51;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 20;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_51;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_47:\n    s_n_llhttp__internal__n_start_req_47: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_47;\n      }\n      switch (*p) {\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_48;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_49;\n        }\n        case 'D': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_50;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_51;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_46:\n    s_n_llhttp__internal__n_start_req_46: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_46;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_47;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_54:\n    s_n_llhttp__internal__n_start_req_54: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_54;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_54;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_56:\n    s_n_llhttp__internal__n_start_req_56: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_56;\n      }\n      switch (*p) {\n        case 'P': {\n          p++;\n          match = 37;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_57:\n    s_n_llhttp__internal__n_start_req_57: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_57;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 42;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_57;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_55:\n    s_n_llhttp__internal__n_start_req_55: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_55;\n      }\n      switch (*p) {\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_56;\n        }\n        case '_': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_57;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_53:\n    s_n_llhttp__internal__n_start_req_53: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_53;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_54;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_55;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_58:\n    s_n_llhttp__internal__n_start_req_58: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_58;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 33;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_58;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_59:\n    s_n_llhttp__internal__n_start_req_59: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_59;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob52, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 26;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_59;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_52:\n    s_n_llhttp__internal__n_start_req_52: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_52;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_53;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_58;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_59;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_61:\n    s_n_llhttp__internal__n_start_req_61: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_61;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob53, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 40;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_61;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_62:\n    s_n_llhttp__internal__n_start_req_62: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_62;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob54, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_62;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_60:\n    s_n_llhttp__internal__n_start_req_60: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_60;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_61;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_62;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_65:\n    s_n_llhttp__internal__n_start_req_65: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_65;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob55, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 18;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_65;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_67:\n    s_n_llhttp__internal__n_start_req_67: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_67;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob56, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 32;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_67;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_68:\n    s_n_llhttp__internal__n_start_req_68: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_68;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob57, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_68;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_66:\n    s_n_llhttp__internal__n_start_req_66: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_66;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_67;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_68;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_69:\n    s_n_llhttp__internal__n_start_req_69: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_69;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 8);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 27;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_69;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_64:\n    s_n_llhttp__internal__n_start_req_64: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_64;\n      }\n      switch (*p) {\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_65;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_66;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_69;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_63:\n    s_n_llhttp__internal__n_start_req_63: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_63;\n      }\n      switch (*p) {\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_64;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req:\n    s_n_llhttp__internal__n_start_req: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_1;\n        }\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_4;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_5;\n        }\n        case 'D': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_10;\n        }\n        case 'F': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_14;\n        }\n        case 'G': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_15;\n        }\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_18;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_19;\n        }\n        case 'M': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_22;\n        }\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_31;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_32;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_33;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_46;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_52;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_60;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_63;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_51;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_status_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: {\n      switch (llhttp__on_status_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_header_field_start;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_line_almost_done:\n    s_n_llhttp__internal__n_res_line_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_line_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status:\n    s_n_llhttp__internal__n_res_status: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_status;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_res_status;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_status:\n    s_n_llhttp__internal__n_span_start_llhttp__on_status: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_status;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_status;\n      goto s_n_llhttp__internal__n_res_status;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_start:\n    s_n_llhttp__internal__n_res_status_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_start;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_res_line_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_status;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_code_otherwise:\n    s_n_llhttp__internal__n_res_status_code_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_code_otherwise;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_45;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_code:\n    s_n_llhttp__internal__n_res_status_code: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_code;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_res_status_code_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_end:\n    s_n_llhttp__internal__n_res_http_end: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_end;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_status_code;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_46;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_minor:\n    s_n_llhttp__internal__n_res_http_minor: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_minor;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_47;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_dot:\n    s_n_llhttp__internal__n_res_http_dot: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_dot;\n      }\n      switch (*p) {\n        case '.': {\n          p++;\n          goto s_n_llhttp__internal__n_res_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_48;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_major:\n    s_n_llhttp__internal__n_res_http_major: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_major;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_49;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_res:\n    s_n_llhttp__internal__n_start_res: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_res;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_res_http_major;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_res;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_52;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_2:\n    s_n_llhttp__internal__n_req_or_res_method_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_method;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_or_res_method_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_50;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_3:\n    s_n_llhttp__internal__n_req_or_res_method_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob61, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_type_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_or_res_method_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_50;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_1:\n    s_n_llhttp__internal__n_req_or_res_method_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_1;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_2;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_50;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method:\n    s_n_llhttp__internal__n_req_or_res_method: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method;\n      }\n      switch (*p) {\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_50;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_or_res:\n    s_n_llhttp__internal__n_start_req_or_res: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_or_res;\n      }\n      switch (*p) {\n        case 'H': {\n          goto s_n_llhttp__internal__n_req_or_res_method;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_type_2;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_load_type:\n    s_n_llhttp__internal__n_invoke_load_type: {\n      switch (llhttp__internal__c_load_type(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_start_req;\n        case 2:\n          goto s_n_llhttp__internal__n_start_res;\n        default:\n          goto s_n_llhttp__internal__n_start_req_or_res;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start:\n    s_n_llhttp__internal__n_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_finish;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    default:\n      /* UNREACHABLE */\n      abort();\n  }\n  s_n_llhttp__internal__n_error_39: {\n    state->error = 0x7;\n    state->reason = \"Invalid characters in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_2: {\n    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags: {\n    switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_update_finish_2;\n      default:\n        goto s_n_llhttp__internal__n_closed;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_1: {\n    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_test_lenient_flags;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_5: {\n    state->error = 0x15;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_10: {\n    state->error = 0x12;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_7: {\n    state->error = 0x15;\n    state->reason = \"on_chunk_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_13: {\n    state->error = 0x14;\n    state->reason = \"`on_chunk_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: {\n    switch (llhttp__on_chunk_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_7;\n      default:\n        goto s_n_llhttp__internal__n_error_13;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_12: {\n    state->error = 0x4;\n    state->reason = \"Content-Length can't be present with Transfer-Encoding\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_2: {\n    state->error = 0x15;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_3: {\n    state->error = 0x12;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: {\n    switch (llhttp__on_message_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_pause_1;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_2;\n      default:\n        goto s_n_llhttp__internal__n_error_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_8: {\n    state->error = 0xc;\n    state->reason = \"Chunk size overflow\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_3: {\n    state->error = 0x15;\n    state->reason = \"on_chunk_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_5: {\n    state->error = 0x14;\n    state->reason = \"`on_chunk_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: {\n    switch (llhttp__on_chunk_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_update_content_length;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_3;\n      default:\n        goto s_n_llhttp__internal__n_error_5;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_body: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_body(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_chunk_data_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags: {\n    switch (llhttp__internal__c_or_flags(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_4: {\n    state->error = 0x15;\n    state->reason = \"on_chunk_header pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_4: {\n    state->error = 0x13;\n    state->reason = \"`on_chunk_header` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: {\n    switch (llhttp__on_chunk_header(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_is_equal_content_length;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_4;\n      default:\n        goto s_n_llhttp__internal__n_error_4;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_6: {\n    state->error = 0x2;\n    state->reason = \"Invalid character in chunk parameters\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_7: {\n    state->error = 0xc;\n    state->reason = \"Invalid character in chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_content_length: {\n    switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_8;\n      default:\n        goto s_n_llhttp__internal__n_chunk_size;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_9: {\n    state->error = 0xc;\n    state->reason = \"Invalid character in chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_body_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_body(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_3: {\n    switch (llhttp__internal__c_update_finish_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_11: {\n    state->error = 0xf;\n    state->reason = \"Request has invalid `Transfer-Encoding`\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause: {\n    state->error = 0x15;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_2: {\n    state->error = 0x12;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: {\n    switch (llhttp__on_message_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n      case 21:\n        goto s_n_llhttp__internal__n_pause;\n      default:\n        goto s_n_llhttp__internal__n_error_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_1: {\n    switch (llhttp__internal__c_or_flags_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_2: {\n    switch (llhttp__internal__c_or_flags_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_upgrade: {\n    switch (llhttp__internal__c_update_upgrade(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_or_flags_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_6: {\n    state->error = 0x15;\n    state->reason = \"Paused by on_headers_complete\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_1: {\n    state->error = 0x11;\n    state->reason = \"User callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: {\n    switch (llhttp__on_headers_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_or_flags_1;\n      case 2:\n        goto s_n_llhttp__internal__n_invoke_update_upgrade;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_6;\n      default:\n        goto s_n_llhttp__internal__n_error_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: {\n    switch (llhttp__before_headers_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags_1: {\n    switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_error_12;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_1: {\n    switch (llhttp__internal__c_test_flags_1(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_test_lenient_flags_1;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags: {\n    switch (llhttp__internal__c_test_flags(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1;\n      default:\n        goto s_n_llhttp__internal__n_invoke_test_flags_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_14;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_error_14;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags_2: {\n    switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_field_colon_discard_ws;\n      default:\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_15: {\n    state->error = 0xb;\n    state->reason = \"Empty Content-Length\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_3: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_4: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_5: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_6: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_1: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_3;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_4;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_5;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_6;\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 2:\n        goto s_n_llhttp__internal__n_error_15;\n      default:\n        goto s_n_llhttp__internal__n_invoke_load_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_1: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_7: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_8: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_9: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_10: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_3: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_7;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_8;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_9;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_10;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_16: {\n    state->error = 0x3;\n    state->reason = \"Missing expected LF after header value\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_17: {\n    state->error = 0xa;\n    state->reason = \"Invalid header value char\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_lenient_flags_3: {\n    switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_value_lenient;\n      default:\n        goto s_n_llhttp__internal__n_error_17;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_3: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_11: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_12: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_13: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_14: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_4: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_11;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_12;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_13;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_14;\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_4: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_token;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_2: {\n    switch (llhttp__internal__c_update_header_state_2(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_5: {\n    switch (llhttp__internal__c_update_header_state_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_6: {\n    switch (llhttp__internal__c_update_header_state_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_19;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_error_19;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_content_length_1: {\n    switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4;\n      default:\n        goto s_n_llhttp__internal__n_header_value_content_length;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_15: {\n    switch (llhttp__internal__c_or_flags_15(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_20;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_error_20;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_18: {\n    state->error = 0x4;\n    state->reason = \"Duplicate Content-Length\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_2: {\n    switch (llhttp__internal__c_test_flags_2(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_header_value_content_length;\n      default:\n        goto s_n_llhttp__internal__n_error_18;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_7: {\n    switch (llhttp__internal__c_update_header_state_7(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_8: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_and_flags: {\n    switch (llhttp__internal__c_and_flags(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_te_chunked;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_16: {\n    switch (llhttp__internal__c_or_flags_16(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_and_flags;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_17: {\n    switch (llhttp__internal__c_or_flags_17(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_8;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_2: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_value_connection;\n      case 2:\n        goto s_n_llhttp__internal__n_invoke_test_flags_2;\n      case 3:\n        goto s_n_llhttp__internal__n_invoke_or_flags_16;\n      case 4:\n        goto s_n_llhttp__internal__n_invoke_or_flags_17;\n      default:\n        goto s_n_llhttp__internal__n_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_21: {\n    state->error = 0xa;\n    state->reason = \"Invalid header token\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_9: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_general;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_header_state: {\n    switch (llhttp__internal__c_store_header_state(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_colon;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_10: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_general;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: {\n    switch (llhttp__on_url_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_http_minor: {\n    switch (llhttp__internal__c_update_http_minor(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_http_major: {\n    switch (llhttp__internal__c_update_http_major(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_http_minor;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_3: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_22: {\n    state->error = 0x7;\n    state->reason = \"Expected CRLF\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_4: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_25: {\n    state->error = 0x17;\n    state->reason = \"Pause on PRI/Upgrade\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_26: {\n    state->error = 0x9;\n    state->reason = \"Expected HTTP/2 Connection Preface\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_24: {\n    state->error = 0x9;\n    state->reason = \"Expected CRLF after version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method_1: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 34:\n        goto s_n_llhttp__internal__n_req_pri_upgrade;\n      default:\n        goto s_n_llhttp__internal__n_req_http_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_minor: {\n    switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_load_method_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_27: {\n    state->error = 0x9;\n    state->reason = \"Invalid minor version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_28: {\n    state->error = 0x9;\n    state->reason = \"Expected dot\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_major: {\n    switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_http_dot;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_29: {\n    state->error = 0x9;\n    state->reason = \"Invalid major version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_23: {\n    state->error = 0x8;\n    state->reason = \"Invalid method for HTTP/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 1:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 2:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 3:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 4:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 5:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 6:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 7:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 8:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 9:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 10:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 11:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 12:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 13:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 14:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 15:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 16:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 17:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 18:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 19:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 20:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 21:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 22:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 23:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 24:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 25:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 26:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 27:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 28:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 29:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 30:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 31:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 32:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 33:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 34:\n        goto s_n_llhttp__internal__n_req_http_major;\n      default:\n        goto s_n_llhttp__internal__n_error_23;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_32: {\n    state->error = 0x8;\n    state->reason = \"Expected HTTP/\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_30: {\n    state->error = 0x8;\n    state->reason = \"Expected SOURCE method for ICE/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method_2: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 33:\n        goto s_n_llhttp__internal__n_req_http_major;\n      default:\n        goto s_n_llhttp__internal__n_error_30;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_31: {\n    state->error = 0x8;\n    state->reason = \"Invalid method for RTSP/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_method_3: {\n    switch (llhttp__internal__c_load_method(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 3:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 6:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 35:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 36:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 37:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 38:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 39:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 40:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 41:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 42:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 43:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 44:\n        goto s_n_llhttp__internal__n_req_http_major;\n      case 45:\n        goto s_n_llhttp__internal__n_req_http_major;\n      default:\n        goto s_n_llhttp__internal__n_error_31;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: {\n    switch (llhttp__on_url_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_req_http_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_5: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_6: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_7: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_8: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_33: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url fragment start\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_9: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_10: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_11: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_34: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url query\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_35: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url path\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_12: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_13: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_14: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_36: {\n    state->error = 0x7;\n    state->reason = \"Double @ in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_37: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url server\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_38: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url server\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_40: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url schema\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_41: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url schema\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_42: {\n    state->error = 0x7;\n    state->reason = \"Unexpected start char in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_is_equal_method: {\n    switch (llhttp__internal__c_is_equal_method(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1;\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_43: {\n    state->error = 0x6;\n    state->reason = \"Expected space after method\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_method_1: {\n    switch (llhttp__internal__c_store_method(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_first_space_before_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_51: {\n    state->error = 0x6;\n    state->reason = \"Invalid method encountered\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_44: {\n    state->error = 0xd;\n    state->reason = \"Response overflow\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_status_code: {\n    switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_44;\n      default:\n        goto s_n_llhttp__internal__n_res_status_code;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_status: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_status(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_status_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_status(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_res_line_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_45: {\n    state->error = 0xd;\n    state->reason = \"Invalid response status\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_status_code: {\n    switch (llhttp__internal__c_update_status_code(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_res_status_code;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_46: {\n    state->error = 0x9;\n    state->reason = \"Expected space after version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_minor_1: {\n    switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_end;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_47: {\n    state->error = 0x9;\n    state->reason = \"Invalid minor version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_48: {\n    state->error = 0x9;\n    state->reason = \"Expected dot\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_major_1: {\n    switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_dot;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_49: {\n    state->error = 0x9;\n    state->reason = \"Invalid major version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_52: {\n    state->error = 0x8;\n    state->reason = \"Expected HTTP/\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type: {\n    switch (llhttp__internal__c_update_type(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_req_first_space_before_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_method: {\n    switch (llhttp__internal__c_store_method(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_type;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_50: {\n    state->error = 0x8;\n    state->reason = \"Invalid word encountered\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type_1: {\n    switch (llhttp__internal__c_update_type_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_major;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type_2: {\n    switch (llhttp__internal__c_update_type(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_start_req;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_8: {\n    state->error = 0x15;\n    state->reason = \"on_message_begin pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error: {\n    state->error = 0x10;\n    state->reason = \"`on_message_begin` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: {\n    switch (llhttp__on_message_begin(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_load_type;\n      case 21:\n        goto s_n_llhttp__internal__n_pause_8;\n      default:\n        goto s_n_llhttp__internal__n_error;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish: {\n    switch (llhttp__internal__c_update_finish(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n}\n\nint llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) {\n  llparse_state_t next;\n\n  /* check lingering errors */\n  if (state->error != 0) {\n    return state->error;\n  }\n\n  /* restart spans */\n  if (state->_span_pos0 != NULL) {\n    state->_span_pos0 = (void*) p;\n  }\n  \n  next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp);\n  if (next == s_error) {\n    return state->error;\n  }\n  state->_current = (void*) (intptr_t) next;\n\n  /* execute spans */\n  if (state->_span_pos0 != NULL) {\n    int error;\n  \n    error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp);\n    if (error != 0) {\n      state->error = error;\n      state->error_pos = endp;\n      return error;\n    }\n  }\n  \n  return 0;\n}\n\n#endif  /* LLHTTP_STRICT_MODE */\n"
  },
  {
    "path": "d2mapapi/simphttp/llhttp/llhttp.h",
    "content": "#ifndef INCLUDE_LLHTTP_H_\n#define INCLUDE_LLHTTP_H_\n\n#define LLHTTP_VERSION_MAJOR 6\n#define LLHTTP_VERSION_MINOR 0\n#define LLHTTP_VERSION_PATCH 6\n\n#ifndef LLHTTP_STRICT_MODE\n# define LLHTTP_STRICT_MODE 0\n#endif\n\n#ifndef INCLUDE_LLHTTP_ITSELF_H_\n#define INCLUDE_LLHTTP_ITSELF_H_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n\ntypedef struct llhttp__internal_s llhttp__internal_t;\nstruct llhttp__internal_s {\n  int32_t _index;\n  void* _span_pos0;\n  void* _span_cb0;\n  int32_t error;\n  const char* reason;\n  const char* error_pos;\n  void* data;\n  void* _current;\n  uint64_t content_length;\n  uint8_t type;\n  uint8_t method;\n  uint8_t http_major;\n  uint8_t http_minor;\n  uint8_t header_state;\n  uint8_t lenient_flags;\n  uint8_t upgrade;\n  uint8_t finish;\n  uint16_t flags;\n  uint16_t status_code;\n  void* settings;\n};\n\nint llhttp__internal_init(llhttp__internal_t* s);\nint llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp);\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* INCLUDE_LLHTTP_ITSELF_H_ */\n\n#ifndef LLLLHTTP_C_HEADERS_\n#define LLLLHTTP_C_HEADERS_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum llhttp_errno {\n  HPE_OK = 0,\n  HPE_INTERNAL = 1,\n  HPE_STRICT = 2,\n  HPE_LF_EXPECTED = 3,\n  HPE_UNEXPECTED_CONTENT_LENGTH = 4,\n  HPE_CLOSED_CONNECTION = 5,\n  HPE_INVALID_METHOD = 6,\n  HPE_INVALID_URL = 7,\n  HPE_INVALID_CONSTANT = 8,\n  HPE_INVALID_VERSION = 9,\n  HPE_INVALID_HEADER_TOKEN = 10,\n  HPE_INVALID_CONTENT_LENGTH = 11,\n  HPE_INVALID_CHUNK_SIZE = 12,\n  HPE_INVALID_STATUS = 13,\n  HPE_INVALID_EOF_STATE = 14,\n  HPE_INVALID_TRANSFER_ENCODING = 15,\n  HPE_CB_MESSAGE_BEGIN = 16,\n  HPE_CB_HEADERS_COMPLETE = 17,\n  HPE_CB_MESSAGE_COMPLETE = 18,\n  HPE_CB_CHUNK_HEADER = 19,\n  HPE_CB_CHUNK_COMPLETE = 20,\n  HPE_PAUSED = 21,\n  HPE_PAUSED_UPGRADE = 22,\n  HPE_PAUSED_H2_UPGRADE = 23,\n  HPE_USER = 24\n};\ntypedef enum llhttp_errno llhttp_errno_t;\n\nenum llhttp_flags {\n  F_CONNECTION_KEEP_ALIVE = 0x1,\n  F_CONNECTION_CLOSE = 0x2,\n  F_CONNECTION_UPGRADE = 0x4,\n  F_CHUNKED = 0x8,\n  F_UPGRADE = 0x10,\n  F_CONTENT_LENGTH = 0x20,\n  F_SKIPBODY = 0x40,\n  F_TRAILING = 0x80,\n  F_TRANSFER_ENCODING = 0x200\n};\ntypedef enum llhttp_flags llhttp_flags_t;\n\nenum llhttp_lenient_flags {\n  LENIENT_HEADERS = 0x1,\n  LENIENT_CHUNKED_LENGTH = 0x2,\n  LENIENT_KEEP_ALIVE = 0x4\n};\ntypedef enum llhttp_lenient_flags llhttp_lenient_flags_t;\n\nenum llhttp_type {\n  HTTP_BOTH = 0,\n  HTTP_REQUEST = 1,\n  HTTP_RESPONSE = 2\n};\ntypedef enum llhttp_type llhttp_type_t;\n\nenum llhttp_finish {\n  HTTP_FINISH_SAFE = 0,\n  HTTP_FINISH_SAFE_WITH_CB = 1,\n  HTTP_FINISH_UNSAFE = 2\n};\ntypedef enum llhttp_finish llhttp_finish_t;\n\nenum llhttp_method {\n  HTTP_DELETE = 0,\n  HTTP_GET = 1,\n  HTTP_HEAD = 2,\n  HTTP_POST = 3,\n  HTTP_PUT = 4,\n  HTTP_CONNECT = 5,\n  HTTP_OPTIONS = 6,\n  HTTP_TRACE = 7,\n  HTTP_COPY = 8,\n  HTTP_LOCK = 9,\n  HTTP_MKCOL = 10,\n  HTTP_MOVE = 11,\n  HTTP_PROPFIND = 12,\n  HTTP_PROPPATCH = 13,\n  HTTP_SEARCH = 14,\n  HTTP_UNLOCK = 15,\n  HTTP_BIND = 16,\n  HTTP_REBIND = 17,\n  HTTP_UNBIND = 18,\n  HTTP_ACL = 19,\n  HTTP_REPORT = 20,\n  HTTP_MKACTIVITY = 21,\n  HTTP_CHECKOUT = 22,\n  HTTP_MERGE = 23,\n  HTTP_MSEARCH = 24,\n  HTTP_NOTIFY = 25,\n  HTTP_SUBSCRIBE = 26,\n  HTTP_UNSUBSCRIBE = 27,\n  HTTP_PATCH = 28,\n  HTTP_PURGE = 29,\n  HTTP_MKCALENDAR = 30,\n  HTTP_LINK = 31,\n  HTTP_UNLINK = 32,\n  HTTP_SOURCE = 33,\n  HTTP_PRI = 34,\n  HTTP_DESCRIBE = 35,\n  HTTP_ANNOUNCE = 36,\n  HTTP_SETUP = 37,\n  HTTP_PLAY = 38,\n  HTTP_PAUSE = 39,\n  HTTP_TEARDOWN = 40,\n  HTTP_GET_PARAMETER = 41,\n  HTTP_SET_PARAMETER = 42,\n  HTTP_REDIRECT = 43,\n  HTTP_RECORD = 44,\n  HTTP_FLUSH = 45\n};\ntypedef enum llhttp_method llhttp_method_t;\n\n#define HTTP_ERRNO_MAP(XX) \\\n  XX(0, OK, OK) \\\n  XX(1, INTERNAL, INTERNAL) \\\n  XX(2, STRICT, STRICT) \\\n  XX(3, LF_EXPECTED, LF_EXPECTED) \\\n  XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \\\n  XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \\\n  XX(6, INVALID_METHOD, INVALID_METHOD) \\\n  XX(7, INVALID_URL, INVALID_URL) \\\n  XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \\\n  XX(9, INVALID_VERSION, INVALID_VERSION) \\\n  XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \\\n  XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \\\n  XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \\\n  XX(13, INVALID_STATUS, INVALID_STATUS) \\\n  XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \\\n  XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \\\n  XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \\\n  XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \\\n  XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \\\n  XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \\\n  XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \\\n  XX(21, PAUSED, PAUSED) \\\n  XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \\\n  XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \\\n  XX(24, USER, USER) \\\n\n\n#define HTTP_METHOD_MAP(XX) \\\n  XX(0, DELETE, DELETE) \\\n  XX(1, GET, GET) \\\n  XX(2, HEAD, HEAD) \\\n  XX(3, POST, POST) \\\n  XX(4, PUT, PUT) \\\n  XX(5, CONNECT, CONNECT) \\\n  XX(6, OPTIONS, OPTIONS) \\\n  XX(7, TRACE, TRACE) \\\n  XX(8, COPY, COPY) \\\n  XX(9, LOCK, LOCK) \\\n  XX(10, MKCOL, MKCOL) \\\n  XX(11, MOVE, MOVE) \\\n  XX(12, PROPFIND, PROPFIND) \\\n  XX(13, PROPPATCH, PROPPATCH) \\\n  XX(14, SEARCH, SEARCH) \\\n  XX(15, UNLOCK, UNLOCK) \\\n  XX(16, BIND, BIND) \\\n  XX(17, REBIND, REBIND) \\\n  XX(18, UNBIND, UNBIND) \\\n  XX(19, ACL, ACL) \\\n  XX(20, REPORT, REPORT) \\\n  XX(21, MKACTIVITY, MKACTIVITY) \\\n  XX(22, CHECKOUT, CHECKOUT) \\\n  XX(23, MERGE, MERGE) \\\n  XX(24, MSEARCH, M-SEARCH) \\\n  XX(25, NOTIFY, NOTIFY) \\\n  XX(26, SUBSCRIBE, SUBSCRIBE) \\\n  XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \\\n  XX(28, PATCH, PATCH) \\\n  XX(29, PURGE, PURGE) \\\n  XX(30, MKCALENDAR, MKCALENDAR) \\\n  XX(31, LINK, LINK) \\\n  XX(32, UNLINK, UNLINK) \\\n  XX(33, SOURCE, SOURCE) \\\n\n\n#define RTSP_METHOD_MAP(XX) \\\n  XX(1, GET, GET) \\\n  XX(3, POST, POST) \\\n  XX(6, OPTIONS, OPTIONS) \\\n  XX(35, DESCRIBE, DESCRIBE) \\\n  XX(36, ANNOUNCE, ANNOUNCE) \\\n  XX(37, SETUP, SETUP) \\\n  XX(38, PLAY, PLAY) \\\n  XX(39, PAUSE, PAUSE) \\\n  XX(40, TEARDOWN, TEARDOWN) \\\n  XX(41, GET_PARAMETER, GET_PARAMETER) \\\n  XX(42, SET_PARAMETER, SET_PARAMETER) \\\n  XX(43, REDIRECT, REDIRECT) \\\n  XX(44, RECORD, RECORD) \\\n  XX(45, FLUSH, FLUSH) \\\n\n\n#define HTTP_ALL_METHOD_MAP(XX) \\\n  XX(0, DELETE, DELETE) \\\n  XX(1, GET, GET) \\\n  XX(2, HEAD, HEAD) \\\n  XX(3, POST, POST) \\\n  XX(4, PUT, PUT) \\\n  XX(5, CONNECT, CONNECT) \\\n  XX(6, OPTIONS, OPTIONS) \\\n  XX(7, TRACE, TRACE) \\\n  XX(8, COPY, COPY) \\\n  XX(9, LOCK, LOCK) \\\n  XX(10, MKCOL, MKCOL) \\\n  XX(11, MOVE, MOVE) \\\n  XX(12, PROPFIND, PROPFIND) \\\n  XX(13, PROPPATCH, PROPPATCH) \\\n  XX(14, SEARCH, SEARCH) \\\n  XX(15, UNLOCK, UNLOCK) \\\n  XX(16, BIND, BIND) \\\n  XX(17, REBIND, REBIND) \\\n  XX(18, UNBIND, UNBIND) \\\n  XX(19, ACL, ACL) \\\n  XX(20, REPORT, REPORT) \\\n  XX(21, MKACTIVITY, MKACTIVITY) \\\n  XX(22, CHECKOUT, CHECKOUT) \\\n  XX(23, MERGE, MERGE) \\\n  XX(24, MSEARCH, M-SEARCH) \\\n  XX(25, NOTIFY, NOTIFY) \\\n  XX(26, SUBSCRIBE, SUBSCRIBE) \\\n  XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \\\n  XX(28, PATCH, PATCH) \\\n  XX(29, PURGE, PURGE) \\\n  XX(30, MKCALENDAR, MKCALENDAR) \\\n  XX(31, LINK, LINK) \\\n  XX(32, UNLINK, UNLINK) \\\n  XX(33, SOURCE, SOURCE) \\\n  XX(34, PRI, PRI) \\\n  XX(35, DESCRIBE, DESCRIBE) \\\n  XX(36, ANNOUNCE, ANNOUNCE) \\\n  XX(37, SETUP, SETUP) \\\n  XX(38, PLAY, PLAY) \\\n  XX(39, PAUSE, PAUSE) \\\n  XX(40, TEARDOWN, TEARDOWN) \\\n  XX(41, GET_PARAMETER, GET_PARAMETER) \\\n  XX(42, SET_PARAMETER, SET_PARAMETER) \\\n  XX(43, REDIRECT, REDIRECT) \\\n  XX(44, RECORD, RECORD) \\\n  XX(45, FLUSH, FLUSH) \\\n\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* LLLLHTTP_C_HEADERS_ */\n\n#ifndef INCLUDE_LLHTTP_API_H_\n#define INCLUDE_LLHTTP_API_H_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include <stddef.h>\n\n#if defined(__wasm__)\n#define LLHTTP_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define LLHTTP_EXPORT\n#endif\n\ntypedef llhttp__internal_t llhttp_t;\ntypedef struct llhttp_settings_s llhttp_settings_t;\n\ntypedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);\ntypedef int (*llhttp_cb)(llhttp_t*);\n\nstruct llhttp_settings_s {\n  /* Possible return values 0, -1, `HPE_PAUSED` */\n  llhttp_cb      on_message_begin;\n\n  /* Possible return values 0, -1, HPE_USER */\n  llhttp_data_cb on_url;\n  llhttp_data_cb on_status;\n  llhttp_data_cb on_header_field;\n  llhttp_data_cb on_header_value;\n\n  /* Possible return values:\n   * 0  - Proceed normally\n   * 1  - Assume that request/response has no body, and proceed to parsing the\n   *      next message\n   * 2  - Assume absence of body (as above) and make `llhttp_execute()` return\n   *      `HPE_PAUSED_UPGRADE`\n   * -1 - Error\n   * `HPE_PAUSED`\n   */\n  llhttp_cb      on_headers_complete;\n\n  /* Possible return values 0, -1, HPE_USER */\n  llhttp_data_cb on_body;\n\n  /* Possible return values 0, -1, `HPE_PAUSED` */\n  llhttp_cb      on_message_complete;\n\n  /* When on_chunk_header is called, the current chunk length is stored\n   * in parser->content_length.\n   * Possible return values 0, -1, `HPE_PAUSED`\n   */\n  llhttp_cb      on_chunk_header;\n  llhttp_cb      on_chunk_complete;\n\n  /* Information-only callbacks, return value is ignored */\n  llhttp_cb      on_url_complete;\n  llhttp_cb      on_status_complete;\n  llhttp_cb      on_header_field_complete;\n  llhttp_cb      on_header_value_complete;\n};\n\n/* Initialize the parser with specific type and user settings.\n *\n * NOTE: lifetime of `settings` has to be at least the same as the lifetime of\n * the `parser` here. In practice, `settings` has to be either a static\n * variable or be allocated with `malloc`, `new`, etc.\n */\nLLHTTP_EXPORT\nvoid llhttp_init(llhttp_t* parser, llhttp_type_t type,\n                 const llhttp_settings_t* settings);\n\n#if defined(__wasm__)\n\nLLHTTP_EXPORT\nllhttp_t* llhttp_alloc(llhttp_type_t type);\n\nLLHTTP_EXPORT\nvoid llhttp_free(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_type(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_http_major(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_http_minor(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_method(llhttp_t* parser);\n\nLLHTTP_EXPORT\nint llhttp_get_status_code(llhttp_t* parser);\n\nLLHTTP_EXPORT\nuint8_t llhttp_get_upgrade(llhttp_t* parser);\n\n#endif  // defined(__wasm__)\n\n/* Reset an already initialized parser back to the start state, preserving the\n * existing parser type, callback settings, user data, and lenient flags.\n */\nLLHTTP_EXPORT\nvoid llhttp_reset(llhttp_t* parser);\n\n/* Initialize the settings object */\nLLHTTP_EXPORT\nvoid llhttp_settings_init(llhttp_settings_t* settings);\n\n/* Parse full or partial request/response, invoking user callbacks along the\n * way.\n *\n * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing\n * interrupts, and such errno is returned from `llhttp_execute()`. If\n * `HPE_PAUSED` was used as a errno, the execution can be resumed with\n * `llhttp_resume()` call.\n *\n * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`\n * is returned after fully parsing the request/response. If the user wishes to\n * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.\n *\n * NOTE: if this function ever returns a non-pause type error, it will continue\n * to return the same error upon each successive call up until `llhttp_init()`\n * is called.\n */\nLLHTTP_EXPORT\nllhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);\n\n/* This method should be called when the other side has no further bytes to\n * send (e.g. shutdown of readable side of the TCP connection.)\n *\n * Requests without `Content-Length` and other messages might require treating\n * all incoming bytes as the part of the body, up to the last byte of the\n * connection. This method will invoke `on_message_complete()` callback if the\n * request was terminated safely. Otherwise a error code would be returned.\n */\nLLHTTP_EXPORT\nllhttp_errno_t llhttp_finish(llhttp_t* parser);\n\n/* Returns `1` if the incoming message is parsed until the last byte, and has\n * to be completed by calling `llhttp_finish()` on EOF\n */\nLLHTTP_EXPORT\nint llhttp_message_needs_eof(const llhttp_t* parser);\n\n/* Returns `1` if there might be any other messages following the last that was\n * successfully parsed.\n */\nLLHTTP_EXPORT\nint llhttp_should_keep_alive(const llhttp_t* parser);\n\n/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set\n * appropriate error reason.\n *\n * Important: do not call this from user callbacks! User callbacks must return\n * `HPE_PAUSED` if pausing is required.\n */\nLLHTTP_EXPORT\nvoid llhttp_pause(llhttp_t* parser);\n\n/* Might be called to resume the execution after the pause in user's callback.\n * See `llhttp_execute()` above for details.\n *\n * Call this only if `llhttp_execute()` returns `HPE_PAUSED`.\n */\nLLHTTP_EXPORT\nvoid llhttp_resume(llhttp_t* parser);\n\n/* Might be called to resume the execution after the pause in user's callback.\n * See `llhttp_execute()` above for details.\n *\n * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`\n */\nLLHTTP_EXPORT\nvoid llhttp_resume_after_upgrade(llhttp_t* parser);\n\n/* Returns the latest return error */\nLLHTTP_EXPORT\nllhttp_errno_t llhttp_get_errno(const llhttp_t* parser);\n\n/* Returns the verbal explanation of the latest returned error.\n *\n * Note: User callback should set error reason when returning the error. See\n * `llhttp_set_error_reason()` for details.\n */\nLLHTTP_EXPORT\nconst char* llhttp_get_error_reason(const llhttp_t* parser);\n\n/* Assign verbal description to the returned error. Must be called in user\n * callbacks right before returning the errno.\n *\n * Note: `HPE_USER` error code might be useful in user callbacks.\n */\nLLHTTP_EXPORT\nvoid llhttp_set_error_reason(llhttp_t* parser, const char* reason);\n\n/* Returns the pointer to the last parsed byte before the returned error. The\n * pointer is relative to the `data` argument of `llhttp_execute()`.\n *\n * Note: this method might be useful for counting the number of parsed bytes.\n */\nLLHTTP_EXPORT\nconst char* llhttp_get_error_pos(const llhttp_t* parser);\n\n/* Returns textual name of error code */\nLLHTTP_EXPORT\nconst char* llhttp_errno_name(llhttp_errno_t err);\n\n/* Returns textual name of HTTP method */\nLLHTTP_EXPORT\nconst char* llhttp_method_name(llhttp_method_t method);\n\n\n/* Enables/disables lenient header value parsing (disabled by default).\n *\n * Lenient parsing disables header value token checks, extending llhttp's\n * protocol support to highly non-compliant clients/server. No\n * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when\n * lenient parsing is \"on\".\n *\n * **(USE AT YOUR OWN RISK)**\n */\nLLHTTP_EXPORT\nvoid llhttp_set_lenient_headers(llhttp_t* parser, int enabled);\n\n\n/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and\n * `Content-Length` headers (disabled by default).\n *\n * Normally `llhttp` would error when `Transfer-Encoding` is present in\n * conjunction with `Content-Length`. This error is important to prevent HTTP\n * request smuggling, but may be less desirable for small number of cases\n * involving legacy servers.\n *\n * **(USE AT YOUR OWN RISK)**\n */\nLLHTTP_EXPORT\nvoid llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);\n\n\n/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0\n * requests responses.\n *\n * Normally `llhttp` would error on (in strict mode) or discard (in loose mode)\n * the HTTP request/response after the request/response with `Connection: close`\n * and `Content-Length`. This is important to prevent cache poisoning attacks,\n * but might interact badly with outdated and insecure clients. With this flag\n * the extra request/response will be parsed normally.\n *\n * **(USE AT YOUR OWN RISK)**\n */\nvoid llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* INCLUDE_LLHTTP_API_H_ */\n\n#endif  /* INCLUDE_LLHTTP_H_ */\n"
  },
  {
    "path": "d2mapapi/simphttp/simphttp.cpp",
    "content": "#include \"simphttp.h\"\n\n#include <string_view>\n\nnamespace simphttp {\n\nconst std::string CRLF = \"\\r\\n\";\n\nServer::Server(Listener fn) :\n    listener(std::move(fn)) {\n\n}\n\nClient::Client(std::string ustr, Listener fn) :\n    listener(std::move(fn)) {\n    auto u = uri::ParseHttpUrl(ustr);\n    opts.host = u.host;\n    if (u.port) {\n        opts.port = u.port;\n    }\n    if (!u.path.empty()) {\n        opts.url = uri::UriEncode(u.path);\n    }\n\n    connect();\n}\n\nClient::Client(Client::Options o, Listener fn) :\n    listener(std::move(fn)) {\n    opts = std::move(o);\n    listener = fn;\n    connect();\n}\n\nvoid free_context(uv_handle_t *handle) {\n    auto *context = reinterpret_cast<Context *>(handle->data);\n    context->writes.clear();\n    free(context);\n}\n\n//\n// Events\n//\ntemplate<class Type>\nvoid attachEvents(Type *instance, llhttp_settings_t &settings) {\n\n    // http parser callback types\n    static std::function<int(llhttp_t *)> on_message_complete;\n\n    static auto callback = instance->listener;\n    // called once a connection has been made and the message is complete.\n    on_message_complete = [&](llhttp_t *parser) -> int {\n        return instance->complete(parser, callback);\n    };\n\n    // called after the url has been parsed.\n    settings.on_url =\n        [](llhttp_t *parser, const char *at, size_t len) -> int {\n            auto *context = static_cast<Context *>(parser->data);\n            if (at && context) { context->url = std::string(at, len); }\n            return 0;\n        };\n\n    // called when there are either fields or values in the request.\n    settings.on_header_field =\n        [](llhttp_t *parser, const char *at, size_t length) -> int {\n            return 0;\n        };\n\n    // called when header value is given\n    settings.on_header_value =\n        [](llhttp_t *parser, const char *at, size_t length) -> int {\n            return 0;\n        };\n\n    // called once all fields and values have been parsed.\n    settings.on_headers_complete =\n        [](llhttp_t *parser) -> int {\n            auto *context = static_cast<Context *>(parser->data);\n            context->method = std::string(llhttp_method_name((llhttp_method_t)parser->method));\n            return 0;\n        };\n\n    // called when there is a body for the request.\n    settings.on_body =\n        [](llhttp_t *parser, const char *at, size_t len) -> int {\n            auto *context = static_cast<Context *>(parser->data);\n            if (at && context && (int)len > -1) {\n                context->body << std::string_view(at, len);\n            }\n            return 0;\n        };\n\n    // called after all other events.\n    settings.on_message_complete =\n        [](llhttp_t *parser) -> int {\n            return on_message_complete(parser);\n        };\n}\n\ntemplate void attachEvents<Client>(Client *instance, llhttp_settings_t &settings);\ntemplate void attachEvents<Server>(Server *instance, llhttp_settings_t &settings);\n\n//\n// Response.\n//\nvoid Response::setHeader(const std::string &key, const std::string &val) {\n    headersSet = true;\n    if (writtenOrEnded) throw std::runtime_error(\"Can not set headers after write\");\n\n    if (key == \"Content-Length\") {\n        contentLengthSet = true;\n    }\n    headers.emplace(key, val);\n}\n\nvoid Response::setStatus(int code) {\n\n    statusSet = true;\n    if (writtenOrEnded) throw std::runtime_error(\"Can not set status after write\");\n    statusCode = code;\n}\n\nvoid Response::setStatus(int code, const std::string &ad) {\n\n    statusSet = true;\n    if (writtenOrEnded) throw std::runtime_error(\"Can not set status after write\");\n    statusCode = code;\n    statusAdjective = ad;\n}\n\nvoid Response::writeOrEnd(const std::string &str, bool end) {\n\n    if (ended) throw std::runtime_error(\"Can not write after end\");\n\n    std::stringstream ss;\n\n    if (!writtenOrEnded) {\n\n        ss << \"HTTP/1.1 \" << statusCode << \" \" << statusAdjective << CRLF;\n\n        for (auto &header: headers) {\n            ss << header.first << \": \" << header.second << CRLF;\n        }\n        ss << CRLF;\n        writtenOrEnded = true;\n    }\n\n    bool isChunked = headers.count(\"Transfer-Encoding\")\n        && headers[\"Transfer-Encoding\"] == \"chunked\";\n\n    if (isChunked) {\n        ss << std::hex << str.size()\n           << std::dec << CRLF << str << CRLF;\n    } else {\n        ss << str;\n    }\n\n    if (isChunked && end) {\n        ss << \"0\" << CRLF << CRLF;\n    }\n\n    auto str2 = ss.str();\n\n    // response buffer\n    uv_buf_t resbuf = {\n        .len = (unsigned long)str2.size(),\n        .base = (char *)str2.c_str(),\n    };\n\n    auto *context = static_cast<Context *>(this->parser.data);\n\n    auto id = write_count++;\n\n    uv_write_t write_req;\n    context->writes.insert({id, write_req});\n\n    if (end) {\n\n        ended = true;\n\n        uv_write(&context->writes.at(id), (uv_stream_t *)&context->handle, &resbuf, 1,\n                 [](uv_write_t *req, int status) {\n                     if (!uv_is_closing((uv_handle_t *)req->handle)) {\n                         uv_close((uv_handle_t *)req->handle, free_context);\n                     }\n                 }\n        );\n    } else {\n        uv_write(&context->writes.at(id), (uv_stream_t *)&context->handle, &resbuf, 1, nullptr);\n    }\n}\n\nvoid Response::write(const std::string &s) {\n    this->writeOrEnd(s, false);\n}\n\nvoid Response::end(const std::string &s) {\n    this->writeOrEnd(s, true);\n}\n\nvoid Response::end() {\n    this->writeOrEnd(\"\", true);\n}\n\nint Server::complete(llhttp_t *parser, const Listener &cb) {\n    auto *context = reinterpret_cast<Context *>(parser->data);\n    Request req;\n    Response res;\n\n    req.url = uri::UriDecode(context->url);\n    req.method = context->method;\n    res.parser = *parser;\n    cb(req, res);\n    return 0;\n}\n\nint Server::listen(const char *ip, int port) {\n    //\n    // parser settings needs to be static.\n    //\n    //\n    static llhttp_settings_t settings;\n    attachEvents(this, settings);\n\n    int status = 0;\n\n#ifdef _WIN32\n    SYSTEM_INFO sysinfo;\n    GetSystemInfo(&sysinfo);\n    int cores = sysinfo.dwNumberOfProcessors;\n#else\n    int cores = sysconf(_SC_NPROCESSORS_ONLN);\n#endif\n\n    std::stringstream cores_string;\n    cores_string << cores;\n\n#ifdef _WIN32\n    SetEnvironmentVariable(\"UV_THREADPOOL_SIZE\", cores_string.str().c_str());\n#else\n    setenv(\"UV_THREADPOOL_SIZE\", cores_string.str().c_str(), 1);\n#endif\n\n    sockaddr_storage address = {};\n\n    static std::function<void(uv_stream_t *, int)> on_connect;\n    static std::function<void(uv_stream_t *, ssize_t, const uv_buf_t *)> read;\n\n    loop_ = uv_default_loop();\n    uv_tcp_init(loop_, &socket_);\n\n    //\n    // @TODO - Not sure exactly how to use this,\n    // after the initial timeout, it just\n    // seems to kill the server.\n    //\n    //uv_tcp_keepalive(&socket_,1,60);\n    uv_tcp_nodelay(&socket_, 1);\n\n    status = uv_ip6_addr(ip, port, (struct sockaddr_in6 *)&address);\n    if (status != 0) {\n        status = uv_ip4_addr(ip, port, (struct sockaddr_in *)&address);\n    }\n    ASSERT_STATUS(status, \"Resolve Address\");\n\n    status = uv_tcp_bind(&socket_, (const struct sockaddr *)&address, 0);\n    ASSERT_STATUS(status, \"Bind\");\n\n    // called once a connection is made.\n    on_connect = [&](uv_stream_t *handle, int status) {\n        auto *context = new Context();\n\n        // init tcp handle\n        uv_tcp_init(loop_, &context->handle);\n\n        // init http parser\n        llhttp_init(&context->parser, HTTP_REQUEST, &settings);\n\n        // client reference for parser routines\n        context->parser.data = context;\n\n        // client reference for handle data on requests\n        context->handle.data = context;\n\n        // accept connection passing in refernce to the client handle\n        uv_accept(handle, (uv_stream_t *)&context->handle);\n\n        // called for every read\n        read = [&](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) {\n            ssize_t parsed;\n            auto *context = static_cast<Context *>(tcp->data);\n\n            if (nread >= 0) {\n                parsed = (ssize_t)llhttp_execute(&context->parser,\n                                                 buf->base,\n                                                 nread);\n\n                // close handle\n                if (parsed < nread) {\n                    uv_close((uv_handle_t *)&context->handle, free_context);\n                }\n            } else {\n                if (nread != UV_EOF) {\n                    // @TODO - debug error\n                }\n\n                // close handle\n                uv_close((uv_handle_t *)&context->handle, free_context);\n            }\n\n            // free request buffer data\n            free(buf->base);\n        };\n\n        // allocate memory and attempt to read.\n        uv_read_start((uv_stream_t *)&context->handle,\n            // allocator\n                      [](uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {\n                          *buf = uv_buf_init((char *)malloc(suggested_size), suggested_size);\n                      },\n\n            // reader\n                      [](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) {\n                          read(tcp, nread, buf);\n                      });\n    };\n\n    status = uv_listen((uv_stream_t *)&socket_, MAX_WRITE_HANDLES,\n        // listener\n                       [](uv_stream_t *socket, int status) {\n                           on_connect(socket, status);\n                       });\n\n    ASSERT_STATUS(status, \"Listen\");\n\n    // init loop\n    uv_run(loop_, UV_RUN_DEFAULT);\n    return 0;\n}\n\nint Client::complete(llhttp_t *parser, const Listener &cb) {\n    auto *context = reinterpret_cast<Context *>(parser->data);\n\n    Response res;\n    res.body = context->body.str();\n    res.parser = *parser;\n\n    cb(res);\n    return 0;\n}\n\nvoid Client::on_connect(uv_connect_t *req, int status) {\n\n    auto *context = reinterpret_cast<Context *>(req->handle->data);\n\n    if (status == -1) {\n        // @TODO\n        // Error Callback\n        uv_close((uv_handle_t *)req->handle, free_context);\n        return;\n    }\n\n    static std::function<void(\n        uv_stream_t *, ssize_t, const uv_buf_t *)> read;\n\n    read = [&](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) {\n\n        auto *context = static_cast<Context *>(tcp->data);\n\n        if (nread >= 0) {\n            auto parsed = (ssize_t)llhttp_execute(\n                &context->parser, buf->base, nread);\n\n            if (parsed < nread) {\n                uv_close((uv_handle_t *)&context->handle, free_context);\n            }\n            if (parsed != nread) {\n                // @TODO\n                // Error Callback\n            }\n        } else {\n            if (nread != UV_EOF) {\n                return; // maybe do something interesting here...\n            }\n            uv_close((uv_handle_t *)&context->handle, free_context);\n        }\n        free(buf->base);\n    };\n\n    uv_buf_t reqbuf;\n    std::string reqstr =\n        opts.method + \" \" + opts.url + \" HTTP/1.1\" + CRLF +\n            //\n            // @TODO\n            // Add user's headers here\n            //\n            \"Connection: keep-alive\" + CRLF + CRLF;\n\n    reqbuf.base = (char *)reqstr.c_str();\n    reqbuf.len = reqstr.size();\n\n    uv_read_start(\n        req->handle,\n        [](uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {\n            *buf = uv_buf_init((char *)malloc(suggested_size), suggested_size);\n        },\n        [](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) {\n            read(tcp, nread, buf);\n        });\n\n    uv_write(\n        &context->write_req,\n        req->handle,\n        &reqbuf,\n        1,\n        nullptr);\n}\n\nvoid Client::connect() {\n    addrinfo ai = {\n        .ai_flags = 0,\n        .ai_family = PF_INET,\n        .ai_socktype = SOCK_STREAM,\n        .ai_protocol = IPPROTO_TCP,\n    };\n\n    loop_ = uv_default_loop();\n\n    static std::function<void(\n        uv_getaddrinfo_t *req, int status, struct addrinfo *res)> on_resolved;\n\n    static std::function<void(uv_connect_t *req, int status)> on_before_connect;\n\n    on_before_connect = [&](uv_connect_t *req, int status) {\n\n        // @TODO\n        // Populate address and time info for logging / stats etc.\n\n        on_connect(req, status);\n    };\n\n    on_resolved = [&](uv_getaddrinfo_t *req, int status, struct addrinfo *res) {\n\n        static llhttp_settings_t settings;\n        attachEvents(this, settings);\n\n        char addr[17] = {'\\0'};\n\n        uv_ip4_name((struct sockaddr_in *)res->ai_addr, addr, 16);\n        uv_freeaddrinfo(res);\n\n        sockaddr_in dest = {};\n        uv_ip4_addr(addr, opts.port, &dest);\n\n        auto *context = new Context();\n\n        context->handle.data = context;\n        llhttp_init(&context->parser, HTTP_RESPONSE, &settings);\n        context->parser.data = context;\n\n        uv_tcp_init(loop_, &context->handle);\n        //uv_tcp_keepalive(&context->handle, 1, 60);\n\n        uv_tcp_connect(\n            &context->connect_req,\n            &context->handle,\n            (const struct sockaddr *)&dest,\n            [](uv_connect_t *req, int status) {\n                on_before_connect(req, status);\n            });\n    };\n\n    auto cb = [](uv_getaddrinfo_t *req, int status, struct addrinfo *res) {\n        on_resolved(req, status, res);\n    };\n\n    uv_getaddrinfo(loop_, &addr_req, cb, opts.host.c_str(), std::to_string(opts.port).c_str(), &ai);\n    uv_run(loop_, UV_RUN_DEFAULT);\n}\n\n}\n"
  },
  {
    "path": "d2mapapi/simphttp/simphttp.h",
    "content": "#pragma once\n\n#include \"uri.h\"\n\n#include <map>\n#include <vector>\n#include <string>\n#include <sstream>\n#include <iostream>\n#include <functional>\n\n#include <llhttp.h>\n#include <uv.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#endif\n\n#define MAX_WRITE_HANDLES 1000\n\n#define ASSERT_STATUS(status, msg) \\\n  if (status != 0) { \\\n    std::cerr << msg << \": \" << uv_err_name(status); \\\n    exit(1); \\\n  }\n\nnamespace simphttp {\n\ntemplate<class Type>\nclass Buffer;\ntemplate<class Type>\nclass IStream;\n\nclass Request;\nclass Response;\nclass Client;\nclass Context;\n\nextern const std::string CRLF;\nextern void free_context(uv_handle_t *);\n\ntemplate<class Type>\nextern void attachEvents(Type *instance, llhttp_settings_t &settings);\n\ntemplate<class Type>\nclass Buffer : public std::stringbuf {\n\n    friend class Request;\n    friend class Response;\n\n    Type *stream;\n\n    explicit Buffer<Type>(std::ostream &str) {};\n    ~Buffer() override = default;\n    int sync() override {\n\n        std::string out = str();\n        std::ostringstream buf;\n        buf << out;\n        out = buf.str();\n        stream->writeOrEnd(out, true);\n        buf.flush();\n        str(\"\");\n        return 0;\n    }\n};\n\nclass Request {\npublic:\n    std::string url;\n    std::string method;\n    std::string status_code;\n    std::stringstream body;\n    std::map<const std::string, const std::string> headers;\n\n    Request() = default;\n    ~Request() = default;\n};\n\nclass Response : public std::ostream {\n\n    friend class Buffer<class Response>;\n    friend class Server;\n\n    std::stringstream stream;\n    Buffer<Response> buffer;\n\n    void writeOrEnd(const std::string &, bool);\n\n    int write_count = 0;\n    bool writtenOrEnded = false;\n    bool ended = false;\n    bool headersSet = false;\n    bool statusSet = false;\n    bool contentLengthSet = false;\n\npublic:\n    llhttp_t parser = {};\n\n    int statusCode = 200;\n    std::string body;\n    std::string statusAdjective = \"OK\";\n    std::map<const std::string, const std::string> headers;\n\n    void setHeader(const std::string &, const std::string &);\n    void setStatus(int);\n    void setStatus(int, const std::string &);\n\n    void write(const std::string &);\n    void end(const std::string &);\n    void end();\n\n    Response() :\n        std::ostream(&buffer),\n        buffer(stream) {\n        buffer.stream = this;\n    }\n    ~Response() override = default;\n};\n\n/*\n  // @TODO\n  // Maybe have each op call write\n  //\n  inline Response &operator << (Response &res, const std::string &s) {\n  res.write(s);\n  return res;\n}*/\n\n\nclass Context : public Request {\npublic:\n    std::map<int, uv_write_t> writes;\n    uv_tcp_t handle;\n    uv_connect_t connect_req;\n    uv_write_t write_req;\n    llhttp_t parser;\n};\n\nclass Client {\n    template<typename Type>\n    friend void attachEvents(Type *instance, llhttp_settings_t &settings);\n    friend class Response;\n\nprivate:\n    typedef std::function<void(\n        Response &res)> Listener;\n\n    Listener listener;\n    uv_loop_t *loop_ = nullptr;\n    uv_tcp_t socket_ = {};\n\n    void connect();\n    int complete(llhttp_t *parser, const Listener &fn);\n    void on_connect(uv_connect_t *req, int status);\n\nprotected:\n    uv_getaddrinfo_t addr_req;\n    uv_shutdown_t shutdown_req;\n\npublic:\n    struct Options {\n        std::string host = \"localhost\";\n        int port = 80;\n        std::string method = \"GET\";\n        std::string url = \"/\";\n    };\n\n    Options opts;\n\n    Client(Options o, Listener listener);\n    Client(std::string u, Listener listener);\n    ~Client() = default;\n};\n\nclass Server {\n    template<typename Type>\n    friend void attachEvents(Type *instance, llhttp_settings_t &settings);\n    friend class Response;\n\nprivate:\n    typedef std::function<void(\n        Request &req,\n        Response &res)> Listener;\n\n    Listener listener;\n    uv_loop_t *loop_ = nullptr;\n    uv_tcp_t socket_ = {};\n\n    int complete(llhttp_t *parser, const Listener &fn);\n\npublic:\n    explicit Server(Listener listener);\n    ~Server() = default;\n    int listen(const char *, int);\n};\n\n} // namespace http\n"
  },
  {
    "path": "d2mapapi/simphttp/uri.h",
    "content": "#ifndef NODEUV_URI\n#define NODEUV_URI\n\n#include <iostream>\n#include <string>\n#include <cstdlib>\n#include <map>\n#include <vector>\n#include <sstream>\n\nnamespace uri {\n\nusing namespace std;\n\ntypedef map<string, string> qsmap;\ntypedef vector<string> split;\n\nstruct url {\n    string protocol;\n    string user;\n    string password;\n    string host;\n    string path;\n    string search;\n    qsmap query;\n    int port = 0;\n};\n\n//--- Helper Functions -------------------------------------------------------------~\nstatic inline string TailSlice(string &subject, const string &delimiter, bool keep_delim = false) {\n    // Chops off the delimiter and everything that follows (destructively)\n    // returns everything after the delimiter\n    auto delimiter_location = subject.find(delimiter);\n    auto delimiter_length = delimiter.length();\n    string output;\n\n    if (delimiter_location < string::npos) {\n        auto start = keep_delim ? delimiter_location : delimiter_location + delimiter_length;\n        auto end = subject.length() - start;\n        output = subject.substr(start, end);\n        subject = subject.substr(0, delimiter_location);\n    }\n    return output;\n}\n\nstatic inline string HeadSlice(string &subject, const string &delimiter) {\n    // Chops off the delimiter and everything that precedes (destructively)\n    // returns everthing before the delimeter\n    auto delimiter_location = subject.find(delimiter);\n    auto delimiter_length = delimiter.length();\n    string output;\n    if (delimiter_location < string::npos) {\n        output = subject.substr(0, delimiter_location);\n        subject = subject.substr(\n            delimiter_location + delimiter_length,\n            subject.length() - (delimiter_location + delimiter_length));\n    }\n    return output;\n}\n\nstatic inline split Split(const std::string &input, const string &separators, bool remove_empty = true) {\n    split list;\n    ostringstream word;\n    for (char n : input) {\n        if (string::npos == separators.find(n))\n            word << n;\n        else {\n            if (!word.str().empty() || !remove_empty) {\n                list.push_back(word.str());\n            }\n            word.str(\"\");\n        }\n    }\n    if (!word.str().empty() || !remove_empty) {\n        list.push_back(word.str());\n    }\n    return list;\n}\n\n//--- Extractors -------------------------------------------------------------------~\nstatic inline int ExtractPort(string &hostport) {\n    int port;\n    string portstring = TailSlice(hostport, \":\");\n    try { port = int(strtol(portstring.c_str(), nullptr, 0)); }\n    catch (const exception &e) { port = -1; }\n    return port;\n}\n\nstatic inline string ExtractPath(string &in) { return TailSlice(in, \"/\", true); }\nstatic inline string ExtractProtocol(string &in) { return HeadSlice(in, \"://\"); }\nstatic inline string ExtractSearch(string &in) { return TailSlice(in, \"?\"); }\nstatic inline string ExtractPassword(string &userpass) { return TailSlice(userpass, \":\"); }\nstatic inline string ExtractUserpass(string &in) { return HeadSlice(in, \"@\"); }\n\n//--- Public Interface -------------------------------------------------------------~\nstatic inline url ParseHttpUrl(string &in) {\n\n    url ret;\n    ret.port = -1;\n\n    ret.search = ExtractSearch(in);\n    ret.protocol = ExtractProtocol(in);\n\n    ret.path = ExtractPath(in);\n\n    string userpass = ExtractUserpass(in);\n    ret.password = ExtractPassword(userpass);\n    ret.user = userpass;\n\n    ret.port = ExtractPort(in);\n    ret.host = in;\n\n    auto pairs = Split(ret.search, \"&\");\n\n    for (auto &p: pairs) {\n        auto pair = Split(p, \"=\");\n        if (pair.size() == 2) {\n            ret.query.insert({pair[0], pair[1]});\n        }\n    }\n    return ret;\n}\n\nconst char HEX2DEC[256] = {\n    /*       0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */\n    /* 0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 1 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 2 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 3 */  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,\n\n    /* 4 */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 5 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 6 */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 7 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\n    /* 8 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* 9 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* A */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* B */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\n    /* C */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* D */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* E */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    /* F */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\n};\n\nstatic inline std::string UriDecode(const std::string &sSrc) {\n\n    // Note from RFC1630:  \"Sequences which start with a percent sign\n    // but are not followed by two hexadecimal characters (0-9, A-F) are reserved\n    // for future extension\"\n\n    const auto *pSrc = (const unsigned char *)sSrc.c_str();\n    const int SRC_LEN = sSrc.length();\n    const unsigned char *const SRC_END = pSrc + SRC_LEN;\n    const unsigned char *const SRC_LAST_DEC = SRC_END - 2;   // last decodable '%'\n\n    char *const pStart = new char[SRC_LEN];\n    char *pEnd = pStart;\n\n    while (pSrc < SRC_LAST_DEC) {\n        if (*pSrc == '%') {\n            char dec1, dec2;\n            if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])\n                && -1 != (dec2 = HEX2DEC[*(pSrc + 2)])) {\n\n                *pEnd++ = (dec1 << 4) + dec2;\n                pSrc += 3;\n                continue;\n            }\n        }\n        *pEnd++ = *pSrc++;\n    }\n\n    // the last 2- chars\n    while (pSrc < SRC_END) {\n        *pEnd++ = *pSrc++;\n    }\n\n    std::string sResult(pStart, pEnd);\n    delete[] pStart;\n    return sResult;\n}\n\n// Only alphanum is safe.\nconst char SAFE[256] = {\n    /*      0 1 2 3  4 5 6 7  8 9 A B  C D E F */\n    /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n\n    /* 4 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    /* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n    /* 6 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    /* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n\n    /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* A */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* B */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\n    /* C */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* D */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* E */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n\nstatic inline std::string UriEncode(const std::string &sSrc) {\n    const char DEC2HEX[16 + 1] = \"0123456789ABCDEF\";\n    const auto *pSrc = (const unsigned char *)sSrc.c_str();\n    const int SRC_LEN = sSrc.length();\n    auto *const pStart = new unsigned char[SRC_LEN * 3];\n    auto *pEnd = pStart;\n    const auto *const SRC_END = pSrc + SRC_LEN;\n\n    for (; pSrc < SRC_END; ++pSrc) {\n        if (SAFE[*pSrc]) {\n            *pEnd++ = *pSrc;\n        } else {\n            // escape this char\n            *pEnd++ = '%';\n            *pEnd++ = DEC2HEX[*pSrc >> 4];\n            *pEnd++ = DEC2HEX[*pSrc & 0x0F];\n        }\n    }\n\n    std::string sResult((char *)pStart, (char *)pEnd);\n    delete[] pStart;\n    return sResult;\n}\n}\n\n#endif\n"
  },
  {
    "path": "d2mapapi/stb/stb_image_write.h",
    "content": "/* stb_image_write - v1.16 - public domain - http://nothings.org/stb\n   writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015\n                                     no warranty implied; use at your own risk\n\n   Before #including,\n\n       #define STB_IMAGE_WRITE_IMPLEMENTATION\n\n   in the file that you want to have the implementation.\n\n   Will probably not work correctly with strict-aliasing optimizations.\n\nABOUT:\n\n   This header file is a library for writing images to C stdio or a callback.\n\n   The PNG output is not optimal; it is 20-50% larger than the file\n   written by a decent optimizing implementation; though providing a custom\n   zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.\n   This library is designed for source code compactness and simplicity,\n   not optimal image file size or run-time performance.\n\nBUILDING:\n\n   You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.\n   You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace\n   malloc,realloc,free.\n   You can #define STBIW_MEMMOVE() to replace memmove()\n   You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function\n   for PNG compression (instead of the builtin one), it must have the following signature:\n   unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);\n   The returned data will be freed with STBIW_FREE() (free() by default),\n   so it must be heap allocated with STBIW_MALLOC() (malloc() by default),\n\nUNICODE:\n\n   If compiling for Windows and you wish to use Unicode filenames, compile\n   with\n       #define STBIW_WINDOWS_UTF8\n   and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert\n   Windows wchar_t filenames to utf8.\n\nUSAGE:\n\n   There are five functions, one for each image file format:\n\n     int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);\n     int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);\n     int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\n\n     void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically\n\n   There are also five equivalent functions that use an arbitrary write function. You are\n   expected to open/close your file-equivalent before and after calling these:\n\n     int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\n     int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\n     int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);\n\n   where the callback is:\n      void stbi_write_func(void *context, void *data, int size);\n\n   You can configure it with these global variables:\n      int stbi_write_tga_with_rle;             // defaults to true; set to 0 to disable RLE\n      int stbi_write_png_compression_level;    // defaults to 8; set to higher for more compression\n      int stbi_write_force_png_filter;         // defaults to -1; set to 0..5 to force a filter mode\n\n\n   You can define STBI_WRITE_NO_STDIO to disable the file variant of these\n   functions, so the library will not use stdio.h at all. However, this will\n   also disable HDR writing, because it requires stdio for formatted output.\n\n   Each function returns 0 on failure and non-0 on success.\n\n   The functions create an image file defined by the parameters. The image\n   is a rectangle of pixels stored from left-to-right, top-to-bottom.\n   Each pixel contains 'comp' channels of data stored interleaved with 8-bits\n   per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is\n   monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.\n   The *data pointer points to the first byte of the top-left-most pixel.\n   For PNG, \"stride_in_bytes\" is the distance in bytes from the first byte of\n   a row of pixels to the first byte of the next row of pixels.\n\n   PNG creates output files with the same number of components as the input.\n   The BMP format expands Y to RGB in the file format and does not\n   output alpha.\n\n   PNG supports writing rectangles of data even when the bytes storing rows of\n   data are not consecutive in memory (e.g. sub-rectangles of a larger image),\n   by supplying the stride between the beginning of adjacent rows. The other\n   formats do not. (Thus you cannot write a native-format BMP through the BMP\n   writer, both because it is in BGR order and because it may have padding\n   at the end of the line.)\n\n   PNG allows you to set the deflate compression level by setting the global\n   variable 'stbi_write_png_compression_level' (it defaults to 8).\n\n   HDR expects linear float data. Since the format is always 32-bit rgb(e)\n   data, alpha (if provided) is discarded, and for monochrome data it is\n   replicated across all three channels.\n\n   TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed\n   data, set the global variable 'stbi_write_tga_with_rle' to 0.\n\n   JPEG does ignore alpha channels in input data; quality is between 1 and 100.\n   Higher quality looks better but results in a bigger image.\n   JPEG baseline (no JPEG progressive).\n\nCREDITS:\n\n\n   Sean Barrett           -    PNG/BMP/TGA\n   Baldur Karlsson        -    HDR\n   Jean-Sebastien Guay    -    TGA monochrome\n   Tim Kelsey             -    misc enhancements\n   Alan Hickman           -    TGA RLE\n   Emmanuel Julien        -    initial file IO callback implementation\n   Jon Olick              -    original jo_jpeg.cpp code\n   Daniel Gibson          -    integrate JPEG, allow external zlib\n   Aarni Koskela          -    allow choosing PNG filter\n\n   bugfixes:\n      github:Chribba\n      Guillaume Chereau\n      github:jry2\n      github:romigrou\n      Sergio Gonzalez\n      Jonas Karlsson\n      Filip Wasil\n      Thatcher Ulrich\n      github:poppolopoppo\n      Patrick Boettcher\n      github:xeekworx\n      Cap Petschulat\n      Simon Rodriguez\n      Ivan Tikhonov\n      github:ignotion\n      Adam Schackart\n      Andrew Kensler\n\nLICENSE\n\n  See end of file for license information.\n\n*/\n\n#ifndef INCLUDE_STB_IMAGE_WRITE_H\n#define INCLUDE_STB_IMAGE_WRITE_H\n\n#include <stdlib.h>\n\n// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'\n#ifndef STBIWDEF\n#ifdef STB_IMAGE_WRITE_STATIC\n#define STBIWDEF  static\n#else\n#ifdef __cplusplus\n#define STBIWDEF  extern \"C\"\n#else\n#define STBIWDEF  extern\n#endif\n#endif\n#endif\n\n#ifndef STB_IMAGE_WRITE_STATIC  // C++ forbids static forward declarations\nSTBIWDEF int stbi_write_tga_with_rle;\nSTBIWDEF int stbi_write_png_compression_level;\nSTBIWDEF int stbi_write_force_png_filter;\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void  *data, int quality);\n\n#ifdef STBIW_WINDOWS_UTF8\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n#endif\n\ntypedef void stbi_write_func(void *context, void *data, int size);\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void  *data, int quality);\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);\n\n#endif//INCLUDE_STB_IMAGE_WRITE_H\n\n#ifdef STB_IMAGE_WRITE_IMPLEMENTATION\n\n#ifdef _WIN32\n   #ifndef _CRT_SECURE_NO_WARNINGS\n   #define _CRT_SECURE_NO_WARNINGS\n   #endif\n   #ifndef _CRT_NONSTDC_NO_DEPRECATE\n   #define _CRT_NONSTDC_NO_DEPRECATE\n   #endif\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\n#include <stdio.h>\n#endif // STBI_WRITE_NO_STDIO\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))\n// ok\n#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBIW_MALLOC\n#define STBIW_MALLOC(sz)        malloc(sz)\n#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)\n#define STBIW_FREE(p)           free(p)\n#endif\n\n#ifndef STBIW_REALLOC_SIZED\n#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)\n#endif\n\n\n#ifndef STBIW_MEMMOVE\n#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)\n#endif\n\n\n#ifndef STBIW_ASSERT\n#include <assert.h>\n#define STBIW_ASSERT(x) assert(x)\n#endif\n\n#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)\n\n#ifdef STB_IMAGE_WRITE_STATIC\nstatic int stbi_write_png_compression_level = 8;\nstatic int stbi_write_tga_with_rle = 1;\nstatic int stbi_write_force_png_filter = -1;\n#else\nint stbi_write_png_compression_level = 8;\nint stbi_write_tga_with_rle = 1;\nint stbi_write_force_png_filter = -1;\n#endif\n\nstatic int stbi__flip_vertically_on_write = 0;\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flag)\n{\n   stbi__flip_vertically_on_write = flag;\n}\n\ntypedef struct\n{\n   stbi_write_func *func;\n   void *context;\n   unsigned char buffer[64];\n   int buf_used;\n} stbi__write_context;\n\n// initialize a callback-based context\nstatic void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)\n{\n   s->func    = c;\n   s->context = context;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbi__stdio_write(void *context, void *data, int size)\n{\n   fwrite(data,1,size,(FILE*) context);\n}\n\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n#ifdef __cplusplus\n#define STBIW_EXTERN extern \"C\"\n#else\n#define STBIW_EXTERN extern\n#endif\nSTBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n   return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbiw__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != _wfopen_s(&f, wFilename, wMode))\n      f = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\nstatic int stbi__start_write_file(stbi__write_context *s, const char *filename)\n{\n   FILE *f = stbiw__fopen(filename, \"wb\");\n   stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);\n   return f != NULL;\n}\n\nstatic void stbi__end_write_file(stbi__write_context *s)\n{\n   fclose((FILE *)s->context);\n}\n\n#endif // !STBI_WRITE_NO_STDIO\n\ntypedef unsigned int stbiw_uint32;\ntypedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];\n\nstatic void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)\n{\n   while (*fmt) {\n      switch (*fmt++) {\n         case ' ': break;\n         case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));\n                     s->func(s->context,&x,1);\n                     break; }\n         case '2': { int x = va_arg(v,int);\n                     unsigned char b[2];\n                     b[0] = STBIW_UCHAR(x);\n                     b[1] = STBIW_UCHAR(x>>8);\n                     s->func(s->context,b,2);\n                     break; }\n         case '4': { stbiw_uint32 x = va_arg(v,int);\n                     unsigned char b[4];\n                     b[0]=STBIW_UCHAR(x);\n                     b[1]=STBIW_UCHAR(x>>8);\n                     b[2]=STBIW_UCHAR(x>>16);\n                     b[3]=STBIW_UCHAR(x>>24);\n                     s->func(s->context,b,4);\n                     break; }\n         default:\n            STBIW_ASSERT(0);\n            return;\n      }\n   }\n}\n\nstatic void stbiw__writef(stbi__write_context *s, const char *fmt, ...)\n{\n   va_list v;\n   va_start(v, fmt);\n   stbiw__writefv(s, fmt, v);\n   va_end(v);\n}\n\nstatic void stbiw__write_flush(stbi__write_context *s)\n{\n   if (s->buf_used) {\n      s->func(s->context, &s->buffer, s->buf_used);\n      s->buf_used = 0;\n   }\n}\n\nstatic void stbiw__putc(stbi__write_context *s, unsigned char c)\n{\n   s->func(s->context, &c, 1);\n}\n\nstatic void stbiw__write1(stbi__write_context *s, unsigned char a)\n{\n   if ((size_t)s->buf_used + 1 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   s->buffer[s->buf_used++] = a;\n}\n\nstatic void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)\n{\n   int n;\n   if ((size_t)s->buf_used + 3 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   n = s->buf_used;\n   s->buf_used = n+3;\n   s->buffer[n+0] = a;\n   s->buffer[n+1] = b;\n   s->buffer[n+2] = c;\n}\n\nstatic void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)\n{\n   unsigned char bg[3] = { 255, 0, 255}, px[3];\n   int k;\n\n   if (write_alpha < 0)\n      stbiw__write1(s, d[comp - 1]);\n\n   switch (comp) {\n      case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case\n      case 1:\n         if (expand_mono)\n            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp\n         else\n            stbiw__write1(s, d[0]);  // monochrome TGA\n         break;\n      case 4:\n         if (!write_alpha) {\n            // composite against pink background\n            for (k = 0; k < 3; ++k)\n               px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;\n            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);\n            break;\n         }\n         /* FALLTHROUGH */\n      case 3:\n         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);\n         break;\n   }\n   if (write_alpha > 0)\n      stbiw__write1(s, d[comp - 1]);\n}\n\nstatic void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)\n{\n   stbiw_uint32 zero = 0;\n   int i,j, j_end;\n\n   if (y <= 0)\n      return;\n\n   if (stbi__flip_vertically_on_write)\n      vdir *= -1;\n\n   if (vdir < 0) {\n      j_end = -1; j = y-1;\n   } else {\n      j_end =  y; j = 0;\n   }\n\n   for (; j != j_end; j += vdir) {\n      for (i=0; i < x; ++i) {\n         unsigned char *d = (unsigned char *) data + (j*x+i)*comp;\n         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);\n      }\n      stbiw__write_flush(s);\n      s->func(s->context, &zero, scanline_pad);\n   }\n}\n\nstatic int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)\n{\n   if (y < 0 || x < 0) {\n      return 0;\n   } else {\n      va_list v;\n      va_start(v, fmt);\n      stbiw__writefv(s, fmt, v);\n      va_end(v);\n      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);\n      return 1;\n   }\n}\n\nstatic int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)\n{\n   if (comp != 4) {\n      // write RGB bitmap\n      int pad = (-x*3) & 3;\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,\n              \"11 4 22 4\" \"4 44 22 444444\",\n              'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header\n               40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header\n   } else {\n      // RGBA bitmaps need a v4 header\n      // use BI_BITFIELDS mode with 32bpp and alpha mask\n      // (straight BI_RGB with alpha mask doesn't work in most readers)\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,\n         \"11 4 22 4\" \"4 44 22 444444 4444 4 444 444 444 444\",\n         'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header\n         108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header\n   }\n}\n\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_bmp_core(&s, x, y, comp, data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_bmp_core(&s, x, y, comp, data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif //!STBI_WRITE_NO_STDIO\n\nstatic int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)\n{\n   int has_alpha = (comp == 2 || comp == 4);\n   int colorbytes = has_alpha ? comp-1 : comp;\n   int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3\n\n   if (y < 0 || x < 0)\n      return 0;\n\n   if (!stbi_write_tga_with_rle) {\n      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,\n         \"111 221 2222 11\", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n   } else {\n      int i,j,k;\n      int jend, jdir;\n\n      stbiw__writef(s, \"111 221 2222 11\", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n\n      if (stbi__flip_vertically_on_write) {\n         j = 0;\n         jend = y;\n         jdir = 1;\n      } else {\n         j = y-1;\n         jend = -1;\n         jdir = -1;\n      }\n      for (; j != jend; j += jdir) {\n         unsigned char *row = (unsigned char *) data + j * x * comp;\n         int len;\n\n         for (i = 0; i < x; i += len) {\n            unsigned char *begin = row + i * comp;\n            int diff = 1;\n            len = 1;\n\n            if (i < x - 1) {\n               ++len;\n               diff = memcmp(begin, row + (i + 1) * comp, comp);\n               if (diff) {\n                  const unsigned char *prev = begin;\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (memcmp(prev, row + k * comp, comp)) {\n                        prev += comp;\n                        ++len;\n                     } else {\n                        --len;\n                        break;\n                     }\n                  }\n               } else {\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (!memcmp(begin, row + k * comp, comp)) {\n                        ++len;\n                     } else {\n                        break;\n                     }\n                  }\n               }\n            }\n\n            if (diff) {\n               unsigned char header = STBIW_UCHAR(len - 1);\n               stbiw__write1(s, header);\n               for (k = 0; k < len; ++k) {\n                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);\n               }\n            } else {\n               unsigned char header = STBIW_UCHAR(len - 129);\n               stbiw__write1(s, header);\n               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);\n            }\n         }\n      }\n      stbiw__write_flush(s);\n   }\n   return 1;\n}\n\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_tga_core(&s, x, y, comp, (void *) data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR writer\n// by Baldur Karlsson\n\n#define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)\n{\n   int exponent;\n   float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));\n\n   if (maxcomp < 1e-32f) {\n      rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;\n   } else {\n      float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;\n\n      rgbe[0] = (unsigned char)(linear[0] * normalize);\n      rgbe[1] = (unsigned char)(linear[1] * normalize);\n      rgbe[2] = (unsigned char)(linear[2] * normalize);\n      rgbe[3] = (unsigned char)(exponent + 128);\n   }\n}\n\nstatic void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length+128);\n   STBIW_ASSERT(length+128 <= 255);\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, &databyte, 1);\n}\n\nstatic void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length);\n   STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, data, length);\n}\n\nstatic void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)\n{\n   unsigned char scanlineheader[4] = { 2, 2, 0, 0 };\n   unsigned char rgbe[4];\n   float linear[3];\n   int x;\n\n   scanlineheader[2] = (width&0xff00)>>8;\n   scanlineheader[3] = (width&0x00ff);\n\n   /* skip RLE for images too small or large */\n   if (width < 8 || width >= 32768) {\n      for (x=0; x < width; x++) {\n         switch (ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         s->func(s->context, rgbe, 4);\n      }\n   } else {\n      int c,r;\n      /* encode into scratch buffer */\n      for (x=0; x < width; x++) {\n         switch(ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         scratch[x + width*0] = rgbe[0];\n         scratch[x + width*1] = rgbe[1];\n         scratch[x + width*2] = rgbe[2];\n         scratch[x + width*3] = rgbe[3];\n      }\n\n      s->func(s->context, scanlineheader, 4);\n\n      /* RLE each component separately */\n      for (c=0; c < 4; c++) {\n         unsigned char *comp = &scratch[width*c];\n\n         x = 0;\n         while (x < width) {\n            // find first run\n            r = x;\n            while (r+2 < width) {\n               if (comp[r] == comp[r+1] && comp[r] == comp[r+2])\n                  break;\n               ++r;\n            }\n            if (r+2 >= width)\n               r = width;\n            // dump up to first run\n            while (x < r) {\n               int len = r-x;\n               if (len > 128) len = 128;\n               stbiw__write_dump_data(s, len, &comp[x]);\n               x += len;\n            }\n            // if there's a run, output it\n            if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd\n               // find next byte after run\n               while (r < width && comp[r] == comp[x])\n                  ++r;\n               // output run up to r\n               while (x < r) {\n                  int len = r-x;\n                  if (len > 127) len = 127;\n                  stbiw__write_run_data(s, len, comp[x]);\n                  x += len;\n               }\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)\n{\n   if (y <= 0 || x <= 0 || data == NULL)\n      return 0;\n   else {\n      // Each component is stored separately. Allocate scratch space for full output scanline.\n      unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);\n      int i, len;\n      char buffer[128];\n      char header[] = \"#?RADIANCE\\n# Written by stb_image_write.h\\nFORMAT=32-bit_rle_rgbe\\n\";\n      s->func(s->context, header, sizeof(header)-1);\n\n#ifdef __STDC_LIB_EXT1__\n      len = sprintf_s(buffer, sizeof(buffer), \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#else\n      len = sprintf(buffer, \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#endif\n      s->func(s->context, buffer, len);\n\n      for(i=0; i < y; i++)\n         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i));\n      STBIW_FREE(scratch);\n      return 1;\n   }\n}\n\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n}\n\nSTBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif // STBI_WRITE_NO_STDIO\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PNG writer\n//\n\n#ifndef STBIW_ZLIB_COMPRESS\n// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()\n#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)\n#define stbiw__sbm(a)   stbiw__sbraw(a)[0]\n#define stbiw__sbn(a)   stbiw__sbraw(a)[1]\n\n#define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))\n#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)\n#define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))\n\n#define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))\n#define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)\n#define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)\n\nstatic void *stbiw__sbgrowf(void **arr, int increment, int itemsize)\n{\n   int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;\n   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);\n   STBIW_ASSERT(p);\n   if (p) {\n      if (!*arr) ((int *) p)[1] = 0;\n      *arr = (void *) ((int *) p + 2);\n      stbiw__sbm(*arr) = m;\n   }\n   return *arr;\n}\n\nstatic unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)\n{\n   while (*bitcount >= 8) {\n      stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));\n      *bitbuffer >>= 8;\n      *bitcount -= 8;\n   }\n   return data;\n}\n\nstatic int stbiw__zlib_bitrev(int code, int codebits)\n{\n   int res=0;\n   while (codebits--) {\n      res = (res << 1) | (code & 1);\n      code >>= 1;\n   }\n   return res;\n}\n\nstatic unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)\n{\n   int i;\n   for (i=0; i < limit && i < 258; ++i)\n      if (a[i] != b[i]) break;\n   return i;\n}\n\nstatic unsigned int stbiw__zhash(unsigned char *data)\n{\n   stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);\n   hash ^= hash << 3;\n   hash += hash >> 5;\n   hash ^= hash << 4;\n   hash += hash >> 17;\n   hash ^= hash << 25;\n   hash += hash >> 6;\n   return hash;\n}\n\n#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))\n#define stbiw__zlib_add(code,codebits) \\\n      (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())\n#define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)\n// default huffman tables\n#define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)\n#define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)\n#define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)\n#define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)\n#define stbiw__zlib_huff(n)  ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))\n#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))\n\n#define stbiw__ZHASH   16384\n\n#endif // STBIW_ZLIB_COMPRESS\n\nSTBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)\n{\n#ifdef STBIW_ZLIB_COMPRESS\n   // user provided a zlib compress implementation, use that\n   return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);\n#else // use builtin\n   static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };\n   static unsigned char  lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5,  0 };\n   static unsigned short distc[]   = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };\n   static unsigned char  disteb[]  = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };\n   unsigned int bitbuf=0;\n   int i,j, bitcount=0;\n   unsigned char *out = NULL;\n   unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));\n   if (hash_table == NULL)\n      return NULL;\n   if (quality < 5) quality = 5;\n\n   stbiw__sbpush(out, 0x78);   // DEFLATE 32K window\n   stbiw__sbpush(out, 0x5e);   // FLEVEL = 1\n   stbiw__zlib_add(1,1);  // BFINAL = 1\n   stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      hash_table[i] = NULL;\n\n   i=0;\n   while (i < data_len-3) {\n      // hash next 3 bytes of data to be compressed\n      int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;\n      unsigned char *bestloc = 0;\n      unsigned char **hlist = hash_table[h];\n      int n = stbiw__sbcount(hlist);\n      for (j=0; j < n; ++j) {\n         if (hlist[j]-data > i-32768) { // if entry lies within window\n            int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);\n            if (d >= best) { best=d; bestloc=hlist[j]; }\n         }\n      }\n      // when hash table entry is too long, delete half the entries\n      if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {\n         STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);\n         stbiw__sbn(hash_table[h]) = quality;\n      }\n      stbiw__sbpush(hash_table[h],data+i);\n\n      if (bestloc) {\n         // \"lazy matching\" - check match at *next* byte, and if it's better, do cur byte as literal\n         h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);\n         hlist = hash_table[h];\n         n = stbiw__sbcount(hlist);\n         for (j=0; j < n; ++j) {\n            if (hlist[j]-data > i-32767) {\n               int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);\n               if (e > best) { // if next match is better, bail on current match\n                  bestloc = NULL;\n                  break;\n               }\n            }\n         }\n      }\n\n      if (bestloc) {\n         int d = (int) (data+i - bestloc); // distance back\n         STBIW_ASSERT(d <= 32767 && best <= 258);\n         for (j=0; best > lengthc[j+1]-1; ++j);\n         stbiw__zlib_huff(j+257);\n         if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);\n         for (j=0; d > distc[j+1]-1; ++j);\n         stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);\n         if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);\n         i += best;\n      } else {\n         stbiw__zlib_huffb(data[i]);\n         ++i;\n      }\n   }\n   // write out final bytes\n   for (;i < data_len; ++i)\n      stbiw__zlib_huffb(data[i]);\n   stbiw__zlib_huff(256); // end of block\n   // pad with 0 bits to byte boundary\n   while (bitcount)\n      stbiw__zlib_add(0,1);\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      (void) stbiw__sbfree(hash_table[i]);\n   STBIW_FREE(hash_table);\n\n   // store uncompressed instead if compression was worse\n   if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {\n      stbiw__sbn(out) = 2;  // truncate to DEFLATE 32K window and FLEVEL = 1\n      for (j = 0; j < data_len;) {\n         int blocklen = data_len - j;\n         if (blocklen > 32767) blocklen = 32767;\n         stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));\n         memcpy(out+stbiw__sbn(out), data+j, blocklen);\n         stbiw__sbn(out) += blocklen;\n         j += blocklen;\n      }\n   }\n\n   {\n      // compute adler32 on input\n      unsigned int s1=1, s2=0;\n      int blocklen = (int) (data_len % 5552);\n      j=0;\n      while (j < data_len) {\n         for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }\n         s1 %= 65521; s2 %= 65521;\n         j += blocklen;\n         blocklen = 5552;\n      }\n      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s2));\n      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s1));\n   }\n   *out_len = stbiw__sbn(out);\n   // make returned pointer freeable\n   STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);\n   return (unsigned char *) stbiw__sbraw(out);\n#endif // STBIW_ZLIB_COMPRESS\n}\n\nstatic unsigned int stbiw__crc32(unsigned char *buffer, int len)\n{\n#ifdef STBIW_CRC32\n    return STBIW_CRC32(buffer, len);\n#else\n   static unsigned int crc_table[256] =\n   {\n      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,\n      0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,\n      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,\n      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\n      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,\n      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\n      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,\n      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,\n      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,\n      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,\n      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,\n      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\n      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,\n      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,\n      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\n      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,\n      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,\n      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,\n      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n   };\n\n   unsigned int crc = ~0u;\n   int i;\n   for (i=0; i < len; ++i)\n      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];\n   return ~crc;\n#endif\n}\n\n#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)\n#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));\n#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])\n\nstatic void stbiw__wpcrc(unsigned char **data, int len)\n{\n   unsigned int crc = stbiw__crc32(*data - len - 4, len+4);\n   stbiw__wp32(*data, crc);\n}\n\nstatic unsigned char stbiw__paeth(int a, int b, int c)\n{\n   int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);\n   if (pb <= pc) return STBIW_UCHAR(b);\n   return STBIW_UCHAR(c);\n}\n\n// @OPTIMIZE: provide an option that always forces left-predict or paeth predict\nstatic void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)\n{\n   static int mapping[] = { 0,1,2,3,4 };\n   static int firstmap[] = { 0,1,0,5,6 };\n   int *mymap = (y != 0) ? mapping : firstmap;\n   int i;\n   int type = mymap[filter_type];\n   unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);\n   int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;\n\n   if (type==0) {\n      memcpy(line_buffer, z, width*n);\n      return;\n   }\n\n   // first loop isn't optimized since it's just one pixel\n   for (i = 0; i < n; ++i) {\n      switch (type) {\n         case 1: line_buffer[i] = z[i]; break;\n         case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;\n         case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;\n         case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;\n         case 5: line_buffer[i] = z[i]; break;\n         case 6: line_buffer[i] = z[i]; break;\n      }\n   }\n   switch (type) {\n      case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;\n      case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;\n      case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;\n      case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;\n      case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;\n      case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;\n   }\n}\n\nSTBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)\n{\n   int force_filter = stbi_write_force_png_filter;\n   int ctype[5] = { -1, 0, 4, 2, 6 };\n   unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };\n   unsigned char *out,*o, *filt, *zlib;\n   signed char *line_buffer;\n   int j,zlen;\n\n   if (stride_bytes == 0)\n      stride_bytes = x * n;\n\n   if (force_filter >= 5) {\n      force_filter = -1;\n   }\n\n   filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;\n   line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }\n   for (j=0; j < y; ++j) {\n      int filter_type;\n      if (force_filter > -1) {\n         filter_type = force_filter;\n         stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);\n      } else { // Estimate the best filter by running through all of them:\n         int best_filter = 0, best_filter_val = 0x7fffffff, est, i;\n         for (filter_type = 0; filter_type < 5; filter_type++) {\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);\n\n            // Estimate the entropy of the line using this filter; the less, the better.\n            est = 0;\n            for (i = 0; i < x*n; ++i) {\n               est += abs((signed char) line_buffer[i]);\n            }\n            if (est < best_filter_val) {\n               best_filter_val = est;\n               best_filter = filter_type;\n            }\n         }\n         if (filter_type != best_filter) {  // If the last iteration already got us the best filter, don't redo it\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);\n            filter_type = best_filter;\n         }\n      }\n      // when we get here, filter_type contains the filter type, and line_buffer contains the data\n      filt[j*(x*n+1)] = (unsigned char) filter_type;\n      STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);\n   }\n   STBIW_FREE(line_buffer);\n   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);\n   STBIW_FREE(filt);\n   if (!zlib) return 0;\n\n   // each tag requires 12 bytes of overhead\n   out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);\n   if (!out) return 0;\n   *out_len = 8 + 12+13 + 12+zlen + 12;\n\n   o=out;\n   STBIW_MEMMOVE(o,sig,8); o+= 8;\n   stbiw__wp32(o, 13); // header length\n   stbiw__wptag(o, \"IHDR\");\n   stbiw__wp32(o, x);\n   stbiw__wp32(o, y);\n   *o++ = 8;\n   *o++ = STBIW_UCHAR(ctype[n]);\n   *o++ = 0;\n   *o++ = 0;\n   *o++ = 0;\n   stbiw__wpcrc(&o,13);\n\n   stbiw__wp32(o, zlen);\n   stbiw__wptag(o, \"IDAT\");\n   STBIW_MEMMOVE(o, zlib, zlen);\n   o += zlen;\n   STBIW_FREE(zlib);\n   stbiw__wpcrc(&o, zlen);\n\n   stbiw__wp32(o,0);\n   stbiw__wptag(o, \"IEND\");\n   stbiw__wpcrc(&o,0);\n\n   STBIW_ASSERT(o == out + *out_len);\n\n   return out;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   FILE *f;\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n\n   f = stbiw__fopen(filename, \"wb\");\n   if (!f) { STBIW_FREE(png); return 0; }\n   fwrite(png, 1, len, f);\n   fclose(f);\n   STBIW_FREE(png);\n   return 1;\n}\n#endif\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n   func(context, png, len);\n   STBIW_FREE(png);\n   return 1;\n}\n\n\n/* ***************************************************************************\n *\n * JPEG writer\n *\n * This is based on Jon Olick's jo_jpeg.cpp:\n * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html\n */\n\nstatic const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,\n      24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };\n\nstatic void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {\n   int bitBuf = *bitBufP, bitCnt = *bitCntP;\n   bitCnt += bs[1];\n   bitBuf |= bs[0] << (24 - bitCnt);\n   while(bitCnt >= 8) {\n      unsigned char c = (bitBuf >> 16) & 255;\n      stbiw__putc(s, c);\n      if(c == 255) {\n         stbiw__putc(s, 0);\n      }\n      bitBuf <<= 8;\n      bitCnt -= 8;\n   }\n   *bitBufP = bitBuf;\n   *bitCntP = bitCnt;\n}\n\nstatic void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {\n   float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;\n   float z1, z2, z3, z4, z5, z11, z13;\n\n   float tmp0 = d0 + d7;\n   float tmp7 = d0 - d7;\n   float tmp1 = d1 + d6;\n   float tmp6 = d1 - d6;\n   float tmp2 = d2 + d5;\n   float tmp5 = d2 - d5;\n   float tmp3 = d3 + d4;\n   float tmp4 = d3 - d4;\n\n   // Even part\n   float tmp10 = tmp0 + tmp3;   // phase 2\n   float tmp13 = tmp0 - tmp3;\n   float tmp11 = tmp1 + tmp2;\n   float tmp12 = tmp1 - tmp2;\n\n   d0 = tmp10 + tmp11;       // phase 3\n   d4 = tmp10 - tmp11;\n\n   z1 = (tmp12 + tmp13) * 0.707106781f; // c4\n   d2 = tmp13 + z1;       // phase 5\n   d6 = tmp13 - z1;\n\n   // Odd part\n   tmp10 = tmp4 + tmp5;       // phase 2\n   tmp11 = tmp5 + tmp6;\n   tmp12 = tmp6 + tmp7;\n\n   // The rotator is modified from fig 4-8 to avoid extra negations.\n   z5 = (tmp10 - tmp12) * 0.382683433f; // c6\n   z2 = tmp10 * 0.541196100f + z5; // c2-c6\n   z4 = tmp12 * 1.306562965f + z5; // c2+c6\n   z3 = tmp11 * 0.707106781f; // c4\n\n   z11 = tmp7 + z3;      // phase 5\n   z13 = tmp7 - z3;\n\n   *d5p = z13 + z2;         // phase 6\n   *d3p = z13 - z2;\n   *d1p = z11 + z4;\n   *d7p = z11 - z4;\n\n   *d0p = d0;  *d2p = d2;  *d4p = d4;  *d6p = d6;\n}\n\nstatic void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {\n   int tmp1 = val < 0 ? -val : val;\n   val = val < 0 ? val-1 : val;\n   bits[1] = 1;\n   while(tmp1 >>= 1) {\n      ++bits[1];\n   }\n   bits[0] = val & ((1<<bits[1])-1);\n}\n\nstatic int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {\n   const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };\n   const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };\n   int dataOff, i, j, n, diff, end0pos, x, y;\n   int DU[64];\n\n   // DCT rows\n   for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);\n   }\n   // DCT columns\n   for(dataOff=0; dataOff<8; ++dataOff) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],\n                     &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);\n   }\n   // Quantize/descale/zigzag the coefficients\n   for(y = 0, j=0; y < 8; ++y) {\n      for(x = 0; x < 8; ++x,++j) {\n         float v;\n         i = y*du_stride+x;\n         v = CDU[i]*fdtbl[j];\n         // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));\n         // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?\n         DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);\n      }\n   }\n\n   // Encode DC\n   diff = DU[0] - DC;\n   if (diff == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);\n   } else {\n      unsigned short bits[2];\n      stbiw__jpg_calcBits(diff, bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   // Encode ACs\n   end0pos = 63;\n   for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {\n   }\n   // end0pos = first element in reverse order !=0\n   if(end0pos == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n      return DU[0];\n   }\n   for(i = 1; i <= end0pos; ++i) {\n      int startpos = i;\n      int nrzeroes;\n      unsigned short bits[2];\n      for (; DU[i]==0 && i<=end0pos; ++i) {\n      }\n      nrzeroes = i-startpos;\n      if ( nrzeroes >= 16 ) {\n         int lng = nrzeroes>>4;\n         int nrmarker;\n         for (nrmarker=1; nrmarker <= lng; ++nrmarker)\n            stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);\n         nrzeroes &= 15;\n      }\n      stbiw__jpg_calcBits(DU[i], bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   if(end0pos != 63) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n   }\n   return DU[0];\n}\n\nstatic int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {\n   // Constants that don't pollute global namespace\n   static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};\n   static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};\n   static const unsigned char std_ac_luminance_values[] = {\n      0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n      0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n      0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n      0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n      0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n      0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n      0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};\n   static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};\n   static const unsigned char std_ac_chrominance_values[] = {\n      0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n      0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n      0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n      0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n      0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n      0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n      0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   // Huffman tables\n   static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};\n   static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};\n   static const unsigned short YAC_HT[256][2] = {\n      {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const unsigned short UVAC_HT[256][2] = {\n      {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,\n                             37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};\n   static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,\n                              99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};\n   static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,\n                                 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };\n\n   int row, col, i, k, subsample;\n   float fdtbl_Y[64], fdtbl_UV[64];\n   unsigned char YTable[64], UVTable[64];\n\n   if(!data || !width || !height || comp > 4 || comp < 1) {\n      return 0;\n   }\n\n   quality = quality ? quality : 90;\n   subsample = quality <= 90 ? 1 : 0;\n   quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;\n   quality = quality < 50 ? 5000 / quality : 200 - quality * 2;\n\n   for(i = 0; i < 64; ++i) {\n      int uvti, yti = (YQT[i]*quality+50)/100;\n      YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);\n      uvti = (UVQT[i]*quality+50)/100;\n      UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);\n   }\n\n   for(row = 0, k = 0; row < 8; ++row) {\n      for(col = 0; col < 8; ++col, ++k) {\n         fdtbl_Y[k]  = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n         fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n      }\n   }\n\n   // Write Headers\n   {\n      static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };\n      static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };\n      const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),\n                                      3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };\n      s->func(s->context, (void*)head0, sizeof(head0));\n      s->func(s->context, (void*)YTable, sizeof(YTable));\n      stbiw__putc(s, 1);\n      s->func(s->context, UVTable, sizeof(UVTable));\n      s->func(s->context, (void*)head1, sizeof(head1));\n      s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));\n      stbiw__putc(s, 0x10); // HTYACinfo\n      s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));\n      stbiw__putc(s, 1); // HTUDCinfo\n      s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));\n      stbiw__putc(s, 0x11); // HTUACinfo\n      s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));\n      s->func(s->context, (void*)head2, sizeof(head2));\n   }\n\n   // Encode 8x8 macroblocks\n   {\n      static const unsigned short fillBits[] = {0x7F, 7};\n      int DCY=0, DCU=0, DCV=0;\n      int bitBuf=0, bitCnt=0;\n      // comp == 2 is grey+alpha (alpha is ignored)\n      int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;\n      const unsigned char *dataR = (const unsigned char *)data;\n      const unsigned char *dataG = dataR + ofsG;\n      const unsigned char *dataB = dataR + ofsB;\n      int x, y, pos;\n      if(subsample) {\n         for(y = 0; y < height; y += 16) {\n            for(x = 0; x < width; x += 16) {\n               float Y[256], U[256], V[256];\n               for(row = y, pos = 0; row < y+16; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+16; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n\n               // subsample U,V\n               {\n                  float subU[64], subV[64];\n                  int yy, xx;\n                  for(yy = 0, pos = 0; yy < 8; ++yy) {\n                     for(xx = 0; xx < 8; ++xx, ++pos) {\n                        int j = yy*32+xx*2;\n                        subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;\n                        subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;\n                     }\n                  }\n                  DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                  DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n               }\n            }\n         }\n      } else {\n         for(y = 0; y < height; y += 8) {\n            for(x = 0; x < width; x += 8) {\n               float Y[64], U[64], V[64];\n               for(row = y, pos = 0; row < y+8; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+8; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y,  DCY, YDC_HT, YAC_HT);\n               DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n               DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n            }\n         }\n      }\n\n      // Do the bit alignment of the EOI marker\n      stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);\n   }\n\n   // EOI\n   stbiw__putc(s, 0xFF);\n   stbiw__putc(s, 0xD9);\n\n   return 1;\n}\n\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);\n}\n\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n#endif // STB_IMAGE_WRITE_IMPLEMENTATION\n\n/* Revision history\n      1.16  (2021-07-11)\n             make Deflate code emit uncompressed blocks when it would otherwise expand\n             support writing BMPs with alpha channel\n      1.15  (2020-07-13) unknown\n      1.14  (2020-02-02) updated JPEG writer to downsample chroma channels\n      1.13\n      1.12\n      1.11  (2019-08-11)\n\n      1.10  (2019-02-07)\n             support utf8 filenames in Windows; fix warnings and platform ifdefs\n      1.09  (2018-02-11)\n             fix typo in zlib quality API, improve STB_I_W_STATIC in C++\n      1.08  (2018-01-29)\n             add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter\n      1.07  (2017-07-24)\n             doc fix\n      1.06 (2017-07-23)\n             writing JPEG (using Jon Olick's code)\n      1.05   ???\n      1.04 (2017-03-03)\n             monochrome BMP expansion\n      1.03   ???\n      1.02 (2016-04-02)\n             avoid allocating large structures on the stack\n      1.01 (2016-01-16)\n             STBIW_REALLOC_SIZED: support allocators with no realloc support\n             avoid race-condition in crc initialization\n             minor compile issues\n      1.00 (2015-09-14)\n             installable file IO function\n      0.99 (2015-09-13)\n             warning fixes; TGA rle support\n      0.98 (2015-04-08)\n             added STBIW_MALLOC, STBIW_ASSERT etc\n      0.97 (2015-01-18)\n             fixed HDR asserts, rewrote HDR rle logic\n      0.96 (2015-01-17)\n             add HDR output\n             fix monochrome BMP\n      0.95 (2014-08-17)\n             add monochrome TGA output\n      0.94 (2014-05-31)\n             rename private functions to avoid conflicts with stb_image.h\n      0.93 (2014-05-27)\n             warning fixes\n      0.92 (2010-08-01)\n             casts to unsigned char to fix warnings\n      0.91 (2010-07-17)\n             first public release\n      0.90   first internal release\n*/\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "deps/CMakeLists.txt",
    "content": "add_subdirectory(glad)\nadd_subdirectory(stb)\nadd_subdirectory(inih)\nadd_subdirectory(CascLib)\n\nfind_package(Git REQUIRED QUIET)\ninclude(ExternalProject)\nif(CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n    set(LUA54_LIB_SUFFIX \"d\")\nendif()\nif(CMAKE_SIZEOF_VOID_P EQUAL 8)\n    set(LUA54_INSTALL_COMMANDS\n        INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/bin64 ${CMAKE_BINARY_DIR}/bin\n                COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/include ${CMAKE_BINARY_DIR}/include/lua\n                COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/lib64 ${CMAKE_BINARY_DIR}/lib\n        )\nelse()\n    set(LUA54_INSTALL_COMMANDS\n        INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/bin ${CMAKE_BINARY_DIR}/bin\n                COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/include ${CMAKE_BINARY_DIR}/include/lua\n                COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/lib ${CMAKE_BINARY_DIR}/lib\n        )\nendif()\nExternalProject_Add(lua54\n    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/lua54\n    GIT_REPOSITORY https://github.com/NLua/lua.git\n    GIT_TAG main\n    GIT_SHALLOW ON\n    EXCLUDE_FROM_ALL ON\n    UPDATE_DISCONNECTED ON\n    STEP_TARGETS update\n    CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR} -DLUA_BUILD_AS_DLL=OFF\n    ${LUA54_INSTALL_COMMANDS}\n    )\nadd_library(lua54-static INTERFACE)\nadd_dependencies(lua54-static lua54)\ntarget_include_directories(lua54-static INTERFACE ${CMAKE_BINARY_DIR}/include/lua)\ntarget_link_directories(lua54-static INTERFACE ${CMAKE_BINARY_DIR}/lib)\ntarget_link_libraries(lua54-static INTERFACE lua54_static${LUA54_LIB_SUFFIX})\nadd_library(lua::lua54 ALIAS lua54-static)\nlist(APPEND EXTERNAL_PROJECTS lua54)\n\nadd_subdirectory(sol3)\n\n# update external project\nadd_custom_command(OUTPUT ${PROJECT_NAME}-reset_projects COMMAND \"\")\nadd_custom_target(${PROJECT_NAME}-update_deps DEPENDS simpio-update_deps ${PROJECT_NAME}-reset_projects)\nforeach(PROJ ${EXTERNAL_PROJECTS})\n    add_dependencies(${PROJECT_NAME}-update_deps ${PROJ}-update)\n    ExternalProject_Get_property(${PROJ} STAMP_DIR)\n    add_custom_command(OUTPUT ${PROJECT_NAME}-reset_projects\n        COMMAND ${CMAKE_COMMAND} -E rm -f ${STAMP_DIR}/${PROJ}-patch ${STAMP_DIR}/${PROJ}-configure ${STAMP_DIR}/${PROJ}-build ${STAMP_DIR}/${PROJ}-install ${STAMP_DIR}/${PROJ}-done\n        APPEND)\nendforeach()\nset_source_files_properties(${PROJECT_NAME}-reset_projects PROPERTIES SYMBOLIC \"true\")\n"
  },
  {
    "path": "deps/CascLib/CMakeLists.txt",
    "content": "set(HEADER_FILES\n    src/CascCommon.h\n    src/CascLib.h\n    src/CascPort.h\n    src/common/Array.h\n    src/common/Common.h\n    src/common/Csv.h\n    src/common/Directory.h\n    src/common/FileStream.h\n    src/common/FileTree.h\n    src/common/ListFile.h\n    src/common/Map.h\n    src/common/Mime.h\n    src/common/Path.h\n    src/common/RootHandler.h\n    src/common/Sockets.h\n    src/jenkins/lookup.h\n    )\n\nset(SRC_FILES\n    src/common/Common.cpp\n    src/common/Directory.cpp\n    src/common/Csv.cpp\n    src/common/FileStream.cpp\n    src/common/FileTree.cpp\n    src/common/ListFile.cpp\n    src/common/Mime.cpp\n    src/common/RootHandler.cpp\n    src/common/Sockets.cpp\n    src/jenkins/lookup3.c\n    src/md5/md5.cpp\n    src/CascDecompress.cpp\n    src/CascDecrypt.cpp\n    src/CascDumpData.cpp\n    src/CascFiles.cpp\n    src/CascFindFile.cpp\n    src/CascIndexFiles.cpp\n    src/CascOpenFile.cpp\n    src/CascOpenStorage.cpp\n    src/CascReadFile.cpp\n    src/CascRootFile_Diablo3.cpp\n    src/CascRootFile_Install.cpp\n    src/CascRootFile_MNDX.cpp\n    src/CascRootFile_Text.cpp\n    src/CascRootFile_TVFS.cpp\n    src/CascRootFile_OW.cpp\n    src/CascRootFile_WoW.cpp\n    )\n\nset(ZLIB_FILES\n    src/zlib/adler32.c\n    src/zlib/crc32.c\n    src/zlib/inffast.c\n    src/zlib/inflate.c\n    src/zlib/inftrees.c\n    src/zlib/zutil.c\n    )\n\nadd_library(casc STATIC EXCLUDE_FROM_ALL ${SRC_FILES} ${HEADER_FILES} ${ZLIB_FILES})\ntarget_compile_definitions(casc PUBLIC CASCLIB_NO_AUTO_LINK_LIBRARY _UNICODE UNICODE PRIVATE STRSAFE_NO_DEPRECATE)\ntarget_include_directories(casc PUBLIC src)\ntarget_link_libraries(casc ws2_32)\nset_target_properties(casc PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\n"
  },
  {
    "path": "deps/CascLib/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Ladislav Zezula\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "deps/CascLib/README.md",
    "content": "# CascLib\n\n**CascLib** is an open-source implementation of library for reading Blizzard's CASC storages since 2014.\n\nFor API documentation, refer to http://www.zezula.net/en/casc/casclib.html .\n\n## Using CascLib as static library in Windows\n1. Clone the CascLib repository into a local folder:\n\n\t`git clone https://github.com/ladislav-zezula/CascLib.git`\n\n2. Open one of the solution files in Microsoft Visual Studio\n\n\t- `CascLib_vs17.sln` for Visual Studio 2017\n\t- `CascLib_vs15.sln` for Visual Studio 2015\n\t- `CascLib_vs08.sln` for Visual Studio 2008\n\n3. Select `Build / Batch Build` and select all `CascLib` build configurations. Do a full build. The result LIB files for each platform are in `.\\bin\\CascLib\\Win32` and `.\\bin\\CascLib\\x64`. The following build configurations are available:\n\n\t- DebugAD\\CascLibDAD.lib (Debug Ansi version with dynamic CRT library)\n\t- DebugAS\\CascLibDAS.lib (Debug Ansi version with static CRT library)\n\t- DebugUD\\CascLibDUD.lib (Debug Unicode version with dynamic CRT library)\n\t- DebugUS\\CascLibDUS.lib (Debug Unicode version with static CRT library)\n\t- ReleaseAD\\CascLibRAD.lib (Release Ansi version with dynamic CRT library)\n\t- ReleaseAS\\CascLibRAS.lib (Release Ansi version with static CRT library)\n\t- ReleaseUD\\CascLibRUD.lib (Release Unicode version with dynamic CRT library)\n\t- ReleaseUS\\CascLibRUS.lib (Release Unicode version with static CRT library)\n\n4. After the build is done, put all 32-bit LIBs to a library directory (e.g. `lib32`) and all 64-bit LIBs into another directory (e.g. `lib64`)\n\n5. Include `CascLib.h` in your project. `CascLib.h` will automatically select the required LIB file, depending on your project settings.\n\n6. Build your project.\n\n## Using CascLib as DLL in Windows\n1. Clone the CascLib repository into a local folder:\n\n\t`git clone https://github.com/ladislav-zezula/CascLib.git`\n\n2. Open one of the solution files in Microsoft Visual Studio\n\n\t- `CascLib_vs17.sln` for Visual Studio 2017\n\t- `CascLib_vs15.sln` for Visual Studio 2015\n\t- `CascLib_vs08.sln` for Visual Studio 2008\n\n3. Select `Build / Batch Build` and check all `CascLib_dll Release` configurations. Do a full build. The result DLL and LIB files for `Win32` and `x64` platforms are in:\n\t- `.\\bin\\CascLib_dll\\Win32\\Release` (32-bit build)\n\t- `.\\bin\\CascLib_dll\\x64\\Release` (64-bit build)\n\n5. Include `CascLib.h` and add `CascLib.lib` to your project and build it.\n"
  },
  {
    "path": "deps/CascLib/src/CascCommon.h",
    "content": "/*****************************************************************************/\n/* CascCommon.h                           Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Common functions for CascLib                                              */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of CascCommon.h                    */\n/*****************************************************************************/\n\n#ifndef __CASCCOMMON_H__\n#define __CASCCOMMON_H__\n\n//-----------------------------------------------------------------------------\n// Compression support\n\n// Include functions from zlib\n#ifndef CASC_USE_SYSTEM_ZLIB\n    #include \"zlib/zlib.h\"\n#else\n    #include <zlib.h>\n#endif\n\n#include \"CascPort.h\"\n#include \"common/Common.h\"\n#include \"common/Array.h\"\n#include \"common/Map.h\"\n#include \"common/FileTree.h\"\n#include \"common/FileStream.h\"\n#include \"common/Directory.h\"\n#include \"common/ListFile.h\"\n#include \"common/Csv.h\"\n#include \"common/Mime.h\"\n#include \"common/Path.h\"\n#include \"common/RootHandler.h\"\n#include \"common/Sockets.h\"\n\n// Headers from Alexander Peslyak's MD5 implementation\n#include \"md5/md5.h\"\n\n// For HashStringJenkins\n#include \"jenkins/lookup.h\"\n\n// On-disk CASC structures\n#include \"CascStructs.h\"\n\n//-----------------------------------------------------------------------------\n// CascLib private defines\n\n#ifdef _DEBUG\n#define BREAK_ON_XKEY3(CKey, v0, v1, v2) if(CKey[0] == v0 && CKey[1] == v1 && CKey[2] == v2) { __debugbreak(); }\n#define BREAKIF(condition)               if(condition)  { __debugbreak(); }\n#else\n#define BREAK_ON_XKEY3(CKey, v0, v1, v2) { /* NOTHING */ }\n#define BREAKIF(condition)               { /* NOTHING */ }\n#endif\n\n#define CASC_MAGIC_STORAGE  0x524F545343534143      // 'CASCSTOR'\n#define CASC_MAGIC_FILE     0x454C494643534143      // 'CASCFILE'\n#define CASC_MAGIC_FIND     0x444E494643534143      // 'CASCFIND'\n\n// For CASC_CDN_DOWNLOAD::Flags\n#define CASC_CDN_FORCE_DOWNLOAD         0x0001      // Force downloading the file even if in the cache\n\n//-----------------------------------------------------------------------------\n// In-memory structures\n\ntypedef enum _CBLD_TYPE\n{\n    CascBuildNone = 0,                              // No build type found\n    CascBuildInfo,                                  // .build.info\n    CascBuildDb,                                    // .build.db (older storages)\n    CascVersionsDb                                  // versions (downloaded online)\n} CBLD_TYPE, *PCBLD_TYPE;\n\ntypedef enum _CSTRTG\n{\n    CascCacheInvalid,                               // Do not cache anything. Used as invalid value\n    CascCacheNothing,                               // Do not cache anything. Used on internal files, where the content is loaded directly to the user buffer\n    CascCacheLastFrame,                             // Only cache one file frame\n} CSTRTG, *PCSTRTG;\n\n// Tag file entry, loaded from the DOWNLOAD file\ntypedef struct _CASC_TAG_ENTRY\n{\n    USHORT HashType;                                // Hash type\n    char TagName[1];                                // Tag name. Variable length.\n} CASC_TAG_ENTRY, *PCASC_TAG_ENTRY;\n\n// Information about index file\ntypedef struct _CASC_INDEX\n{\n    LPTSTR szFileName;                              // Full name of the index file\n    LPBYTE pbFileData;                              // Loaded content of the index file\n    size_t cbFileData;                               // Size of the index file\n    DWORD NewSubIndex;                              // New subindex\n    DWORD OldSubIndex;                              // Old subindex\n} CASC_INDEX, *PCASC_INDEX;\n\n// Normalized header of the index files.\n// Both version 1 and version 2 are converted to this structure\ntypedef struct _CASC_INDEX_HEADER\n{\n    USHORT IndexVersion;                            // 5 for index v 1.0, 7 for index version 2.0\n    BYTE   BucketIndex;                             // Should be the same as the first byte of the hex filename.\n    BYTE   StorageOffsetLength;                     // Length, in bytes, of the StorageOffset field in the EKey entry\n    BYTE   EncodedSizeLength;                       // Length, in bytes, of the EncodedSize in the EKey entry\n    BYTE   EKeyLength;                              // Length, in bytes, of the (trimmed) EKey in the EKey entry\n    BYTE   FileOffsetBits;                          // Number of bits of the archive file offset in StorageOffset field. Rest is data segment index\n    BYTE   Alignment;\n    ULONGLONG SegmentSize;                          // Size of one data segment (aka data.### file)\n    size_t HeaderLength;                            // Length of the on-disk header structure, in bytes\n    size_t HeaderPadding;                           // Length of padding after the header\n    size_t EntryLength;                             // Length of the on-disk EKey entry structure, in bytes\n    size_t EKeyCount;                               // Number of EKey entries. Only supplied for index files version 1.\n\n} CASC_INDEX_HEADER, *PCASC_INDEX_HEADER;\n\n// Normalized footer of the archive index files (md5.index)\ntypedef struct _CASC_ARCINDEX_FOOTER\n{\n    BYTE   TocHash[MD5_HASH_SIZE];                  // Hash of the structure\n    BYTE   FooterHash[MD5_HASH_SIZE];               // MD5 hash of the footer, possibly shortened\n    BYTE   Version;                                 // Version of the index footer\n    BYTE   OffsetBytes;                             // Length, in bytes, of the file offset field\n    BYTE   SizeBytes;                               // Length, in bytes, of the file size field\n    BYTE   EKeyLength;                              // Length, in bytes, of the EKey field\n    BYTE   FooterHashBytes;                         // Length, in bytes, of the hash and checksum\n    BYTE   Alignment[3];\n    size_t ElementCount;                            // total number of elements in the index file\n    size_t PageLength;                              // Length, in bytes, of the index page\n    size_t ItemLength;                              // Length, in bytes, of the single item\n    size_t FooterLength;                            // Length, in bytes, of the index footer structure\n\n} CASC_ARCINDEX_FOOTER, *PCASC_ARCINDEX_FOOTER;\n\n// Normalized header of the ENCODING file\ntypedef struct _CASC_ENCODING_HEADER\n{\n    USHORT Magic;                                   // FILE_MAGIC_ENCODING ('EN')\n    USHORT Version;                                 // Expected to be 1 by CascLib\n    BYTE   CKeyLength;                              // The content key length in ENCODING file. Usually 0x10\n    BYTE   EKeyLength;                              // The encoded key length in ENCODING file. Usually 0x10\n    DWORD  CKeyPageSize;                            // Size of the CKey page in bytes\n    DWORD  EKeyPageSize;                            // Size of the CKey page in bytes\n    DWORD  CKeyPageCount;                           // Number of CKey pages in the page table\n    DWORD  EKeyPageCount;                           // Number of EKey pages in the page table\n    DWORD  ESpecBlockSize;                          // Size of the ESpec string block, in bytes\n} CASC_ENCODING_HEADER, *PCASC_ENCODING_HEADER;\n\ntypedef struct _CASC_DOWNLOAD_HEADER\n{\n    USHORT Magic;                                   // FILE_MAGIC_DOWNLOAD ('DL')\n    USHORT Version;                                 // Version\n    USHORT EKeyLength;                              // Length of the EKey\n    USHORT EntryHasChecksum;                        // If nonzero, then the entry has checksum\n    DWORD  EntryCount;\n    DWORD  TagCount;\n    USHORT FlagByteSize;\n    USHORT BasePriority;\n\n    size_t HeaderLength;                            // Length of the on-disk header, in bytes\n    size_t EntryLength;                             // Length of the on-disk entry, in bytes\n\n} CASC_DOWNLOAD_HEADER, *PCASC_DOWNLOAD_HEADER;\n\ntypedef struct _CASC_DOWNLOAD_ENTRY\n{\n    BYTE EKey[MD5_HASH_SIZE];\n    ULONGLONG EncodedSize;\n    DWORD Checksum;\n    DWORD Flags;\n    BYTE Priority;\n} CASC_DOWNLOAD_ENTRY, *PCASC_DOWNLOAD_ENTRY;\n\n// Capturable tag structure for loading from DOWNLOAD manifest\ntypedef struct _CASC_TAG_ENTRY1\n{\n    const char * szTagName;                         // Tag name\n    LPBYTE Bitmap;                                  // Bitmap\n    size_t BitmapLength;                            // Length of the bitmap, in bytes\n    size_t NameLength;                              // Length of the tag name, in bytes, not including '\\0'\n    size_t TagLength;                               // Length of the on-disk tag, in bytes\n    DWORD TagValue;                                 // Tag value\n} CASC_TAG_ENTRY1, *PCASC_TAG_ENTRY1;\n\n// Tag structure for storing in arrays\ntypedef struct _CASC_TAG_ENTRY2\n{\n    size_t NameLength;                              // Length of the on-disk tag, in bytes\n    DWORD TagValue;                                 // Tag value\n    char szTagName[0x08];                           // Tag string. This member can be longer than declared. Aligned to 8 bytes.\n} CASC_TAG_ENTRY2, *PCASC_TAG_ENTRY2;\n\ntypedef struct _CASC_INSTALL_HEADER\n{\n    USHORT Magic;                                   // FILE_MAGIC_DOWNLOAD ('DL')\n    BYTE   Version;                                 // Version\n    BYTE   EKeyLength;                              // Length of the EKey\n    DWORD  EntryCount;\n    DWORD  TagCount;\n\n    size_t HeaderLength;                            // Length of the on-disk header, in bytes\n} CASC_INSTALL_HEADER, *PCASC_INSTALL_HEADER;\n\ntypedef struct _CASC_FILE_FRAME\n{\n    CONTENT_KEY FrameHash;                          // MD5 hash of the file frame\n    ULONGLONG StartOffset;                          // Starting offset of the file span\n    ULONGLONG EndOffset;                            // Ending offset of the file span\n    ULONGLONG DataFileOffset;                       // Offset in the data file (data.###)\n    DWORD EncodedSize;                              // Encoded size of the frame\n    DWORD ContentSize;                              // Content size of the frame\n} CASC_FILE_FRAME, *PCASC_FILE_FRAME;\n\ntypedef struct _CASC_FILE_SPAN\n{\n    ULONGLONG StartOffset;                          // Starting offset of the file span\n    ULONGLONG EndOffset;                            // Ending offset of the file span\n    PCASC_FILE_FRAME pFrames;\n    TFileStream * pStream;                          // [Opened] stream for the file span\n    DWORD ArchiveIndex;                             // Index of the archive\n    DWORD ArchiveOffs;                              // Offset in the archive\n    DWORD HeaderSize;                               // Size of encoded frame headers\n    DWORD FrameCount;                               // Number of frames in this span\n\n} CASC_FILE_SPAN, *PCASC_FILE_SPAN;\n\n// Structure for downloading a file from the CDN (https://wowdev.wiki/TACT#File_types)\n// Remote path is combined as the following:\n//  [szCdnsHost]       /[szCdnsPath]/[szPathType]/EKey[0-1]/EKey[2-3]/[EKey].[Extension]\n//  level3.blizzard.com/tpr/bnt001  /data        /fe       /3d       /fe3d7cf9d04e07066de32bd95a5c2627.index\ntypedef struct _CASC_CDN_DOWNLOAD\n{\n    ULONGLONG ArchiveOffs;                          // Archive offset (if pbArchiveKey != NULL)\n    LPCTSTR szCdnsHost;                             // Address of the remote CDN server. (\"level3.blizzard.com\")\n                                                    // If NULL, the downloader will try all CDN servers from the storage\n    LPCTSTR szCdnsPath;                             // Remote CDN path (\"tpr/bnt001\")\n    LPCTSTR szPathType;                             // Path type (\"config\", \"data\", \"patch\")\n    LPCTSTR szLoPaType;                             // Local path type (\"config\", \"data\", \"patch\"). If NULL, it's gonna be the same like szPathType, If \"\", then it's not used\n    LPCTSTR szFileName;                             // Plain file name, without path and extension\n    LPBYTE  pbArchiveKey;                            // If non-NULL, then the file is present in the archive.\n    LPBYTE  pbEKey;                                 // 16-byte EKey of the file of of the archive\n    LPCTSTR szExtension;                            // Extension for the file. Can be NULL.\n\n    LPTSTR szLocalPath;                             // Pointer to the variable that, upon success, reveives the local path where the file was downloaded\n    size_t ccLocalPath;                             // Maximum length of szLocalPath, in TCHARs\n    DWORD ArchiveIndex;                             // Index of the archive (if pbArchiveKey != NULL)\n    DWORD EncodedSize;                              // Encoded length (if pbArchiveKey != NULL)\n    DWORD Flags;                                    // See CASC_CDN_FLAG_XXX\n\n} CASC_CDN_DOWNLOAD, *PCASC_CDN_DOWNLOAD;\n\n//-----------------------------------------------------------------------------\n// Structures for CASC storage and CASC file\n\nstruct TCascStorage\n{\n    TCascStorage();\n    ~TCascStorage();\n\n    TCascStorage * AddRef();\n    TCascStorage * Release();\n\n    static TCascStorage * IsValid(HANDLE hStorage)\n    {\n        TCascStorage * hs = (TCascStorage *)hStorage;\n\n        return (hs != INVALID_HANDLE_VALUE &&\n                hs != NULL &&\n                hs->ClassName == CASC_MAGIC_STORAGE) ? hs : NULL;\n    }\n\n    // Class recognizer. Has constant value of 'CASCSTOR' (CASC_MAGIC_STORAGE)\n    ULONGLONG ClassName;\n\n    // Class members\n    PCASC_OPEN_STORAGE_ARGS pArgs;                  // Open storage arguments. Only valid during opening the storage\n    CASC_LOCK StorageLock;                          // Lock for multi-threaded operations\n\n    LPCTSTR szIndexFormat;                          // Format of the index file name\n    LPTSTR  szCodeName;                             // On local storage, this select a product in a multi-product storage. For online storage, this selects a product\n    LPTSTR  szRootPath;                             // Path where the build file is\n    LPTSTR  szDataPath;                             // This is the directory where data files are\n    LPTSTR  szIndexPath;                            // This is the directory where index files are\n    LPTSTR  szBuildFile;                            // Build file name (.build.info or .build.db)\n    LPTSTR  szCdnServers;                           // Multi-SZ list of CDN servers\n    LPTSTR  szCdnPath;                              // Remote CDN sub path for the product\n    LPSTR   szRegion;                               // Product region. Only when \"versions\" is used as storage root file\n    LPSTR   szBuildKey;                             // Product build key, aka MD5 of the build file\n    DWORD dwDefaultLocale;                          // Default locale, read from \".build.info\"\n    DWORD dwBuildNumber;                            // Product build number\n    DWORD dwRefCount;                               // Number of references\n    DWORD dwFeatures;                               // List of CASC features. See CASC_FEATURE_XXX\n\n    CBLD_TYPE BuildFileType;                        // Type of the build file\n\n    QUERY_KEY CdnConfigKey;                         // Currently selected CDN config file. Points to \"config\\%02X\\%02X\\%s\n    QUERY_KEY CdnBuildKey;                          // Currently selected CDN build file. Points to \"config\\%02X\\%02X\\%s\n\n    QUERY_KEY ArchiveGroup;                         // Key array of the \"archive-group\"\n    QUERY_KEY ArchivesKey;                          // Key array of the \"archives\"\n    QUERY_KEY PatchArchivesKey;                     // Key array of the \"patch-archives\"\n    QUERY_KEY PatchArchivesGroup;                   // Key array of the \"patch-archive-group\"\n    QUERY_KEY BuildFiles;                           // List of supported build files\n\n    TFileStream * DataFiles[CASC_MAX_DATA_FILES];   // Array of open data files\n    CASC_INDEX IndexFiles[CASC_INDEX_COUNT];        // Array of found index files\n    CASC_MAP IndexEKeyMap;\n\n    CASC_CKEY_ENTRY EncodingCKey;                   // Information about ENCODING file\n    CASC_CKEY_ENTRY DownloadCKey;                   // Information about DOWNLOAD file\n    CASC_CKEY_ENTRY InstallCKey;                    // Information about INSTALL file\n    CASC_CKEY_ENTRY PatchFile;                      // Information about PATCH file\n    CASC_CKEY_ENTRY RootFile;                       // Information about ROOT file\n    CASC_CKEY_ENTRY SizeFile;                       // Information about SIZE file\n    CASC_CKEY_ENTRY VfsRoot;                        // The main VFS root file\n    CASC_ARRAY VfsRootList;                         // List of CASC_EKEY_ENTRY for each TVFS sub-root\n\n    TRootHandler * pRootHandler;                    // Common handler for various ROOT file formats\n    CASC_ARRAY IndexArray;                          // Array of CASC_EKEY_ENTRY, loaded from online indexes\n    CASC_ARRAY CKeyArray;                           // Array of CASC_CKEY_ENTRY, loaded from ENCODING file\n    CASC_ARRAY TagsArray;                           // Array of CASC_DOWNLOAD_TAG2\n    CASC_MAP IndexMap;                              // Map of EKey -> IndexArray (for online archives)\n    CASC_MAP CKeyMap;                               // Map of CKey -> CKeyArray\n    CASC_MAP EKeyMap;                               // Map of EKey -> CKeyArray\n    size_t LocalFiles;                              // Number of files that are present locally\n    size_t TotalFiles;                              // Total number of files in the storage, some may not be present locally\n    size_t EKeyEntries;                             // Number of CKeyEntry-ies loaded from text build file\n    size_t EKeyLength;                              // EKey length from the index files\n    DWORD FileOffsetBits;                           // Number of bits in the storage offset which mean data segent offset\n\n    CASC_KEY_MAP KeyMap;                            // Growable map of encryption keys\n    ULONGLONG  LastFailKeyName;                     // The value of the encryption key that recently was NOT found.\n};\n\nstruct TCascFile\n{\n    TCascFile(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry);\n    ~TCascFile();\n\n    DWORD OpenFileSpans(LPCTSTR szSpanList);\n    void InitFileSpans(PCASC_FILE_SPAN pSpans, DWORD dwSpanCount);\n    void InitCacheStrategy();\n\n    static TCascFile * IsValid(HANDLE hFile)\n    {\n        TCascFile * hf = (TCascFile *)hFile;\n\n        return (hf != INVALID_HANDLE_VALUE &&\n                hf != NULL &&\n                hf->ClassName == CASC_MAGIC_FILE &&\n                hf->pCKeyEntry != NULL) ? hf : NULL;\n    }\n\n    // Class recognizer. Has constant value of 'CASCFILE' (CASC_MAGIC_FILE)\n    ULONGLONG ClassName;\n\n    // Class members\n    TCascStorage * hs;                              // Pointer to storage structure\n\n    PCASC_CKEY_ENTRY pCKeyEntry;                    // Pointer to the first CKey entry. Each entry describes one file span\n    PCASC_FILE_SPAN pFileSpan;                      // Pointer to the first file span entry\n    ULONGLONG ContentSize;                          // Content size. This is the summed content size of all file spans\n    ULONGLONG EncodedSize;                          // Encoded size. This is the summed encoded size of all file spans\n    ULONGLONG FilePointer;                          // Current file pointer\n    DWORD SpanCount;                                // Number of file spans. There is one CKey entry for each file span\n    DWORD bVerifyIntegrity:1;                       // If true, then the data are validated more strictly when read\n    DWORD bDownloadFileIf:1;                        // If true, then the data will be downloaded from the online storage if missing\n    DWORD bCloseFileStream:1;                       // If true, file stream needs to be closed during CascCloseFile\n    DWORD bOvercomeEncrypted:1;                     // If true, then CascReadFile will fill the part that is encrypted (and key was not found) with zeros\n    DWORD bFreeCKeyEntries:1;                       // If true, dectructor will free the array of CKey entries\n\n    ULONGLONG FileCacheStart;                       // Starting offset of the file cached area\n    ULONGLONG FileCacheEnd;                         // Ending offset of the file cached area\n    LPBYTE pbFileCache;                             // Pointer to file cached area\n    CSTRTG CacheStrategy;                           // Caching strategy. See CSTRTG enum for more info\n};\n\nstruct TCascSearch\n{\n    TCascSearch(TCascStorage * ahs, LPCTSTR aszListFile, const char * aszMask)\n    {\n        // Init the class\n        ClassName = CASC_MAGIC_FIND;\n        hs = ahs->AddRef();\n\n        // Init provider-specific data\n        pCache = NULL;\n        nFileIndex = 0;\n        nSearchState = 0;\n        bListFileUsed = false;\n\n        // Allocate mask\n        szListFile = CascNewStr(aszListFile);\n        szMask = CascNewStr((aszMask != NULL) ? aszMask : \"*\");\n    }\n\n    ~TCascSearch()\n    {\n        // Dereference the CASC storage\n        hs = hs->Release();\n        ClassName = 0;\n\n        // Free the rest of the members\n        CASC_FREE(szMask);\n        CASC_FREE(szListFile);\n        CASC_FREE(pCache);\n    }\n\n    static TCascSearch * IsValid(HANDLE hFind)\n    {\n        TCascSearch * pSearch = (TCascSearch *)hFind;\n\n        return (hFind != INVALID_HANDLE_VALUE &&\n                hFind != NULL &&\n                pSearch->ClassName == CASC_MAGIC_FIND &&\n                pSearch->szMask != NULL) ? pSearch : NULL;\n    }\n\n    ULONGLONG ClassName;                            // Contains 'CASCFIND'\n\n    TCascStorage * hs;                              // Pointer to the storage handle\n    LPTSTR szListFile;                              // Name of the listfile\n    void * pCache;                                  // Listfile cache\n    char * szMask;                                  // Search mask\n\n    // Provider-specific data\n    size_t nFileIndex;                              // Root-specific search context\n    DWORD nSearchState:8;                           // The current search state (0 = listfile, 1 = nameless, 2 = done)\n    DWORD bListFileUsed:1;                          // TRUE: The listfile has already been loaded\n};\n\n//-----------------------------------------------------------------------------\n// Common functions (CascCommon.cpp)\n\ninline void FreeCascBlob(PQUERY_KEY pBlob)\n{\n    if(pBlob != NULL)\n    {\n        CASC_FREE(pBlob->pbData);\n        pBlob->cbData = 0;\n    }\n}\n\n//-----------------------------------------------------------------------------\n// Text file parsing (CascFiles.cpp)\n\nbool  InvokeProgressCallback(TCascStorage * hs, LPCSTR szMessage, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue);\nDWORD GetFileSpanInfo(PCASC_CKEY_ENTRY pCKeyEntry, PULONGLONG PtrContentSize, PULONGLONG PtrEncodedSize = NULL);\nDWORD DownloadFileFromCDN(TCascStorage * hs, CASC_CDN_DOWNLOAD & CdnsInfo);\nDWORD CheckGameDirectory(TCascStorage * hs, LPTSTR szDirectory);\nDWORD LoadCdnsFile(TCascStorage * hs);\nDWORD LoadBuildInfo(TCascStorage * hs);\nDWORD LoadCdnConfigFile(TCascStorage * hs);\nDWORD LoadCdnBuildFile(TCascStorage * hs);\n\nLPBYTE LoadInternalFileToMemory(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD * pcbFileData);\nLPBYTE LoadFileToMemory(LPCTSTR szFileName, DWORD * pcbFileData);\nbool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD dwOpenFlags, HANDLE * PtrFileHandle);\nbool SetCacheStrategy(HANDLE hFile, CSTRTG CacheStrategy);\n\n//-----------------------------------------------------------------------------\n// Internal file functions\n\nvoid * ProbeOutputBuffer(void * pvBuffer, size_t cbLength, size_t cbMinLength, size_t * pcbLengthNeeded);\n\nPCASC_CKEY_ENTRY FindCKeyEntry_CKey(TCascStorage * hs, LPBYTE pbCKey, PDWORD PtrIndex = NULL);\nPCASC_CKEY_ENTRY FindCKeyEntry_EKey(TCascStorage * hs, LPBYTE pbEKey, PDWORD PtrIndex = NULL);\n\nsize_t GetTagBitmapLength(LPBYTE pbFilePtr, LPBYTE pbFileEnd, DWORD EntryCount);\n\nDWORD CascDecompress(LPBYTE pvOutBuffer, PDWORD pcbOutBuffer, LPBYTE pvInBuffer, DWORD cbInBuffer);\nDWORD CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer);\n\nDWORD CascLoadEncryptionKeys(TCascStorage * hs);\nDWORD CascDecrypt(TCascStorage * hs, LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex);\n\n//-----------------------------------------------------------------------------\n// Support for index files\n\nbool CopyEKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry);\n\nDWORD LoadIndexFiles(TCascStorage * hs);\nvoid  FreeIndexFiles(TCascStorage * hs);\n\n//-----------------------------------------------------------------------------\n// Support for ROOT file\n\nDWORD RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);\nDWORD RootHandler_CreateTVFS(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);\nDWORD RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);\nDWORD RootHandler_CreateWoW(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask);\nDWORD RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);\nDWORD RootHandler_CreateStarcraft1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);\nDWORD RootHandler_CreateInstall(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);\n\n//-----------------------------------------------------------------------------\n// Dumpers (CascDumpData.cpp)\n\n#ifdef _DEBUG\nvoid CascDumpFile(HANDLE hFile, const char * szDumpFile = NULL);\nvoid CascDumpStorage(HANDLE hStorage, const char * szDumpFile = NULL);\n#endif\n\n#endif // __CASCCOMMON_H__\n"
  },
  {
    "path": "deps/CascLib/src/CascDecompress.cpp",
    "content": "/*****************************************************************************/\n/* CascDecompress.cpp                     Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Decompression functions                                                   */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 02.05.14  1.00  Lad  The first version of CascDecompress.cpp              */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nDWORD CascDecompress(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer)\n{\n    z_stream z;                        // Stream information for zlib\n    DWORD dwErrCode = ERROR_FILE_CORRUPT;\n    uInt cbOutBuffer = *pcbOutBuffer;\n    int nResult;\n\n    // Fill the stream structure for zlib\n    z.next_in   = pbInBuffer;\n    z.avail_in  = cbInBuffer;\n    z.total_in  = cbInBuffer;\n    z.next_out  = pbOutBuffer;\n    z.avail_out = cbOutBuffer;\n    z.total_out = 0;\n    z.zalloc    = NULL;\n    z.zfree     = NULL;\n\n    // Reset the total number of output bytes\n    cbOutBuffer = 0;\n\n    // Initialize the decompression structure\n    if((nResult = inflateInit(&z)) == Z_OK)\n    {\n        // Call zlib to decompress the data\n        nResult = inflate(&z, Z_NO_FLUSH);\n        if (nResult == Z_OK || nResult == Z_STREAM_END)\n        {\n            // Give the size of the uncompressed data\n            cbOutBuffer = z.total_out;\n            dwErrCode = ERROR_SUCCESS;\n        }\n\n        inflateEnd(&z);\n    }\n\n    // Give the caller the number of bytes needed\n    pcbOutBuffer[0] = cbOutBuffer;\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascDecrypt.cpp",
    "content": "/*****************************************************************************/\n/* CascDecrypt.cpp                        Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Decryption functions for CascLib                                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 31.10.15  1.00  Lad  The first version of CascDecrypt.cpp                 */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local structures\n\n// For Salsa20 decryption process\ntypedef struct _CASC_SALSA20\n{\n    DWORD Key[CASC_KEY_LENGTH];\n    DWORD dwRounds;\n\n} CASC_SALSA20, *PCASC_SALSA20;\n\n// For static-stored keys\nstruct CASC_ENCRYPTION_KEY\n{\n    ULONGLONG KeyName;                          // \"Name\" of the key\n    BYTE Key[CASC_KEY_LENGTH];                  // The key itself\n};\n\n// For keys inside the key map\nstruct CASC_ENCRYPTION_KEY2 : public CASC_ENCRYPTION_KEY\n{\n    CASC_ENCRYPTION_KEY2 * pNext;               // Pointer to the next key wihh the same hash\n};\ntypedef CASC_ENCRYPTION_KEY2 * PCASC_ENCRYPTION_KEY2;\n\n//-----------------------------------------------------------------------------\n// Known encryption keys. See https://wowdev.wiki/CASC for updates\n\nstatic const char * szKeyConstant16 = \"expand 16-byte k\";\nstatic const char * szKeyConstant32 = \"expand 32-byte k\";\n\nstatic CASC_ENCRYPTION_KEY StaticCascKeys[] =\n{\n    // Key Name               Encryption key                                                                                         Seen in\n    // ---------------------- ---------------------------------------------------------------------------------------------------    -----------\n\n    // Battle.net app\n    { 0x2C547F26A2613E01ULL, { 0x37, 0xC5, 0x0C, 0x10, 0x2D, 0x4C, 0x9E, 0x3A, 0x5A, 0xC0, 0x69, 0xF0, 0x72, 0xB1, 0x41, 0x7D } },   // Battle.net App Alpha 1.5.0\n\n    // Starcraft\n//  { 0xD0CAE11366CEEA83ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 1.12.3.2609 (build 45364)\n\n    // Warcraft III Reforged beta (build)\n    { 0x6E4296823E7D561EULL, { 0xC0, 0xBF, 0xA2, 0x94, 0x3A, 0xC3, 0xE9, 0x22, 0x86, 0xE4, 0x44, 0x3E, 0xE3, 0x56, 0x0D, 0x65 } },   // 1.32.0.13369 Base content (Beta Week 0)\n    { 0xE04D60E31DDEBF63ULL, { 0x26, 0x3D, 0xB5, 0xC4, 0x02, 0xDA, 0x8D, 0x4D, 0x68, 0x63, 0x09, 0xCB, 0x2E, 0x32, 0x54, 0xD0 } },   // 1.32.0.13445 Base content (Beta Week 1)\n\n    // Overwatch\n    { 0xFB680CB6A8BF81F3ULL, { 0x62, 0xD9, 0x0E, 0xFA, 0x7F, 0x36, 0xD7, 0x1C, 0x39, 0x8A, 0xE2, 0xF1, 0xFE, 0x37, 0xBD, 0xB9 } },   // 0.8.0.24919_retailx64 (hardcoded)\n    { 0x402CD9D8D6BFED98ULL, { 0xAE, 0xB0, 0xEA, 0xDE, 0xA4, 0x76, 0x12, 0xFE, 0x6C, 0x04, 0x1A, 0x03, 0x95, 0x8D, 0xF2, 0x41 } },   // 0.8.0.24919_retailx64 (hardcoded)\n    { 0xDBD3371554F60306ULL, { 0x34, 0xE3, 0x97, 0xAC, 0xE6, 0xDD, 0x30, 0xEE, 0xFD, 0xC9, 0x8A, 0x2A, 0xB0, 0x93, 0xCD, 0x3C } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0x11A9203C9881710AULL, { 0x2E, 0x2C, 0xB8, 0xC3, 0x97, 0xC2, 0xF2, 0x4E, 0xD0, 0xB5, 0xE4, 0x52, 0xF1, 0x8D, 0xC2, 0x67 } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0xA19C4F859F6EFA54ULL, { 0x01, 0x96, 0xCB, 0x6F, 0x5E, 0xCB, 0xAD, 0x7C, 0xB5, 0x28, 0x38, 0x91, 0xB9, 0x71, 0x2B, 0x4B } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0x87AEBBC9C4E6B601ULL, { 0x68, 0x5E, 0x86, 0xC6, 0x06, 0x3D, 0xFD, 0xA6, 0xC9, 0xE8, 0x52, 0x98, 0x07, 0x6B, 0x3D, 0x42 } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0xDEE3A0521EFF6F03ULL, { 0xAD, 0x74, 0x0C, 0xE3, 0xFF, 0xFF, 0x92, 0x31, 0x46, 0x81, 0x26, 0x98, 0x57, 0x08, 0xE1, 0xB9 } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0x8C9106108AA84F07ULL, { 0x53, 0xD8, 0x59, 0xDD, 0xA2, 0x63, 0x5A, 0x38, 0xDC, 0x32, 0xE7, 0x2B, 0x11, 0xB3, 0x2F, 0x29 } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0x49166D358A34D815ULL, { 0x66, 0x78, 0x68, 0xCD, 0x94, 0xEA, 0x01, 0x35, 0xB9, 0xB1, 0x6C, 0x93, 0xB1, 0x12, 0x4A, 0xBA } },   // 0.8.0.24919_retailx64 (streamed from server)\n    { 0x1463A87356778D14ULL, { 0x69, 0xBD, 0x2A, 0x78, 0xD0, 0x5C, 0x50, 0x3E, 0x93, 0x99, 0x49, 0x59, 0xB3, 0x0E, 0x5A, 0xEC } },   //  ? 1.0.3.0 (streamed from server)\n    { 0x5E152DE44DFBEE01ULL, { 0xE4, 0x5A, 0x17, 0x93, 0xB3, 0x7E, 0xE3, 0x1A, 0x8E, 0xB8, 0x5C, 0xEE, 0x0E, 0xEE, 0x1B, 0x68 } },   //  ? 1.0.3.0 (streamed from server)\n    { 0x9B1F39EE592CA415ULL, { 0x54, 0xA9, 0x9F, 0x08, 0x1C, 0xAD, 0x0D, 0x08, 0xF7, 0xE3, 0x36, 0xF4, 0x36, 0x8E, 0x89, 0x4C } },   //  ? 1.0.3.0 (streamed from server)\n    { 0x24C8B75890AD5917ULL, { 0x31, 0x10, 0x0C, 0x00, 0xFD, 0xE0, 0xCE, 0x18, 0xBB, 0xB3, 0x3F, 0x3A, 0xC1, 0x5B, 0x30, 0x9F } },   //  ? 1.0.3.0 (included in game)\n    { 0xEA658B75FDD4890FULL, { 0xDE, 0xC7, 0xA4, 0xE7, 0x21, 0xF4, 0x25, 0xD1, 0x33, 0x03, 0x98, 0x95, 0xC3, 0x60, 0x36, 0xF8 } },   //  ? 1.0.3.0 (included in game)\n    { 0x026FDCDF8C5C7105ULL, { 0x8F, 0x41, 0x80, 0x9D, 0xA5, 0x53, 0x66, 0xAD, 0x41, 0x6D, 0x3C, 0x33, 0x74, 0x59, 0xEE, 0xE3 } },   // (included in game)\n    { 0xCAE3FAC925F20402ULL, { 0x98, 0xB7, 0x8E, 0x87, 0x74, 0xBF, 0x27, 0x50, 0x93, 0xCB, 0x1B, 0x5F, 0xC7, 0x14, 0x51, 0x1B } },   // (included in game)\n    { 0x061581CA8496C80CULL, { 0xDA, 0x2E, 0xF5, 0x05, 0x2D, 0xB9, 0x17, 0x38, 0x0B, 0x8A, 0xA6, 0xEF, 0x7A, 0x5F, 0x8E, 0x6A } },   //\n    { 0xBE2CB0FAD3698123ULL, { 0x90, 0x2A, 0x12, 0x85, 0x83, 0x6C, 0xE6, 0xDA, 0x58, 0x95, 0x02, 0x0D, 0xD6, 0x03, 0xB0, 0x65 } },   //\n    { 0x57A5A33B226B8E0AULL, { 0xFD, 0xFC, 0x35, 0xC9, 0x9B, 0x9D, 0xB1, 0x1A, 0x32, 0x62, 0x60, 0xCA, 0x24, 0x6A, 0xCB, 0x41 } },   // 1.1.0.0.30200 Ana\n    { 0x42B9AB1AF5015920ULL, { 0xC6, 0x87, 0x78, 0x82, 0x3C, 0x96, 0x4C, 0x6F, 0x24, 0x7A, 0xCC, 0x0F, 0x4A, 0x25, 0x84, 0xF8 } },   // 1.2.0.1.30684 Summer Games\n    { 0x4F0FE18E9FA1AC1AULL, { 0x89, 0x38, 0x1C, 0x74, 0x8F, 0x65, 0x31, 0xBB, 0xFC, 0xD9, 0x77, 0x53, 0xD0, 0x6C, 0xC3, 0xCD } },   // 1.2.0.1.30684\n    { 0x7758B2CF1E4E3E1BULL, { 0x3D, 0xE6, 0x0D, 0x37, 0xC6, 0x64, 0x72, 0x35, 0x95, 0xF2, 0x7C, 0x5C, 0xDB, 0xF0, 0x8B, 0xFA } },   // 1.2.0.1.30684\n    { 0xE5317801B3561125ULL, { 0x7D, 0xD0, 0x51, 0x19, 0x9F, 0x84, 0x01, 0xF9, 0x5E, 0x4C, 0x03, 0xC8, 0x84, 0xDC, 0xEA, 0x33 } },   // 1.4.0.2.32143 Halloween Terror\n    { 0x16B866D7BA3A8036ULL, { 0x13, 0x95, 0xE8, 0x82, 0xBF, 0x25, 0xB4, 0x81, 0xF6, 0x1A, 0x4D, 0x62, 0x11, 0x41, 0xDA, 0x6E } },   // 1.4.1.0.31804 Bastion Blizzcon 2016 skin\n    { 0x11131FFDA0D18D30ULL, { 0xC3, 0x2A, 0xD1, 0xB8, 0x25, 0x28, 0xE0, 0xA4, 0x56, 0x89, 0x7B, 0x3C, 0xE1, 0xC2, 0xD2, 0x7E } },   // 1.5.0.1.32795 Sombra\n    { 0xCAC6B95B2724144AULL, { 0x73, 0xE4, 0xBE, 0xA1, 0x45, 0xDF, 0x2B, 0x89, 0xB6, 0x5A, 0xEF, 0x02, 0xF8, 0x3F, 0xA2, 0x60 } },   // 1.5.0.1.32795 Ecopoint: Antarctica\n    { 0xB7DBC693758A5C36ULL, { 0xBC, 0x3A, 0x92, 0xBF, 0xE3, 0x02, 0x51, 0x8D, 0x91, 0xCC, 0x30, 0x79, 0x06, 0x71, 0xBF, 0x10 } },   // 1.5.0.1.32795 Genji Oni skin\n    { 0x90CA73B2CDE3164BULL, { 0x5C, 0xBF, 0xF1, 0x1F, 0x22, 0x72, 0x0B, 0xAC, 0xC2, 0xAE, 0x6A, 0xAD, 0x8F, 0xE5, 0x33, 0x17 } },   // 1.6.1.0.33236 Oasis map\n    { 0x6DD3212FB942714AULL, { 0xE0, 0x2C, 0x16, 0x43, 0x60, 0x2E, 0xC1, 0x6C, 0x3A, 0xE2, 0xA4, 0xD2, 0x54, 0xA0, 0x8F, 0xD9 } },   // 1.6.1.0.33236\n    { 0x11DDB470ABCBA130ULL, { 0x66, 0x19, 0x87, 0x66, 0xB1, 0xC4, 0xAF, 0x75, 0x89, 0xEF, 0xD1, 0x3A, 0xD4, 0xDD, 0x66, 0x7A } },   // 1.6.1.0.33236 Winter Wonderland\n    { 0x5BEF27EEE95E0B4BULL, { 0x36, 0xBC, 0xD2, 0xB5, 0x51, 0xFF, 0x1C, 0x84, 0xAA, 0x3A, 0x39, 0x94, 0xCC, 0xEB, 0x03, 0x3E } },   //\n    { 0x9359B46E49D2DA42ULL, { 0x17, 0x3D, 0x65, 0xE7, 0xFC, 0xAE, 0x29, 0x8A, 0x93, 0x63, 0xBD, 0x6A, 0xA1, 0x89, 0xF2, 0x00 } },   //               Diablo's 20th anniversary\n    { 0x1A46302EF8896F34ULL, { 0x80, 0x29, 0xAD, 0x54, 0x51, 0xD4, 0xBC, 0x18, 0xE9, 0xD0, 0xF5, 0xAC, 0x44, 0x9D, 0xC0, 0x55 } },   // 1.7.0.2.34156 Year of the Rooster\n    { 0x693529F7D40A064CULL, { 0xCE, 0x54, 0x87, 0x3C, 0x62, 0xDA, 0xA4, 0x8E, 0xFF, 0x27, 0xFC, 0xC0, 0x32, 0xBD, 0x07, 0xE3 } },   // 1.8.0.0.34470 CTF Maps\n    { 0x388B85AEEDCB685DULL, { 0xD9, 0x26, 0xE6, 0x59, 0xD0, 0x4A, 0x09, 0x6B, 0x24, 0xC1, 0x91, 0x51, 0x07, 0x6D, 0x37, 0x9A } },   // 1.8.0.0.34470 Numbani Update (Doomfist teaser)\n    { 0xE218F69AAC6C104DULL, { 0xF4, 0x3D, 0x12, 0xC9, 0x4A, 0x9A, 0x52, 0x84, 0x97, 0x97, 0x1F, 0x1C, 0xBE, 0x41, 0xAD, 0x4D } },   // 1.9.0.0.34986 Orisa\n    { 0xF432F0425363F250ULL, { 0xBA, 0x69, 0xF2, 0xB3, 0x3C, 0x27, 0x68, 0xF5, 0xF2, 0x9B, 0xFE, 0x78, 0xA5, 0xA1, 0xFA, 0xD5 } },   // 1.10.0.0.35455 Uprising\n    { 0x061D52F86830B35DULL, { 0xD7, 0x79, 0xF9, 0xC6, 0xCC, 0x9A, 0x4B, 0xE1, 0x03, 0xA4, 0xE9, 0x0A, 0x73, 0x38, 0xF7, 0x93 } },   // 1.10.0.0.35455 D.Va Officer Skin (HotS Nexus Challenge 2)\n    { 0x1275C84CF113EF65ULL, { 0xCF, 0x58, 0xB6, 0x93, 0x3E, 0xAF, 0x98, 0xAF, 0x53, 0xE7, 0x6F, 0x84, 0x26, 0xCC, 0x7E, 0x6C } },   //\n    { 0xD9C7C7AC0F14C868ULL, { 0x3A, 0xFD, 0xF6, 0x8E, 0x3A, 0x5D, 0x63, 0xBA, 0xBA, 0x1E, 0x68, 0x21, 0x88, 0x3F, 0x06, 0x7D } },   //\n    { 0xBD4E42661A432951ULL, { 0x6D, 0xE8, 0xE2, 0x8C, 0x85, 0x11, 0x64, 0x4D, 0x55, 0x95, 0xFC, 0x45, 0xE5, 0x35, 0x14, 0x72 } },   // 1.11.0.0.36376 Anniversary event\n    { 0xC43CB14355249451ULL, { 0x0E, 0xA2, 0xB4, 0x4F, 0x96, 0xA2, 0x69, 0xA3, 0x86, 0x85, 0x6D, 0x04, 0x9A, 0x3D, 0xEC, 0x86 } },   // 1.12.0.0.37104 Horizon Lunar Colony\n    { 0xE6D914F8E4744953ULL, { 0xC8, 0x47, 0x7C, 0x28, 0x9D, 0xCE, 0x66, 0xD9, 0x13, 0x65, 0x07, 0xA3, 0x3A, 0xA3, 0x33, 0x01 } },   // 1.13.0.0.37646 Doomfist\n    { 0x5694C503F8C80178ULL, { 0x7F, 0x4C, 0xF1, 0xC1, 0xFB, 0xBA, 0xD9, 0x2B, 0x18, 0x43, 0x36, 0xD6, 0x77, 0xEB, 0xF9, 0x37 } },   // 1.13.0.0.37646 Doomfist\n    { 0x21DBFD65F3E54269ULL, { 0xAB, 0x58, 0x0C, 0x38, 0x37, 0xCA, 0xF8, 0xA4, 0x61, 0xF2, 0x43, 0xA5, 0x66, 0xB2, 0xAE, 0x4D } },   // 1.13.0.0.37646 Summer Games 2017\n//  { 0x27ABA5F88DD8D078ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },     // 1.13.0.0.37646\n    { 0x21E1F90E71D33C71ULL, { 0x32, 0x87, 0x42, 0x33, 0x91, 0x62, 0xB3, 0x26, 0x76, 0xC8, 0x03, 0xC2, 0x25, 0x59, 0x31, 0xA6 } },   // 1.14.1.0.39083 Deathmatch\n    { 0xD9CB055BCDD40B6EULL, { 0x49, 0xFB, 0x44, 0x77, 0xA4, 0xA0, 0x82, 0x53, 0x27, 0xE9, 0xA7, 0x36, 0x82, 0xBE, 0xCD, 0x0C } },   // 1.15.0.0.????? Junkertown\n    { 0x8175CE3C694C6659ULL, { 0xE3, 0xF3, 0xFA, 0x77, 0x26, 0xC7, 0x0D, 0x26, 0xAE, 0x13, 0x0D, 0x96, 0x9D, 0xDD, 0xF3, 0x99 } },   // 1.16.0.0.40011 Halloween 2017\n    { 0xB8DE51690075435AULL, { 0xC0, 0x7E, 0x92, 0x60, 0xBB, 0x71, 0x12, 0x17, 0xE7, 0xDE, 0x6F, 0xED, 0x91, 0x1F, 0x42, 0x96 } },   // 1.16.0.0.????? Winston Blizzcon 2017 skin\n    { 0xF6CF23955B5D437DULL, { 0xAE, 0xBA, 0x22, 0x73, 0x28, 0xA5, 0xB0, 0xAA, 0x9F, 0x51, 0xDA, 0xE3, 0xF6, 0xA7, 0xDF, 0xE4 } },   // 1.17.0.2.41350 Moira\n    { 0x0E4D9426F2891F5CULL, { 0x9F, 0xF0, 0x64, 0xC3, 0x8B, 0xE5, 0x2C, 0xCD, 0xF7, 0x37, 0x48, 0x18, 0x0F, 0x62, 0x82, 0x05 } },   // 1.18.1.2.42076 Winter Wonderland 2017\n    { 0x9240BA6A2A0CF684ULL, { 0xDF, 0x2E, 0x37, 0xD7, 0x8B, 0x43, 0x10, 0x8F, 0xA6, 0x24, 0x20, 0x68, 0xB7, 0x0D, 0x1F, 0x65 } },   // 1.19.1.3.42563 Overwatch League\n    { 0x82297FBAB7F5EB80ULL, { 0xB5, 0x34, 0xC2, 0x09, 0x65, 0x85, 0x2F, 0xB1, 0x5A, 0xEC, 0xAC, 0x17, 0xE3, 0x81, 0xB4, 0x17 } },   // 1.19.1.3.42563 Jan 2017 Lootbox Update\n    { 0x9ADF00AA1A174A69ULL, { 0x9A, 0x4A, 0xC8, 0x99, 0x26, 0x1A, 0x2F, 0x1C, 0x69, 0x69, 0xF3, 0x93, 0x97, 0xC3, 0x58, 0xE7 } },   // 1.19.1.3.42563 Blizzard World\n    { 0xCFA05AA76B49F881ULL, { 0x52, 0x6D, 0xDD, 0xEF, 0x19, 0xBF, 0x37, 0x3C, 0x25, 0xB6, 0x29, 0xA3, 0x34, 0xCD, 0x72, 0x37 } },   // 1.19.1.3.42563 WoW's Battle For Azeroth Preorder\n    { 0x493455579DA0B18EULL, { 0xC0, 0xBA, 0xBF, 0x72, 0xAD, 0x2C, 0x05, 0xDF, 0xC1, 0x40, 0x17, 0xD1, 0xAD, 0xBF, 0x59, 0x77 } },   // 1.19.3.1.43036 Inaugural Season Spray/Icon ??\n    { 0x6362C5AD65DAE686ULL, { 0x62, 0xF6, 0x03, 0xD5, 0x39, 0x0F, 0x76, 0x3E, 0xD5, 0x17, 0x73, 0xF0, 0x16, 0x4F, 0xED, 0xB5 } },   // 1.19.3.1.43036 White/Gray OWL Skins ??\n    { 0x8162E5313A9C135DULL, { 0xF4, 0x07, 0x83, 0x4D, 0x95, 0x21, 0x58, 0x7C, 0x50, 0x12, 0xB0, 0xA5, 0x9D, 0x7E, 0x06, 0x4B } },   // 1.20.0.2.43435 Lunar New Year 2018 (Dog) / Ayutthaya / Comp CTF\n//  { 0x68EAE8FDC008C381ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 1.20.0.2.43435\n    { 0xF412C6327C4BF091ULL, { 0x6F, 0xAF, 0xC6, 0x48, 0xCB, 0xF1, 0xC2, 0x11, 0x5B, 0x76, 0x95, 0x93, 0xC1, 0x70, 0xE7, 0x32 } },   // 1.20.0.2.43435 SC2 20th Anniversary (Kerrigan Skin)\n    { 0x3B3ED0874091B174ULL, { 0x5D, 0x09, 0xC2, 0x68, 0x8B, 0x1D, 0x9F, 0x1A, 0x4D, 0xB6, 0x46, 0x02, 0xC1, 0x66, 0x1D, 0x24 } },   // 1.21.?.?.????? Brigitte\n    { 0x37FD04E05D2A6292ULL, { 0xF0, 0x64, 0x55, 0xE5, 0x6C, 0xD1, 0x44, 0x91, 0x42, 0x95, 0xF2, 0xEF, 0x15, 0x3D, 0x23, 0xBA } },   // 1.21.?.?.????? Brigitte Cosmetics\n    { 0xC0DDC77552BE5794ULL, { 0xF2, 0xBB, 0x7F, 0x35, 0x99, 0x0E, 0x29, 0x00, 0xCB, 0xD8, 0x77, 0xB4, 0xD3, 0xA7, 0x13, 0x9C } },   // 1.22.?.?.????? OWL away skins\n    { 0x68D8EB839DC15D75ULL, { 0x29, 0xAF, 0xFE, 0xCA, 0x52, 0x99, 0xC4, 0x14, 0x0A, 0x12, 0xA6, 0x6F, 0x95, 0x4E, 0xF1, 0xE3 } },   // 1.22.?.?.????? Archives 2018 (Retribution)\n    { 0x209F33BBAC9D1295ULL, { 0xBD, 0x53, 0x54, 0x38, 0xD0, 0xCD, 0xEE, 0x0E, 0x95, 0x67, 0xE0, 0xEF, 0x67, 0x1C, 0x80, 0x9F } },   // 1.23.?.?.????? Rialto\n    { 0xA55F8C6F20454D94ULL, { 0x42, 0xD7, 0x62, 0x85, 0x41, 0x24, 0x61, 0xB0, 0xC7, 0x5A, 0xB7, 0x5F, 0xB5, 0x2F, 0x59, 0x6E } },   // 1.23.?.?.????? Mercy BCRF Items\n    { 0x3EEEDB8E7C29A09BULL, { 0x83, 0x7A, 0xC7, 0x93, 0x05, 0xE4, 0xBF, 0xBA, 0x3B, 0x22, 0x26, 0xF1, 0xB9, 0x82, 0x00, 0xBF } },   // 1.24.?.?.????? Anniversary 2018 Map/Items\n    { 0x22C1AF6758F8449EULL, { 0x28, 0xAA, 0x1B, 0xD2, 0xB9, 0xA1, 0xE3, 0x63, 0x39, 0x89, 0xB1, 0xBB, 0xF6, 0x4A, 0xEA, 0xC4 } },   // 1.26.?.?.????? Emily / Comp Season 11 / Comp 3v3 Items\n    { 0x11B2E01B9331799EULL, { 0x9A, 0x1C, 0x99, 0x30, 0x3D, 0x6A, 0x58, 0x97, 0x8E, 0x29, 0xC9, 0x88, 0x73, 0x32, 0x7A, 0x6A } },   // 1.26.?.?.????? Wrecking Ball\n    { 0x8498337C740329B3ULL, { 0xEC, 0x73, 0xD6, 0x63, 0xE3, 0xFC, 0x72, 0x41, 0x6B, 0x3E, 0x46, 0x79, 0x15, 0x70, 0x8B, 0x4F } },   // 1.26.?.?.????? Wrecking Ball Cosmetics\n    { 0xE6E8BCABE3CC96C1ULL, { 0x57, 0x72, 0x7E, 0x52, 0x60, 0x06, 0x65, 0xEA, 0xC0, 0x2B, 0xD8, 0x7F, 0x06, 0x92, 0x89, 0x8F } },   // 1.26.?.?.????? OWL Grand Finals Unlocks / Lucio Emote\n    { 0x5D4AC0DC6F3113BAULL, { 0xD1, 0xC9, 0xF1, 0xFF, 0x69, 0x58, 0x5D, 0x13, 0x98, 0xEB, 0xA0, 0x46, 0x34, 0x81, 0xF5, 0xCF } },   // 1.27.?.?.????? Summer Games 2018\n    { 0x27F9D85973DCD5AFULL, { 0xC5, 0xFE, 0x10, 0x15, 0xBC, 0xE0, 0xB7, 0x84, 0x8F, 0x02, 0x28, 0x68, 0xAF, 0xF6, 0x54, 0xD1 } },   // 1.27.?.?.????? Summer Games 2018\n    { 0x67AAD845CC0F03BDULL, { 0x6C, 0xD8, 0xAD, 0x3F, 0x37, 0xF5, 0x4A, 0xBE, 0xC7, 0x63, 0x02, 0x94, 0xD4, 0x90, 0x41, 0xBF } },   // 1.27.?.?.????? D.Va Nano Cola Challenge\n    { 0xCA13F0C79042A1A0ULL, { 0xFC, 0xD8, 0x9C, 0xE8, 0x81, 0x2E, 0x63, 0x46, 0x07, 0x6F, 0xC8, 0x2D, 0xD7, 0xA9, 0x24, 0x87 } },   // 1.28.?.?.????? Busan\n    { 0xC4D84093A32684BDULL, { 0x38, 0xE1, 0x82, 0x42, 0x3E, 0xED, 0xD8, 0xE3, 0xF5, 0x7A, 0xC1, 0xD4, 0x07, 0xB4, 0x70, 0xD0 } },   // 1.28.?.?.????? Blizzcon 2018 Sombra Demon Hunter Skin\n    { 0x0BFE5A2B3C606BA1ULL, { 0xD6, 0x41, 0x9B, 0x8E, 0x42, 0x82, 0x0B, 0x0B, 0x24, 0xE0, 0x8D, 0xA4, 0x44, 0xA0, 0x68, 0x22 } },   // 1.29.?.?.????? Halloween Terror 2018\n    { 0x402CD9D8D6BFED98ULL, { 0xAE, 0xB0, 0xEA, 0xDE, 0xA4, 0x76, 0x12, 0xFE, 0x6C, 0x04, 0x1A, 0x03, 0x95, 0x8D, 0xF2, 0x41 } },   // 1.29.?.?.?????\n    { 0xF1CBDF48147D26C6ULL, { 0x4B, 0x69, 0x44, 0x69, 0x51, 0x57, 0xD4, 0x3D, 0x33, 0xE4, 0x0B, 0x56, 0x92, 0x44, 0x5A, 0xDB } },   // 1.30.?.?.????? 1.30 + World Cup Viewer\n    { 0x01A48CFAE25F85CDULL, { 0x60, 0xD7, 0x7A, 0x58, 0x06, 0x2D, 0x03, 0xDC, 0x69, 0x3C, 0x01, 0x95, 0x4D, 0xD1, 0x80, 0x21 } },   // 1.30.?.?.????? 1.30 + World Cup Viewer\n    { 0xFEBBF66DAEF6C9BEULL, { 0x4A, 0x22, 0x0A, 0xE3, 0xA6, 0x80, 0x8E, 0xD2, 0x69, 0x74, 0x10, 0xC9, 0x4C, 0x1C, 0xE9, 0x70 } },   // 1.30.0.1.????? Ashe\n    { 0x2AD4834DAB3986ABULL, { 0xEA, 0x69, 0x71, 0xF7, 0x8A, 0xBE, 0xBD, 0x2A, 0xF8, 0x83, 0xD4, 0x6A, 0x54, 0x86, 0xF3, 0x9F } },   // 1.31.?.?.????? Winter 2018\n    { 0xD89B24D62F00A04EULL, { 0xC3, 0xA4, 0xD0, 0x10, 0xAA, 0xA7, 0x28, 0x7A, 0x3E, 0xAC, 0xCD, 0x45, 0xED, 0x47, 0x13, 0x45 } },   // 1.31.?.?.????? Bastet Challenge\n    { 0x32DDC40236DAEA7BULL, { 0x2D, 0xBD, 0xE4, 0xFB, 0x9F, 0xDA, 0x77, 0x6A, 0xA2, 0x94, 0x87, 0x08, 0x54, 0xFE, 0x9B, 0x02 } },   // 1.31.?.?.????? Lunar New Year 2019 (Pig)\n    { 0xF481EFC2302EE415ULL, { 0x37, 0xA7, 0xF2, 0xB8, 0x7D, 0x0B, 0x8B, 0x70, 0x04, 0x56, 0xC6, 0xA9, 0x2C, 0x71, 0xD6, 0xDD } },   // 1.33.?.?.????? Paris Map\n    { 0xD1AC8C1903524D9AULL, { 0xD7, 0x81, 0xD0, 0xAA, 0x35, 0xE5, 0xC1, 0x06, 0xBC, 0xA7, 0xCF, 0x01, 0xDE, 0xBD, 0x14, 0x94 } },   // 1.34.0.1.55918 Baptiste\n    { 0x71EEBE93590AA903ULL, { 0x0C, 0xCD, 0x10, 0xD4, 0x55, 0x3E, 0xEC, 0x7E, 0x97, 0xFD, 0x36, 0xA9, 0xE8, 0xAD, 0xF0, 0xFF } },   // 1.34.0.1.55918 Baptiste Cosmetics\n\n    // Streamed WoW keys\n    { 0xFA505078126ACB3EULL, { 0xBD, 0xC5, 0x18, 0x62, 0xAB, 0xED, 0x79, 0xB2, 0xDE, 0x48, 0xC8, 0xE7, 0xE6, 0x6C, 0x62, 0x00 } },   // 15  WOW-20740patch7.0.1_Beta  <not used between 7.0 and 7.3>\n    { 0xFF813F7D062AC0BCULL, { 0xAA, 0x0B, 0x5C, 0x77, 0xF0, 0x88, 0xCC, 0xC2, 0xD3, 0x90, 0x49, 0xBD, 0x26, 0x7F, 0x06, 0x6D } },   // 25  WOW-20740patch7.0.1_Beta  <not used between 7.0 and 7.3>\n    { 0xD1E9B5EDF9283668ULL, { 0x8E, 0x4A, 0x25, 0x79, 0x89, 0x4E, 0x38, 0xB4, 0xAB, 0x90, 0x58, 0xBA, 0x5C, 0x73, 0x28, 0xEE } },   // 39  WOW-20740patch7.0.1_Beta  Enchanted Torch pet\n    { 0xB76729641141CB34ULL, { 0x98, 0x49, 0xD1, 0xAA, 0x7B, 0x1F, 0xD0, 0x98, 0x19, 0xC5, 0xC6, 0x62, 0x83, 0xA3, 0x26, 0xEC } },   // 40  WOW-20740patch7.0.1_Beta  Enchanted Pen pet\n    { 0xFFB9469FF16E6BF8ULL, { 0xD5, 0x14, 0xBD, 0x19, 0x09, 0xA9, 0xE5, 0xDC, 0x87, 0x03, 0xF4, 0xB8, 0xBB, 0x1D, 0xFD, 0x9A } },   // 41  WOW-20740patch7.0.1_Beta  <not used between 7.0 and 7.3>\n    { 0x23C5B5DF837A226CULL, { 0x14, 0x06, 0xE2, 0xD8, 0x73, 0xB6, 0xFC, 0x99, 0x21, 0x7A, 0x18, 0x08, 0x81, 0xDA, 0x8D, 0x62 } },   // 42  WOW-20740patch7.0.1_Beta  Enchanted Cauldron pet\n//  { 0x3AE403EF40AC3037ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 51  WOW-21249patch7.0.3_Beta  <not used between 7.0 and 7.3>\n    { 0xE2854509C471C554ULL, { 0x43, 0x32, 0x65, 0xF0, 0xCD, 0xEB, 0x2F, 0x4E, 0x65, 0xC0, 0xEE, 0x70, 0x08, 0x71, 0x4D, 0x9E } },   // 52  WOW-21249patch7.0.3_Beta  Warcraft movie items\n    { 0x8EE2CB82178C995AULL, { 0xDA, 0x6A, 0xFC, 0x98, 0x9E, 0xD6, 0xCA, 0xD2, 0x79, 0x88, 0x59, 0x92, 0xC0, 0x37, 0xA8, 0xEE } },   // 55  WOW-21531patch7.0.3_Beta  BlizzCon 2016 Murlocs\n    { 0x5813810F4EC9B005ULL, { 0x01, 0xBE, 0x8B, 0x43, 0x14, 0x2D, 0xD9, 0x9A, 0x9E, 0x69, 0x0F, 0xAD, 0x28, 0x8B, 0x60, 0x82 } },   // 56  WOW-21531patch7.0.3_Beta  Fel Kitten\n    { 0x7F9E217166ED43EAULL, { 0x05, 0xFC, 0x92, 0x7B, 0x9F, 0x4F, 0x5B, 0x05, 0x56, 0x81, 0x42, 0x91, 0x2A, 0x05, 0x2B, 0x0F } },   // 57  WOW-21531patch7.0.3_Beta  Legion music <not used in 7.3>\n    { 0xC4A8D364D23793F7ULL, { 0xD1, 0xAC, 0x20, 0xFD, 0x14, 0x95, 0x7F, 0xAB, 0xC2, 0x71, 0x96, 0xE9, 0xF6, 0xE7, 0x02, 0x4A } },   // 58  WOW-21691patch7.0.3_Beta  Demon Hunter #1 cinematic (legion_dh1)\n    { 0x40A234AEBCF2C6E5ULL, { 0xC6, 0xC5, 0xF6, 0xC7, 0xF7, 0x35, 0xD7, 0xD9, 0x4C, 0x87, 0x26, 0x7F, 0xA4, 0x99, 0x4D, 0x45 } },   // 59  WOW-21691patch7.0.3_Beta  Demon Hunter #2 cinematic (legion_dh2)\n    { 0x9CF7DFCFCBCE4AE5ULL, { 0x72, 0xA9, 0x7A, 0x24, 0xA9, 0x98, 0xE3, 0xA5, 0x50, 0x0F, 0x38, 0x71, 0xF3, 0x76, 0x28, 0xC0 } },   // 60  WOW-21691patch7.0.3_Beta  Val'sharah #1 cinematic (legion_val_yd)\n    { 0x4E4BDECAB8485B4FULL, { 0x38, 0x32, 0xD7, 0xC4, 0x2A, 0xAC, 0x92, 0x68, 0xF0, 0x0B, 0xE7, 0xB6, 0xB4, 0x8E, 0xC9, 0xAF } },   // 61  WOW-21691patch7.0.3_Beta  Val'sharah #2 cinematic (legion_val_yx)\n    { 0x94A50AC54EFF70E4ULL, { 0xC2, 0x50, 0x1A, 0x72, 0x65, 0x4B, 0x96, 0xF8, 0x63, 0x50, 0xC5, 0xA9, 0x27, 0x96, 0x2F, 0x7A } },   // 62  WOW-21691patch7.0.3_Beta  Sylvanas warchief cinematic (legion_org_vs)\n    { 0xBA973B0E01DE1C2CULL, { 0xD8, 0x3B, 0xBC, 0xB4, 0x6C, 0xC4, 0x38, 0xB1, 0x7A, 0x48, 0xE7, 0x6C, 0x4F, 0x56, 0x54, 0xA3 } },   // 63  WOW-21691patch7.0.3_Beta  Stormheim Sylvanas vs Greymane cinematic (legion_sth)\n    { 0x494A6F8E8E108BEFULL, { 0xF0, 0xFD, 0xE1, 0xD2, 0x9B, 0x27, 0x4F, 0x6E, 0x7D, 0xBD, 0xB7, 0xFF, 0x81, 0x5F, 0xE9, 0x10 } },   // 64  WOW-21691patch7.0.3_Beta  Harbingers Gul'dan video (legion_hrb_g)\n    { 0x918D6DD0C3849002ULL, { 0x85, 0x70, 0x90, 0xD9, 0x26, 0xBB, 0x28, 0xAE, 0xDA, 0x4B, 0xF0, 0x28, 0xCA, 0xCC, 0x4B, 0xA3 } },   // 65  WOW-21691patch7.0.3_Beta  Harbingers Khadgar video (legion_hrb_k)\n    { 0x0B5F6957915ADDCAULL, { 0x4D, 0xD0, 0xDC, 0x82, 0xB1, 0x01, 0xC8, 0x0A, 0xBA, 0xC0, 0xA4, 0xD5, 0x7E, 0x67, 0xF8, 0x59 } },   // 66  WOW-21691patch7.0.3_Beta  Harbingers Illidan video (legion_hrb_i)\n    { 0x794F25C6CD8AB62BULL, { 0x76, 0x58, 0x3B, 0xDA, 0xCD, 0x52, 0x57, 0xA3, 0xF7, 0x3D, 0x15, 0x98, 0xA2, 0xCA, 0x2D, 0x99 } },   // 67  WOW-21846patch7.0.3_Beta  Suramar cinematic (legion_su_i)\n    { 0xA9633A54C1673D21ULL, { 0x1F, 0x8D, 0x46, 0x7F, 0x5D, 0x6D, 0x41, 0x1F, 0x8A, 0x54, 0x8B, 0x63, 0x29, 0xA5, 0x08, 0x7E } },   // 68  WOW-21846patch7.0.3_Beta  legion_su_r cinematic\n    { 0x5E5D896B3E163DEAULL, { 0x8A, 0xCE, 0x8D, 0xB1, 0x69, 0xE2, 0xF9, 0x8A, 0xC3, 0x6A, 0xD5, 0x2C, 0x08, 0x8E, 0x77, 0xC1 } },   // 69  WOW-21846patch7.0.3_Beta  Broken Shore intro cinematic (legion_bs_i)\n    { 0x0EBE36B5010DFD7FULL, { 0x9A, 0x89, 0xCC, 0x7E, 0x3A, 0xCB, 0x29, 0xCF, 0x14, 0xC6, 0x0B, 0xC1, 0x3B, 0x1E, 0x46, 0x16 } },   // 70  WOW-21846patch7.0.3_Beta  Alliance Broken Shore cinematic (legion_bs_a)\n    { 0x01E828CFFA450C0FULL, { 0x97, 0x2B, 0x6E, 0x74, 0x42, 0x0E, 0xC5, 0x19, 0xE6, 0xF9, 0xD9, 0x7D, 0x59, 0x4A, 0xA3, 0x7C } },   // 71  WOW-21846patch7.0.3_Beta  Horde Broken Shore cinematic (legion_bs_h)\n    { 0x4A7BD170FE18E6AEULL, { 0xAB, 0x55, 0xAE, 0x1B, 0xF0, 0xC7, 0xC5, 0x19, 0xAF, 0xF0, 0x28, 0xC1, 0x56, 0x10, 0xA4, 0x5B } },   // 72  WOW-21846patch7.0.3_Beta  Khadgar & Light's Heart cinematic (legion_iq_lv)\n    { 0x69549CB975E87C4FULL, { 0x7B, 0x6F, 0xA3, 0x82, 0xE1, 0xFA, 0xD1, 0x46, 0x5C, 0x85, 0x1E, 0x3F, 0x47, 0x34, 0xA1, 0xB3 } },   // 73  WOW-21846patch7.0.3_Beta  legion_iq_id cinematic\n    { 0x460C92C372B2A166ULL, { 0x94, 0x6D, 0x56, 0x59, 0xF2, 0xFA, 0xF3, 0x27, 0xC0, 0xB7, 0xEC, 0x82, 0x8B, 0x74, 0x8A, 0xDB } },   // 74  WOW-21952patch7.0.3_Beta  Stormheim Alliance cinematic (legion_g_a_sth)\n    { 0x8165D801CCA11962ULL, { 0xCD, 0x0C, 0x0F, 0xFA, 0xAD, 0x93, 0x63, 0xEC, 0x14, 0xDD, 0x25, 0xEC, 0xDD, 0x2A, 0x5B, 0x62 } },   // 75  WOW-21952patch7.0.3_Beta  Stormheim Horde cinematic (legion_g_h_sth)\n    { 0xA3F1C999090ADAC9ULL, { 0xB7, 0x2F, 0xEF, 0x4A, 0x01, 0x48, 0x8A, 0x88, 0xFF, 0x02, 0x28, 0x0A, 0xA0, 0x7A, 0x92, 0xBB } },   // 81  WOW-22578patch7.1.0_PTR   Firecat Mount\n//  { 0x18AFDF5191923610ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 82  WOW-22578patch7.1.0_PTR   <not used between 7.1 and 7.3>\n//  { 0x3C258426058FBD93ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 91  WOW-23436patch7.2.0_PTR   <not used between 7.2 and 7.3>\n    { 0x094E9A0474876B98ULL, { 0xE5, 0x33, 0xBB, 0x6D, 0x65, 0x72, 0x7A, 0x58, 0x32, 0x68, 0x0D, 0x62, 0x0B, 0x0B, 0xC1, 0x0B } },   // 92  WOW-23910patch7.2.5_PTR   shadowstalkerpanthermount, shadowstalkerpantherpet\n    { 0x3DB25CB86A40335EULL, { 0x02, 0x99, 0x0B, 0x12, 0x26, 0x0C, 0x1E, 0x9F, 0xDD, 0x73, 0xFE, 0x47, 0xCB, 0xAB, 0x70, 0x24 } },   // 93  WOW-23789patch7.2.0_PTR   legion_72_ots\n    { 0x0DCD81945F4B4686ULL, { 0x1B, 0x78, 0x9B, 0x87, 0xFB, 0x3C, 0x92, 0x38, 0xD5, 0x28, 0x99, 0x7B, 0xFA, 0xB4, 0x41, 0x86 } },   // 94  WOW-23789patch7.2.0_PTR   legion_72_tst\n    { 0x486A2A3A2803BE89ULL, { 0x32, 0x67, 0x9E, 0xA7, 0xB0, 0xF9, 0x9E, 0xBF, 0x4F, 0xA1, 0x70, 0xE8, 0x47, 0xEA, 0x43, 0x9A } },   // 95  WOW-23789patch7.2.0_PTR   legion_72_ars\n    { 0x71F69446AD848E06ULL, { 0xE7, 0x9A, 0xEB, 0x88, 0xB1, 0x50, 0x9F, 0x62, 0x8F, 0x38, 0x20, 0x82, 0x01, 0x74, 0x1C, 0x30 } },   // 97  WOW-24473patch7.3.0_PTR   BlizzCon 2017 Mounts (AllianceShipMount and HordeZeppelinMount)\n    { 0x211FCD1265A928E9ULL, { 0xA7, 0x36, 0xFB, 0xF5, 0x8D, 0x58, 0x7B, 0x39, 0x72, 0xCE, 0x15, 0x4A, 0x86, 0xAE, 0x45, 0x40 } },   // 98  WOW-24473patch7.3.0_PTR   \"Shadow\" fox pet (store)\n    { 0x0ADC9E327E42E98CULL, { 0x01, 0x7B, 0x34, 0x72, 0xC1, 0xDE, 0xE3, 0x04, 0xFA, 0x0B, 0x2F, 0xF8, 0xE5, 0x3F, 0xF7, 0xD6 } },   // 99  WOW-23910patch7.2.5_PTR   legion_72_tsf\n    { 0xBAE9F621B60174F1ULL, { 0x38, 0xC3, 0xFB, 0x39, 0xB4, 0x97, 0x17, 0x60, 0xB4, 0xB9, 0x82, 0xFE, 0x9F, 0x09, 0x50, 0x14 } },   // 100 WOW-24727patch7.3.0_PTR   Rejection of the Gift cinematic (legion_73_agi)\n    { 0x34DE1EEADC97115EULL, { 0x2E, 0x3A, 0x53, 0xD5, 0x9A, 0x49, 0x1E, 0x5C, 0xD1, 0x73, 0xF3, 0x37, 0xF7, 0xCD, 0x8C, 0x61 } },   // 101 WOW-24727patch7.3.0_PTR   Resurrection of Alleria Windrunner cinematic (legion_73_avt)\n    { 0xE07E107F1390A3DFULL, { 0x29, 0x0D, 0x27, 0xB0, 0xE8, 0x71, 0xF8, 0xC5, 0xB1, 0x4A, 0x14, 0xE5, 0x14, 0xD0, 0xF0, 0xD9 } },   // 102 WOW-25079patch7.3.2_PTR   Tottle battle pet, Raptor mount, Horse mount (104 files)\n    { 0x32690BF74DE12530ULL, { 0xA2, 0x55, 0x62, 0x10, 0xAE, 0x54, 0x22, 0xE6, 0xD6, 0x1E, 0xDA, 0xAF, 0x12, 0x2C, 0xB6, 0x37 } },   // 103 WOW-24781patch7.3.0_PTR   legion_73_pan\n    { 0xBF3734B1DCB04696ULL, { 0x48, 0x94, 0x61, 0x23, 0x05, 0x0B, 0x00, 0xA7, 0xEF, 0xB1, 0xC0, 0x29, 0xEE, 0x6C, 0xC4, 0x38 } },   // 104 WOW-25079patch7.3.2_PTR   legion_73_afn\n    { 0x74F4F78002A5A1BEULL, { 0xC1, 0x4E, 0xEC, 0x8D, 0x5A, 0xEE, 0xF9, 0x3F, 0xA8, 0x11, 0xD4, 0x50, 0xB4, 0xE4, 0x6E, 0x91 } },   // 105 WOW-25079patch7.3.2_PTR   SilithusPhase01 map\n//  { 0x423F07656CA27D23ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 107 WOW-25600patch7.3.5_PTR   bltestmap\n//  { 0x0691678F83E8A75DULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 108 WOW-25600patch7.3.5_PTR   filedataid 1782602-1782603\n//  { 0x324498590F550556ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 109 WOW-25600patch7.3.5_PTR   filedataid 1782615-1782619\n//  { 0xC02C78F40BEF5998ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 110 WOW-25600patch7.3.5_PTR   test/testtexture.blp (fdid 1782613)\n//  { 0x47011412CCAAB541ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 111 WOW-25600patch7.3.5_PTR   unused in 25600\n//  { 0x23B6F5764CE2DDD6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 112 WOW-25600patch7.3.5_PTR   unused in 25600\n//  { 0x8E00C6F405873583ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 113 WOW-25600patch7.3.5_PTR   filedataid 1783470-1783472\n    { 0x78482170E4CFD4A6ULL, { 0x76, 0x85, 0x40, 0xC2, 0x0A, 0x5B, 0x15, 0x35, 0x83, 0xAD, 0x7F, 0x53, 0x13, 0x0C, 0x58, 0xFE } },   // 114 WOW-25600patch7.3.5_PTR   Magni Bronzebeard VO\n    { 0xB1EB52A64BFAF7BFULL, { 0x45, 0x81, 0x33, 0xAA, 0x43, 0x94, 0x9A, 0x14, 0x16, 0x32, 0xC4, 0xF8, 0x59, 0x6D, 0xE2, 0xB0 } },   // 115 WOW-25600patch7.3.5_PTR   dogmount, 50 files\n    { 0xFC6F20EE98D208F6ULL, { 0x57, 0x79, 0x0E, 0x48, 0xD3, 0x55, 0x00, 0xE7, 0x0D, 0xF8, 0x12, 0x59, 0x4F, 0x50, 0x7B, 0xE7 } },   // 117 WOW-25632patch7.3.5_PTR   shop stuff\n    { 0x402CFABF2020D9B7ULL, { 0x67, 0x19, 0x7B, 0xCD, 0x9D, 0x0E, 0xF0, 0xC4, 0x08, 0x53, 0x78, 0xFA, 0xA6, 0x9A, 0x32, 0x64 } },   // 118 WOW-25678patch7.3.5_PTR   filedataid 1854762\n    { 0x6FA0420E902B4FBEULL, { 0x27, 0xB7, 0x50, 0x18, 0x4E, 0x53, 0x29, 0xC4, 0xE4, 0x45, 0x5C, 0xBD, 0x3E, 0x1F, 0xD5, 0xAB } },   // 119 WOW-25744patch7.3.5_PTR   legion_735_epa / legion_735_eph\n    { 0x1076074F2B350A2DULL, { 0x88, 0xBF, 0x0C, 0xD0, 0xD5, 0xBA, 0x15, 0x9A, 0xE7, 0xCB, 0x91, 0x6A, 0xFB, 0xE1, 0x38, 0x65 } },   // 121 WOW-26287patch8.0.1_Beta  skiff\n    { 0x816F00C1322CDF52ULL, { 0x6F, 0x83, 0x22, 0x99, 0xA7, 0x57, 0x89, 0x57, 0xEE, 0x86, 0xB7, 0xF9, 0xF1, 0x5B, 0x01, 0x88 } },   // 122 WOW-26287patch8.0.1_Beta  snowkid\n    { 0xDDD295C82E60DB3CULL, { 0x34, 0x29, 0xCC, 0x59, 0x27, 0xD1, 0x62, 0x97, 0x65, 0x97, 0x4F, 0xD9, 0xAF, 0xAB, 0x75, 0x80 } },   // 123 WOW-26287patch8.0.1_Beta  redbird\n    { 0x83E96F07F259F799ULL, { 0x91, 0xF7, 0xD0, 0xE7, 0xA0, 0x2C, 0xDE, 0x0D, 0xE0, 0xBD, 0x36, 0x7F, 0xAB, 0xCB, 0x8A, 0x6E } },   // 124 WOW-26522patch8.0.1_Beta  BlizzCon 2018 (Alliance and Horde banners and cloaks)\n    { 0x49FBFE8A717F03D5ULL, { 0xC7, 0x43, 0x77, 0x70, 0xCF, 0x15, 0x3A, 0x31, 0x35, 0xFA, 0x6D, 0xC5, 0xE4, 0xC8, 0x5E, 0x65 } },   // 225 WOW-27826patch8.1.0_PTR   Meatwagon mount (Warcraft 3: Reforged)\n    { 0xC1E5D7408A7D4484ULL, { 0xA7, 0xD8, 0x8E, 0x52, 0x74, 0x9F, 0xA5, 0x45, 0x9D, 0x64, 0x45, 0x23, 0xF8, 0x35, 0x96, 0x51 } },   // 226 WOW-26871patch8.0.1_Beta  Sylvanas Warbringer cinematic\n    { 0xE46276EB9E1A9854ULL, { 0xCC, 0xCA, 0x36, 0xE3, 0x02, 0xF9, 0x45, 0x9B, 0x1D, 0x60, 0x52, 0x6A, 0x31, 0xBE, 0x77, 0xC8 } },   // 227 WOW-26871patch8.0.1_Beta  ltc_a, ltc_h and ltt cinematics\n    { 0xD245B671DD78648CULL, { 0x19, 0xDC, 0xB4, 0xD4, 0x5A, 0x65, 0x8B, 0x54, 0x35, 0x1D, 0xB7, 0xDD, 0xC8, 0x1D, 0xE7, 0x9E } },   // 228 WOW-26871patch8.0.1_Beta  stz, zia, kta, jnm & ja cinematics\n    { 0x4C596E12D36DDFC3ULL, { 0xB8, 0x73, 0x19, 0x26, 0x38, 0x94, 0x99, 0xCB, 0xD4, 0xAD, 0xBF, 0x50, 0x06, 0xCA, 0x03, 0x91 } },   // 229 WOW-26871patch8.0.1_Beta  bar cinematic\n    { 0x0C9ABD5081C06411ULL, { 0x25, 0xA7, 0x7C, 0xD8, 0x00, 0x19, 0x7E, 0xE6, 0xA3, 0x2D, 0xD6, 0x3F, 0x04, 0xE1, 0x15, 0xFA } },   // 230 WOW-26871patch8.0.1_Beta  zcf cinematic\n    { 0x3C6243057F3D9B24ULL, { 0x58, 0xAE, 0x3E, 0x06, 0x42, 0x10, 0xE3, 0xED, 0xF9, 0xC1, 0x25, 0x9C, 0xDE, 0x91, 0x4C, 0x5D } },   // 231 WOW-26871patch8.0.1_Beta  ktf cinematic\n    { 0x7827FBE24427E27DULL, { 0x34, 0xA4, 0x32, 0x04, 0x20, 0x73, 0xCD, 0x0B, 0x51, 0x62, 0x70, 0x68, 0xD2, 0xE0, 0xBD, 0x3E } },   // 232 WOW-26871patch8.0.1_Beta  rot cinematic\n    { 0xFAF9237E1186CF66ULL, { 0xAE, 0x78, 0x78, 0x40, 0x04, 0x1E, 0x9B, 0x41, 0x98, 0xF4, 0x79, 0x71, 0x4D, 0xAD, 0x56, 0x2C } },   // 233 WOW-28048patch8.1.0_PTR   DB2 partial encryption test battle pet\n//  { 0x5DD92EE32BBF9ABDULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 234 WOW-27004patch8.0.1_Subm  filedataid 2238294\n    { 0x0B68A7AF5F85F7EEULL, { 0x27, 0xAA, 0x01, 0x10, 0x82, 0xF5, 0xE8, 0xBB, 0xBD, 0x71, 0xD1, 0xBA, 0x04, 0xF6, 0xAB, 0xA4 } },   // 236 WOW-28151patch8.1.0_PTR   encrypted06 Flying pig mount\n//  { 0x01531713C83FCC39ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 237 WOW-28151patch8.1.0_PTR   fdid 2460009, 2460732\n    { 0x76E4F6739A35E8D7ULL, { 0x05, 0xCF, 0x27, 0x67, 0x22, 0xE7, 0x16, 0x5C, 0x5A, 0x4F, 0x65, 0x95, 0x25, 0x6A, 0x0B, 0xFB } },   // 238 WOW-28294patch8.1.0_PTR   Sylverian Dreamer mount\n    { 0x66033F28DC01923CULL, { 0x9F, 0x95, 0x19, 0x86, 0x14, 0x90, 0xC5, 0xA9, 0xFF, 0xD4, 0xD8, 0x2A, 0x6D, 0x00, 0x67, 0xDB } },   // 239 WOW-28294patch8.1.0_PTR   Vulpine Familiar mount\n    { 0xFCF34A9B05AE7E6AULL, { 0xE7, 0xC2, 0xC8, 0xF7, 0x7E, 0x30, 0xAC, 0x24, 0x0F, 0x39, 0xEC, 0x23, 0x97, 0x12, 0x96, 0xE5 } },   // 240 WOW-28151patch8.1.0_PTR   Alliance fireworks\n    { 0xE2F6BD41298A2AB9ULL, { 0xC5, 0xDC, 0x1B, 0xB4, 0x3B, 0x8C, 0xF3, 0xF0, 0x85, 0xD6, 0x98, 0x68, 0x26, 0xB9, 0x28, 0xEC } },   // 241 WOW-28151patch8.1.0_PTR   Horde fireworks\n    { 0x14C4257E557B49A1ULL, { 0x06, 0x4A, 0x97, 0x09, 0xF4, 0x2D, 0x50, 0xCB, 0x5F, 0x8B, 0x94, 0xBC, 0x1A, 0xCF, 0xDD, 0x5D } },   // 242 WOW-28440patch8.1.0_PTR   dor cinematic\n    { 0x1254E65319C6EEFFULL, { 0x79, 0xD2, 0xB3, 0xD1, 0xCC, 0xB0, 0x15, 0x47, 0x4E, 0x71, 0x58, 0x81, 0x38, 0x64, 0xB8, 0xE6 } },   // 243 WOW-28440patch8.1.0_PTR   akt cinematic\n    { 0xC8753773ADF1174CULL, { 0x1E, 0x0E, 0x37, 0xD4, 0x2E, 0xE5, 0xCE, 0x5E, 0x80, 0x67, 0xF0, 0x39, 0x4B, 0x09, 0x05, 0xF2 } },   // 244 WOW-28938patch8.1.5_PTR   Obsidian Worldbreaker mount & Lil' Nefarian pet\n    { 0x2170BCAA9FA96E22ULL, { 0x6D, 0xDA, 0x6D, 0x48, 0xD7, 0x2D, 0xC8, 0x00, 0x5D, 0xB9, 0xDC, 0x15, 0x36, 0x8D, 0x35, 0xBC } },   // 245 WOW-28938patch8.1.5_PTR   baby alpaca pet\n//  { 0x75485627AA225F4DULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 246 WOW-28938patch8.1.5_PTR   fdid 2741546, 2741548, 2741549\n    { 0x08717B15BF3C7955ULL, { 0x4B, 0x06, 0xBF, 0x9D, 0x17, 0x66, 0x3C, 0xEB, 0x33, 0x12, 0xEA, 0x3C, 0x69, 0xFB, 0xC5, 0xDD } },   // 248 WOW-29220patch8.1.5_PTR   inv_encrypted20.blp (fdid 2823166)\n//  { 0xD19DCF7ACA8D96D6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 249 WOW-30080patch8.2.0_PTR   starts at fdid 2843110, 10 files\n    { 0x9FD609902B4B2E07ULL, { 0xAB, 0xE0, 0xC5, 0xF9, 0xC1, 0x23, 0xE6, 0xE2, 0x4E, 0x7B, 0xEA, 0x43, 0xC2, 0xBF, 0x00, 0xAC } },   // 250 WOW-29418patch8.1.5_PTR   Derek Proudmoore cinematic (dpr, 5 files)\n//  { 0xCB26B441FAE4C8CDULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 251 WOW-30080patch8.2.0_PTR   fdid 2888623, 2892270, 2892271, 2892272, 2892274, 2892275\n    { 0xA98C7594F55C02F0ULL, { 0xEE, 0xDB, 0x77, 0x47, 0x3B, 0x72, 0x1D, 0xED, 0x62, 0x04, 0xA9, 0x76, 0xC9, 0xA6, 0x61, 0xE7 } },   // 252 WOW-30080patch8.2.0_PTR   BlizzCon 2019 - Murloc pets\n    { 0x259EE68CD9E76DBAULL, { 0x46, 0x5D, 0x78, 0x4F, 0x10, 0x19, 0x66, 0x1C, 0xCF, 0x41, 0x7F, 0xE4, 0x66, 0x80, 0x12, 0x83 } },   // 253 WOW-30080patch8.2.0_PTR   Alabaster mounts (30 files)\n    { 0x6A026290FBDB3754ULL, { 0x3D, 0x2D, 0x62, 0x08, 0x50, 0xA6, 0x76, 0x5D, 0xD5, 0x91, 0x22, 0x4F, 0x60, 0x5B, 0x94, 0x9A } },   // 255 WOW-30080patch8.2.0_PTR   BlizzCon 2019 - Wendigo transmog set\n    { 0xCF72FD04608D36EDULL, { 0xA0, 0xA8, 0x89, 0x97, 0x6D, 0x02, 0xFA, 0x8D, 0x00, 0xF7, 0xAF, 0x00, 0x17, 0xAD, 0x72, 0x1F } },   // 257 WOW-30262patch8.2.0_PTR   Azshara Warbringer cinematic (5 files)\n    { 0x17F07C2E3A45DB3DULL, { 0x6D, 0x38, 0x86, 0xBD, 0xB9, 0x1E, 0x71, 0x5A, 0xE7, 0x18, 0x2D, 0x9F, 0x3A, 0x08, 0xF2, 0xC9 } },   // 258 WOW-30262patch8.2.0_PTR   Solesa Naksu Nazjatar phase (34 files)\n    { 0xDFAB5841B87802B5ULL, { 0xF3, 0x7E, 0x96, 0xED, 0x8A, 0x1F, 0x8D, 0x85, 0x2F, 0x07, 0x5D, 0xDE, 0x37, 0xC7, 0x13, 0x27 } },   // 259 WOW-31337patch8.2.5_PTR   Ratmount2 Flying Rat Mount\n    { 0xC050FA06BB0538F6ULL, { 0xC5, 0x52, 0xF5, 0xD0, 0xB7, 0x22, 0x31, 0x50, 0x2D, 0x25, 0x47, 0x31, 0x4E, 0x60, 0x15, 0xF7 } },   // 260 WOW-30495patch8.2.0_PTR   Crossroads cinematic (5 files)\n    { 0xAB5CDD3FC321831FULL, { 0xE1, 0x38, 0x4F, 0x5B, 0x06, 0xEB, 0xBC, 0xD3, 0x33, 0x69, 0x5A, 0xA6, 0xFF, 0xC6, 0x83, 0x18 } },   // 261 WOW-30495patch8.2.0_PTR   Azshara kill cinematic (5 files)\n    { 0xA7B7D1F12395040EULL, { 0x36, 0xAD, 0x3B, 0x31, 0x27, 0x3F, 0x1E, 0xBC, 0xEE, 0x85, 0x20, 0xAA, 0xA7, 0x4B, 0x12, 0xF2 } },   // 262 WOW-30495patch8.2.0_PTR   Nazjatar intro cinematics (9 files)\n    { 0x83A2AB72DD8AE992ULL, { 0x02, 0x3C, 0xFF, 0x06, 0x2B, 0x19, 0xA5, 0x29, 0xB9, 0xF1, 0x4F, 0x9B, 0x7A, 0xAA, 0xC5, 0xBB } },   // 263 WOW-31337patch8.2.5_PTR   8.2.5 War Campaign scenario/models\n    { 0xBEAF567CC45362F0ULL, { 0x8B, 0xD3, 0xED, 0x79, 0x24, 0x05, 0xD9, 0xEE, 0x74, 0x2B, 0xF6, 0xAF, 0xA9, 0x44, 0x57, 0x8A } },   // 264 WOW-31337patch8.2.5_PTR   8.2.5 War Campaign quests/vo\n    { 0x7BB3A77FD8D14783ULL, { 0x4C, 0x94, 0xE3, 0x60, 0x9C, 0xFE, 0x0A, 0x82, 0x00, 0x0A, 0x0B, 0xD4, 0x60, 0x69, 0xAC, 0x6F } },   // 265 WOW-31337patch8.2.5_PTR   8.2.5 War Campaign epilogue quests\n    { 0x8F4098E2470FE0C8ULL, { 0xAA, 0x71, 0x8D, 0x1F, 0x1A, 0x23, 0x07, 0x8D, 0x49, 0xAD, 0x0C, 0x60, 0x6A, 0x72, 0xF3, 0xD5 } },   // 266 WOW-31337patch8.2.5_PTR   8.2.5 War Campaign epilogue in-game cinematic5\n    { 0x6AC5C837A2027A6BULL, { 0xB0, 0xB7, 0xCE, 0x09, 0x17, 0x63, 0xD1, 0x5E, 0x7F, 0x69, 0xA8, 0xE2, 0x34, 0x2C, 0xDD, 0x7C } },   // 267 WOW-31337patch8.2.5_PTR   Shadowlands CE rewards\n    { 0x302AAD8B1F441D95ULL, { 0x24, 0xB8, 0x64, 0x38, 0xCF, 0x02, 0x53, 0x86, 0x49, 0xE5, 0xBA, 0x67, 0x2F, 0xD5, 0x99, 0x3A } },   // 271 WOW-31337patch8.2.5_PTR   RaF mounts & armor\n//  { 0x5C909F00088734B9ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 272 WOW-31337patch8.2.5_PTR   Unused in 8.2.5\n    { 0xF785977C76DE9C77ULL, { 0x7F, 0x3C, 0x19, 0x51, 0xF5, 0x28, 0x3A, 0x18, 0xC1, 0xC6, 0xD4, 0x5B, 0x68, 0x67, 0xB5, 0x1A } },   // 273 WOW-31337patch8.2.5_PTR   Starts at fdid 3071600, 313 files, Winter Veil?\n    { 0x1CDAF3931871BEC3ULL, { 0x66, 0xB4, 0xD3, 0x4A, 0x3A, 0xF3, 0x0E, 0x5E, 0xB7, 0xF4, 0x14, 0xF6, 0xC3, 0x0A, 0xAF, 0x4F } },   // 275 WOW-31337patch8.2.5_PTR   Winter Veil 2019 toy/achievement (28 files)\n    { 0x814E1AB43F3F9345ULL, { 0xB6, 0x5E, 0x2A, 0x63, 0xA1, 0x16, 0xAA, 0x25, 0x1F, 0xA5, 0xD7, 0xB0, 0xBA, 0xAB, 0xF7, 0x78 } },   // 276 WOW-31599patch8.2.5_PTR   The Negotiation cinematic (5 files)\n    { 0x1FBE97A317FFBEFAULL, { 0xBD, 0x71, 0xF7, 0x8D, 0x43, 0x11, 0x7C, 0x68, 0x72, 0x4B, 0xB6, 0xE0, 0xD9, 0x57, 0x7E, 0x08 } },   // 277 WOW-31599patch8.2.5_PTR   Reckoning cinematic (5 files)\n//  { 0x30581F81528FB27CULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 278 WOW-32044patch8.3.0_PTR   Contains creature that uses monkey sounds\n//  { 0x4287F49A5BB366DAULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 279 WOW-31599patch8.2.5_PTR   Unused in 8.2.5\n    { 0xD134F430A45C1CF2ULL, { 0x54, 0x3D, 0xA7, 0x84, 0xD4, 0xBD, 0x24, 0x28, 0xCF, 0xB5, 0xEB, 0xFE, 0xBA, 0x76, 0x2A, 0x90 } },   // 280 WOW-32044patch8.3.0_PTR   Encrypted map w/ Icecrown assets, Darion Mograine VO\n//  { 0x01C82EE0725EDA3AULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 281 WOW-31812patch8.2.5_PTR   Unused in 8.2.5\n//  { 0x04C0C50B5BE0CC78ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 282 WOW-31812patch8.2.5_PTR   Unused in 8.2.5\n//  { 0xA26FD104489B3DE5ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 283 WOW-31812patch8.2.5_PTR   Unused in 8.2.5\n//  { 0xEA6C3B8F210A077FULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 284 WOW-32044patch8.3.0_PTR   18 files, 3159888 is a creature that uses gronn sounds, likely a mount\n//  { 0x4A738212694AD0B6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 285 WOW-32044patch8.3.0_PTR   Unused in 32044\n//  { 0x2A430C60DDCC75FFULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 286 WOW-32044patch8.3.0_PTR   254 files, appears to be items\n    { 0x0A096FB251CFF471ULL, { 0x05, 0xC7, 0x59, 0x12, 0xEC, 0xFF, 0x04, 0x0F, 0x85, 0xFB, 0x46, 0x97, 0xC9, 0x9C, 0x77, 0x03 } },   // 287 WOW-32414patch8.3.0_PTR   In-game scene & VO\n//  { 0x205AFFCDFBA639CBULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 288 WOW-32414patch8.3.0_PTR   \n    { 0x32B62CF10571971FULL, { 0x18, 0xB8, 0x3F, 0xDD, 0x5E, 0x4B, 0x39, 0x7F, 0xB8, 0x9B, 0xB5, 0x72, 0x46, 0x75, 0xCC, 0xBA } },   // 289 WOW-32489patch8.3.0_PTR   In-game Wrathion scene\n//  { 0xB408D6CDE8E0D4C1ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 290 WOW-33978patch9.0.1_Beta\n    { 0x1DBE03EF5A0059E1ULL, { 0xD6, 0x3B, 0x26, 0x3C, 0xB1, 0xC7, 0xE8, 0x56, 0x23, 0xCC, 0x42, 0x58, 0x79, 0xCC, 0x59, 0x2D } },   // 294 WOW-32489patch8.3.0_PTR   Cinematic\n    { 0x29D08CEA080FDB84ULL, { 0x06, 0x51, 0x32, 0xA6, 0x42, 0x8B, 0x19, 0xDF, 0xCB, 0x2B, 0x68, 0x94, 0x8B, 0xE9, 0x58, 0xF5 } },   // 295 WOW-32489patch8.3.0_PTR   Cinematic\n    { 0x3FE91B3FD7F18B37ULL, { 0xC9, 0x13, 0xB1, 0xC2, 0x0D, 0xAE, 0xC8, 0x04, 0xE9, 0xF8, 0xD3, 0x52, 0x7F, 0x2A, 0x05, 0xF7 } },   // 296 WOW-32489patch8.3.0_PTR   Cinematic\n//  { 0xF7BECC6682B9EF36ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 297 WOW-33978patch9.0.1_Beta\n//  { 0xDCB5C5DC78520BD6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 298 WOW-33978patch9.0.1_Beta\n//  { 0x566DF4A5A9E3341FULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 299 WOW-33978patch9.0.1_Beta\n//  { 0x9183F8AAA603704DULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 300 WOW-33978patch9.0.1_Beta\n//  { 0x856D38B447512C51ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 301 WOW-33978patch9.0.1_Beta\n//  { 0x1D0614B43A9D6DF9ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } },   // 302 WOW-33978patch9.0.1_Beta\n    { 0x00179EB433442A73ULL, { 0xD4, 0x1D, 0x69, 0x4C, 0x0D, 0xF8, 0x63, 0x10, 0x5C, 0x53, 0x49, 0xFD, 0x4F, 0xFB, 0xC2, 0x56 } },   // WOW-33978patch9.0.1_Beta\n    { 0x033DBFE564685CF6ULL, { 0xA1, 0xE3, 0xB2, 0x4B, 0xFE, 0x85, 0x78, 0xC0, 0x3D, 0x0F, 0xCC, 0x7F, 0x19, 0xE6, 0xD0, 0x69 } },   // WOW-33978patch9.0.1_Beta\n    { 0x05EC085870DF2AF0ULL, { 0x31, 0xE6, 0xAB, 0x03, 0xA0, 0x9E, 0x68, 0xC8, 0xFB, 0x55, 0xBF, 0x19, 0x5E, 0x1F, 0x1B, 0x99 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0626C885AF0EEF65ULL, { 0x55, 0x7E, 0xC9, 0x97, 0xAD, 0x64, 0x62, 0x1C, 0xFE, 0x2B, 0x3D, 0x79, 0xA5, 0xB7, 0x50, 0x65 } },   // WOW-33978patch9.0.1_Beta\n    { 0x070994B8FE881897ULL, { 0xA5, 0x4A, 0x65, 0x23, 0x5D, 0x6D, 0x64, 0x87, 0x27, 0x7C, 0x36, 0x10, 0xBA, 0x84, 0xAB, 0xF5 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0811E03FCFB84903ULL, { 0x6E, 0x56, 0x77, 0x05, 0x1E, 0xE0, 0x92, 0xA5, 0x7C, 0xF6, 0x56, 0xE1, 0xC5, 0x00, 0x2F, 0xFC } },   // WOW-33978patch9.0.1_Beta\n    { 0x0993C8311127F20EULL, { 0xE9, 0x53, 0xC3, 0x57, 0x4C, 0x3E, 0xE5, 0x43, 0xD9, 0xF5, 0x52, 0xED, 0xC8, 0x2F, 0x20, 0xE9 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0A5E25A024FBA6B1ULL, { 0xBB, 0x8F, 0x7B, 0x18, 0x15, 0x09, 0xA9, 0x31, 0x7B, 0xE1, 0x59, 0x26, 0x34, 0x62, 0xF2, 0x8D } },   // WOW-33978patch9.0.1_Beta\n    { 0x0C15F03D0FE27E48ULL, { 0x74, 0x33, 0x79, 0x1B, 0xF3, 0x45, 0x89, 0xEB, 0x64, 0x32, 0x99, 0x7E, 0x10, 0xA2, 0x54, 0x22 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0C2D617E60368120ULL, { 0x94, 0xB8, 0x12, 0x27, 0x1D, 0x6D, 0xE6, 0xC3, 0x18, 0x14, 0x40, 0xD0, 0xAA, 0x27, 0x65, 0x3D } },   // WOW-33978patch9.0.1_Beta\n    { 0x0C49BD78283973B0ULL, { 0x34, 0xB5, 0xBC, 0x69, 0xC1, 0x2A, 0xA3, 0x7A, 0xD7, 0x12, 0x9B, 0x7E, 0x28, 0xC1, 0xDA, 0x58 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0CA696AE84A34281ULL, { 0x9E, 0x0C, 0xBF, 0x53, 0x20, 0x5A, 0x20, 0x64, 0x3A, 0x92, 0x30, 0xE9, 0x4E, 0xCB, 0x0E, 0x3E } },   // WOW-33978patch9.0.1_Beta\n    { 0x0D069101292C9EF9ULL, { 0x11, 0x6A, 0x8D, 0x4C, 0x1B, 0xA6, 0x65, 0xE1, 0x55, 0x52, 0xCA, 0x69, 0xCD, 0x7C, 0xB3, 0x67 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0DE2CF914415467AULL, { 0xAF, 0x90, 0xC0, 0x00, 0x65, 0x47, 0xCA, 0x72, 0x72, 0x34, 0xC7, 0xAF, 0xA3, 0xAB, 0xA8, 0xA7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0DFACE33557D5092ULL, { 0x61, 0x54, 0x99, 0x41, 0x94, 0x26, 0x6E, 0xEF, 0x93, 0xD7, 0x5F, 0x2C, 0x23, 0xEA, 0x52, 0xB5 } },   // WOW-33978patch9.0.1_Beta\n    { 0x0FC6144903CFC12BULL, { 0x3B, 0x15, 0xF8, 0x9E, 0x91, 0x2F, 0xE4, 0x3D, 0x89, 0x64, 0x3D, 0xCB, 0xA9, 0x45, 0xE5, 0xCD } },   // WOW-33978patch9.0.1_Beta\n    { 0x100C57C7D8B42E58ULL, { 0x24, 0xF7, 0x54, 0x23, 0x09, 0x73, 0x46, 0xC7, 0x92, 0x7F, 0x14, 0x51, 0x93, 0xB6, 0xD5, 0xFE } },   // WOW-33978patch9.0.1_Beta\n    { 0x1108F594E9F5BCB7ULL, { 0x47, 0x80, 0xC7, 0xB3, 0x7A, 0x42, 0xFA, 0x64, 0xD4, 0x90, 0xFB, 0xB6, 0xDE, 0xE9, 0x30, 0xDC } },   // WOW-33978patch9.0.1_Beta\n    { 0x13DA86340D87FEB9ULL, { 0x55, 0x24, 0xD9, 0x49, 0x18, 0x52, 0x37, 0x1F, 0x19, 0x15, 0xCC, 0x1F, 0xDF, 0xD0, 0x53, 0xD1 } },   // WOW-33978patch9.0.1_Beta\n    { 0x141A5383D3AEEB59ULL, { 0xD5, 0xDF, 0xE7, 0x38, 0x99, 0xD2, 0x86, 0xE3, 0x02, 0x2F, 0xAC, 0xAD, 0x3E, 0x70, 0x4B, 0xE3 } },   // WOW-33978patch9.0.1_Beta\n    { 0x1423888694CDE5FCULL, { 0xE7, 0xFA, 0x1C, 0xD3, 0x4A, 0xEA, 0xB1, 0xB6, 0x1B, 0x0A, 0x6C, 0x9E, 0xA6, 0xA9, 0x04, 0x08 } },   // WOW-33978patch9.0.1_Beta\n    { 0x153616FF38D5E460ULL, { 0x0A, 0x94, 0x08, 0xA4, 0x9A, 0x1C, 0xE0, 0x5B, 0x90, 0x30, 0x4D, 0x01, 0x7D, 0xE7, 0x58, 0x92 } },   // WOW-33978patch9.0.1_Beta\n    { 0x15D5A13976DCBD05ULL, { 0xD1, 0x7D, 0x19, 0xEE, 0x14, 0xF7, 0xDD, 0x88, 0x0F, 0x0E, 0xF6, 0xCE, 0x64, 0x44, 0x54, 0xBE } },   // WOW-33978patch9.0.1_Beta\n    { 0x15FA2DA0B33C39EEULL, { 0xA2, 0x94, 0x10, 0xBB, 0x93, 0x1D, 0xA3, 0xE7, 0x84, 0x85, 0x96, 0xFB, 0xA7, 0x7F, 0x50, 0x37 } },   // WOW-33978patch9.0.1_Beta\n    { 0x17ABC9D27E24B4D7ULL, { 0xFA, 0x41, 0x45, 0x70, 0x62, 0x60, 0x5A, 0x17, 0x3D, 0x10, 0xFB, 0x90, 0xE0, 0x77, 0x9A, 0x44 } },   // WOW-33978patch9.0.1_Beta\n    { 0x188E37F5AB501082ULL, { 0xE5, 0x66, 0x96, 0x36, 0x09, 0x3C, 0xE1, 0xB8, 0x99, 0x75, 0x6B, 0xE6, 0x9B, 0x8C, 0x2C, 0x58 } },   // WOW-33978patch9.0.1_Beta\n    { 0x18C32E5601F89AC3ULL, { 0xC8, 0x64, 0x03, 0x2D, 0x3E, 0x9D, 0xA9, 0x29, 0xF9, 0xFE, 0xC6, 0xE5, 0xB5, 0x38, 0x94, 0xA1 } },   // WOW-33978patch9.0.1_Beta\n    { 0x1A16C07D5F35124FULL, { 0x34, 0xAB, 0xF6, 0xA4, 0x68, 0x69, 0xE0, 0x0C, 0xBB, 0x83, 0x94, 0x7C, 0xFD, 0x6A, 0x39, 0x47 } },   // WOW-33978patch9.0.1_Beta\n    { 0x1A4F317C88C93C04ULL, { 0xFF, 0x16, 0x9D, 0x5A, 0xB8, 0x13, 0x5D, 0x38, 0xEC, 0x92, 0xFE, 0xAB, 0xEE, 0x0E, 0x39, 0x7B } },   // WOW-33978patch9.0.1_Beta\n    { 0x1ABF6A7265BBC7AFULL, { 0x9E, 0x12, 0x7C, 0xE7, 0x16, 0x69, 0x1C, 0x50, 0xB5, 0xD4, 0x95, 0x9D, 0xAD, 0xA8, 0xEB, 0xEC } },   // WOW-33978patch9.0.1_Beta\n    { 0x1BD281160FB552FDULL, { 0xEA, 0x57, 0x6F, 0x20, 0xAA, 0x9A, 0xF5, 0x8A, 0x76, 0xF4, 0xB8, 0x43, 0xF5, 0x3A, 0x8E, 0x5D } },   // WOW-33978patch9.0.1_Beta\n    { 0x1BE9A4EEC5B455C5ULL, { 0xBA, 0xFC, 0x5C, 0xC3, 0x9B, 0xDD, 0xC1, 0xD8, 0x02, 0xBA, 0x07, 0x46, 0x41, 0x42, 0x7D, 0x68 } },   // WOW-33978patch9.0.1_Beta\n    { 0x1DCF36E171124EFCULL, { 0xC6, 0x59, 0x7A, 0xA9, 0x76, 0x98, 0x8B, 0xD4, 0xCF, 0x57, 0xB8, 0x33, 0x04, 0xDA, 0x19, 0x34 } },   // WOW-33978patch9.0.1_Beta\n    { 0x1E47BD8DB4D6032FULL, { 0x0F, 0x81, 0x0C, 0x27, 0xE9, 0x10, 0xA5, 0xFF, 0xD1, 0x47, 0x79, 0x27, 0xE2, 0x40, 0x64, 0x59 } },   // WOW-33978patch9.0.1_Beta\n    { 0x1FB4F1C56721C87EULL, { 0x64, 0x8C, 0x26, 0x55, 0xE0, 0xAF, 0x50, 0xF4, 0x26, 0xC5, 0xCD, 0x2C, 0x4F, 0xD2, 0x21, 0xE7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x225902F0EC8BF0FCULL, { 0x09, 0x81, 0x25, 0xBC, 0x75, 0x9E, 0x47, 0xA4, 0x4F, 0x46, 0x7E, 0xCC, 0x28, 0x48, 0x07, 0x47 } },   // WOW-33978patch9.0.1_Beta\n    { 0x225EADE089BA38D8ULL, { 0xFD, 0x5D, 0x6A, 0x9A, 0xDA, 0x76, 0xC7, 0x06, 0x7A, 0x83, 0xBF, 0x5E, 0x56, 0x92, 0xC6, 0xC3 } },   // WOW-33978patch9.0.1_Beta\n    { 0x22EE6101A078F310ULL, { 0xEC, 0x43, 0x74, 0x15, 0xFA, 0x5B, 0xC5, 0x98, 0x79, 0xBB, 0xAA, 0x5C, 0x5F, 0xF3, 0x6A, 0xCD } },   // WOW-33978patch9.0.1_Beta\n    { 0x23457E4AB5352E38ULL, { 0xEE, 0x3F, 0xDC, 0xA7, 0x8B, 0x42, 0xC0, 0x75, 0x03, 0xEF, 0x98, 0x86, 0xF9, 0x8B, 0xB0, 0x28 } },   // WOW-33978patch9.0.1_Beta\n    { 0x236B38CBE43FC318ULL, { 0x14, 0x89, 0xB7, 0x05, 0x62, 0xD5, 0x6A, 0x60, 0x76, 0x00, 0xFA, 0xA8, 0x0A, 0x5A, 0xFD, 0xEF } },   // WOW-33978patch9.0.1_Beta\n    { 0x264DB70A1A6CC720ULL, { 0x94, 0x88, 0x48, 0x13, 0x6B, 0xDD, 0x11, 0xD9, 0x95, 0xF3, 0xC4, 0x16, 0x9B, 0x8A, 0x9C, 0xAF } },   // WOW-33978patch9.0.1_Beta\n    { 0x2678A2608A95FAAEULL, { 0xDB, 0x72, 0x2D, 0x47, 0x18, 0xB8, 0xB2, 0xC3, 0x13, 0x17, 0xB8, 0x43, 0xF6, 0x2D, 0x5F, 0xA8 } },   // WOW-33978patch9.0.1_Beta\n    { 0x27683B8282673916ULL, { 0x9A, 0x06, 0x02, 0xC6, 0x62, 0x4A, 0xD2, 0xB1, 0x85, 0x18, 0x7C, 0x8B, 0xD7, 0xAF, 0x81, 0x7A } },   // WOW-33978patch9.0.1_Beta\n    { 0x278A558C1E4C9789ULL, { 0x7C, 0xCF, 0xEE, 0xF6, 0x2E, 0xD5, 0x65, 0x60, 0xFD, 0x12, 0x94, 0xBB, 0x79, 0x7E, 0xC0, 0x0C } },   // WOW-33978patch9.0.1_Beta\n    { 0x29C4474FA5A650C2ULL, { 0xB4, 0x5A, 0x3E, 0x43, 0xB8, 0x18, 0x52, 0xD2, 0x69, 0x70, 0x0D, 0x11, 0xCA, 0xAA, 0x52, 0x74 } },   // WOW-33978patch9.0.1_Beta\n    { 0x29E553202112D688ULL, { 0xBB, 0x29, 0xC4, 0x2B, 0x23, 0xD1, 0x0E, 0xBE, 0x4E, 0xC7, 0x33, 0xC0, 0x4F, 0xB1, 0x9E, 0x0C } },   // WOW-33978patch9.0.1_Beta\n    { 0x2A50EBBA4B44FBF5ULL, { 0x7F, 0x1F, 0xA1, 0x12, 0x4C, 0xC3, 0xF4, 0x70, 0xAD, 0x48, 0x30, 0xB6, 0xD6, 0xA1, 0xF5, 0x13 } },   // WOW-33978patch9.0.1_Beta\n    { 0x2AFA1E90F5548DADULL, { 0x76, 0x6F, 0x2A, 0x52, 0x49, 0x29, 0xD9, 0x97, 0x83, 0x5D, 0xAE, 0x83, 0xC9, 0xB3, 0xDF, 0x4B } },   // WOW-33978patch9.0.1_Beta\n    { 0x2CDD202075F2BB7BULL, { 0x8B, 0x78, 0x02, 0x28, 0xAD, 0x85, 0xC5, 0xB0, 0x26, 0x53, 0xB9, 0x0E, 0x6A, 0x98, 0x28, 0x44 } },   // WOW-33978patch9.0.1_Beta\n    { 0x2D5511A1586B85BDULL, { 0x3A, 0x2A, 0x7A, 0x6B, 0x63, 0xE6, 0xA7, 0x0E, 0x26, 0x52, 0xDB, 0x45, 0x1C, 0x80, 0xA8, 0x78 } },   // WOW-33978patch9.0.1_Beta\n    { 0x2D6ADB0D7D20DA8FULL, { 0x39, 0x5C, 0xD9, 0xDF, 0xCF, 0x86, 0xA5, 0xF5, 0x53, 0x1A, 0x1C, 0xA3, 0xDE, 0x43, 0x96, 0x04 } },   // WOW-33978patch9.0.1_Beta\n    { 0x323E310D6BD63AC9ULL, { 0x52, 0x19, 0xD6, 0xB2, 0x0E, 0x8E, 0xA3, 0xF9, 0x72, 0xFD, 0x85, 0xD3, 0x55, 0xD3, 0x30, 0xD8 } },   // WOW-33978patch9.0.1_Beta\n    { 0x337A168A21969F6CULL, { 0x67, 0x03, 0x67, 0x8A, 0x02, 0x29, 0x4E, 0x8E, 0x8B, 0xCF, 0xC4, 0x23, 0xF0, 0xFF, 0xF9, 0x35 } },   // WOW-33978patch9.0.1_Beta\n    { 0x33801621A7C885FDULL, { 0x93, 0xBE, 0xD4, 0x71, 0xDD, 0x0C, 0xF9, 0x02, 0xA3, 0xA2, 0x43, 0xD8, 0xA3, 0x44, 0x11, 0xC5 } },   // WOW-33978patch9.0.1_Beta\n    { 0x34487D8CF061757AULL, { 0x33, 0x26, 0x12, 0x28, 0xE6, 0x94, 0xDD, 0x95, 0x9A, 0xC9, 0xA6, 0x8B, 0x73, 0x6F, 0x6A, 0xF3 } },   // WOW-33978patch9.0.1_Beta\n    { 0x35FC62C0E25BFA2CULL, { 0x69, 0x0D, 0x5E, 0xC1, 0xE5, 0x6A, 0xA0, 0x50, 0x49, 0x5B, 0x7B, 0xAE, 0x51, 0x3C, 0xAB, 0xCF } },   // WOW-33978patch9.0.1_Beta\n    { 0x3692291361CDD66BULL, { 0x87, 0x81, 0x36, 0x91, 0xB2, 0xFA, 0xEA, 0xBC, 0x9A, 0x28, 0x26, 0x5B, 0xE0, 0x3F, 0xAE, 0x7E } },   // WOW-33978patch9.0.1_Beta\n    { 0x38138436341EB55EULL, { 0xCD, 0x0D, 0xF8, 0x43, 0x30, 0x6C, 0x37, 0xB5, 0x17, 0x68, 0x91, 0xFC, 0x56, 0xDF, 0x7D, 0x57 } },   // WOW-33978patch9.0.1_Beta\n    { 0x390336A9AC1ADBD3ULL, { 0xF1, 0x93, 0xE1, 0xAC, 0x0A, 0x1C, 0x80, 0x93, 0xF2, 0x31, 0x82, 0x47, 0xF1, 0xED, 0xC6, 0xA4 } },   // WOW-33978patch9.0.1_Beta\n    { 0x41A0F110F49EB86AULL, { 0xDF, 0x50, 0xC9, 0x44, 0xB4, 0x2E, 0xF1, 0x6B, 0x4E, 0x6F, 0xA3, 0xE3, 0xF2, 0x8E, 0x70, 0xF7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x41BDEA4884539B22ULL, { 0x14, 0xC6, 0xE1, 0xA2, 0xC0, 0xBB, 0xCF, 0x1E, 0x6D, 0x21, 0xA2, 0x1F, 0x39, 0xD5, 0x51, 0xCA } },   // WOW-33978patch9.0.1_Beta\n    { 0x41E698459DAD7101ULL, { 0xBF, 0xE8, 0x76, 0x01, 0x16, 0x60, 0xAD, 0x32, 0xA5, 0x72, 0x7E, 0x48, 0x9F, 0x83, 0x64, 0x68 } },   // WOW-33978patch9.0.1_Beta\n    { 0x4223772617A3212AULL, { 0xC4, 0x09, 0x63, 0x17, 0x1B, 0x49, 0x6B, 0xB7, 0x65, 0xA5, 0x6E, 0xC3, 0xF2, 0x2D, 0xD6, 0x48 } },   // WOW-33978patch9.0.1_Beta\n    { 0x422ABA4AE3E43AC5ULL, { 0xA0, 0xAE, 0x8D, 0xA9, 0x66, 0x39, 0x3F, 0x20, 0x60, 0x12, 0xA6, 0x1A, 0xE8, 0x19, 0xBD, 0xEA } },   // WOW-33978patch9.0.1_Beta\n    { 0x429E445F8823DE47ULL, { 0xCB, 0x10, 0x47, 0x34, 0xDC, 0x4A, 0xDE, 0x45, 0x4A, 0x7A, 0x1A, 0x17, 0x96, 0x42, 0x3B, 0x21 } },   // WOW-33978patch9.0.1_Beta\n    { 0x43855C4ABC59CD03ULL, { 0x91, 0xA3, 0x74, 0xB1, 0xE8, 0xCF, 0xE4, 0x6D, 0x2B, 0x82, 0xC7, 0x69, 0x52, 0x2D, 0x7F, 0xAF } },   // WOW-33978patch9.0.1_Beta\n    { 0x44324FEB63BAD71BULL, { 0xBA, 0xA7, 0xA3, 0x31, 0x1F, 0x36, 0xD3, 0xF6, 0xC1, 0x58, 0x9F, 0xBF, 0x34, 0xF1, 0x63, 0xAF } },   // WOW-33978patch9.0.1_Beta\n    { 0x445C444DDCB144D0ULL, { 0xE1, 0x1F, 0x30, 0x61, 0x10, 0xA2, 0x47, 0xAC, 0x08, 0x7E, 0x44, 0x66, 0xE8, 0x50, 0x5A, 0xC2 } },   // WOW-33978patch9.0.1_Beta\n    { 0x4570E5C612AD4680ULL, { 0xC7, 0x5A, 0x72, 0x40, 0xBF, 0x08, 0x89, 0xBD, 0xB5, 0x0D, 0xB2, 0x14, 0x7C, 0xAE, 0xC2, 0x9F } },   // WOW-33978patch9.0.1_Beta\n    { 0x463B8AC09861DBF2ULL, { 0x85, 0x14, 0x8A, 0x61, 0x6B, 0x3D, 0x2C, 0x0F, 0x3B, 0x50, 0x22, 0xB8, 0x71, 0xE4, 0xAB, 0x2F } },   // WOW-33978patch9.0.1_Beta\n    { 0x46B9652048C5B9EBULL, { 0x42, 0xAD, 0x0B, 0xE5, 0x4B, 0xCF, 0xED, 0x59, 0x75, 0xC3, 0x5B, 0xC8, 0x00, 0xF6, 0x94, 0x4B } },   // WOW-33978patch9.0.1_Beta\n    { 0x477AF884E1779F04ULL, { 0x81, 0xE7, 0x36, 0x61, 0x9B, 0x2A, 0xA8, 0xD3, 0xBE, 0xB3, 0x80, 0x01, 0x8C, 0x04, 0xC0, 0x97 } },   // WOW-33978patch9.0.1_Beta\n    { 0x49E4DB410ACD71E4ULL, { 0xEC, 0xAD, 0x54, 0xE4, 0xCC, 0x6A, 0xE5, 0xA2, 0xB1, 0xCD, 0xFC, 0x94, 0xDC, 0xC4, 0xA7, 0xE0 } },   // WOW-33978patch9.0.1_Beta\n    { 0x4BA04135745B0C77ULL, { 0x48, 0xAC, 0x8F, 0x63, 0xF9, 0xF6, 0xD4, 0xFC, 0x7B, 0xBE, 0xF2, 0xF8, 0x97, 0x40, 0xB7, 0x3F } },   // WOW-33978patch9.0.1_Beta\n    { 0x4C3638A33B225E20ULL, { 0x85, 0xB3, 0x19, 0x7B, 0x10, 0x55, 0x03, 0xD9, 0xBC, 0x11, 0x76, 0xA6, 0xCE, 0x90, 0xB2, 0x1B } },   // WOW-33978patch9.0.1_Beta\n    { 0x4CA3E38A5F339D85ULL, { 0x65, 0xDA, 0x28, 0xD6, 0x97, 0xE8, 0x2F, 0x7F, 0xB3, 0x26, 0x98, 0xF5, 0xDC, 0x13, 0xFE, 0x67 } },   // WOW-33978patch9.0.1_Beta\n    { 0x4D356B23BBB63ABFULL, { 0x5B, 0x31, 0xF5, 0xD4, 0x37, 0x18, 0x20, 0xE0, 0x86, 0xD1, 0x59, 0x1F, 0x20, 0x96, 0x3C, 0x6F } },   // WOW-33978patch9.0.1_Beta\n    { 0x4D81CA32AF4851B8ULL, { 0x2F, 0xAF, 0x21, 0x8D, 0x81, 0x0A, 0x5D, 0x2C, 0x5B, 0xCD, 0x6E, 0xBE, 0x7A, 0xF6, 0x7C, 0x66 } },   // WOW-33978patch9.0.1_Beta\n    { 0x4E8FD51F7FDCB494ULL, { 0x6F, 0x19, 0x66, 0x48, 0xE9, 0xE0, 0xBD, 0x75, 0xC4, 0xC9, 0x63, 0x21, 0x4F, 0xBF, 0x43, 0x53 } },   // WOW-33978patch9.0.1_Beta\n    { 0x4F29CD1DBFF6A704ULL, { 0x19, 0xF0, 0x45, 0x81, 0x27, 0x1E, 0xB2, 0x56, 0xF1, 0x05, 0x34, 0xE5, 0x0C, 0x82, 0x9D, 0x30 } },   // WOW-33978patch9.0.1_Beta\n    { 0x50BDE6C6B138D920ULL, { 0x86, 0x3D, 0xE7, 0xEA, 0x7E, 0xDE, 0x52, 0x18, 0xCE, 0x92, 0x86, 0x36, 0x0D, 0xD5, 0x4C, 0xE3 } },   // WOW-33978patch9.0.1_Beta\n    { 0x51C45371AA62A30DULL, { 0x80, 0x29, 0x74, 0xB8, 0x2D, 0x99, 0x83, 0xCD, 0x78, 0xB6, 0x65, 0x33, 0x20, 0xD3, 0xDA, 0xA5 } },   // WOW-33978patch9.0.1_Beta\n    { 0x53422759826BCE28ULL, { 0x46, 0x7F, 0x7B, 0xB8, 0x45, 0xB5, 0x0A, 0xBE, 0x1B, 0x0B, 0xD7, 0x18, 0x95, 0xFD, 0x78, 0x38 } },   // WOW-33978patch9.0.1_Beta\n    { 0x54E0E8C0E9A4CEE7ULL, { 0x41, 0x8D, 0x3F, 0xA2, 0xCB, 0xA3, 0xD9, 0x72, 0x29, 0x36, 0x1E, 0x2D, 0xE7, 0x96, 0x79, 0x28 } },   // WOW-33978patch9.0.1_Beta\n    { 0x550AB6D42C0118D3ULL, { 0xBF, 0x50, 0x7B, 0x7E, 0xAC, 0x67, 0x29, 0x55, 0x0E, 0x87, 0xBD, 0x44, 0x4B, 0xB7, 0x0F, 0x35 } },   // WOW-33978patch9.0.1_Beta\n    { 0x577E78AECCE3D388ULL, { 0x19, 0x6B, 0x59, 0x45, 0x39, 0x36, 0x4E, 0xCC, 0xFF, 0xD9, 0x2E, 0x71, 0xD9, 0x19, 0x30, 0x20 } },   // WOW-33978patch9.0.1_Beta\n    { 0x587E8D3EB9594F4AULL, { 0x0E, 0xDE, 0x7A, 0x2C, 0x7B, 0xE8, 0xA1, 0x9A, 0x98, 0x73, 0x88, 0xC3, 0xF6, 0x04, 0x67, 0x55 } },   // WOW-33978patch9.0.1_Beta\n    { 0x591C8211EE53BFDBULL, { 0x46, 0xA6, 0x19, 0xF7, 0xA6, 0xC4, 0xE0, 0xCE, 0x54, 0x2B, 0xB1, 0xA9, 0xE4, 0x71, 0x3F, 0x34 } },   // WOW-33978patch9.0.1_Beta\n    { 0x597B3EA295C88FA7ULL, { 0x2D, 0x36, 0x4A, 0xE4, 0xD4, 0x6C, 0xEF, 0x42, 0x2A, 0x6F, 0x53, 0x1D, 0x9B, 0x1A, 0x7A, 0xD2 } },   // WOW-33978patch9.0.1_Beta\n    { 0x59CBA5A49554EB2FULL, { 0x4B, 0x5F, 0xF9, 0xC6, 0x7E, 0x02, 0x1C, 0x5E, 0x2A, 0xA3, 0xB0, 0x5A, 0xC9, 0xE0, 0x50, 0x96 } },   // WOW-33978patch9.0.1_Beta\n    { 0x5B1A3C7FC9D58D21ULL, { 0xA4, 0x8B, 0xA8, 0xE3, 0x19, 0x20, 0x7B, 0x2C, 0x04, 0xE8, 0x2B, 0x25, 0xC0, 0xF3, 0xC1, 0x49 } },   // WOW-33978patch9.0.1_Beta\n    { 0x5B256C6230E168FFULL, { 0x89, 0xF3, 0x1D, 0x0F, 0xA3, 0x81, 0xD7, 0x23, 0x55, 0x56, 0x6B, 0x01, 0x24, 0xB8, 0xE1, 0xF2 } },   // WOW-33978patch9.0.1_Beta\n    { 0x5B657AE4D191AAFBULL, { 0xF8, 0x84, 0xAA, 0xC1, 0xE2, 0xAB, 0x1C, 0x41, 0x3F, 0x7B, 0xAD, 0xDD, 0x14, 0x9D, 0x09, 0x61 } },   // WOW-33978patch9.0.1_Beta\n    { 0x5B93089CD9316EFEULL, { 0x95, 0x76, 0x53, 0xD3, 0x4A, 0xBF, 0x29, 0x88, 0x46, 0xFF, 0x56, 0x04, 0xC1, 0xEB, 0x06, 0xD0 } },   // WOW-33978patch9.0.1_Beta\n    { 0x5C172612CB60DEF2ULL, { 0xF5, 0x10, 0xBF, 0xEF, 0xFF, 0x2F, 0x87, 0x0B, 0x08, 0x93, 0x1B, 0x62, 0x52, 0x6F, 0x01, 0xFE } },   // WOW-33978patch9.0.1_Beta\n    { 0x5E6EB3F5C47183FFULL, { 0x73, 0xEC, 0xB7, 0xAE, 0x15, 0x19, 0xE3, 0x9C, 0xC8, 0xBB, 0xD8, 0xF9, 0x90, 0xF3, 0xAC, 0xFB } },   // WOW-33978patch9.0.1_Beta\n    { 0x5E7181FBA91F3766ULL, { 0x2F, 0x6A, 0xAB, 0xDC, 0x38, 0x9E, 0xA1, 0x0A, 0x11, 0xA9, 0xF1, 0x83, 0x58, 0x04, 0xF8, 0x6C } },   // WOW-33978patch9.0.1_Beta\n    { 0x5E7B9DCD0092888BULL, { 0x6F, 0xE5, 0xA1, 0x40, 0x39, 0x93, 0xAE, 0x2A, 0x22, 0xA4, 0xF1, 0xAD, 0x31, 0x14, 0x4D, 0xAB } },   // WOW-33978patch9.0.1_Beta\n    { 0x5F1C8C3CFABDC578ULL, { 0xEA, 0x5A, 0x36, 0x31, 0x46, 0x09, 0xC6, 0x70, 0x84, 0xDB, 0x63, 0xCF, 0xF7, 0x87, 0xDF, 0xCA } },   // WOW-33978patch9.0.1_Beta\n    { 0x62EDE4DE7880CC68ULL, { 0xEA, 0xAA, 0x8D, 0x5C, 0x76, 0xEA, 0x95, 0x76, 0x31, 0x52, 0xAE, 0x50, 0x3C, 0xF5, 0x67, 0x45 } },   // WOW-33978patch9.0.1_Beta\n    { 0x637AD198DBD985ECULL, { 0xA8, 0x31, 0xE0, 0x85, 0xC7, 0xA0, 0x98, 0x45, 0x57, 0xE7, 0x97, 0x30, 0x5C, 0xB2, 0xA2, 0x63 } },   // WOW-33978patch9.0.1_Beta\n    { 0x6444A004E5F352B9ULL, { 0x76, 0x8A, 0x1C, 0x07, 0x02, 0x50, 0xD1, 0x70, 0x95, 0x02, 0x3D, 0xBD, 0xBD, 0x02, 0x3B, 0xC7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x649F6483822B8C3EULL, { 0xDB, 0xD9, 0x35, 0x20, 0x0A, 0x22, 0xE7, 0x89, 0x75, 0x89, 0x40, 0xE9, 0x1E, 0x1C, 0xFC, 0xAE } },   // WOW-33978patch9.0.1_Beta\n    { 0x650E0558CFE68DBDULL, { 0xE4, 0x98, 0x29, 0x4E, 0x3A, 0x2C, 0xB7, 0xF1, 0x0B, 0x0F, 0x1A, 0xC8, 0x98, 0xF3, 0x79, 0xB6 } },   // WOW-33978patch9.0.1_Beta\n    { 0x667C9AD6F57610C7ULL, { 0xF7, 0xF9, 0x8E, 0xFE, 0x5D, 0xB2, 0x27, 0x92, 0x8F, 0x97, 0x02, 0x85, 0x20, 0xD9, 0x7F, 0xC3 } },   // WOW-33978patch9.0.1_Beta\n    { 0x67AD32C6DFF4B640ULL, { 0x03, 0x32, 0x11, 0xB8, 0x92, 0xF5, 0x2C, 0xBE, 0x56, 0x10, 0x51, 0xEB, 0xAA, 0xC8, 0xCE, 0x2F } },   // WOW-33978patch9.0.1_Beta\n    { 0x6870068DF23BA71BULL, { 0x58, 0x97, 0x6C, 0xEA, 0xF5, 0xE2, 0xAB, 0x19, 0x38, 0x01, 0xD7, 0x13, 0xAB, 0xEC, 0x60, 0x5B } },   // WOW-33978patch9.0.1_Beta\n    { 0x69CADB492EBF739EULL, { 0x63, 0xA4, 0x2B, 0xB5, 0x28, 0x05, 0x0C, 0x59, 0x47, 0x73, 0x5C, 0x18, 0x36, 0x60, 0x5C, 0x95 } },   // WOW-33978patch9.0.1_Beta\n    { 0x6B20D9D506B930E6ULL, { 0xA4, 0x2E, 0xEC, 0xB7, 0x63, 0xC8, 0x79, 0xC3, 0x9C, 0xFC, 0xC3, 0x82, 0x0C, 0xC0, 0x57, 0x13 } },   // WOW-33978patch9.0.1_Beta\n    { 0x6BF0360FC30A1651ULL, { 0x7A, 0x69, 0xDC, 0x9A, 0x2E, 0xF9, 0x6E, 0x9E, 0xFA, 0x1F, 0x4E, 0xE3, 0x75, 0x44, 0xD0, 0x60 } },   // WOW-33978patch9.0.1_Beta\n    { 0x6C3380DB72AFCF88ULL, { 0xC5, 0xED, 0xF5, 0x55, 0xCE, 0x52, 0xF6, 0x71, 0x7B, 0x38, 0x28, 0x1C, 0x1B, 0x46, 0xCC, 0xDC } },   // WOW-33978patch9.0.1_Beta\n    { 0x6CEAD213E31A6F01ULL, { 0x1D, 0x26, 0x3C, 0xFB, 0x4B, 0xD4, 0xDE, 0x9E, 0xBF, 0x59, 0xB1, 0x28, 0x7E, 0x39, 0x7F, 0xFE } },   // WOW-33978patch9.0.1_Beta\n    { 0x6D6AD51EAA144766ULL, { 0x3E, 0xDD, 0x69, 0x0A, 0x09, 0x18, 0xA4, 0x2B, 0x49, 0xCB, 0xE2, 0x14, 0xBC, 0x90, 0x5D, 0x22 } },   // WOW-33978patch9.0.1_Beta\n    { 0x6E92CDCE4FEA3B27ULL, { 0xE9, 0x88, 0x05, 0xA6, 0xB0, 0xD4, 0xEA, 0x3C, 0x28, 0x0A, 0x4E, 0xF4, 0x9A, 0xE5, 0x10, 0x11 } },   // WOW-33978patch9.0.1_Beta\n    { 0x6EA6B9E529B29CC8ULL, { 0x7D, 0x8F, 0xE7, 0x88, 0xCA, 0x9A, 0xF0, 0x7F, 0x99, 0xC3, 0xDC, 0xA6, 0x1E, 0x1F, 0xBA, 0xC7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x72337416FD82C794ULL, { 0xF4, 0x78, 0x2D, 0x77, 0xEA, 0xDA, 0x33, 0x0A, 0x2D, 0xD1, 0x78, 0x9D, 0x64, 0x7F, 0x27, 0xBF } },   // WOW-33978patch9.0.1_Beta\n    { 0x725E3CA857E0D99FULL, { 0x91, 0xD3, 0xAB, 0xCC, 0xDE, 0xE7, 0x20, 0xF4, 0xBA, 0xD5, 0xB9, 0x0E, 0xFA, 0xB9, 0x04, 0xFC } },   // WOW-33978patch9.0.1_Beta\n    { 0x747A16FD3A3F6970ULL, { 0x16, 0x26, 0xFE, 0x4D, 0x37, 0x25, 0xE1, 0xD1, 0x7D, 0xEE, 0xE1, 0xC2, 0xDF, 0xEE, 0x85, 0xD4 } },   // WOW-33978patch9.0.1_Beta\n    { 0x75BD0F89A7DF7076ULL, { 0x9A, 0x4F, 0x51, 0xF7, 0xDB, 0x21, 0xD0, 0x49, 0x32, 0xAF, 0x81, 0x86, 0x42, 0xCC, 0x7B, 0xEC } },   // WOW-33978patch9.0.1_Beta\n    { 0x75E2B6A4145B00DBULL, { 0xE0, 0x9B, 0x5A, 0x79, 0xB5, 0xFB, 0xAD, 0xE1, 0x9D, 0x1D, 0x97, 0x9B, 0x2C, 0x32, 0xE4, 0xB7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x77F0A6FE6BE42E62ULL, { 0x35, 0xBA, 0xB9, 0x29, 0x81, 0xF6, 0x04, 0xEF, 0x4C, 0x3C, 0x22, 0x53, 0xC0, 0x3D, 0x36, 0xCE } },   // WOW-33978patch9.0.1_Beta\n    { 0x7810113EF44E92B2ULL, { 0xA2, 0x18, 0x6B, 0x58, 0x6A, 0xE6, 0x86, 0xF3, 0xE1, 0x57, 0x9F, 0xFA, 0x9D, 0xDF, 0x17, 0x03 } },   // WOW-33978patch9.0.1_Beta\n    { 0x78B7C378F1424152ULL, { 0xDF, 0x20, 0xB3, 0xFA, 0x41, 0x5B, 0x16, 0x25, 0xAA, 0x7D, 0x82, 0x22, 0x61, 0x2F, 0x75, 0xA0 } },   // WOW-33978patch9.0.1_Beta\n    { 0x79383B3295AA93C4ULL, { 0xEF, 0xDE, 0x6A, 0xEB, 0xDA, 0x6A, 0xBE, 0xD6, 0x5B, 0x2F, 0xE9, 0x1F, 0x33, 0x95, 0xDA, 0x4E } },   // WOW-33978patch9.0.1_Beta\n    { 0x7AD23E997C77CBEBULL, { 0x05, 0x6F, 0x35, 0x4E, 0xA0, 0x86, 0x41, 0x26, 0x53, 0x44, 0x33, 0x6C, 0xEF, 0x0C, 0xDB, 0x8D } },   // WOW-33978patch9.0.1_Beta\n    { 0x7C86AE10DE9A2D24ULL, { 0x7B, 0x0A, 0x70, 0xD0, 0xD1, 0x6E, 0xA7, 0x34, 0x5B, 0xFF, 0xDD, 0x56, 0xF6, 0x5E, 0xA2, 0x7F } },   // WOW-33978patch9.0.1_Beta\n    { 0x7CD6AC9BD4B6C2F1ULL, { 0x20, 0xE7, 0x93, 0x06, 0x6B, 0x7D, 0x48, 0x94, 0x6B, 0xCE, 0x64, 0xA1, 0x6E, 0x72, 0x31, 0xD7 } },   // WOW-33978patch9.0.1_Beta\n    { 0x7E1F1D367C75D4E3ULL, { 0x37, 0x15, 0xB8, 0x5F, 0x6E, 0xCD, 0xBD, 0x3B, 0x1D, 0x85, 0x89, 0x60, 0x22, 0x53, 0xDC, 0x75 } },   // WOW-33978patch9.0.1_Beta\n    { 0x7E4C540FC51875ECULL, { 0x36, 0x71, 0xFC, 0xCE, 0xDF, 0xF2, 0x7D, 0x9F, 0x46, 0x3F, 0x6A, 0x5B, 0xED, 0xE5, 0xE2, 0x2D } },   // WOW-33978patch9.0.1_Beta\n    { 0x7E766271DF1A2F90ULL, { 0x2C, 0xEC, 0x2B, 0x76, 0xCF, 0x05, 0x63, 0x4D, 0xFB, 0xC4, 0xCB, 0x1F, 0xB9, 0x8C, 0xBC, 0x4F } },   // WOW-33978patch9.0.1_Beta\n    { 0x7F7D6EDEF8F5BCFCULL, { 0xF1, 0xD5, 0x9F, 0xEC, 0x5C, 0xB7, 0x4B, 0x2E, 0x66, 0x38, 0x00, 0xB7, 0xDA, 0xBF, 0x32, 0x16 } },   // WOW-33978patch9.0.1_Beta\n    { 0x801FD0E0D505C316ULL, { 0x91, 0x30, 0x64, 0x6A, 0xD7, 0x52, 0x44, 0xBB, 0x44, 0x5B, 0x66, 0x88, 0xA5, 0x00, 0x7B, 0x5C } },   // WOW-33978patch9.0.1_Beta\n    { 0x8281CFAEB6AE6182ULL, { 0xC3, 0x25, 0x34, 0xB1, 0x97, 0x5C, 0x71, 0x07, 0xB6, 0x38, 0xD4, 0x77, 0x94, 0xA9, 0xF3, 0xF2 } },   // WOW-33978patch9.0.1_Beta\n    { 0x834E863E91A946E0ULL, { 0xFF, 0xC4, 0x7E, 0x87, 0xFA, 0xD8, 0x8A, 0x87, 0x24, 0xE2, 0xCF, 0x3E, 0xAE, 0xE1, 0xAA, 0x06 } },   // WOW-33978patch9.0.1_Beta\n    { 0x85B1F0C5AFA7684AULL, { 0x7A, 0x29, 0xDC, 0xA9, 0x90, 0xAA, 0x0A, 0x7D, 0xF1, 0x99, 0x4E, 0xAF, 0x00, 0x04, 0x54, 0xB8 } },   // WOW-33978patch9.0.1_Beta\n    { 0x85CB9DF9FC580C0EULL, { 0xD1, 0x70, 0xBC, 0xFC, 0x13, 0xB1, 0xA2, 0x18, 0x5C, 0x4F, 0xE1, 0x3C, 0x5F, 0x55, 0x5E, 0x2D } },   // WOW-33978patch9.0.1_Beta\n    { 0x867D98DC263C7AE1ULL, { 0xD6, 0xC5, 0xAE, 0x41, 0x33, 0xA0, 0xD3, 0x2F, 0x6A, 0x33, 0x39, 0x19, 0xC9, 0x95, 0xC2, 0x9F } },   // WOW-33978patch9.0.1_Beta\n    { 0x86ACAF9277898823ULL, { 0xE6, 0x3D, 0xFD, 0x69, 0x16, 0xBD, 0xDE, 0x96, 0x32, 0x63, 0x3B, 0x25, 0x5B, 0xEE, 0x73, 0x10 } },   // WOW-33978patch9.0.1_Beta\n    { 0x87413DE10A58AB14ULL, { 0x0B, 0x08, 0x32, 0x50, 0x17, 0x72, 0x9F, 0xD1, 0xBF, 0x2B, 0xA6, 0xC9, 0xEC, 0x03, 0xB0, 0x91 } },   // WOW-33978patch9.0.1_Beta\n    { 0x8831955158E50488ULL, { 0x12, 0x5E, 0x99, 0x2B, 0x50, 0xDD, 0x3C, 0x1D, 0x9B, 0xD5, 0xA4, 0x7D, 0xCA, 0xD7, 0x4F, 0x63 } },   // WOW-33978patch9.0.1_Beta\n    { 0x8A34D884566690F3ULL, { 0xD7, 0x7E, 0x4B, 0x5D, 0x2D, 0x5F, 0x2A, 0x07, 0xD1, 0xB7, 0x4C, 0x77, 0x2C, 0x7B, 0x9E, 0x1D } },   // WOW-33978patch9.0.1_Beta\n    { 0x8AA33E951B061C6CULL, { 0x45, 0xF8, 0xA8, 0x73, 0x94, 0x61, 0xA1, 0x5B, 0x5E, 0xEC, 0xDB, 0x8E, 0xD6, 0xD6, 0x68, 0x20 } },   // WOW-33978patch9.0.1_Beta\n    { 0x8AB2DCD201956FF5ULL, { 0xF4, 0x91, 0x31, 0x04, 0x7B, 0x25, 0xA7, 0xD3, 0x00, 0x67, 0xC7, 0xCB, 0x31, 0xF4, 0xB7, 0xC8 } },   // WOW-33978patch9.0.1_Beta\n    { 0x8AFF128B2C44402FULL, { 0x09, 0x28, 0x59, 0x7D, 0xDA, 0x06, 0x1C, 0xCA, 0x27, 0x72, 0x63, 0x9B, 0x18, 0x15, 0x3B, 0xBA } },   // WOW-33978patch9.0.1_Beta\n    { 0x929399E254952F89ULL, { 0x76, 0x23, 0x36, 0xB5, 0x0C, 0xBB, 0x8C, 0xBF, 0xA6, 0xEC, 0x6F, 0xF2, 0x97, 0x00, 0x96, 0x40 } },   // WOW-33978patch9.0.1_Beta\n    { 0x93A98F82D5B5FA3DULL, { 0x9A, 0x84, 0x56, 0x3A, 0xC7, 0xF1, 0x9E, 0x66, 0xAC, 0x4F, 0x63, 0x34, 0x6D, 0x58, 0xCB, 0xBC } },   // WOW-33978patch9.0.1_Beta\n    { 0x9440B38F8FC83801ULL, { 0xF2, 0x35, 0xB5, 0x29, 0x24, 0x61, 0xAD, 0xD2, 0xCD, 0x58, 0x27, 0x5F, 0xDA, 0xBF, 0x2D, 0x91 } },   // WOW-33978patch9.0.1_Beta\n    { 0x953B60DFAAD53C53ULL, { 0x0F, 0xFD, 0xE3, 0x48, 0xDB, 0xBF, 0x68, 0x28, 0x10, 0x38, 0x61, 0xE7, 0xC2, 0x02, 0xEE, 0x03 } },   // WOW-33978patch9.0.1_Beta\n    { 0x96CDB729EF5FF4D8ULL, { 0x9D, 0x5C, 0xD0, 0x16, 0x7D, 0xA6, 0x0B, 0x4A, 0x5D, 0x5B, 0x7E, 0xB1, 0x0F, 0x1F, 0x44, 0x02 } },   // WOW-33978patch9.0.1_Beta\n    { 0x96D55B6111ADB046ULL, { 0x7D, 0x8B, 0x9D, 0x2B, 0x57, 0x88, 0xCF, 0x14, 0x94, 0xE1, 0xBE, 0x73, 0xA3, 0x2A, 0x0A, 0xEB } },   // WOW-33978patch9.0.1_Beta\n    { 0x994C40C879819D41ULL, { 0x88, 0xA3, 0x28, 0x44, 0xB2, 0x2E, 0xB1, 0xE8, 0x36, 0x2B, 0x72, 0x8A, 0xE5, 0x1F, 0x66, 0x63 } },   // WOW-33978patch9.0.1_Beta\n    { 0x9A4F5BC0D2DF3E7CULL, { 0x27, 0x5D, 0x03, 0x60, 0xE8, 0x11, 0xEE, 0x2F, 0x3E, 0xB3, 0xBC, 0xCA, 0x96, 0xFA, 0x39, 0x88 } },   // WOW-33978patch9.0.1_Beta\n    { 0x9BB64D7C24F7F570ULL, { 0xA5, 0xF5, 0x27, 0xB1, 0x2A, 0x7C, 0x54, 0x49, 0x01, 0x30, 0x1F, 0x0C, 0xC4, 0xF7, 0x5A, 0xC6 } },   // WOW-33978patch9.0.1_Beta\n    { 0x9CAE05184985E6FAULL, { 0x7D, 0x79, 0xCA, 0x06, 0x09, 0xB2, 0xA9, 0xF5, 0x2C, 0x17, 0xB4, 0x91, 0xB2, 0x2F, 0xF2, 0x95 } },   // WOW-33978patch9.0.1_Beta\n    { 0x9DE3C22E44D3D817ULL, { 0x2A, 0xD1, 0x8A, 0xE6, 0x65, 0x74, 0xB1, 0x78, 0x4A, 0x9B, 0x52, 0xC4, 0xE4, 0x5C, 0x47, 0x0C } },   // WOW-33978patch9.0.1_Beta\n    { 0x9E10A1C6E2156E96ULL, { 0xA1, 0x4F, 0x9D, 0x5B, 0x4B, 0x8E, 0x6F, 0xFC, 0x17, 0x33, 0x48, 0xA8, 0x16, 0x89, 0x88, 0x2D } },   // WOW-33978patch9.0.1_Beta\n    { 0x9E84167C7BCCAECFULL, { 0xBB, 0x28, 0xC7, 0x41, 0x89, 0x32, 0x7B, 0xEC, 0x53, 0xC1, 0xF1, 0xD9, 0x0D, 0x62, 0xBD, 0xA6 } },   // WOW-33978patch9.0.1_Beta\n    { 0xA1651FBBB33533C8ULL, { 0xAB, 0x1E, 0x3D, 0x12, 0x8C, 0x6E, 0xC9, 0x4E, 0x6C, 0x7E, 0x0B, 0xAB, 0x3F, 0xF9, 0x6B, 0x54 } },   // WOW-33978patch9.0.1_Beta\n    { 0xA1F082630668B975ULL, { 0xA0, 0xC9, 0xAB, 0x98, 0x7F, 0x54, 0x4D, 0xAD, 0x86, 0x73, 0x5E, 0xEC, 0x3A, 0xB7, 0x0C, 0xBC } },   // WOW-33978patch9.0.1_Beta\n    { 0xA2A3787CEE9A05EEULL, { 0x2F, 0xAA, 0x35, 0x7F, 0x63, 0xC7, 0x2E, 0x74, 0x9B, 0x42, 0x3E, 0x45, 0xA7, 0x21, 0xE5, 0x49 } },   // WOW-33978patch9.0.1_Beta\n    { 0xA6D012ADD54A30CEULL, { 0x22, 0xE1, 0x30, 0x2E, 0xEB, 0xD9, 0x98, 0xCB, 0x7F, 0x05, 0xBC, 0xAF, 0x1D, 0x85, 0x39, 0xC6 } },   // WOW-33978patch9.0.1_Beta\n    { 0xA7E2CEFD0280FD3AULL, { 0x08, 0x90, 0x89, 0x66, 0x8F, 0xD4, 0xF2, 0xCA, 0x94, 0xE0, 0x28, 0xCE, 0x0E, 0x8F, 0x0E, 0xAD } },   // WOW-33978patch9.0.1_Beta\n    { 0xA8E1094D80B82D21ULL, { 0x8F, 0xA8, 0xB2, 0xEE, 0x12, 0xF4, 0x5E, 0xD0, 0xF2, 0x40, 0x1C, 0x03, 0x3B, 0x32, 0x43, 0x8C } },   // WOW-33978patch9.0.1_Beta\n    { 0xAA15EAD581169812ULL, { 0x60, 0xAA, 0x2D, 0x1C, 0xB7, 0xC2, 0x92, 0x84, 0xDD, 0x63, 0x6E, 0x35, 0x77, 0xAF, 0x3E, 0xFD } },   // WOW-33978patch9.0.1_Beta\n    { 0xAA3EB38B572073F9ULL, { 0xE5, 0xBC, 0x7A, 0x03, 0x54, 0xB6, 0x45, 0x39, 0xCA, 0x59, 0xB6, 0x78, 0x70, 0x3C, 0xE4, 0x72 } },   // WOW-33978patch9.0.1_Beta\n    { 0xAA7119519C968451ULL, { 0x57, 0x84, 0xAC, 0xD6, 0x7A, 0xAD, 0xFF, 0xA5, 0xA3, 0x50, 0x84, 0xC8, 0xB7, 0x97, 0x4B, 0x7E } },   // WOW-33978patch9.0.1_Beta\n    { 0xAAAD5C17B34A935FULL, { 0xB0, 0x95, 0x4F, 0x6A, 0x29, 0x14, 0x19, 0x10, 0x81, 0x00, 0x93, 0x49, 0xAF, 0x44, 0x43, 0xC3 } },   // WOW-33978patch9.0.1_Beta\n    { 0xABA6C1AFDB427F54ULL, { 0x29, 0x75, 0xC6, 0x9D, 0xA6, 0x14, 0xC3, 0xFF, 0x32, 0xEE, 0xC3, 0xFE, 0xD8, 0x47, 0x29, 0xDE } },   // WOW-33978patch9.0.1_Beta\n    { 0xADC58189215E1C48ULL, { 0x1F, 0xFB, 0xD3, 0xB8, 0xE6, 0x2A, 0x10, 0x24, 0x92, 0xDC, 0x30, 0x73, 0x21, 0x16, 0xF1, 0x62 } },   // WOW-33978patch9.0.1_Beta\n    { 0xAFEE51897035872EULL, { 0xF0, 0x85, 0xEA, 0xBC, 0x11, 0xE2, 0x92, 0xD2, 0x0C, 0x77, 0x8B, 0x6D, 0x89, 0x2A, 0xBD, 0x1E } },   // WOW-33978patch9.0.1_Beta\n    { 0xAFFFA5791F73520AULL, { 0xA9, 0x67, 0xF2, 0xF4, 0x7E, 0x7C, 0xC0, 0x05, 0xCB, 0x8D, 0x7E, 0x92, 0x84, 0x78, 0x15, 0x8E } },   // WOW-33978patch9.0.1_Beta\n    { 0xB032F43502EDFA5AULL, { 0x4B, 0x0E, 0xF7, 0x9E, 0x47, 0x2D, 0x00, 0x2F, 0x8E, 0x71, 0x7E, 0xED, 0x75, 0xB0, 0x3E, 0x69 } },   // WOW-33978patch9.0.1_Beta\n    { 0xB23472311441BF43ULL, { 0x3E, 0xE4, 0x12, 0x48, 0xB9, 0x9B, 0xF6, 0xA1, 0x7E, 0xF9, 0x63, 0xC2, 0xD6, 0x88, 0x7B, 0xF5 } },   // WOW-33978patch9.0.1_Beta\n    { 0xB4582D7E642035F5ULL, { 0xCA, 0x5B, 0x90, 0xA2, 0x8C, 0x7D, 0xAE, 0xF5, 0xAC, 0x8B, 0xA2, 0x6A, 0x3B, 0x7E, 0xB2, 0x6F } },   // WOW-33978patch9.0.1_Beta\n    { 0xB46B23A8B047E71AULL, { 0x5F, 0xD3, 0xB3, 0xE6, 0xFF, 0x1B, 0xEB, 0x79, 0x6B, 0x13, 0xA0, 0x44, 0x7C, 0x8C, 0x9E, 0xCE } },   // WOW-33978patch9.0.1_Beta\n    { 0xB62985BE1B0E820CULL, { 0x7B, 0xCB, 0x7A, 0x3A, 0x7A, 0x7F, 0xE6, 0x72, 0xD7, 0xBB, 0x8D, 0xAB, 0x4C, 0x32, 0x66, 0xCA } },   // WOW-33978patch9.0.1_Beta\n    { 0xB76D3CD9FA80EF23ULL, { 0x43, 0x2F, 0xDE, 0xF3, 0x70, 0xE6, 0x84, 0x73, 0xCE, 0xB7, 0x5B, 0xE4, 0x80, 0x28, 0x71, 0x49 } },   // WOW-33978patch9.0.1_Beta\n    { 0xB881ACD9C433C39BULL, { 0x41, 0x5B, 0xEC, 0x80, 0x13, 0x4B, 0x91, 0xEB, 0xA7, 0xA8, 0x94, 0xE8, 0x11, 0x1F, 0x16, 0xED } },   // WOW-33978patch9.0.1_Beta\n    { 0xB8F711CD1BCCCB5AULL, { 0x06, 0x8D, 0xA8, 0x49, 0x5F, 0x4F, 0x87, 0x05, 0x08, 0xDF, 0xAF, 0xCE, 0xFA, 0xB3, 0x4F, 0x6C } },   // WOW-33978patch9.0.1_Beta\n    { 0xBA2586D5321809C9ULL, { 0x37, 0x08, 0xFF, 0xBC, 0xD5, 0xDE, 0x8B, 0xA1, 0x1E, 0x7A, 0xE2, 0xF2, 0x10, 0x88, 0xF5, 0xE0 } },   // WOW-33978patch9.0.1_Beta\n    { 0xBB56A0BAE42B0A58ULL, { 0x36, 0xF6, 0x57, 0xC6, 0x27, 0x16, 0xEA, 0x72, 0xEB, 0x46, 0x44, 0x6C, 0xD3, 0x6E, 0xF0, 0x81 } },   // WOW-33978patch9.0.1_Beta\n    { 0xBBC9FAFBFB8A476EULL, { 0xDF, 0x8F, 0x45, 0x6C, 0xE6, 0xF4, 0x2B, 0x83, 0x29, 0xD6, 0xAB, 0x75, 0x44, 0x5E, 0x93, 0x47 } },   // WOW-33978patch9.0.1_Beta\n    { 0xBDE676123BBB010AULL, { 0x9A, 0x68, 0x26, 0xB6, 0x35, 0x2B, 0xF4, 0x47, 0xC5, 0x52, 0x6F, 0x3D, 0x80, 0xB2, 0xA4, 0x2A } },   // WOW-33978patch9.0.1_Beta\n    { 0xBE78B15D2D2FFC28ULL, { 0x18, 0x63, 0x5E, 0xA1, 0xEA, 0x0D, 0x52, 0xA8, 0x04, 0x34, 0x5D, 0x74, 0x2E, 0x47, 0xE7, 0xFF } },   // WOW-33978patch9.0.1_Beta\n    { 0xBF0DA6AAE66E25A0ULL, { 0xFB, 0x2D, 0xEA, 0x41, 0xD6, 0x00, 0xF3, 0x95, 0xB4, 0x1F, 0x1D, 0x21, 0x9C, 0x2F, 0xDE, 0x4D } },   // WOW-33978patch9.0.1_Beta\n    { 0xBF26C727BFC92EAFULL, { 0x5E, 0xD5, 0x02, 0xEE, 0xFB, 0x92, 0x1A, 0x27, 0xC1, 0x83, 0x6A, 0x8E, 0x5E, 0x4A, 0x15, 0x92 } },   // WOW-33978patch9.0.1_Beta\n    { 0xBF874CF500A50632ULL, { 0x87, 0xB9, 0x5B, 0xE0, 0x9C, 0xEE, 0x36, 0xDC, 0x91, 0x43, 0x04, 0x70, 0x95, 0x2E, 0xF3, 0x26 } },   // WOW-33978patch9.0.1_Beta\n    { 0xBF87DE9EFBA3E7E7ULL, { 0x2A, 0x2C, 0x1E, 0x9A, 0xCA, 0x4F, 0xCD, 0x01, 0xF8, 0xF6, 0x40, 0x66, 0x76, 0x70, 0x63, 0x79 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC132034A5F2F7E10ULL, { 0x27, 0x3B, 0xA2, 0x00, 0x5D, 0x7C, 0xDE, 0xDD, 0xB1, 0x67, 0x5C, 0x8C, 0x0F, 0x74, 0x1B, 0x7A } },   // WOW-33978patch9.0.1_Beta\n    { 0xC16F60A6BAD360C0ULL, { 0xBB, 0x8E, 0xF0, 0x39, 0x32, 0xAC, 0x38, 0xC6, 0xCE, 0x11, 0xFE, 0x67, 0x96, 0xEB, 0xBD, 0xEC } },   // WOW-33978patch9.0.1_Beta\n    { 0xC2BCD68E7A2AE4AFULL, { 0x89, 0x48, 0x11, 0x50, 0x8B, 0x28, 0xE9, 0x0B, 0xFA, 0xB0, 0x28, 0x4D, 0xA2, 0x3E, 0xE5, 0x06 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC312DAF915B31117ULL, { 0xDA, 0xB0, 0x06, 0x6B, 0x4F, 0x8C, 0xD0, 0x79, 0x54, 0x8C, 0xE7, 0x52, 0x88, 0x4E, 0x19, 0x49 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC63B911BD06869D3ULL, { 0xCB, 0x82, 0xD1, 0x56, 0x11, 0xA0, 0x96, 0xAA, 0xD6, 0xB2, 0xD9, 0x48, 0x8A, 0x87, 0x93, 0x9A } },   // WOW-33978patch9.0.1_Beta\n    { 0xC65443D5AB354639ULL, { 0xA9, 0x85, 0x72, 0x55, 0xBB, 0x6E, 0x5A, 0x75, 0xFA, 0x9A, 0xFE, 0xC8, 0xDA, 0xC2, 0xB0, 0x7A } },   // WOW-33978patch9.0.1_Beta\n    { 0xC8167C2D20426AD8ULL, { 0xF4, 0xF7, 0x7B, 0x2C, 0xA8, 0x36, 0xA4, 0xF9, 0xBE, 0x53, 0x61, 0x6E, 0xC6, 0x2D, 0x61, 0x84 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC88BB3653C3C964FULL, { 0x7B, 0x61, 0xCA, 0x6E, 0x9C, 0x98, 0x29, 0xF2, 0xF4, 0x52, 0xD2, 0x17, 0x37, 0xD9, 0xD7, 0x23 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC926C2CBE0DFF9BEULL, { 0x9D, 0x29, 0x47, 0x37, 0xAB, 0x13, 0xC3, 0x6B, 0x02, 0xEC, 0x0E, 0x0B, 0x77, 0x65, 0x7B, 0x13 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC9A159E7B047AE82ULL, { 0xE4, 0x3C, 0x35, 0x49, 0xE6, 0x0E, 0xB1, 0x2C, 0x49, 0xF9, 0xE9, 0x57, 0x38, 0x61, 0xA5, 0xE0 } },   // WOW-33978patch9.0.1_Beta\n    { 0xC9F63551DC0A7DD3ULL, { 0xAA, 0xD6, 0xE9, 0xB5, 0x71, 0x97, 0x1E, 0x0A, 0xE9, 0x21, 0x22, 0xE9, 0x77, 0x28, 0x96, 0xDC } },   // WOW-33978patch9.0.1_Beta\n    { 0xC9FDAB91F9DABA18ULL, { 0x02, 0x5D, 0xF3, 0x9D, 0x8B, 0xF6, 0x32, 0xE6, 0x8B, 0x0A, 0x4E, 0x74, 0xC1, 0x44, 0x2A, 0x24 } },   // WOW-33978patch9.0.1_Beta\n    { 0xCA9C5B912FFBCAC7ULL, { 0xAF, 0xEE, 0xA5, 0xF1, 0x64, 0xC4, 0x0C, 0xF3, 0x84, 0x98, 0xD8, 0xBC, 0x5A, 0x0C, 0x6B, 0x8F } },   // WOW-33978patch9.0.1_Beta\n    { 0xCB4D2A3F81E1794EULL, { 0x12, 0x0C, 0x6B, 0x4A, 0x25, 0x41, 0xB5, 0xA9, 0x79, 0x81, 0x0C, 0x35, 0x38, 0x8C, 0x56, 0xF1 } },   // WOW-33978patch9.0.1_Beta\n    { 0xCBBACF102B89411FULL, { 0xE0, 0x4C, 0x71, 0x77, 0x15, 0xB0, 0x06, 0x11, 0xAC, 0x7E, 0xA9, 0x7D, 0x0B, 0x45, 0xAA, 0x0C } },   // WOW-33978patch9.0.1_Beta\n    { 0xD0C5486A7AD05CF9ULL, { 0x54, 0x84, 0xBE, 0x9C, 0xB3, 0x7D, 0xE9, 0x51, 0x12, 0xA1, 0x8B, 0x60, 0x52, 0xC5, 0xA7, 0xE5 } },   // WOW-33978patch9.0.1_Beta\n    { 0xD362C01C25B71B50ULL, { 0x08, 0xFB, 0x22, 0xF6, 0xA9, 0x52, 0x2A, 0x48, 0xCA, 0x24, 0x79, 0xCD, 0xED, 0x66, 0xA1, 0x75 } },   // WOW-33978patch9.0.1_Beta\n    { 0xD3CD986A5533AE96ULL, { 0x56, 0x70, 0x8F, 0x30, 0x77, 0xB7, 0x24, 0x88, 0x10, 0xC7, 0xB8, 0x7E, 0xDA, 0xCF, 0x25, 0xC2 } },   // WOW-33978patch9.0.1_Beta\n    { 0xD628DFD6FD4C4629ULL, { 0x30, 0x0F, 0x61, 0x98, 0xF8, 0xD3, 0x4F, 0x71, 0x81, 0x11, 0x61, 0x52, 0x13, 0x31, 0x4E, 0x07 } },   // WOW-33978patch9.0.1_Beta\n    { 0xD843A7FFCE96C7AEULL, { 0x08, 0xF1, 0xDE, 0x2D, 0x96, 0xEB, 0x99, 0x9C, 0x89, 0xA1, 0xD4, 0xE3, 0xBD, 0x22, 0x34, 0x3D } },   // WOW-33978patch9.0.1_Beta\n    { 0xD8EDA6A4C2799AFCULL, { 0x82, 0xD9, 0x7B, 0x8F, 0x98, 0x6A, 0xF1, 0x57, 0x66, 0xC8, 0x9F, 0x61, 0x1C, 0x14, 0x68, 0x88 } },   // WOW-33978patch9.0.1_Beta\n    { 0xDB37969AE172E0A2ULL, { 0xE0, 0x71, 0xBF, 0xF3, 0x31, 0x7D, 0x6F, 0xCC, 0x61, 0x12, 0xE8, 0xCB, 0xF0, 0x4B, 0x9E, 0x84 } },   // WOW-33978patch9.0.1_Beta\n    { 0xDBD4F370AE374627ULL, { 0x0D, 0x78, 0x08, 0xF6, 0x29, 0xBE, 0x2E, 0x0B, 0xE2, 0x80, 0x73, 0x1F, 0x9C, 0xCD, 0x51, 0xAE } },   // WOW-33978patch9.0.1_Beta\n    { 0xDC692CF534CF6094ULL, { 0xA6, 0x41, 0xD3, 0x32, 0xCE, 0x02, 0xCF, 0x14, 0x71, 0x42, 0x9F, 0xA3, 0x5B, 0x9C, 0xC2, 0x2A } },   // WOW-33978patch9.0.1_Beta\n    { 0xDE7D8C810DEBCCBBULL, { 0x39, 0xBD, 0x23, 0xF7, 0xBA, 0x29, 0x73, 0xCF, 0x57, 0x36, 0xE8, 0xA4, 0xD1, 0x37, 0xA2, 0x59 } },   // WOW-33978patch9.0.1_Beta\n    { 0xDFDBE74EFD0C1D9AULL, { 0x80, 0xA6, 0x40, 0x5D, 0xCA, 0x4A, 0xDB, 0x58, 0x04, 0xDF, 0xF3, 0x9E, 0x25, 0xAA, 0x6A, 0xF0 } },   // WOW-33978patch9.0.1_Beta\n    { 0xE186FB75B0C94A7CULL, { 0x9F, 0x7B, 0x27, 0xC6, 0xD8, 0x4C, 0x80, 0x59, 0xEF, 0xD8, 0x81, 0x56, 0x0C, 0x84, 0xFB, 0xF2 } },   // WOW-33978patch9.0.1_Beta\n    { 0xE26933D3B03457B8ULL, { 0xE4, 0xE9, 0x79, 0x3A, 0x4B, 0x0F, 0xFA, 0x09, 0xC6, 0x9A, 0x2F, 0xB3, 0xC4, 0x86, 0xE4, 0x5C } },   // WOW-33978patch9.0.1_Beta\n    { 0xE2D4CD545D19C5B3ULL, { 0x5F, 0x4D, 0xC6, 0x65, 0x17, 0xB5, 0x26, 0xCF, 0x48, 0x18, 0xDD, 0xDA, 0x50, 0xAE, 0xD6, 0x2A } },   // WOW-33978patch9.0.1_Beta\n    { 0xE321D1E0F5FD72D1ULL, { 0x39, 0x7A, 0xB9, 0x76, 0xC9, 0xFF, 0x03, 0x78, 0x37, 0xF9, 0x26, 0x00, 0xBE, 0x75, 0x4C, 0x63 } },   // WOW-33978patch9.0.1_Beta\n    { 0xE50F70F06A579FCCULL, { 0xE2, 0xB1, 0x53, 0x8D, 0x2C, 0x14, 0xAD, 0x00, 0xC9, 0xF2, 0xB1, 0xFE, 0x56, 0xC1, 0xF0, 0xD2 } },   // WOW-33978patch9.0.1_Beta\n    { 0xE6DE529515D5322EULL, { 0x1D, 0x58, 0x84, 0x6A, 0x1C, 0x87, 0x1B, 0xA0, 0x8C, 0x2E, 0xCD, 0x7B, 0x32, 0xFA, 0xCA, 0x41 } },   // WOW-33978patch9.0.1_Beta\n    { 0xE6F58B08B45D7A12ULL, { 0x18, 0xF3, 0x4D, 0xA5, 0xA6, 0x91, 0xF6, 0xAA, 0xF1, 0xF9, 0xA7, 0x05, 0xB6, 0x56, 0xE0, 0x1F } },   // WOW-33978patch9.0.1_Beta\n    { 0xE7357F7B88B8338DULL, { 0x9B, 0xAC, 0x5D, 0x21, 0x9C, 0xE7, 0x19, 0x84, 0xCB, 0xD6, 0xBE, 0x98, 0xE7, 0x2A, 0xB8, 0x3C } },   // WOW-33978patch9.0.1_Beta\n    { 0xE8F494F7E371D157ULL, { 0x4E, 0x2C, 0xDA, 0xA4, 0x18, 0x44, 0x03, 0x48, 0xE4, 0x39, 0x99, 0x5D, 0x64, 0x28, 0x4B, 0x73 } },   // WOW-33978patch9.0.1_Beta\n    { 0xE995E22AF7111D57ULL, { 0x33, 0xE8, 0xD6, 0x3D, 0xF4, 0xA8, 0xCE, 0x36, 0xD1, 0x88, 0xEC, 0x07, 0x22, 0x09, 0xD1, 0x84 } },   // WOW-33978patch9.0.1_Beta\n    { 0xEA9589F00A338035ULL, { 0xEC, 0xCB, 0x9C, 0xA5, 0x7C, 0xA0, 0x30, 0x33, 0x9B, 0x2D, 0xBA, 0x74, 0x5B, 0x5C, 0x14, 0x9B } },   // WOW-33978patch9.0.1_Beta\n    { 0xEAC344DACB040496ULL, { 0x51, 0x22, 0xD6, 0x18, 0x1F, 0x79, 0x71, 0x9A, 0x81, 0x7B, 0xBF, 0x84, 0xA2, 0xB5, 0x7B, 0xA1 } },   // WOW-33978patch9.0.1_Beta\n    { 0xEB5B9AA992D0582BULL, { 0x3A, 0xC4, 0xA8, 0x0F, 0x38, 0x66, 0x3F, 0xB3, 0xAD, 0xEB, 0x1C, 0xE5, 0x5E, 0xD3, 0xC1, 0x4D } },   // WOW-33978patch9.0.1_Beta\n    { 0xEB824892D843D365ULL, { 0x39, 0x4F, 0xCE, 0x26, 0x76, 0x68, 0x05, 0xA7, 0x68, 0x14, 0xB2, 0x5B, 0x4B, 0x72, 0xB4, 0xD8 } },   // WOW-33978patch9.0.1_Beta\n    { 0xEC434CD731FF1D6EULL, { 0x84, 0xC4, 0x3B, 0x20, 0xA6, 0x33, 0x66, 0x82, 0xB5, 0xAA, 0x1D, 0x7C, 0xFA, 0x00, 0xDA, 0xE3 } },   // WOW-33978patch9.0.1_Beta\n    { 0xED4548400C6CD9B3ULL, { 0xDD, 0xAE, 0x53, 0x8A, 0x39, 0x59, 0x16, 0x11, 0xBF, 0x1D, 0x2E, 0xEE, 0x97, 0x34, 0xF8, 0xDD } },   // WOW-33978patch9.0.1_Beta\n    { 0xED85FA32ABE4D31AULL, { 0xC9, 0x35, 0xBB, 0xCB, 0x24, 0x70, 0xF2, 0x97, 0xEA, 0x61, 0xF8, 0x66, 0x9D, 0xE7, 0x38, 0x10 } },   // WOW-33978patch9.0.1_Beta\n    { 0xEDB14BC9682C3EC7ULL, { 0x07, 0x63, 0x2A, 0xA3, 0x73, 0xD5, 0x08, 0xD9, 0x94, 0x81, 0x64, 0x6E, 0xF5, 0x2C, 0x6F, 0x21 } },   // WOW-33978patch9.0.1_Beta\n    { 0xEFD8CF7039C9E3ABULL, { 0x6B, 0xA7, 0x1A, 0xEC, 0x7C, 0xF7, 0xED, 0x83, 0xE7, 0xD4, 0x7A, 0x47, 0xE1, 0xAA, 0x97, 0x58 } },   // WOW-33978patch9.0.1_Beta\n    { 0xEFF36C5D384458ADULL, { 0x9F, 0x0B, 0x12, 0x0C, 0x9D, 0x86, 0xB5, 0x9B, 0x2C, 0x8B, 0x5E, 0xB0, 0x6C, 0xE0, 0x33, 0xC2 } },   // WOW-33978patch9.0.1_Beta\n    { 0xF04AF4C9E8BD1063ULL, { 0x62, 0xDB, 0x73, 0x69, 0x77, 0x96, 0x60, 0xE4, 0xAC, 0x83, 0xB1, 0xAF, 0x77, 0xCD, 0x86, 0x0A } },   // WOW-33978patch9.0.1_Beta\n    { 0xF0C135866D740895ULL, { 0x44, 0xAD, 0xC9, 0xAC, 0xBE, 0xD5, 0x0F, 0x49, 0x0A, 0xD8, 0xD5, 0xEE, 0xA8, 0x13, 0xDB, 0x69 } },   // WOW-33978patch9.0.1_Beta\n    { 0xF399E2091BB4EB3DULL, { 0xC3, 0x8C, 0x68, 0x01, 0x59, 0xE6, 0x3F, 0x03, 0x65, 0xFF, 0x10, 0xC6, 0xB4, 0x8C, 0xF6, 0xBC } },   // WOW-33978patch9.0.1_Beta\n    { 0xF4941ADAEFD62B50ULL, { 0x4E, 0x37, 0xCC, 0x48, 0xF5, 0x1E, 0x3B, 0x5F, 0x73, 0xCC, 0xD7, 0x41, 0x90, 0x91, 0xE3, 0xB6 } },   // WOW-33978patch9.0.1_Beta\n    { 0xF4A0D7C6BE16E9E6ULL, { 0xB9, 0x6B, 0x07, 0x4E, 0x60, 0xBB, 0x6B, 0x0C, 0x3F, 0xFD, 0x1F, 0xBC, 0x87, 0x77, 0x36, 0x7C } },   // WOW-33978patch9.0.1_Beta\n    { 0xF5BC79A1093D4297ULL, { 0xE1, 0x18, 0x0A, 0x55, 0xA6, 0x7B, 0x29, 0xAC, 0xDA, 0x9B, 0x6A, 0x3A, 0x70, 0x4C, 0x90, 0x27 } },   // WOW-33978patch9.0.1_Beta\n    { 0xF88CD79C16ED40C1ULL, { 0xED, 0x5B, 0xC5, 0xBF, 0x5D, 0x1E, 0xD1, 0x69, 0x51, 0x9F, 0x85, 0x9F, 0x4C, 0xEB, 0xAB, 0xA9 } },   // WOW-33978patch9.0.1_Beta\n    { 0xF9B971BF3BAE0F5FULL, { 0x41, 0x6A, 0x38, 0x03, 0x5B, 0xAD, 0xD4, 0xC2, 0x7A, 0x14, 0xF1, 0xE8, 0x74, 0xB1, 0x0F, 0xFC } },   // WOW-33978patch9.0.1_Beta\n    { 0xFA6C85CFB99D0738ULL, { 0x41, 0xFA, 0x48, 0x6B, 0x2F, 0xEB, 0x68, 0xFB, 0x96, 0x64, 0xD4, 0x22, 0xAA, 0xF1, 0x71, 0x38 } },   // WOW-33978patch9.0.1_Beta\n    { 0xFB90D71D100E9595ULL, { 0xB7, 0xA7, 0x6E, 0x35, 0x33, 0x75, 0x11, 0xB4, 0xA2, 0x6E, 0xE9, 0xBE, 0x0E, 0xCA, 0xD3, 0xD0 } },   // WOW-33978patch9.0.1_Beta\n    { 0xFD06442092131C5EULL, { 0x3E, 0x55, 0xE1, 0x47, 0xB6, 0x53, 0xB5, 0xF9, 0xE6, 0x8E, 0xAB, 0x44, 0x90, 0x8F, 0xBD, 0xC1 } },   // WOW-33978patch9.0.1_Beta\n    { 0xFD0BA919048A69AAULL, { 0x66, 0xE4, 0x75, 0xF4, 0x60, 0x26, 0xB0, 0x91, 0xAD, 0xD4, 0xA3, 0xE1, 0xBC, 0x61, 0x96, 0x91 } },   // WOW-33978patch9.0.1_Beta\n    { 0xFF08D3B90FB93B8CULL, { 0xD4, 0x27, 0x97, 0x22, 0xFB, 0x8B, 0xDD, 0x2A, 0xA8, 0xB3, 0xA4, 0xC7, 0x4E, 0xFD, 0x44, 0xCA } },   // WOW-33978patch9.0.1_Beta\n    { 0xFF7C9A1B789D0D42ULL, { 0xA9, 0xEC, 0x27, 0x53, 0x3B, 0x7D, 0x9D, 0xB1, 0xE2, 0x39, 0xEC, 0x68, 0x8B, 0xA6, 0x53, 0xF4 } },   // WOW-33978patch9.0.1_Beta\n};\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nstatic void Initialize(PCASC_SALSA20 pState, LPBYTE pbKey, DWORD cbKeyLength, LPBYTE pbVector)\n{\n    const char * szConstants = (cbKeyLength == 32) ? szKeyConstant32 : szKeyConstant16;\n    DWORD KeyIndex = cbKeyLength - 0x10;\n\n    memset(pState, 0, sizeof(CASC_SALSA20));\n    pState->Key[0]  = *(PDWORD)(szConstants + 0x00);\n    pState->Key[1]  = *(PDWORD)(pbKey + 0x00);\n    pState->Key[2]  = *(PDWORD)(pbKey + 0x04);\n    pState->Key[3]  = *(PDWORD)(pbKey + 0x08);\n    pState->Key[4]  = *(PDWORD)(pbKey + 0x0C);\n    pState->Key[5]  = *(PDWORD)(szConstants + 0x04);\n    pState->Key[6]  = *(PDWORD)(pbVector + 0x00);\n    pState->Key[7]  = *(PDWORD)(pbVector + 0x04);\n    pState->Key[8]  = 0;\n    pState->Key[9]  = 0;\n    pState->Key[10] = *(PDWORD)(szConstants + 0x08);\n    pState->Key[11] = *(PDWORD)(pbKey + KeyIndex + 0x00);\n    pState->Key[12] = *(PDWORD)(pbKey + KeyIndex + 0x04);\n    pState->Key[13] = *(PDWORD)(pbKey + KeyIndex + 0x08);\n    pState->Key[14] = *(PDWORD)(pbKey + KeyIndex + 0x0C);\n    pState->Key[15] = *(PDWORD)(szConstants + 0x0C);\n\n    pState->dwRounds = 20;\n}\n\nstatic int Decrypt(PCASC_SALSA20 pState, LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer)\n{\n    LPBYTE pbXorValue;\n    DWORD KeyMirror[0x10];\n    DWORD XorValue[0x10];\n    DWORD BlockSize;\n    DWORD i;\n\n    // Repeat until we have data to read\n    while(cbInBuffer > 0)\n    {\n        // Create the copy of the key\n        memcpy(KeyMirror, pState->Key, sizeof(KeyMirror));\n\n        // Shuffle the key\n        for(i = 0; i < pState->dwRounds; i += 2)\n        {\n            KeyMirror[0x04] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x0C]), 0x07);\n            KeyMirror[0x08] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x00]), 0x09);\n            KeyMirror[0x0C] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x04]), 0x0D);\n            KeyMirror[0x00] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x08]), 0x12);\n\n            KeyMirror[0x09] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x01]), 0x07);\n            KeyMirror[0x0D] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x05]), 0x09);\n            KeyMirror[0x01] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x09]), 0x0D);\n            KeyMirror[0x05] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x0D]), 0x12);\n\n            KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x06]), 0x07);\n            KeyMirror[0x02] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0A]), 0x09);\n            KeyMirror[0x06] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x0E]), 0x0D);\n            KeyMirror[0x0A] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x02]), 0x12);\n\n            KeyMirror[0x03] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0B]), 0x07);\n            KeyMirror[0x07] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x0F]), 0x09);\n            KeyMirror[0x0B] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x03]), 0x0D);\n            KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x07]), 0x12);\n\n            KeyMirror[0x01] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x03]), 0x07);\n            KeyMirror[0x02] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x00]), 0x09);\n            KeyMirror[0x03] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x01]), 0x0D);\n            KeyMirror[0x00] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x02]), 0x12);\n\n            KeyMirror[0x06] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x04]), 0x07);\n            KeyMirror[0x07] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x05]), 0x09);\n            KeyMirror[0x04] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x06]), 0x0D);\n            KeyMirror[0x05] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x07]), 0x12);\n\n            KeyMirror[0x0B] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x09]), 0x07);\n            KeyMirror[0x08] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x0A]), 0x09);\n            KeyMirror[0x09] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x0B]), 0x0D);\n            KeyMirror[0x0A] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x08]), 0x12);\n\n            KeyMirror[0x0C] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0E]), 0x07);\n            KeyMirror[0x0D] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x0F]), 0x09);\n            KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x0C]), 0x0D);\n            KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0D]), 0x12);\n        }\n\n        // Set the number of remaining bytes\n        pbXorValue = (LPBYTE)XorValue;\n        BlockSize = (DWORD)CASCLIB_MIN(cbInBuffer, 0x40);\n\n        // Prepare the XOR constants\n        for(i = 0; i < 16; i++)\n        {\n            XorValue[i] = KeyMirror[i] + pState->Key[i];\n        }\n\n        // Decrypt the block\n        for(i = 0; i < BlockSize; i++)\n        {\n            pbOutBuffer[i] = pbInBuffer[i] ^ pbXorValue[i];\n        }\n\n        pState->Key[8] = pState->Key[8] + 1;\n        if(pState->Key[8] == 0)\n            pState->Key[9] = pState->Key[9] + 1;\n\n        // Adjust buffers\n        pbOutBuffer += BlockSize;\n        pbInBuffer += BlockSize;\n        cbInBuffer -= BlockSize;\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic int Decrypt_Salsa20(LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer, LPBYTE pbKey, DWORD cbKeySize, LPBYTE pbVector)\n{\n    CASC_SALSA20 SalsaState;\n\n    Initialize(&SalsaState, pbKey, cbKeySize, pbVector);\n    return Decrypt(&SalsaState, pbOutBuffer, pbInBuffer, cbInBuffer);\n}\n\n//-----------------------------------------------------------------------------\n// Key map implementation\n\nstatic PCASC_ENCRYPTION_KEY2 CreateKeyItem(ULONGLONG KeyName, LPBYTE Key)\n{\n    PCASC_ENCRYPTION_KEY2 pNewItem;\n\n    if((pNewItem = new CASC_ENCRYPTION_KEY2) != NULL)\n    {\n        memset(pNewItem, 0, sizeof(CASC_ENCRYPTION_KEY2));\n        pNewItem->KeyName = KeyName;\n        memcpy(pNewItem->Key, Key, CASC_KEY_LENGTH);\n    }\n\n    return pNewItem;\n}\n\nCASC_KEY_MAP::CASC_KEY_MAP()\n{\n    memset(HashTable, 0, sizeof(HashTable));\n}\n\nCASC_KEY_MAP::~CASC_KEY_MAP()\n{\n    PCASC_ENCRYPTION_KEY2 pNextItem;\n    PCASC_ENCRYPTION_KEY2 pKeyItem;\n\n    for(size_t i = 0; i < CASC_KEY_TABLE_SIZE; i++)\n    {\n        if((pKeyItem = (PCASC_ENCRYPTION_KEY2)HashTable[i]) != NULL)\n        {\n            while(pKeyItem != NULL)\n            {\n                pNextItem = pKeyItem->pNext;\n                delete pKeyItem;\n                pKeyItem = pNextItem;\n            }\n        }\n    }\n}\n\nLPBYTE CASC_KEY_MAP::FindKey(ULONGLONG KeyName)\n{\n    PCASC_ENCRYPTION_KEY2 pKeyItem = NULL;\n    size_t HashIndex = (size_t)(KeyName & CASC_KEY_TABLE_MASK);\n\n    // Check the key chain beginning at the hash table\n    pKeyItem = (PCASC_ENCRYPTION_KEY2)HashTable[HashIndex];\n    while(pKeyItem != NULL)\n    {\n        if(pKeyItem->KeyName == KeyName)\n            return pKeyItem->Key;\n        pKeyItem = pKeyItem->pNext;\n    }\n\n    // Not found\n    return NULL;\n}\n\nbool CASC_KEY_MAP::AddKey(ULONGLONG KeyName, LPBYTE Key)\n{\n    PCASC_ENCRYPTION_KEY2 pKeyItem;\n    PCASC_ENCRYPTION_KEY2 pNewItem;\n    size_t HashIndex = (size_t)(KeyName & CASC_KEY_TABLE_MASK);\n\n    // Is the key already there?\n    if(FindKey(KeyName) == NULL)\n    {\n        // Create new key item\n        if((pNewItem = CreateKeyItem(KeyName, Key)) == NULL)\n            return false;\n\n        if(HashTable[HashIndex] != NULL)\n        {\n            // Get the last-in-chain key item\n            pKeyItem = (PCASC_ENCRYPTION_KEY2)(HashTable[HashIndex]);\n            while(pKeyItem->pNext != NULL)\n                pKeyItem = pKeyItem->pNext;\n\n            // Insert the key to the chain\n            pKeyItem->pNext = pNewItem;\n            return true;\n        }\n        else\n        {\n            HashTable[HashIndex] = pNewItem;\n            return true;\n        }\n    }\n\n    // Already exists, it's OK\n    return true;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nDWORD CascLoadEncryptionKeys(TCascStorage * hs)\n{\n    for(size_t i = 0; i < _countof(StaticCascKeys); i++)\n    {\n        if(!hs->KeyMap.AddKey(StaticCascKeys[i].KeyName, StaticCascKeys[i].Key))\n        {\n            return ERROR_NOT_ENOUGH_MEMORY;\n        }\n    }\n\n    return ERROR_SUCCESS;\n}\n\nbool WINAPI CascAddEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPBYTE Key)\n{\n    TCascStorage * hs;\n\n    // Validate the storage handle\n    hs = TCascStorage::IsValid(hStorage);\n    if (hs == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // Add the key to the map and return result\n    return hs->KeyMap.AddKey(KeyName, Key);\n}\n\nbool WINAPI CascAddStringEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPCSTR szKey)\n{\n    BYTE Key[CASC_KEY_LENGTH];\n\n    // Check the length of the string key\n    if(strlen(szKey) != CASC_KEY_LENGTH * 2)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // Convert the string key to the binary array\n    if(BinaryFromString(szKey, CASC_KEY_LENGTH * 2, Key) != ERROR_SUCCESS)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    return CascAddEncryptionKey(hStorage, KeyName, Key);\n}\n\nLPBYTE WINAPI CascFindEncryptionKey(HANDLE hStorage, ULONGLONG KeyName)\n{\n    TCascStorage * hs;\n\n    // Validate the storage handle\n    hs = TCascStorage::IsValid(hStorage);\n    if (hs == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return NULL;\n    }\n\n    // Return the result from the map's search function\n    return hs->KeyMap.FindKey(KeyName);\n}\n\nbool WINAPI CascGetNotFoundEncryptionKey(HANDLE hStorage, ULONGLONG * KeyName)\n{\n    TCascStorage * hs;\n\n    // Validate the storage handle\n    if ((hs = TCascStorage::IsValid(hStorage)) == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // If there was no decryption key error, just return false with ERROR_SUCCESS\n    if(hs->LastFailKeyName == 0)\n    {\n        SetCascError(ERROR_SUCCESS);\n        return false;\n    }\n\n    // Give the name of the key that failed most recently\n    KeyName[0] = hs->LastFailKeyName;\n    return true;\n}\n\nbool WINAPI CascImportKeysFromString(HANDLE hStorage, LPCSTR szKeyList)\n{\n    // Verify parameters\n    if(TCascStorage::IsValid(hStorage) == NULL || szKeyList == NULL || szKeyList[0] == 0)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // Parse text file\n    while(szKeyList[0])\n    {\n        ULONGLONG KeyName = 0;\n        DWORD dwErrCode;\n        BYTE KeyValue[CASC_KEY_LENGTH];\n\n        // Capture key name\n        dwErrCode = ConvertStringToInt(szKeyList, 0, KeyName, &szKeyList);\n        if(dwErrCode != ERROR_SUCCESS)\n        {\n            SetCascError(dwErrCode);\n            return false;\n        }\n\n        // TACT key list downloaded from https://wow.tools/api.php?type=tactkeys ends with a single zero\n        if(KeyName == 0)\n            break;\n\n        // We only expect spaces and tabs at this point. Anything else will lead\n        // to end of the loop.\n        while(szKeyList[0] == 0x09 || szKeyList[0] == 0x20)\n            szKeyList++;\n        if(szKeyList[0] == 0x0A || szKeyList[0] == 0x0D)\n            break;\n\n        // Convert the string to binary\n        dwErrCode = BinaryFromString(szKeyList, CASC_KEY_LENGTH * 2, KeyValue);\n        if(dwErrCode != ERROR_SUCCESS)\n        {\n            SetCascError(dwErrCode);\n            return false;\n        }\n\n        // Add the encryption key. Note that if the key already exists with the same value,\n        // CascAddEncryptionKey will consider it success.\n        if(!CascAddEncryptionKey(hStorage, KeyName, KeyValue))\n            return false;\n\n        // Move to the next key\n        while(szKeyList[0] != 0 && szKeyList[0] != 0x0A && szKeyList[0] != 0x0D)\n            szKeyList++;\n        while(szKeyList[0] == 0x0A || szKeyList[0] == 0x0D)\n            szKeyList++;\n    }\n\n    return true;\n}\n\nbool WINAPI CascImportKeysFromFile(HANDLE hStorage, LPCTSTR szFileName)\n{\n    TFileStream * pFileStream;\n    ULONGLONG FileSize = 0;\n    LPSTR szKeyList;\n    bool bResult = false;\n\n    // Open the file\n    if((pFileStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY)) != NULL)\n    {\n        // Load the entire file to memory, up to 10 MB\n        if(FileStream_GetSize(pFileStream, &FileSize) && FileSize < 0xA00000)\n        {\n            DWORD FileSize32 = (DWORD)FileSize;\n\n            // Allocate buffer for the key stream\n            if((szKeyList = CASC_ALLOC<char>(FileSize32 + 1)) != NULL)\n            {\n                // Read the entire file and terminate it with zero\n                FileStream_Read(pFileStream, NULL, szKeyList, FileSize32);\n                szKeyList[FileSize] = 0;\n\n                // Import the buffer\n                bResult = CascImportKeysFromString(hStorage, szKeyList);\n                CASC_FREE(szKeyList);\n            }\n        }\n        else\n            SetCascError(ERROR_FILE_TOO_LARGE);\n\n        FileStream_Close(pFileStream);\n    }\n\n    return bResult;\n}\n\nDWORD CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer)\n{\n    // Check the buffer size\n    if((cbInBuffer - 1) > pcbOutBuffer[0])\n        return ERROR_INSUFFICIENT_BUFFER;\n\n    // Copy the data\n    memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);\n    pcbOutBuffer[0] = cbInBuffer;\n    return ERROR_SUCCESS;\n}\n\nDWORD CascDecrypt(TCascStorage * hs, LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex)\n{\n    ULONGLONG KeyName = 0;\n    LPBYTE pbBufferEnd = pbInBuffer + cbInBuffer;\n    LPBYTE pbKey;\n    DWORD KeyNameSize;\n    DWORD dwShift = 0;\n    DWORD IVSize;\n    BYTE Vector[0x08];\n    BYTE EncryptionType;\n    DWORD dwErrCode;\n\n    // Verify and retrieve the key name size\n    if(pbInBuffer >= pbBufferEnd)\n        return ERROR_FILE_CORRUPT;\n    if(pbInBuffer[0] != 0 && pbInBuffer[0] != 8)\n        return ERROR_NOT_SUPPORTED;\n    KeyNameSize = *pbInBuffer++;\n\n    // Copy the key name\n    if((pbInBuffer + KeyNameSize) >= pbBufferEnd)\n        return ERROR_FILE_CORRUPT;\n    memcpy(&KeyName, pbInBuffer, KeyNameSize);\n    pbInBuffer += KeyNameSize;\n\n    // Verify and retrieve the Vector size\n    if(pbInBuffer >= pbBufferEnd)\n        return ERROR_FILE_CORRUPT;\n    if(pbInBuffer[0] != 4 && pbInBuffer[0] != 8)\n        return ERROR_NOT_SUPPORTED;\n    IVSize = *pbInBuffer++;\n\n    // Copy the initialization vector\n    if((pbInBuffer + IVSize) >= pbBufferEnd)\n        return ERROR_FILE_CORRUPT;\n    memset(Vector, 0, sizeof(Vector));\n    memcpy(Vector, pbInBuffer, IVSize);\n    pbInBuffer += IVSize;\n\n    // Verify and retrieve the encryption type\n    if(pbInBuffer >= pbBufferEnd)\n        return ERROR_FILE_CORRUPT;\n    if(pbInBuffer[0] != 'S' && pbInBuffer[0] != 'A')\n        return ERROR_NOT_SUPPORTED;\n    EncryptionType = *pbInBuffer++;\n\n    // Do we have enough space in the output buffer?\n    if((DWORD)(pbBufferEnd - pbInBuffer) > pcbOutBuffer[0])\n        return ERROR_INSUFFICIENT_BUFFER;\n\n    // Check if we know the key\n    pbKey = hs->KeyMap.FindKey(KeyName);\n    if(pbKey == NULL)\n    {\n        hs->LastFailKeyName = KeyName;\n        return ERROR_FILE_ENCRYPTED;\n    }\n\n    // Shuffle the Vector with the block index\n    // Note that there's no point to go beyond 32 bits, unless the file has\n    // more than 0xFFFFFFFF frames.\n    for(size_t i = 0; i < sizeof(dwFrameIndex); i++)\n    {\n        Vector[i] = Vector[i] ^ (BYTE)((dwFrameIndex >> dwShift) & 0xFF);\n        dwShift += 8;\n    }\n\n    // Perform the decryption-specific action\n    switch(EncryptionType)\n    {\n        case 'S':   // Salsa20\n            dwErrCode = Decrypt_Salsa20(pbOutBuffer, pbInBuffer, (pbBufferEnd - pbInBuffer), pbKey, 0x10, Vector);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n\n            // Supply the size of the output buffer\n            pcbOutBuffer[0] = (DWORD)(pbBufferEnd - pbInBuffer);\n            return ERROR_SUCCESS;\n\n            //      case 'A':\n            //          return ERROR_NOT_SUPPORTED;\n    }\n\n    assert(false);\n    return ERROR_NOT_SUPPORTED;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascDumpData.cpp",
    "content": "/*****************************************************************************/\n/* CascDumpData.cpp                       Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* System-dependent directory functions for CascLib                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 07.05.14  1.00  Lad  The first version of CascDumpData.cpp                */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n#ifdef _DEBUG       // The entire feature is only valid for debug purposes\n\n//-----------------------------------------------------------------------------\n// Forward definitions\n\nint CaptureEncodingHeader(CASC_ENCODING_HEADER & EnHeader, LPBYTE pbFileData, size_t cbFileData);\nint CaptureDownloadHeader(CASC_DOWNLOAD_HEADER & DlHeader, LPBYTE pbFileData, size_t cbFileData);\nint CaptureDownloadEntry(CASC_DOWNLOAD_HEADER & DlHeader, CASC_DOWNLOAD_ENTRY & DlEntry, LPBYTE pbFilePtr, LPBYTE pbFileEnd);\nint CaptureDownloadTag(CASC_DOWNLOAD_HEADER & DlHeader, CASC_TAG_ENTRY1 & DlTag, LPBYTE pbFilePtr, LPBYTE pbFileEnd);\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nstatic char * StringFromLPTSTR(LPCTSTR szString, char * szBuffer, size_t cchBuffer)\n{\n    char * szSaveBuffer = szBuffer;\n    char * szBufferEnd = szBuffer + cchBuffer - 1;\n\n    while (szBuffer < szBufferEnd && szString[0] != 0)\n        *szBuffer++ = (char)*szString++;\n    szBuffer[0] = 0;\n\n    return szSaveBuffer;\n}\n\n// Either opens a dump file or returns \"stdout\"\nstatic FILE * OpenDumpFile(const char * szDumpFile)\n{\n    if(szDumpFile != NULL)\n    {\n        return fopen(szDumpFile, \"wt\");\n    }\n    else\n    {\n        return stdout;\n    }\n}\n\n// Closes the dump file if it was open by OpenDumpFile\nstatic void CloseDumpFile(const char * szDumpFile, FILE * fp)\n{\n    if(szDumpFile != NULL && fp != NULL)\n        fclose(fp);\n}\n\nstatic void DumpKey(FILE * fp, const char * szInFormat, LPBYTE pbData, size_t cbData)\n{\n    const char * szFormatSpec;\n    LPBYTE pbDataEnd = pbData + cbData;\n    char szFormat[0x100];\n    char szKey[MD5_STRING_SIZE + 1];\n\n    // First line: Copy the line with the complete format\n    CascStrCopy(szFormat, _countof(szFormat), szInFormat);\n    szFormatSpec = strstr(szFormat, \"%s\");\n\n    // Dump all keys, every one on a new line\n    while(pbData < pbDataEnd)\n    {\n        // Fump the line\n        StringFromBinary(pbData, MD5_HASH_SIZE, szKey);\n        fprintf(fp, szFormat, szKey);\n\n        // If there will be more lines, then we clear the entire part until \"%s\"\n        if(szFormatSpec != NULL)\n            memset(szFormat, ' ', (szFormatSpec - szFormat));\n        \n        // Move pointers\n        pbData += MD5_HASH_SIZE;\n    }\n}\n\n/*\nvoid CascDumpSparseArray(const char * szFileName, void * pvSparseArray)\n{\n    TSparseArray * pSparseArray = (TSparseArray *)pvSparseArray;\n    FILE * fp;\n\n    // Create the dump file\n    fp = fopen(szFileName, \"wt\");\n    if(fp != NULL)\n    {\n        // Write header\n        fprintf(fp, \"##   Value\\n--   -----\\n\");\n\n        // Write the values\n        for(DWORD i = 0; i < pSparseArray->TotalItemCount; i++)\n        {\n            DWORD Value = 0;\n\n            if(pSparseArray->IsItemPresent(i))\n            {\n                Value = pSparseArray->GetItemValue(i);\n                fprintf(fp, \"%02X    %02X\\n\", i, Value);\n            }\n            else\n            {\n                fprintf(fp, \"%02X    --\\n\", i);\n            }\n        }\n\n        fclose(fp);\n    }\n}\n\nvoid CascDumpNameFragTable(const char * szFileName, void * pMarFile)\n{\n    TFileNameDatabase * pDB = ((PMAR_FILE)pMarFile)->pDatabasePtr->pDB;\n    FILE * fp;\n\n    // Create the dump file\n    fp = fopen(szFileName, \"wt\");\n    if(fp != NULL)\n    {\n        PNAME_FRAG pNameTable = pDB->NameFragTable.ItemArray;\n        const char * szNames = pDB->IndexStruct_174.ItemArray;\n        const char * szLastEntry;\n        char szMatchType[0x100];\n\n        // Dump the table header\n        fprintf(fp, \"Indx  ThisHash NextHash FragOffs\\n\");\n        fprintf(fp, \"----  -------- -------- --------\\n\");\n\n        // Dump all name entries\n        for(DWORD i = 0; i < pDB->NameFragTable.ItemCount; i++)\n        {\n            // Reset both match types\n            szMatchType[0] = 0;\n            szLastEntry = \"\";\n\n            // Only if the table entry is not empty\n            if(pNameTable->ItemIndex != 0xFFFFFFFF)\n            {\n                // Prepare the entry\n                if(IS_SINGLE_CHAR_MATCH(pDB->NameFragTable, i))\n                    CascStrPrintf(szMatchType, _countof(szMatchType), \"SINGLE_CHAR (\\'%c\\')\", (pNameTable->FragOffs & 0xFF));\n                else\n                    CascStrPrintf(szMatchType, _countof(szMatchType), \"NAME_FRAGMT (\\\"%s\\\")\", szNames + pNameTable->FragOffs);\n            }\n\n            // Dump the entry\n            fprintf(fp, \"0x%02X  %08x %08x %08x %s%s\\n\", i, pNameTable->ItemIndex,\n                                                            pNameTable->NextIndex,\n                                                            pNameTable->FragOffs,\n                                                            szMatchType,\n                                                            szLastEntry);\n            pNameTable++;\n        }\n        fclose(fp);\n    }\n}\n\nvoid CascDumpFileNames(const char * szFileName, void * pvMarFile)\n{\n    TMndxFindResult Struct1C;\n    PMAR_FILE pMarFile = (PMAR_FILE)pvMarFile;\n    FILE * fp;\n    char szNameBuff[0x200];\n    bool bFindResult;\n\n    // Create the dump file\n    fp = fopen(szFileName, \"wt\");\n    if(fp != NULL)\n    {\n        // Set an empty path as search mask (?)\n        Struct1C.SetSearchPath(\"\", 0);\n\n        // Keep searching\n        for(;;)\n        {\n            // Search the next file name\n            pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult);\n\n            // Stop the search in case of failure\n            if(!bFindResult)\n                break;\n\n            // Printf the found file name\n            memcpy(szNameBuff, Struct1C.szFoundPath, Struct1C.cchFoundPath);\n            szNameBuff[Struct1C.cchFoundPath] = 0;\n            fprintf(fp, \"%s\\n\", szNameBuff);\n        }\n\n        fclose(fp);\n    }\n\n    // Free the search structures\n    Struct1C.FreeStruct40();\n}\n\n\nvoid DumpEKeyEntries(TCascStorage * hs, FILE * fp)\n{\n    // Dump header\n    fprintf(fp, \"=== Ekey Entries ============================================================\\n\");\n\n    // Dump index entries from all index files\n    for(int file = 0; file < CASC_INDEX_COUNT; file++)\n    {\n        PCASC_EKEY_ENTRY pEKeyEntry = hs->IndexFile[file].pEKeyEntries;\n        DWORD nEKeyEntries = hs->IndexFile[file].nEKeyEntries;\n\n        // Only if they are present\n        if(pEKeyEntry && nEKeyEntries)\n        {\n//          fprintf(fp, \"--- Index: %03u --------------------------------------------------------------\\n\", file);\n            for(DWORD entry = 0; entry < nEKeyEntries; entry++, pEKeyEntry++)\n                DumpEKeyEntry(fp, pEKeyEntry->EKey, CASC_EKEY_SIZE, pEKeyEntry->StorageOffset, ConvertBytesToInteger_4_LE(pEKeyEntry->EncodedSize));\n        }\n    }\n\n    // Dump tail\n    fprintf(fp, \"=============================================================================\\n\\n\");\n}\n*/\n\n//-----------------------------------------------------------------------------\n// Dumping the ENCODING manifest\n/*\nstatic void DumpESpecEntries(FILE * fp, LPBYTE pbDataPtr, LPBYTE pbDataEnd)\n{\n    fprintf(fp, \"--- ESpec Entries -----------------------------------------------------------\\n\");\n\n    while(pbDataPtr < pbDataEnd)\n    {\n        const char * szESpecEntry = (const char *)pbDataPtr;\n\n        // Find the end of the entry\n        while((pbDataPtr < pbDataEnd) && (pbDataPtr[0] != 0))\n        {\n            pbDataPtr++;\n        }\n\n        // Dump the entry\n        if(pbDataPtr[0] == 0)\n        {\n            fprintf(fp, \"%s\\n\", szESpecEntry);\n            pbDataPtr++;\n        }\n    }\n}\n\nstatic void DumpCKeyEntry(PCASC_CKEY_ENTRY pCKeyEntry, FILE * fp, DWORD nIndex)\n{\n    LPBYTE pbEKey;\n    char szStringBuff[MD5_STRING_SIZE + 1];\n\n    // Print the CKey and number of EKeys\n    fprintf(fp, \"[0x%02X] %s (EKeys: %02u): \", nIndex, StringFromBinary(pCKeyEntry->CKey, MD5_HASH_SIZE, szStringBuff), pCKeyEntry->EKeyCount);\n    pbEKey = pCKeyEntry->EKey;\n\n    // Print the EKeys\n    for(USHORT i = 0; i < pCKeyEntry->EKeyCount; i++, pbEKey += MD5_HASH_SIZE)\n        fprintf(fp, \" %s \", StringFromBinary(pbEKey, MD5_HASH_SIZE, szStringBuff));\n    fprintf(fp, \"\\n\");\n}\n\nstatic void DumpCKeyPages(FILE * fp, CASC_ENCODING_HEADER & EnHeader, LPBYTE pbDataPtr, LPBYTE pbDataEnd)\n{\n    // Get the CKey page header and the page itself\n    PFILE_CKEY_PAGE pPageHeader = (PFILE_CKEY_PAGE)pbDataPtr;\n    LPBYTE pbPageEntry = (LPBYTE)(pPageHeader + EnHeader.CKeyPageCount);\n\n    fprintf(fp, \"--- CKey Pages --------------------------------------------------------------\\n\");\n    for(DWORD i = 0; i < EnHeader.CKeyPageCount; i++, pPageHeader++)\n    {\n        LPBYTE pbCKeyEntry = pbPageEntry;\n        LPBYTE pbEndOfPage = pbPageEntry + EnHeader.CKeyPageSize;\n        DWORD nCKeyIndex = 0;\n\n        // Check if there is enough space in the buffer\n        if((pbPageEntry + EnHeader.CKeyPageSize) > pbDataEnd)\n            break;\n\n        DumpKey(fp, \"First CKey:     %s\\n\", pPageHeader->FirstKey, EnHeader.CKeyLength);\n        DumpKey(fp, \"Page hash:      %s\\n\", pPageHeader->SegmentHash, MD5_HASH_SIZE);\n        fprintf(fp, \"\\n\");\n\n        // Parse all CKey entries\n        while(pbCKeyEntry <= pbEndOfPage)\n        {\n            PCASC_CKEY_ENTRY pCKeyEntry = (PCASC_CKEY_ENTRY)pbCKeyEntry;\n\n            // Get pointer to the encoding entry\n            if(pCKeyEntry->EKeyCount == 0)\n                break;\n\n            // Dump this encoding entry\n            DumpCKeyEntry(pCKeyEntry, fp, nCKeyIndex++);\n\n            // Move to the next encoding entry\n            pbCKeyEntry += sizeof(FILE_CKEY_ENTRY) + ((pCKeyEntry->EKeyCount - 1) * EnHeader.CKeyLength);\n        }\n\n        // Move to the next segment\n        pbPageEntry += EnHeader.CKeyPageSize;\n        fprintf(fp, \"\\n\");\n    }\n}\n\nvoid DumpEncodingManifest(TCascStorage * hs, LPBYTE pbData, ULONG cbData, FILE * fp)\n{\n    // Dump header\n    fprintf(fp, \"=== ENCODING Manifest =======================================================\\n\");\n\n    // Dump the encoding file\n    if(hs->EncodingManifest.pbData && hs->EncodingManifest.cbData)\n    {\n        CASC_ENCODING_HEADER EnHeader;\n        LPBYTE pbFilePtr = hs->EncodingManifest.pbData;\n        DWORD cbDataSize;\n\n        // Capture the header of the ENCODING file\n        if(CaptureEncodingHeader(EnHeader, hs->EncodingManifest.pbData, hs->EncodingManifest.cbData) == ERROR_SUCCESS)\n        {\n            // Dump the ENCODING file info\n            fprintf(fp, \"Magic:            %u\\n\",   EnHeader.Magic);\n            fprintf(fp, \"Version:          %u\\n\",   EnHeader.Version);\n            fprintf(fp, \"CKey Length:      %02X\\n\", EnHeader.CKeyLength);\n            fprintf(fp, \"EKey Length:      %02X\\n\", EnHeader.EKeyLength);\n            fprintf(fp, \"CKey page size:   %08X\\n\", EnHeader.CKeyPageSize);\n            fprintf(fp, \"CKey page count:  %08X\\n\", EnHeader.CKeyPageCount);\n            fprintf(fp, \"EKey page size:   %08X\\n\", EnHeader.EKeyPageSize);\n            fprintf(fp, \"EKey page count:  %08X\\n\", EnHeader.EKeyPageCount);\n            fprintf(fp, \"ESpec block size: %08X\\n\", EnHeader.ESpecBlockSize);\n            pbFilePtr += sizeof(FILE_ENCODING_HEADER);\n\n            // Dump all ESpec entries\n            DumpESpecEntries(fp, pbFilePtr, pbFilePtr + EnHeader.ESpecBlockSize);\n            pbFilePtr += EnHeader.ESpecBlockSize;\n\n            // Parse all CKey pages and dump them\n            cbDataSize = EnHeader.CKeyPageCount * (sizeof(FILE_CKEY_PAGE) + EnHeader.CKeyPageSize);\n            DumpCKeyPages(fp, EnHeader, pbFilePtr, pbFilePtr + cbDataSize);\n            pbFilePtr += cbDataSize;\n        }\n    }\n    else\n    {\n        fprintf(fp, \"(empty)\\n\");\n    }\n\n    // Dump tail\n    fprintf(fp, \"=============================================================================\\n\\n\");\n}\n*/\n//-----------------------------------------------------------------------------\n// Dumping the DOWNLOAD manifest\n/*\nstatic void DumpDownloadEntries(FILE * fp, CASC_DOWNLOAD_HEADER & DlHeader, LPBYTE pbDownloadPtr, LPBYTE pbDownloadEnd)\n{\n    fprintf(fp, \"--- DOWNLOAD Entries --------------------------------------------------------\\n\");\n    fprintf(fp, \"Index    EKey                             FileSize   Checksum Flags    Prio\\n\");\n    fprintf(fp, \"-------- -------------------------------- ---------- -------- -------- ----\\n\");\n\n    for(DWORD i = 0; i < DlHeader.EntryCount; i++)\n    {\n        CASC_DOWNLOAD_ENTRY DlEntry;\n        char szEKey[MD5_STRING_SIZE+1];\n        char szChksum[0x40];\n        char szFlags[0x40];\n\n        if(CaptureDownloadEntry(DlHeader, DlEntry, pbDownloadPtr, pbDownloadEnd) != ERROR_SUCCESS)\n            break;\n\n        // Dump the entry\n        StringFromBinary(DlEntry.EKey, DlHeader.EKeyLength, szEKey);\n        CascStrPrintf(szChksum, _countof(szChksum), (DlHeader.EntryHasChecksum ? \"%08X\" : \"<none>  \"), DlEntry.Checksum);\n        CascStrPrintf(szFlags,  _countof(szFlags), (DlHeader.FlagByteSize ? \"%08X\" : \"<none>  \"), DlEntry.Flags);\n        fprintf(fp, \"[%06X] %-16s %010I64X %s %s %04X\\n\", i, szEKey, DlEntry.FileSize, szChksum, szFlags, DlEntry.Priority);\n\n        // Move to the next entry\n        pbDownloadPtr += DlHeader.EntryLength;\n    }\n\n    fprintf(fp, \"\\n\");\n}\n\nstatic void DumpDownloadTags(FILE * fp, CASC_DOWNLOAD_HEADER & DlHeader, LPBYTE pbFilePtr, LPBYTE pbFileEnd)\n{\n    CASC_TAG_ENTRY1 DlTag;\n\n    fprintf(fp, \"--- DOWNLOAD Tags ---------------------------------------------------------\\n\");\n    for(DWORD i = 0; i < DlHeader.TagCount; i++)\n    {\n        // Capture the download tag\n        if(CaptureDownloadTag(DlHeader, DlTag, pbFilePtr, pbFileEnd) != ERROR_SUCCESS)\n            break;\n\n        // Dump the tag\n        fprintf(fp, \"[%02X]: %08X = %s\\n\", i, DlTag.TagValue, DlTag.szTagName);\n        pbFilePtr += DlTag.TagLength;\n    }\n}\n\nvoid DumpDownloadManifest(TCascStorage * hs, FILE * fp)\n{\n    // Dump header\n    fprintf(fp, \"=== DOWNLOAD Manifest =======================================================\\n\");\n\n    // Dump the encoding file\n    if(hs->DownloadManifest.pbData && hs->DownloadManifest.cbData)\n    {\n        CASC_DOWNLOAD_HEADER DlHeader;\n        LPBYTE pbFileEnd = hs->DownloadManifest.pbData + hs->DownloadManifest.cbData;\n        LPBYTE pbFilePtr = hs->DownloadManifest.pbData;\n\n        // Capture the header of the ENCODING file\n        if(CaptureDownloadHeader(DlHeader, hs->DownloadManifest.pbData, hs->DownloadManifest.cbData) == ERROR_SUCCESS)\n        {\n            // Dump the DOWNLOAD header\n            fprintf(fp, \"Magic:            %u\\n\",   DlHeader.Magic);\n            fprintf(fp, \"Version:          %u\\n\",   DlHeader.Version);\n            fprintf(fp, \"EKey Length:      %02X\\n\", DlHeader.EKeyLength);\n            fprintf(fp, \"Checksum present: %s\\n\",   DlHeader.EntryHasChecksum ? \"Yes\" : \"No\");\n            fprintf(fp, \"Entry Count:      %08X\\n\", DlHeader.EntryCount);\n            fprintf(fp, \"Tag Count:        %08X\\n\", DlHeader.TagCount);\n            fprintf(fp, \"Flag byte size:   %08X\\n\", DlHeader.FlagByteSize);\n            fprintf(fp, \"Base priority:    %08X\\n\", DlHeader.BasePriority);\n            fprintf(fp, \"Header length:    %08X\\n\", (DWORD)DlHeader.HeaderLength);\n            fprintf(fp, \"Entry length:     %08X\\n\", (DWORD)DlHeader.EntryLength);\n            fprintf(fp, \"\\n\");\n            pbFilePtr += DlHeader.HeaderLength;\n\n            // Dump all download entries\n            DumpDownloadEntries(fp, DlHeader, pbFilePtr, pbFileEnd);\n            pbFilePtr += DlHeader.EntryLength * DlHeader.EntryCount;\n\n            // Dump all tags\n            DumpDownloadTags(fp, DlHeader, pbFilePtr, pbFileEnd);\n        }\n    }\n    else\n    {\n        fprintf(fp, \"(empty)\\n\");\n    }\n\n    // Dump tail\n    fprintf(fp, \"=============================================================================\\n\\n\");\n}\n*/\n//-----------------------------------------------------------------------------\n// Public dumping functions\n\nvoid CascDumpFile(const char * szDumpFile, HANDLE hFile)\n{\n    FILE * fp;\n    DWORD dwBytesRead = 1;\n    DWORD dwFilePos = CascSetFilePointer(hFile, 0, NULL, FILE_BEGIN);\n    BYTE Buffer[0x1000];\n\n    // Create/open the dump file\n    fp = OpenDumpFile(szDumpFile);\n    if(fp != NULL)\n    {\n        // Read data as long as we can, write as long as we can\n        while(dwBytesRead != 0)\n        {\n            // Read from the source file\n            if(!CascReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead))\n                break;\n\n            // Write to the destination file\n            if(fwrite(Buffer, 1, dwBytesRead, fp) != dwBytesRead)\n                break;\n        }\n\n        // Restore the file pointer\n        CascSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);\n\n        // Close the dump file\n        CloseDumpFile(szDumpFile, fp);\n    }\n}\n\nvoid CascDumpStorage(HANDLE hStorage, const char * szDumpFile)\n{\n    TCascStorage * hs;\n    FILE * fp = stdout;\n    char szStringBuff[0x800];\n\n    // Verify the storage handle\n    hs = TCascStorage::IsValid(hStorage);\n    if(hs == NULL)\n        return;\n\n    // Create/open the dump file\n    fp = OpenDumpFile(szDumpFile);\n    if(fp != NULL)\n    {\n        // Dump the basic storage info\n        fprintf(fp, \"=== Basic Storage Info ======================================================\\n\");\n        fprintf(fp, \"DataPath:  %s\\n\", StringFromLPTSTR(hs->szDataPath, szStringBuff, sizeof(szStringBuff)));\n        fprintf(fp, \"IndexPath: %s\\n\", StringFromLPTSTR(hs->szIndexPath, szStringBuff, sizeof(szStringBuff)));\n        fprintf(fp, \"BuildFile: %s\\n\", StringFromLPTSTR(hs->szBuildFile, szStringBuff, sizeof(szStringBuff)));\n        fprintf(fp, \"CDN Server: %s\\n\", StringFromLPTSTR(hs->szCdnServers, szStringBuff, sizeof(szStringBuff)));\n        fprintf(fp, \"CDN Path: %s\\n\", StringFromLPTSTR(hs->szCdnPath, szStringBuff, sizeof(szStringBuff)));\n        DumpKey(fp, \"CDN Config Key: %s\\n\", hs->CdnConfigKey.pbData, hs->CdnConfigKey.cbData);\n        DumpKey(fp, \"CDN Build Key:  %s\\n\", hs->CdnBuildKey.pbData, hs->CdnBuildKey.cbData);\n        DumpKey(fp, \"Archives Key:   %s\\n\", hs->ArchivesKey.pbData, hs->ArchivesKey.cbData);\n        DumpKey(fp, \"ROOT file:      %s\\n\", hs->RootFile.CKey, CASC_CKEY_SIZE);\n        DumpKey(fp, \"PATCH file:     %s\\n\", hs->PatchFile.CKey, CASC_CKEY_SIZE);\n        DumpKey(fp, \"ENCODING file:  %s\\n\", hs->EncodingCKey.CKey, CASC_CKEY_SIZE);\n        DumpKey(fp, \"DOWNLOAD file:  %s\\n\", hs->DownloadCKey.CKey, CASC_CKEY_SIZE);\n        DumpKey(fp, \"INSTALL file:   %s\\n\", hs->InstallCKey.CKey, CASC_CKEY_SIZE);\n        fprintf(fp, \"\\n\");\n\n        // Dump the complete ENCODING manifest\n//      DumpEncodingManifest(hs, fp);\n\n        // Dump the complete ENCODING manifest\n//      DumpDownloadManifest(hs, fp);\n\n        // Close the dump file\n        CloseDumpFile(szDumpFile, fp);\n    }\n}\n\n#else // _DEBUG\n\n// so linker won't mind this .cpp file is empty in non-DEBUG builds\nvoid unused_symbol() { }\n\n#endif // _DEBUG\n"
  },
  {
    "path": "deps/CascLib/src/CascFiles.cpp",
    "content": "/*****************************************************************************/\n/* CascFiles.cpp                          Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Various text file parsers                                                 */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of CascBuildCfg.cpp                */\n/* 30.10.15  1.00  Lad  Renamed to CascFiles.cpp                             */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n#ifdef _MSC_VER\n#pragma comment(lib, \"ws2_32.lib\")          // Internet functions for HTTP stream\n#endif\n\n//-----------------------------------------------------------------------------\n// Local defines\n\ntypedef DWORD (*PARSECSVFILE)(TCascStorage * hs, CASC_CSV & Csv);\ntypedef DWORD (*PARSETEXTFILE)(TCascStorage * hs, void * pvListFile);\ntypedef DWORD (*PARSE_VARIABLE)(TCascStorage * hs, const char * szVariableName, const char * szDataBegin, const char * szDataEnd, void * pvParam);\n\n#define MAX_VAR_NAME 80\n\n//-----------------------------------------------------------------------------\n// Local structures\n\nstruct TBuildFileInfo\n{\n    LPCTSTR szFileName;\n    CBLD_TYPE BuildFileType;\n};\n\nstruct TGameLocaleString\n{\n    const char * szLocale;\n    DWORD dwLocale;\n};\n\nstatic const TBuildFileInfo BuildTypes[] =\n{\n    {_T(\".build.info\"), CascBuildInfo},             // Since HOTS build 30027, the game uses .build.info file for storage info\n    {_T(\".build.db\"),   CascBuildDb},               // Older CASC storages\n    {_T(\"versions\"),    CascVersionsDb},            // Older CASC storages\n    {NULL, CascBuildNone}\n};\n\nstatic LPCTSTR DataDirs[] =\n{\n    _T(\"data\") _T(PATH_SEP_STRING) _T(\"casc\"),      // Overwatch\n    _T(\"data\"),                                     // TACT casc (for Linux systems)\n    _T(\"Data\"),                                     // World of Warcraft, Diablo\n    _T(\"SC2Data\"),                                  // Starcraft II (Legacy of the Void) build 38749\n    _T(\"HeroesData\"),                               // Heroes of the Storm\n    _T(\"BNTData\"),                                  // Heroes of the Storm, until build 30414\n    NULL,\n};\n\nstatic LPCTSTR bnet_region = _T(\"us\");\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nstatic bool inline IsWhiteSpace(const char * szVarValue)\n{\n    return (0 <= szVarValue[0] && szVarValue[0] <= 0x20);\n}\n\nstatic bool inline IsValueSeparator(const char * szVarValue)\n{\n    return (IsWhiteSpace(szVarValue) || (szVarValue[0] == '|'));\n}\n\nstatic bool IsCharDigit(BYTE OneByte)\n{\n    return ('0' <= OneByte && OneByte <= '9');\n}\n\nstatic bool StringEndsWith(LPCSTR szString, size_t nLength, LPCSTR szSuffix, size_t nSuffixLength)\n{\n    return ((nLength > nSuffixLength) && !strcmp(szString + nLength - nSuffixLength, szSuffix));\n}\n\nstatic const char * CaptureDecimalInteger(const char * szDataPtr, const char * szDataEnd, PDWORD PtrValue)\n{\n    const char * szSaveDataPtr = szDataPtr;\n    DWORD TotalValue = 0;\n    DWORD AddValue = 0;\n\n    // Skip all spaces\n    while (szDataPtr < szDataEnd && szDataPtr[0] == ' ')\n        szDataPtr++;\n\n    // Load the number\n    while (szDataPtr < szDataEnd && szDataPtr[0] != ' ')\n    {\n        // Must only contain decimal digits ('0' - '9')\n        if(!IsCharDigit(szDataPtr[0]))\n            break;\n\n        // Get the next value and verify overflow\n        AddValue = szDataPtr[0] - '0';\n        if((TotalValue + AddValue) < TotalValue)\n            return NULL;\n\n        TotalValue = (TotalValue * 10) + AddValue;\n        szDataPtr++;\n    }\n\n    // If there were no decimal digits, we consider it failure\n    if(szDataPtr == szSaveDataPtr)\n        return NULL;\n\n    // Give the result\n    PtrValue[0] = TotalValue;\n    return szDataPtr;\n}\n\nstatic const char * CaptureSingleString(const char * szDataPtr, const char * szDataEnd, char * szBuffer, size_t ccBuffer)\n{\n    char * szBufferEnd = szBuffer + ccBuffer - 1;\n\n    // Skip all whitespaces\n    while (szDataPtr < szDataEnd && IsWhiteSpace(szDataPtr))\n        szDataPtr++;\n\n    // Copy the string\n    while (szDataPtr < szDataEnd && szBuffer < szBufferEnd && !IsWhiteSpace(szDataPtr) && szDataPtr[0] != '=')\n        *szBuffer++ = *szDataPtr++;\n\n    szBuffer[0] = 0;\n    return szDataPtr;\n}\n\nstatic const char * CaptureSingleHash(const char * szDataPtr, const char * szDataEnd, LPBYTE HashValue, size_t HashLength)\n{\n    const char * szHashString;\n    size_t HashStringLength = HashLength * 2;\n\n    // Skip all whitespaces\n    while (szDataPtr < szDataEnd && IsWhiteSpace(szDataPtr))\n        szDataPtr++;\n    szHashString = szDataPtr;\n\n    // Count all hash characters\n    for (size_t i = 0; i < HashStringLength; i++)\n    {\n        if(szDataPtr >= szDataEnd || isxdigit(szDataPtr[0]) == 0)\n            return NULL;\n        szDataPtr++;\n    }\n\n    // There must be a separator or end-of-string\n    if(szDataPtr > szDataEnd || IsWhiteSpace(szDataPtr) == false)\n        return NULL;\n\n    // Give the values\n    BinaryFromString(szHashString, HashStringLength, HashValue);\n    return szDataPtr;\n}\n\nstatic const char * CaptureHashCount(const char * szDataPtr, const char * szDataEnd, size_t * PtrHashCount)\n{\n    BYTE HashValue[MD5_HASH_SIZE];\n    size_t HashCount = 0;\n\n    // Capculate the hash count\n    while (szDataPtr < szDataEnd)\n    {\n        // Check one hash\n        szDataPtr = CaptureSingleHash(szDataPtr, szDataEnd, HashValue, MD5_HASH_SIZE);\n        if(szDataPtr == NULL)\n            return NULL;\n\n        // Skip all whitespaces\n        while (szDataPtr < szDataEnd && IsWhiteSpace(szDataPtr))\n            szDataPtr++;\n\n        HashCount++;\n    }\n\n    // Give results\n    PtrHashCount[0] = HashCount;\n    return szDataPtr;\n}\n\nstatic DWORD GetLocaleValue(LPCSTR szTag)\n{\n    DWORD Language = 0;\n\n    // Convert the string language to integer\n    Language = (Language << 0x08) | szTag[0];\n    Language = (Language << 0x08) | szTag[1];\n    Language = (Language << 0x08) | szTag[2];\n    Language = (Language << 0x08) | szTag[3];\n\n    // Language-specific action\n    switch(Language)\n    {\n        case 0x656e5553: return CASC_LOCALE_ENUS;\n        case 0x656e4742: return CASC_LOCALE_ENGB;\n        case 0x656e434e: return CASC_LOCALE_ENCN;\n        case 0x656e5457: return CASC_LOCALE_ENTW;\n        case 0x65734553: return CASC_LOCALE_ESES;\n        case 0x65734d58: return CASC_LOCALE_ESMX;\n        case 0x70744252: return CASC_LOCALE_PTBR;\n        case 0x70745054: return CASC_LOCALE_PTPT;\n        case 0x7a68434e: return CASC_LOCALE_ZHCN;\n        case 0x7a685457: return CASC_LOCALE_ZHTW;\n        case 0x6b6f4b52: return CASC_LOCALE_KOKR;\n        case 0x66724652: return CASC_LOCALE_FRFR;\n        case 0x64654445: return CASC_LOCALE_DEDE;\n        case 0x72755255: return CASC_LOCALE_RURU;\n        case 0x69744954: return CASC_LOCALE_ITIT;\n    }\n\n    return 0;\n}\n\nstatic bool CheckConfigFileVariable(\n    TCascStorage * hs,                  // Pointer to storage structure\n    const char * szLinePtr,             // Pointer to the begin of the line\n    const char * szLineEnd,             // Pointer to the end of the line\n    const char * szVarName,             // Pointer to the variable to check\n    PARSE_VARIABLE PfnParseProc,        // Pointer to the parsing function\n    void * pvParseParam)                // Pointer to the parameter passed to parsing function\n{\n    char szVariableName[MAX_VAR_NAME];\n\n    // Capture the variable from the line\n    szLinePtr = CaptureSingleString(szLinePtr, szLineEnd, szVariableName, sizeof(szVariableName));\n    if(szLinePtr == NULL)\n        return false;\n\n    // Verify whether this is the variable\n    if(!CascCheckWildCard(szVariableName, szVarName))\n        return false;\n\n    // Skip the spaces and '='\n    while (szLinePtr < szLineEnd && (IsWhiteSpace(szLinePtr) || szLinePtr[0] == '='))\n        szLinePtr++;\n\n    // Call the parsing function only if there is some data\n    if(szLinePtr >= szLineEnd)\n        return false;\n\n    return (PfnParseProc(hs, szVariableName, szLinePtr, szLineEnd, pvParseParam) == ERROR_SUCCESS);\n}\n\nstatic DWORD LoadHashArray(\n    PQUERY_KEY pBlob,\n    const char * szLinePtr,\n    const char * szLineEnd,\n    size_t HashCount)\n{\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // Allocate the blob buffer\n    pBlob->cbData = (DWORD)(HashCount * MD5_HASH_SIZE);\n    pBlob->pbData = CASC_ALLOC<BYTE>(pBlob->cbData);\n    if(pBlob->pbData != NULL)\n    {\n        LPBYTE pbBuffer = pBlob->pbData;\n\n        for (size_t i = 0; i < HashCount; i++)\n        {\n            // Capture the hash value\n            szLinePtr = CaptureSingleHash(szLinePtr, szLineEnd, pbBuffer, MD5_HASH_SIZE);\n            if(szLinePtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // Move buffer\n            pbBuffer += MD5_HASH_SIZE;\n        }\n        \n        dwErrCode = ERROR_SUCCESS;\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD LoadMultipleHashes(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd)\n{\n    size_t HashCount = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Retrieve the hash count\n    if(CaptureHashCount(szLineBegin, szLineEnd, &HashCount) == NULL)\n        return ERROR_BAD_FORMAT;\n\n    // Do nothing if there is no data\n    if(HashCount != 0)\n    {\n        dwErrCode = LoadHashArray(pBlob, szLineBegin, szLineEnd, HashCount);\n    }\n\n    return dwErrCode;\n}\n\n// Loads a query key from the text form\n// A QueryKey is an array of \"ContentKey EncodedKey1 ... EncodedKeyN\"\nstatic DWORD LoadQueryKey(TCascStorage * /* hs */, const char * /* szVariableName */, const char * szDataBegin, const char * szDataEnd, void * pvParam)\n{\n    return LoadMultipleHashes((PQUERY_KEY)pvParam, szDataBegin, szDataEnd);\n}\n\nstatic DWORD LoadCKeyEntry(TCascStorage * hs, const char * szVariableName, const char * szDataPtr, const char * szDataEnd, void * pvParam)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = (PCASC_CKEY_ENTRY)pvParam;\n    size_t nLength = strlen(szVariableName);\n    size_t HashCount = 0;\n\n    // Ignore \"xxx-config\" items\n    if(StringEndsWith(szVariableName, nLength, \"-config\", 7))\n        return ERROR_SUCCESS;\n\n    // If the variable ends at \"-size\", it means we need to capture the size\n    if(StringEndsWith(szVariableName, nLength, \"-size\", 5))\n    {\n        DWORD ContentSize = CASC_INVALID_SIZE;\n        DWORD EncodedSize = CASC_INVALID_SIZE;\n\n        // Load the content size\n        szDataPtr = CaptureDecimalInteger(szDataPtr, szDataEnd, &ContentSize);\n        if(szDataPtr == NULL)\n            return ERROR_BAD_FORMAT;\n\n        CaptureDecimalInteger(szDataPtr, szDataEnd, &EncodedSize);\n        pCKeyEntry->ContentSize = ContentSize;\n        pCKeyEntry->EncodedSize = EncodedSize;\n        return ERROR_SUCCESS;\n    }\n\n    // If the string doesn't end with \"-config\", assume it's the CKey/EKey\n    else\n    {\n        // Get the number of hashes. It is expected to be 1 or 2\n        if(CaptureHashCount(szDataPtr, szDataEnd, &HashCount) != NULL)\n        {\n            // Capture the CKey\n            if(HashCount >= 1)\n            {\n                // Load the CKey. This should alway be there\n                szDataPtr = CaptureSingleHash(szDataPtr, szDataEnd, pCKeyEntry->CKey, MD5_HASH_SIZE);\n                if(szDataPtr == NULL)\n                    return ERROR_BAD_FORMAT;\n                pCKeyEntry->Flags |= CASC_CE_HAS_CKEY;\n            }\n\n            // Capture EKey, if any\n            if(HashCount == 2)\n            {\n                // Load the EKey into the structure\n                szDataPtr = CaptureSingleHash(szDataPtr, szDataEnd, pCKeyEntry->EKey, MD5_HASH_SIZE);\n                if(szDataPtr == NULL)\n                    return ERROR_BAD_FORMAT;\n                pCKeyEntry->Flags |= CASC_CE_HAS_EKEY;\n\n                // Increment the number of EKey entries loaded from text build file\n                hs->EKeyEntries++;\n            }\n\n            return (HashCount == 1 || HashCount == 2) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n        }\n    }\n\n    // Unrecognized\n    return ERROR_BAD_FORMAT;\n}\n\n// For files like PATCH, which only contain EKey in the build file\nstatic DWORD LoadEKeyEntry(TCascStorage * hs, const char * szVariableName, const char * szDataPtr, const char * szDataEnd, void * pvParam)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = (PCASC_CKEY_ENTRY)pvParam;\n    DWORD dwErrCode;\n\n    // Load the entry as if it was a CKey. Then move CKey into EKey and adjust flags\n    if((dwErrCode = LoadCKeyEntry(hs, szVariableName, szDataPtr, szDataEnd, pvParam)) == ERROR_SUCCESS)\n    {\n        if((pCKeyEntry->Flags & (CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY | CASC_CE_HAS_EKEY_PARTIAL)) == CASC_CE_HAS_CKEY)\n        {\n            // Move the CKey into EKey\n            CopyMemory16(pCKeyEntry->EKey, pCKeyEntry->CKey);\n            ZeroMemory16(pCKeyEntry->CKey);\n\n            // Adjust flags\n            pCKeyEntry->Flags = (pCKeyEntry->Flags & ~CASC_CE_HAS_CKEY) | CASC_CE_HAS_EKEY;\n        }\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD LoadVfsRootEntry(TCascStorage * hs, const char * szVariableName, const char * szDataPtr, const char * szDataEnd, void * pvParam)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n    CASC_ARRAY * pArray = (CASC_ARRAY *)pvParam;\n    const char * szVarPtr = szVariableName;\n    const char * szVarEnd = szVarPtr + strlen(szVarPtr);\n    DWORD VfsRootIndex = CASC_INVALID_INDEX;\n\n    // Skip the \"vfs-\" part\n    if(!strncmp(szVariableName, \"vfs-\", 4))\n    {\n        // Then, there must be a decimal number as index\n        if((szVarPtr = CaptureDecimalInteger(szVarPtr + 4, szVarEnd, &VfsRootIndex)) != NULL)\n        {\n            // We expect the array to be initialized\n            assert(pArray->IsInitialized());\n\n            // The index of the key must not be NULL\n            if(VfsRootIndex != 0)\n            {\n                // Make sure that he entry is in the array\n                pCKeyEntry = (PCASC_CKEY_ENTRY)pArray->ItemAt(VfsRootIndex - 1);\n                if(pCKeyEntry == NULL)\n                {\n                    // Insert a new entry\n                    pCKeyEntry = (PCASC_CKEY_ENTRY)pArray->InsertAt(VfsRootIndex - 1);\n                    if(pCKeyEntry == NULL)\n                        return ERROR_NOT_ENOUGH_MEMORY;\n                    \n                    // Initialize the new entry\n                    pCKeyEntry->Init();\n                }\n\n                // Call just a normal parse function\n                return LoadCKeyEntry(hs, szVariableName, szDataPtr, szDataEnd, pCKeyEntry);\n            }\n        }\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD LoadBuildProductId(TCascStorage * hs, const char * /* szVariableName */, const char * szDataBegin, const char * szDataEnd, void * /* pvParam */)\n{\n    size_t nLength = (szDataEnd - szDataBegin);\n\n    if(hs->szCodeName == NULL)\n    {\n        if((hs->szCodeName = CASC_ALLOC<TCHAR>(nLength + 1)) != NULL)\n        {\n            CascStrCopy(hs->szCodeName, nLength + 1, szDataBegin, nLength);\n        }\n    }\n\n    return ERROR_SUCCESS;\n}\n\n// \"B29049\"\n// \"WOW-18125patch6.0.1\"\n// \"30013_Win32_2_2_0_Ptr_ptr\"\n// \"prometheus-0_8_0_0-24919\"\nstatic DWORD LoadBuildNumber(TCascStorage * hs, const char * /* szVariableName */, const char * szDataBegin, const char * szDataEnd, void * /* pvParam */)\n{\n    DWORD dwBuildNumber = 0;\n    DWORD dwMaxValue = 0;\n\n    // Parse the string and take the largest decimal numeric value\n    // \"build-name = 1.21.5.4037-retail\"\n    while(szDataBegin < szDataEnd)\n    {\n        // There must be at least three digits (build 99 anyone?)\n        if(IsCharDigit(szDataBegin[0]))\n        {\n            dwBuildNumber = (dwBuildNumber * 10) + (szDataBegin[0] - '0');\n            dwMaxValue = CASCLIB_MAX(dwBuildNumber, dwMaxValue);\n        }\n        else\n        {\n            // Reset build number when we find non-digit char\n            dwBuildNumber = 0;\n        }\n\n        // Move to the next\n        szDataBegin++;\n    }\n\n    // If not there, just take value from build file\n    if((hs->dwBuildNumber = dwMaxValue) == 0)\n        hs->dwBuildNumber = hs->CdnBuildKey.pbData[0] % 100;\n    return ERROR_BAD_FORMAT;\n}\n\nstatic int LoadQueryKey(const CASC_CSV_COLUMN & Column, QUERY_KEY & Key)\n{\n    // Check the input data\n    if(Column.szValue == NULL)\n        return ERROR_BUFFER_OVERFLOW;\n    if(Column.nLength != MD5_STRING_SIZE)\n        return ERROR_BAD_FORMAT;\n\n    return LoadHashArray(&Key, Column.szValue, Column.szValue + Column.nLength, 1);\n}\n\nstatic void SetProductCodeName(TCascStorage * hs, LPCSTR szCodeName)\n{\n    if(hs->szCodeName == NULL && szCodeName != NULL)\n    {\n        hs->szCodeName = CascNewStrA2T(szCodeName);\n    }\n}\n\nstatic DWORD GetDefaultCdnPath(TCascStorage * hs, const CASC_CSV_COLUMN & Column)\n{\n    if(hs->szCdnPath == NULL && Column.nLength != 0)\n    {\n        hs->szCdnPath = CascNewStrA2T(Column.szValue);\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD GetDefaultLocaleMask(TCascStorage * hs, const CASC_CSV_COLUMN & Column)\n{\n    LPCSTR szTagEnd = Column.szValue + Column.nLength - 4;\n    LPCSTR szTagPtr = Column.szValue;\n    DWORD dwLocaleMask = 0;\n\n    while(szTagPtr < szTagEnd)\n    {\n        DWORD dwLocaleValue = GetLocaleValue(szTagPtr);\n\n        if(dwLocaleValue != 0)\n        {\n            dwLocaleMask = dwLocaleMask | GetLocaleValue(szTagPtr);\n            szTagPtr += 4;\n        }\n        else\n        {\n            szTagPtr++;\n        }\n    }\n\n    hs->dwDefaultLocale = dwLocaleMask;\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD ParseFile_CDNS(TCascStorage * hs, CASC_CSV & Csv)\n{\n    const char * szWantedRegion = hs->szRegion;\n    const char * szRegion;\n    size_t nLineCount;\n\n    // Fix the region\n    if(szWantedRegion == NULL || !_stricmp(szWantedRegion, \"beta\") || !_stricmp(szWantedRegion, \"xx\"))\n        szWantedRegion = \"us\";\n\n    // Determine the row count\n    nLineCount = Csv.GetLineCount();\n\n    // Find the active config\n    for(size_t i = 0; i < nLineCount; i++)\n    {\n        // Retrieve the region\n        if((szRegion = Csv[i][\"Name!STRING:0\"].szValue) != NULL)\n        {\n            // Is it the version we are looking for?\n            if(!strcmp(Csv[i][\"Name!STRING:0\"].szValue, szWantedRegion))\n            {\n                // Save the list of CDN servers\n                hs->szCdnServers = CascNewStrA2T(Csv[i][\"Hosts!STRING:0\"].szValue);\n\n                // Save the CDN subpath\n                hs->szCdnPath = CascNewStrA2T(Csv[i][\"Path!STRING:0\"].szValue);\n\n                // Check and return result\n                return (hs->szCdnServers && hs->szCdnPath) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n            }\n        }\n    }\n\n    return ERROR_FILE_NOT_FOUND;\n}\n\nstatic DWORD ParseFile_BuildInfo(TCascStorage * hs, CASC_CSV & Csv)\n{\n    PFNPRODUCTCALLBACK PfnProductCallback = hs->pArgs->PfnProductCallback;\n    LPCSTR szProductColumn = \"Product!STRING:0\";\n    LPCSTR szCodeName;\n    void * PtrProductParam = hs->pArgs->PtrProductParam;\n    size_t nProductColumnIndex = Csv.GetColumnIndex(szProductColumn);\n    size_t nLineCount = Csv.GetLineCount();\n    size_t nSelected = CASC_INVALID_INDEX;\n    DWORD dwErrCode;\n\n    //\n    // Find the configuration that we're gonna load.\n    //\n\n    // If the product is not specified and there is product callback, we use the callback to specify the product\n    if(hs->szCodeName == NULL && nProductColumnIndex != CASC_INVALID_INDEX && PfnProductCallback != NULL)\n    {\n        LPCSTR ProductsList[0x40] = {NULL};\n        size_t nProductCount = 0;\n        size_t nChoiceIndex = CASC_INVALID_INDEX;\n        size_t nDefault = CASC_INVALID_INDEX;\n\n        // Load all products to the array\n        for(size_t i = 0; i < nLineCount; i++)\n        {\n            // Ignore anything that is not marked \"active\"\n            if(!strcmp(Csv[i][\"Active!DEC:1\"].szValue, \"1\"))\n            {\n                ProductsList[nProductCount] = Csv[i][\"Product!STRING:0\"].szValue;\n                nProductCount++;\n                nDefault = i;\n            }\n        }\n        \n        // Only if there is more than one active products\n        if(nProductCount > 1)\n        {\n            // Ask the callback to choose the product\n            if(!PfnProductCallback(PtrProductParam, ProductsList, nProductCount, &nChoiceIndex) || (nChoiceIndex >= nProductCount))\n                return ERROR_CANCELLED;\n\n            // We now have preferred product to open\n            SetProductCodeName(hs, ProductsList[nChoiceIndex]);\n        }\n        else if(nProductCount == 1)\n        {\n            // We now have preferred product to open\n            SetProductCodeName(hs, ProductsList[nDefault]);\n        }\n        else\n        {\n            return ERROR_FILE_NOT_FOUND;\n        }\n    }\n\n    // Parse all lines in the CSV file. Either take the first that is active\n    // or take the one that has been selected by the callback\n    for(size_t i = 0; i < nLineCount; i++)\n    {\n        // Ignore anything that is not marked \"active\"\n        if(!strcmp(Csv[i][\"Active!DEC:1\"].szValue, \"1\"))\n        {\n            // If the product code is specified and exists in the build file, we need to check it\n            if(hs->szCodeName != NULL && (szCodeName = Csv[i][\"Product!STRING:0\"].szValue) != NULL)\n            {\n                TCHAR szBuffer[0x20];\n\n                // Skip if they are not equal\n                CascStrCopy(szBuffer, _countof(szBuffer), szCodeName);\n                if(_tcsicmp(hs->szCodeName, szBuffer))\n                    continue;\n\n                // Save the code name of the selected product\n                SetProductCodeName(hs, Csv[i][\"Product!STRING:0\"].szValue);\n                nSelected = i;\n                break;\n            }\n\n            // If the caller didn't specify the product code name, pick the first active\n            nSelected = i;\n            break;\n        }\n    }\n\n    // Load the selected product\n    if(nSelected < nLineCount)\n    {\n        // Extract the CDN build key\n        dwErrCode = LoadQueryKey(Csv[nSelected][\"Build Key!HEX:16\"], hs->CdnBuildKey);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Extract the CDN config key\n        dwErrCode = LoadQueryKey(Csv[nSelected][\"CDN Key!HEX:16\"], hs->CdnConfigKey);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Get the CDN path\n        GetDefaultCdnPath(hs, Csv[nSelected][\"CDN Path!STRING:0\"]);\n\n        // If we found tags, we can extract language build from it\n        GetDefaultLocaleMask(hs, Csv[nSelected][\"Tags!STRING:0\"]);\n\n        // If we found version, extract a build number\n        const CASC_CSV_COLUMN & VerColumn = Csv[nSelected][\"Version!STRING:0\"];\n        if(VerColumn.szValue && VerColumn.nLength)\n        {\n            LoadBuildNumber(hs, NULL, VerColumn.szValue, VerColumn.szValue + VerColumn.nLength, NULL);\n        }\n\n        // Verify all variables\n        return (hs->CdnBuildKey.pbData != NULL && hs->CdnConfigKey.pbData != NULL) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n    }\n\n    return ERROR_FILE_NOT_FOUND;\n}\n\nstatic DWORD ParseFile_VersionsDb(TCascStorage * hs, CASC_CSV & Csv)\n{\n    size_t nLineCount = Csv.GetLineCount();\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Find the active config\n    for (size_t i = 0; i < nLineCount; i++)\n    {\n        // Either take the version required or take the first one\n        if(hs->szRegion == NULL || !strcmp(Csv[i][\"Region!STRING:0\"].szValue, hs->szRegion))\n        {\n            // Extract the CDN build key\n            dwErrCode = LoadQueryKey(Csv[i][\"BuildConfig!HEX:16\"], hs->CdnBuildKey);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n\n            // Extract the CDN config key\n            dwErrCode = LoadQueryKey(Csv[i][\"CDNConfig!HEX:16\"], hs->CdnConfigKey);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n\n            const CASC_CSV_COLUMN & VerColumn = Csv[i][\"VersionsName!String:0\"];\n            if(VerColumn.szValue && VerColumn.nLength)\n            {\n                LoadBuildNumber(hs, NULL, VerColumn.szValue, VerColumn.szValue + VerColumn.nLength, NULL);\n            }\n\n            // Verify all variables\n            if(hs->CdnBuildKey.pbData != NULL && hs->CdnConfigKey.pbData != NULL)\n            {\n                // If we have manually given build key, override the value\n                if(hs->szBuildKey != NULL)\n                    dwErrCode = BinaryFromString(hs->szBuildKey, MD5_STRING_SIZE, hs->CdnBuildKey.pbData);\n                return dwErrCode;\n            }\n\n            return ERROR_BAD_FORMAT;\n        }\n    }\n\n    return ERROR_FILE_NOT_FOUND;\n}\n\nstatic DWORD ParseFile_BuildDb(TCascStorage * hs, CASC_CSV & Csv)\n{\n    DWORD dwErrCode;\n\n    // Extract the CDN build key\n    dwErrCode = LoadQueryKey(Csv[CSV_ZERO][CSV_ZERO], hs->CdnBuildKey);\n    if(dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Extract the CDN config key\n    dwErrCode = LoadQueryKey(Csv[CSV_ZERO][1], hs->CdnConfigKey);\n    if(dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Verify all variables\n    return (hs->CdnBuildKey.pbData != NULL && hs->CdnConfigKey.pbData != NULL) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n}\n\nstatic DWORD ParseFile_CdnConfig(TCascStorage * hs, void * pvListFile)\n{\n    const char * szLineBegin;\n    const char * szLineEnd;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Keep parsing the listfile while there is something in there\n    for(;;)\n    {\n        // Get the next line\n        if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd))\n            break;\n\n        // CDN key of ARCHIVE-GROUP. Archive-group is actually a very special '.index' file.\n        // It is essentially a merger of all .index files, with a structure change\n        // When \".index\" added after the ARCHIVE-GROUP, we get file name in \"indices\" folder\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"archive-group\", LoadQueryKey, &hs->ArchiveGroup))\n            continue;\n\n        // CDN key of all archives. When \".index\" added to the string, we get file name in \"indices\" folder\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"archives\", LoadQueryKey, &hs->ArchivesKey))\n            continue;\n\n        // CDN keys of patch archives (needs research) \n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"patch-archives\", LoadQueryKey, &hs->PatchArchivesKey))\n            continue;\n\n        // CDN key of probably the combined patch index file (needs research)\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"patch-archive-group\", LoadQueryKey, &hs->PatchArchivesGroup))\n            continue;\n\n        // List of build configs this config supports (optional)\n        // Points to file: \"data\\config\\%02X\\%02X\\%s\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"builds\", LoadQueryKey, &hs->BuildFiles))\n            continue;\n    }\n\n    // Check if all required fields are present\n    if(hs->ArchivesKey.pbData == NULL || hs->ArchivesKey.cbData == 0)\n        return ERROR_BAD_FORMAT;\n\n    return dwErrCode;\n}\n\nstatic DWORD ParseFile_CdnBuild(TCascStorage * hs, void * pvListFile)\n{\n    const char * szLineBegin;\n    const char * szLineEnd = NULL;\n    DWORD dwErrCode;\n\n    // Initialize the empty VFS array\n    dwErrCode = hs->VfsRootList.Create<CASC_CKEY_ENTRY>(0x10);\n    if(dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Parse all variables\n    while(ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd) != 0)\n    {\n        // Product name and build name\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"build-uid\", LoadBuildProductId, NULL))\n            continue;\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"build-name\", LoadBuildNumber, NULL))\n            continue;\n\n        // Content key of the ROOT file. Look this up in ENCODING to get the encoded key\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"root*\", LoadCKeyEntry, &hs->RootFile))\n            continue;\n\n        // Content key [+ encoded key] of the INSTALL file\n        // If EKey is absent, you need to query the ENCODING file for it\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"install*\", LoadCKeyEntry, &hs->InstallCKey))\n            continue;\n\n        // Content key [+ encoded key] of the DOWNLOAD file\n        // If EKey is absent, you need to query the ENCODING file for it\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"download*\", LoadCKeyEntry, &hs->DownloadCKey))\n            continue;\n\n        // Content key + encoded key of the ENCODING file. Contains CKey+EKey\n        // If either none or 1 is found, the game (at least Wow) switches to plain-data(?). Seen in build 20173 \n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"encoding*\", LoadCKeyEntry, &hs->EncodingCKey))\n            continue;\n\n        // PATCH file\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"patch*\", LoadEKeyEntry, &hs->PatchFile))\n            continue;\n\n        // SIZE file\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"size*\", LoadCKeyEntry, &hs->SizeFile))\n            continue;\n\n        // VFS root file (the root file of the storage VFS)\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"vfs-root*\", LoadCKeyEntry, &hs->VfsRoot))\n            continue;\n\n        // Load a directory entry to the VFS\n        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, \"vfs-*\", LoadVfsRootEntry, &hs->VfsRootList))\n            continue;\n    }\n\n    // Special case: Some builds of WoW (22267) don't have the variable in the build file\n    if(hs->szCodeName == NULL && hs->szCdnPath != NULL)\n    {\n        hs->szCodeName = CascNewStr(GetPlainFileName(hs->szCdnPath));\n    }\n\n    // Both CKey and EKey of ENCODING file is required\n    if((hs->EncodingCKey.Flags & (CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY)) != (CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY))\n        dwErrCode = ERROR_BAD_FORMAT;\n    return dwErrCode;\n}\n\nstatic DWORD CheckDataDirectory(TCascStorage * hs, LPTSTR szDirectory)\n{\n    TCHAR szDataPath[MAX_PATH];\n    DWORD dwErrCode = ERROR_FILE_NOT_FOUND;\n\n    // Try all known subdirectories\n    for(size_t i = 0; DataDirs[i] != NULL; i++)\n    {\n        // Create the eventual data path\n        CombinePath(szDataPath, _countof(szDataPath), szDirectory, DataDirs[i], NULL);\n\n        // Does that directory exist?\n        if(DirectoryExists(szDataPath))\n        {\n            hs->szRootPath = CascNewStr(szDirectory);\n            hs->szDataPath = CascNewStr(szDataPath);\n            return ERROR_SUCCESS;\n        }\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD LoadCsvFile(TCascStorage * hs, LPBYTE pbFileData, size_t cbFileData, PARSECSVFILE PfnParseProc, bool bHasHeader)\n{\n    CASC_CSV Csv(0x40, bHasHeader);\n    DWORD dwErrCode;\n\n    // Load the external file to memory\n    if((dwErrCode = Csv.Load(pbFileData, cbFileData)) == ERROR_SUCCESS)\n        dwErrCode = PfnParseProc(hs, Csv);\n    return dwErrCode;\n}\n\nstatic DWORD LoadCsvFile(TCascStorage * hs, LPCTSTR szFileName, PARSECSVFILE PfnParseProc, bool bHasHeader)\n{\n    CASC_CSV Csv(0x40, bHasHeader);\n    DWORD dwErrCode;\n\n    // Load the external file to memory\n    if((dwErrCode = Csv.Load(szFileName)) == ERROR_SUCCESS)\n        dwErrCode = PfnParseProc(hs, Csv);\n    return dwErrCode;\n}\n\nstatic LPCTSTR ExtractCdnServerName(LPTSTR szServerName, size_t cchServerName, LPCTSTR szCdnServers)\n{\n    LPCTSTR szSeparator;\n\n    if(szCdnServers[0] != 0)\n    {\n        szSeparator = _tcschr(szCdnServers, _T(' '));\n        if(szSeparator != NULL)\n        {\n            // Copy one server name\n            CascStrCopy(szServerName, cchServerName, szCdnServers, (szSeparator - szCdnServers));\n\n            // Skip all separators\n            while(szSeparator[0] == ' ' || szSeparator[0] == 0x09)\n                szSeparator++;\n            return szSeparator;\n        }\n        else\n        {\n            CascStrCopy(szServerName, MAX_PATH, szCdnServers);\n            return szCdnServers + _tcslen(szCdnServers);\n        }\n    }\n\n    return NULL;\n}\n\nstatic void CreateRemoteAndLocalPath(TCascStorage * hs, CASC_CDN_DOWNLOAD & CdnsInfo, CASC_PATH<TCHAR> & RemotePath, CASC_PATH<TCHAR> & LocalPath)\n{\n    PCASC_EKEY_ENTRY pEKeyEntry;\n    ULONGLONG ByteMask = 1;\n    DWORD ArchiveIndex;\n\n    // Append the CDN host / root folder\n    RemotePath.SetPathRoot(CdnsInfo.szCdnsHost);\n    RemotePath.AppendString(CdnsInfo.szCdnsPath, true);\n    LocalPath.SetPathRoot(hs->szRootPath);\n\n    // If there is an EKey, take EKey\n    if(CdnsInfo.pbEKey != NULL)\n    {\n        // The file is given by EKey. It's either a loose file, or it's stored in an archive.\n        // We check that using the EKey map\n        if((pEKeyEntry = (PCASC_EKEY_ENTRY)hs->IndexMap.FindObject(CdnsInfo.pbEKey)) != NULL)\n        {\n            // Change the path type to \"data\"\n            RemotePath.AppendString(_T(\"data\"), true);\n            LocalPath.AppendString(_T(\"data\"), true);\n\n            // Append the EKey of the archive instead of the file itself\n            ArchiveIndex = (DWORD)(pEKeyEntry->StorageOffset >> hs->FileOffsetBits);\n            CdnsInfo.pbArchiveKey = hs->ArchivesKey.pbData + (MD5_HASH_SIZE * ArchiveIndex);\n            RemotePath.AppendEKey(CdnsInfo.pbArchiveKey);\n            LocalPath.AppendEKey(CdnsInfo.pbArchiveKey);\n\n            // Get the archive index and archive offset\n            CdnsInfo.ArchiveIndex = ArchiveIndex;\n            CdnsInfo.ArchiveOffs = pEKeyEntry->StorageOffset & ((ByteMask << hs->FileOffsetBits) - 1);\n            CdnsInfo.EncodedSize = pEKeyEntry->EncodedSize;\n        }\n        else\n        {\n            // Append the path type\n            RemotePath.AppendString(CdnsInfo.szPathType, true);\n            LocalPath.AppendString((CdnsInfo.szLoPaType != NULL) ? CdnsInfo.szLoPaType : CdnsInfo.szPathType, true);\n\n            // Append the EKey\n            RemotePath.AppendEKey(CdnsInfo.pbEKey);\n            LocalPath.AppendEKey(CdnsInfo.pbEKey);\n        }\n    }\n    else\n    {\n        assert(CdnsInfo.szFileName != NULL);\n        RemotePath.AppendString(CdnsInfo.szFileName, true);\n        LocalPath.AppendString(CdnsInfo.szFileName, true);\n    }\n\n    // Append extension\n    RemotePath.AppendString(CdnsInfo.szExtension, false);\n    LocalPath.AppendString(CdnsInfo.szExtension, false);\n}\n\nstatic DWORD ForcePathExist(LPCTSTR szFileName, bool bIsFileName)\n{\n    LPTSTR szLocalPath;\n    size_t nIndex;\n    bool bFirstSeparator = false;\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // Sanity checks\n    if(szFileName && szFileName[0])\n    {\n        szLocalPath = CascNewStr(szFileName);\n        if(szLocalPath != NULL)\n        {\n            // Get the end of search\n            if(bIsFileName)\n                CutLastPathPart(szLocalPath);\n\n            // Check the entire path\n            if(_taccess(szLocalPath, 0) != 0)\n            {\n                // Searth the entire path\n                for(nIndex = 0; szLocalPath[nIndex] != 0; nIndex++)\n                {\n                    if(szLocalPath[nIndex] == '\\\\' || szLocalPath[nIndex] == '/')\n                    {\n                        // Cut the path and verify whether the folder/file exists\n                        szLocalPath[nIndex] = 0;\n\n                        // Skip the very first separator\n                        if(bFirstSeparator == true)\n                        {\n                            // Is it there?\n                            if(DirectoryExists(szLocalPath) == false && MakeDirectory(szLocalPath) == false)\n                            {\n                                dwErrCode = ERROR_PATH_NOT_FOUND;\n                                break;\n                            }\n                        }\n\n                        // Restore the character\n                        szLocalPath[nIndex] = PATH_SEP_CHAR;\n                        bFirstSeparator = true;\n                        dwErrCode = ERROR_SUCCESS;\n                    }\n                }\n\n                // Now check the final path\n                if(DirectoryExists(szLocalPath) || MakeDirectory(szLocalPath))\n                {\n                    dwErrCode = ERROR_SUCCESS;\n                }\n            }\n            else\n            {\n                dwErrCode = ERROR_SUCCESS;\n            }\n\n            CASC_FREE(szLocalPath);\n        }\n    }\n\n    return dwErrCode;\n}\n\nstatic bool FileAlreadyExists(LPCTSTR szFileName)\n{\n    TFileStream * pStream;\n    ULONGLONG FileSize = 0;\n\n    // The file open must succeed and also must be of non-zero size\n    if((pStream = FileStream_OpenFile(szFileName, 0)) != NULL)\n    {\n        FileStream_GetSize(pStream, &FileSize);\n        FileStream_Close(pStream);\n    }\n\n    return (FileSize != 0);\n}\n\nstatic DWORD DownloadFile(\n    LPCTSTR szRemoteName,\n    LPCTSTR szLocalName,\n    PULONGLONG PtrByteOffset,\n    DWORD cbReadSize,\n    DWORD dwPortFlags)\n{\n    TFileStream * pRemStream;\n    TFileStream * pLocStream;\n    LPBYTE pbFileData;\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // Open the remote stream\n    pRemStream = FileStream_OpenFile(szRemoteName, BASE_PROVIDER_HTTP | STREAM_PROVIDER_FLAT | dwPortFlags);\n    if(pRemStream != NULL)\n    {\n        // Will we download the entire file or just a part of it?\n        if(PtrByteOffset == NULL)\n        {\n            ULONGLONG FileSize = 0;\n\n            // Retrieve the file size, but not longer than 1 GB\n            if(FileStream_GetSize(pRemStream, &FileSize) && 0 < FileSize && FileSize < 0x40000000)\n            {\n                // Cut the file size down to 32 bits\n                cbReadSize = (DWORD)FileSize;\n            }\n        }\n\n        // Shall we read something?\n        if((cbReadSize != 0) && (pbFileData = CASC_ALLOC<BYTE>(cbReadSize)) != NULL)\n        {\n            // Read all required data from the remote file\n            if(FileStream_Read(pRemStream, PtrByteOffset, pbFileData, cbReadSize))\n            {\n                pLocStream = FileStream_CreateFile(szLocalName, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT);\n                if(pLocStream != NULL)\n                {\n                    if(FileStream_Write(pLocStream, NULL, pbFileData, cbReadSize))\n                        dwErrCode = ERROR_SUCCESS;\n\n                    FileStream_Close(pLocStream);\n                }\n            }\n\n            // Free the data buffer\n            CASC_FREE(pbFileData);\n        }\n\n        // Close the remote stream\n        FileStream_Close(pRemStream);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD RibbitDownloadFile(LPCTSTR szProduct, LPCTSTR szFileName, QUERY_KEY & FileData)\n{\n    TFileStream * pStream;\n    ULONGLONG FileSize = 0;\n    TCHAR szRemoteUrl[256];\n    DWORD dwErrCode = ERROR_CAN_NOT_COMPLETE;\n\n    // Construct the full URL (https://wowdev.wiki/Ribbit)\n    // Old (HTTP) download: wget http://us.patch.battle.net:1119/wow_classic/cdns\n    CascStrPrintf(szRemoteUrl, _countof(szRemoteUrl), _T(\"ribbit://%s.version.battle.net/v1/products/%s/%s\"), bnet_region, szProduct, szFileName);\n\n    // Open the file stream\n    if((pStream = FileStream_OpenFile(szRemoteUrl, 0)) != NULL)\n    {\n        if(FileStream_GetSize(pStream, &FileSize) && FileSize <= 0x04000000)\n        {\n            // Fill-in the file pointer and size\n            FileData.pbData = CASC_ALLOC<BYTE>((size_t)FileSize);\n            if(FileData.pbData != NULL)\n            {\n                if(FileStream_Read(pStream, NULL, FileData.pbData, (DWORD)FileSize))\n                {\n                    FileData.cbData = (size_t)FileSize;\n                    dwErrCode = ERROR_SUCCESS;\n                }\n                else\n                {\n                    dwErrCode = GetCascError();\n                    CASC_FREE(FileData.pbData);\n                    FileData.pbData = NULL;\n                }\n            }\n            else\n            {\n                dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n            }\n        }\n        else\n        {\n            dwErrCode = GetCascError();\n        }\n\n        // Close the remote stream\n        FileStream_Close(pStream);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD DownloadFileFromCDN2(TCascStorage * hs, CASC_CDN_DOWNLOAD & CdnsInfo)\n{\n    CASC_PATH<TCHAR> RemotePath(URL_SEP_CHAR);\n    CASC_PATH<TCHAR> LocalPath(PATH_SEP_CHAR);\n    DWORD dwErrCode;\n\n    // Assemble both the remote and local path\n    assert(CdnsInfo.szCdnsHost != NULL && CdnsInfo.szCdnsHost[0] != 0);\n    CreateRemoteAndLocalPath(hs, CdnsInfo, RemotePath, LocalPath);\n\n    // Check whether the local file exists\n    if((CdnsInfo.Flags & CASC_CDN_FORCE_DOWNLOAD) || !FileAlreadyExists(LocalPath))\n    {\n        // Make sure that the path exists\n        dwErrCode = ForcePathExist(LocalPath, true);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Attempt to download the file\n        dwErrCode = DownloadFile(RemotePath, LocalPath, NULL, 0, 0);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n    }\n\n    // Give the path to the caller, if any\n    LocalPath.Copy(CdnsInfo.szLocalPath, CdnsInfo.ccLocalPath);\n    return ERROR_SUCCESS;\n}\n\nDWORD DownloadFileFromCDN(TCascStorage * hs, CASC_CDN_DOWNLOAD & CdnsInfo)\n{\n    LPCTSTR szCdnServers = hs->szCdnServers;\n    TCHAR szCdnHost[MAX_PATH] = _T(\"\");\n    DWORD dwErrCode = ERROR_CAN_NOT_COMPLETE;\n\n    // If we have a given CDN server, use it. If not, try all CDNs\n    // from the storage's configuration\n    if(CdnsInfo.szCdnsHost == NULL)\n    {\n        // Try all download servers\n        while((szCdnServers = ExtractCdnServerName(szCdnHost, _countof(szCdnHost), szCdnServers)) != NULL)\n        {\n            CdnsInfo.szCdnsHost = szCdnHost;\n            if((dwErrCode = DownloadFileFromCDN2(hs, CdnsInfo)) == ERROR_SUCCESS)\n                return ERROR_SUCCESS;\n        }\n    }\n    else\n    {\n        dwErrCode = DownloadFileFromCDN2(hs, CdnsInfo);\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD FetchAndLoadConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey, PARSETEXTFILE PfnParseProc)\n{\n    LPCTSTR szPathType = _T(\"config\");\n    TCHAR szLocalPath[MAX_PATH];\n    TCHAR szSubDir[0x80] = _T(\"\");\n    void * pvListFile = NULL;\n    DWORD dwErrCode = ERROR_CAN_NOT_COMPLETE;\n\n    // If online storage, we download the file. Otherwise, create a local path\n    if(hs->dwFeatures & CASC_FEATURE_ONLINE)\n    {\n        CASC_CDN_DOWNLOAD CdnsInfo = {0};\n\n        // Prepare the download structure for \"%CDNS_HOST%/%CDNS_PATH%/##/##/EKey\" file\n        CdnsInfo.szCdnsPath = hs->szCdnPath;\n        CdnsInfo.szPathType = szPathType;\n        CdnsInfo.pbEKey = pFileKey->pbData;\n        CdnsInfo.szLocalPath = szLocalPath;\n        CdnsInfo.ccLocalPath = _countof(szLocalPath);\n\n        // Download the config file\n        dwErrCode = DownloadFileFromCDN(hs, CdnsInfo);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n    }\n    else\n    {\n        CASC_PATH<TCHAR> Path;\n\n        Path.AppendString(hs->szDataPath, false);\n        Path.AppendString(szSubDir, true);\n        Path.AppendString(szPathType, true);\n        Path.AppendEKey(pFileKey->pbData);\n        Path.Copy(szLocalPath, _countof(szLocalPath));\n    }\n\n    // Load and verify the external listfile\n    pvListFile = ListFile_OpenExternal(szLocalPath);\n    if(pvListFile != NULL)\n    {\n        if(ListFile_VerifyMD5(pvListFile, pFileKey->pbData))\n        {\n            dwErrCode = PfnParseProc(hs, pvListFile);\n        }\n        else\n        {\n            dwErrCode = ERROR_FILE_CORRUPT;\n        }\n        CASC_FREE(pvListFile);\n    }\n    else\n    {\n        dwErrCode = ERROR_FILE_NOT_FOUND;\n    }\n\n    return dwErrCode;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nbool InvokeProgressCallback(TCascStorage * hs, LPCSTR szMessage, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue)\n{\n    PCASC_OPEN_STORAGE_ARGS pArgs = hs->pArgs;\n    bool bResult = false;\n\n    if(pArgs && pArgs->PfnProgressCallback)\n        bResult = pArgs->PfnProgressCallback(pArgs->PtrProgressParam, szMessage, szObject, CurrentValue, TotalValue);\n    return bResult;\n}\n\nDWORD GetFileSpanInfo(PCASC_CKEY_ENTRY pCKeyEntry, PULONGLONG PtrContentSize, PULONGLONG PtrEncodedSize)\n{\n    ULONGLONG ContentSize = 0;\n    ULONGLONG EncodedSize = 0;\n    DWORD dwSpanCount = pCKeyEntry->SpanCount;\n    bool bContentSizeError = false;\n    bool bEncodedSizeError = false;\n\n    // Sanity check\n    assert(pCKeyEntry->SpanCount != 0);\n\n    // Sum the file size over all file spans\n    // Note: The first file span, if referenced by the ROOT folder, gets the same size\n    // like the entire file (example: zone\\base.xpak, zone\\base.xpak_1)\n    for(DWORD i = 0; i < dwSpanCount; i++, pCKeyEntry++)\n    {\n        if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE)\n            bContentSizeError = true;\n        if(pCKeyEntry->EncodedSize == CASC_INVALID_SIZE)\n            bEncodedSizeError = true;\n\n        ContentSize = ContentSize + pCKeyEntry->ContentSize;\n        EncodedSize = EncodedSize + pCKeyEntry->EncodedSize;\n    }\n\n    // Reset the sizes if there was an error\n    PtrContentSize[0] = (bContentSizeError == false) ? ContentSize : CASC_INVALID_SIZE64;\n    PtrEncodedSize[0] = (bEncodedSizeError == false) ? EncodedSize : CASC_INVALID_SIZE64;\n    return dwSpanCount;\n}\n\n// Checks whether there is a \".build.info\" or \".build.db\".\n// If yes, the function sets \"szDataPath\" and \"szIndexPath\"\n// in the storage structure and returns ERROR_SUCCESS\nDWORD CheckGameDirectory(TCascStorage * hs, LPTSTR szDirectory)\n{\n    TFileStream * pStream;\n    TCHAR szBuildFile[MAX_PATH];\n    DWORD dwErrCode = ERROR_FILE_NOT_FOUND;\n\n    // Try to find any of the root files used in the history\n    for (size_t i = 0; BuildTypes[i].szFileName != NULL; i++)\n    {\n        // Create the full name of the .agent.db file\n        CombinePath(szBuildFile, _countof(szBuildFile), szDirectory, BuildTypes[i].szFileName, NULL);\n\n        // Attempt to open the file\n        pStream = FileStream_OpenFile(szBuildFile, STREAM_FLAG_READ_ONLY);\n        if(pStream != NULL)\n        {\n            // Free the stream\n            FileStream_Close(pStream);\n\n            // Check for the data directory\n            dwErrCode = CheckDataDirectory(hs, szDirectory);\n            if(dwErrCode == ERROR_SUCCESS)\n            {\n                hs->szBuildFile = CascNewStr(szBuildFile);\n                hs->BuildFileType = BuildTypes[i].BuildFileType;\n                return ERROR_SUCCESS;\n            }\n        }\n    }\n\n    return dwErrCode;\n}\n\nDWORD LoadBuildInfo(TCascStorage * hs)\n{\n    PARSECSVFILE PfnParseProc = NULL;\n    DWORD dwErrCode;\n    bool bHasHeader = true;\n\n    // We support \".build.info\", \".build.db\" or \"versions\"\n    switch (hs->BuildFileType)\n    {\n        case CascBuildInfo:\n            PfnParseProc = ParseFile_BuildInfo;\n            break;\n\n        case CascVersionsDb:\n            PfnParseProc = ParseFile_VersionsDb;\n            break;\n\n        case CascBuildDb:\n            PfnParseProc = ParseFile_BuildDb;\n            bHasHeader = false;\n            break;\n\n        default:\n            return ERROR_NOT_SUPPORTED;\n    }\n\n    // If the storage is online storage, we need to download \"versions\"\n    if(hs->dwFeatures & CASC_FEATURE_ONLINE)\n    {\n        QUERY_KEY FileData;\n\n        // Inform the user about loading the build.info/build.db/versions\n        if(InvokeProgressCallback(hs, \"Downloading the \\\"versions\\\" file\", NULL, 0, 0))\n            return ERROR_CANCELLED;\n\n        // Download the file using Ribbit protocol\n        dwErrCode = RibbitDownloadFile(hs->szCodeName, _T(\"versions\"), FileData);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Parse the downloaded file\n            dwErrCode = LoadCsvFile(hs, FileData.pbData, FileData.cbData, ParseFile_VersionsDb, true);\n        }\n    }\n    else\n    {\n        assert(hs->szBuildFile != NULL);\n        dwErrCode = LoadCsvFile(hs, hs->szBuildFile, PfnParseProc, bHasHeader);\n    }\n\n    return dwErrCode;\n}\n\nDWORD LoadCdnsFile(TCascStorage * hs)\n{\n    QUERY_KEY FileData;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Sanity checks\n    assert(hs->dwFeatures & CASC_FEATURE_ONLINE);\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Downloading the \\\"cdns\\\" file\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Download the file using Ribbit protocol\n    dwErrCode = RibbitDownloadFile(hs->szCodeName, _T(\"cdns\"), FileData);\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // Parse the downloaded file\n        dwErrCode = LoadCsvFile(hs, FileData.pbData, FileData.cbData, ParseFile_CDNS, true);\n    }\n\n    return dwErrCode;\n}\n\nDWORD LoadCdnConfigFile(TCascStorage * hs)\n{\n    // The CKey for the CDN config should have been loaded already\n    assert(hs->CdnConfigKey.pbData != NULL && hs->CdnConfigKey.cbData == MD5_HASH_SIZE);\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading CDN config file\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Load the CDN config file\n    return FetchAndLoadConfigFile(hs, &hs->CdnConfigKey, ParseFile_CdnConfig);\n}\n\nDWORD LoadCdnBuildFile(TCascStorage * hs)\n{\n    // The CKey for the CDN config should have been loaded already\n    assert(hs->CdnBuildKey.pbData != NULL && hs->CdnBuildKey.cbData == MD5_HASH_SIZE);\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading CDN build file\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Load the CDN config file. Note that we don't\n    // need it for anything, really, so we don't care if it fails\n    return FetchAndLoadConfigFile(hs, &hs->CdnBuildKey, ParseFile_CdnBuild);\n}\n\nLPBYTE LoadInternalFileToMemory(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD * pcbFileData)\n{\n    LPBYTE pbFileData = NULL;\n    HANDLE hFile = NULL;\n    DWORD dwFileSizeHi = 0;\n    DWORD cbFileData = 0;\n    DWORD dwBytesRead = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Open the file either by CKey or by EKey\n    if(OpenFileByCKeyEntry(hs, pCKeyEntry, CASC_STRICT_DATA_CHECK, &hFile))\n    {\n        // Make the file not cached. We always load the entire file to memory,\n        // so no need to cache (and needlessly copy from one buffer to another)\n        SetCacheStrategy(hFile, CascCacheNothing);\n\n        // Retrieve the size of the file. Note that the caller might specify\n        // the real size of the file, in case the file size is not retrievable\n        // or if the size is wrong. Example: ENCODING file has size specified in BUILD\n        if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE)\n        {\n            cbFileData = CascGetFileSize(hFile, &dwFileSizeHi);\n            if(cbFileData == CASC_INVALID_SIZE || dwFileSizeHi != 0)\n                dwErrCode = ERROR_FILE_CORRUPT;\n        }\n        else\n        {\n            cbFileData = pCKeyEntry->ContentSize;\n        }\n\n        // Load the entire file to memory\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Allocate space for the ENCODING file\n            pbFileData = CASC_ALLOC<BYTE>(cbFileData);\n            if(pbFileData != NULL)\n            {\n                // Read the entire file to memory\n                CascReadFile(hFile, pbFileData, cbFileData, &dwBytesRead);\n                if(dwBytesRead != cbFileData)\n                {\n                    dwErrCode = ERROR_FILE_CORRUPT;\n                }\n            }\n            else\n            {\n                dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n            }\n        }\n\n        // Close the file\n        CascCloseFile(hFile);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    // Handle errors\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        // Free the file data\n        CASC_FREE(pbFileData);\n        cbFileData = 0;\n\n        // Set the last error\n        SetCascError(dwErrCode);\n    }\n\n    // Give the loaded file length\n    if(pcbFileData != NULL)\n        *pcbFileData = cbFileData;\n    return pbFileData;\n}\n\nLPBYTE LoadFileToMemory(LPCTSTR szFileName, DWORD * pcbFileData)\n{\n    TFileStream * pStream;\n    ULONGLONG FileSize = 0;\n    LPBYTE pbFileData = NULL;\n    DWORD cbFileData = 0;\n\n    // Open the stream for read-only access and read the file\n    pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_FLAG_WRITE_SHARE | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);\n    if(pStream != NULL)\n    {\n        // Retrieve the file size\n        FileStream_GetSize(pStream, &FileSize);\n        cbFileData = (DWORD)FileSize;\n\n        // Do not load zero files or too large files\n        if(0 < FileSize && FileSize <= 0x2000000)\n        {\n            // Allocate file data buffer. Make it 1 byte longer\n            // so string functions can put '\\0' there\n            pbFileData = CASC_ALLOC<BYTE>(cbFileData + 1);\n            if(pbFileData != NULL)\n            {\n                if(FileStream_Read(pStream, NULL, pbFileData, cbFileData))\n                {\n                    // Terminate the data with zero so various string-based functions can process it\n                    pbFileData[cbFileData] = 0;\n                }\n                else\n                {\n                    CASC_FREE(pbFileData);\n                    cbFileData = 0;\n                }\n            }\n            else\n            {\n                SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n                cbFileData = 0;\n            }\n        }\n        else\n        {\n            SetCascError(ERROR_BAD_FORMAT);\n            cbFileData = 0;\n            assert(false);\n        }\n\n        // Close the file stream\n        FileStream_Close(pStream);\n    }\n\n    // Give out values\n    if(pcbFileData != NULL)\n        pcbFileData[0] = cbFileData;\n    return pbFileData;\n}\n\n"
  },
  {
    "path": "deps/CascLib/src/CascFindFile.cpp",
    "content": "/*****************************************************************************/\n/* CascFindFile.cpp                       Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* System-dependent directory functions for CascLib                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 10.05.14  1.00  Lad  The first version of CascFindFile.cpp                */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local functions\n\n// Reset the search structure. Called before each search\nstatic void ResetFindData(PCASC_FIND_DATA pFindData)\n{\n    // Reset the variables\n    ZeroMemory16(pFindData->CKey);\n    ZeroMemory16(pFindData->EKey);\n    pFindData->szFileName[0] = 0;\n    pFindData->szPlainName = pFindData->szFileName;\n    pFindData->TagBitMask = 0;\n    pFindData->FileSize = CASC_INVALID_SIZE64;\n    pFindData->dwFileDataId = CASC_INVALID_ID;\n    pFindData->dwLocaleFlags = CASC_INVALID_ID;\n    pFindData->dwContentFlags = CASC_INVALID_ID;\n    pFindData->dwSpanCount = 1;\n    pFindData->NameType = CascNameFull;\n    pFindData->bFileAvailable = false;\n}\n\nstatic void SupplyFakeFileName(PCASC_FIND_DATA pFindData, PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    // If there is a file data ID, create fake file name\n    if(pFindData->dwFileDataId != CASC_INVALID_ID)\n    {\n        CascStrPrintf(pFindData->szFileName, _countof(pFindData->szFileName), \"FILE%08X.dat\", pFindData->dwFileDataId);\n        pFindData->NameType = CascNameDataId;\n        return;\n    }\n\n    // If there is a CKey, convert the CKey to file name\n    if(pCKeyEntry->Flags & CASC_CE_HAS_CKEY)\n    {\n        StringFromBinary(pFindData->CKey, MD5_HASH_SIZE, pFindData->szFileName);\n        pFindData->NameType = CascNameCKey;\n        return;\n    }\n\n    // EKey should be always present\n    if(pCKeyEntry->Flags & CASC_CE_HAS_EKEY)\n    {\n        StringFromBinary(pFindData->EKey, MD5_HASH_SIZE, pFindData->szFileName);\n        pFindData->NameType = CascNameEKey;\n        return;\n    }\n\n    assert(false);\n}\n\nstatic bool CopyCKeyEntryToFindData(PCASC_FIND_DATA pFindData, PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    ULONGLONG ContentSize = 0;\n    ULONGLONG EncodedSize = 0;\n\n    // Supply both keys\n    CopyMemory16(pFindData->CKey, pCKeyEntry->CKey);\n    CopyMemory16(pFindData->EKey, pCKeyEntry->EKey);\n\n    // Supply the tag mask\n    pFindData->TagBitMask = pCKeyEntry->TagBitMask;\n    \n    // Supply the plain name. Only do that if the found name is not a CKey/EKey\n    if(pFindData->szFileName[0] != 0)\n        pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName);\n\n    // If we retrieved the file size directly from the root provider, use it\n    // Otherwise, supply EncodedSize or ContentSize, whichever is available (but ContentSize > EncodedSize)\n    pFindData->dwSpanCount = GetFileSpanInfo(pCKeyEntry, &ContentSize, &EncodedSize);\n    if(pFindData->FileSize == CASC_INVALID_SIZE64)\n    {\n        if(ContentSize != CASC_INVALID_SIZE64)\n            pFindData->FileSize = ContentSize;\n        else \n            pFindData->FileSize = EncodedSize;\n    }\n\n    // Set flag indicating that the file is locally available\n    pFindData->bFileAvailable = (pCKeyEntry->Flags & CASC_CE_FILE_IS_LOCAL);\n\n    // Supply a fake file name, if there is none supplied by the root handler\n    if(pFindData->szFileName[0] == 0)\n        SupplyFakeFileName(pFindData, pCKeyEntry);\n    return true;\n}\n\n// Perform searching using root-specific provider.\n// The provider may need the listfile\nstatic bool DoStorageSearch_RootFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n    TCascStorage * hs = pSearch->hs;\n\n    // Reset the search structure\n    ResetFindData(pFindData);\n\n    // Enumerate over all files\n    for(;;)\n    {\n        // Attempt to find (the next) file from the root handler\n        pCKeyEntry = hs->pRootHandler->Search(pSearch, pFindData);\n        if(pCKeyEntry == NULL)\n            return false;\n\n        // The entry is expected to be referenced by the root directory\n        assert(pCKeyEntry->RefCount != 0);\n\n        // Copy the CKey entry to the find data and return it\n        return CopyCKeyEntryToFindData(pFindData, pCKeyEntry);\n    }\n}\n\nstatic bool DoStorageSearch_CKey(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n    TCascStorage * hs = pSearch->hs;\n    size_t nTotalItems = hs->CKeyArray.ItemCount();\n\n    // Reset the find data structure\n    ResetFindData(pFindData);\n\n    // Check for CKeys that haven't been found yet\n    while(pSearch->nFileIndex < nTotalItems)\n    {\n        // Locate the n-th CKey entry.\n        pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.ItemAt(pSearch->nFileIndex++);\n        //BREAK_ON_XKEY3(pCKeyEntry->CKey, 0x2B, 0xfc, 0xe4);\n\n        // Only report files that are unreferenced by the ROOT handler\n        if(pCKeyEntry->IsFile() && pCKeyEntry->RefCount == 0)\n        {\n            return CopyCKeyEntryToFindData(pFindData, pCKeyEntry);\n        }\n    }\n\n    // Nameless search ended\n    return false;\n}\n\nstatic bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)\n{\n    // State 0: No search done yet\n    if(pSearch->nSearchState == 0)\n    {\n        // Does the search specify listfile?\n        if(pSearch->szListFile != NULL)\n            pSearch->pCache = ListFile_OpenExternal(pSearch->szListFile);\n\n        // Move the search phase to the listfile searching\n        pSearch->nSearchState = 1;\n        pSearch->nFileIndex = 0;\n    }\n\n    // State 1: Searching the list file\n    if(pSearch->nSearchState == 1)\n    {\n        if(DoStorageSearch_RootFile(pSearch, pFindData))\n            return true;\n\n        // Move to the nameless search state\n        pSearch->nSearchState = 2;\n        pSearch->nFileIndex = 0;\n    }\n\n    // State 2: Searching the remaining entries by CKey\n    if(pSearch->nSearchState == 2 && (pSearch->szMask == NULL || !strcmp(pSearch->szMask, \"*\")))\n    {\n        if(DoStorageSearch_CKey(pSearch, pFindData))\n            return true;\n\n        // Move to the final search state\n        pSearch->nSearchState++;\n        pSearch->nFileIndex = 0;\n    }\n\n    return false;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nHANDLE WINAPI CascFindFirstFile(\n    HANDLE hStorage,\n    LPCSTR szMask,\n    PCASC_FIND_DATA pFindData,\n    LPCTSTR szListFile)\n{\n    TCascStorage * hs;\n    TCascSearch * pSearch = NULL;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Check parameters\n    if((hs = TCascStorage::IsValid(hStorage)) == NULL)\n        dwErrCode = ERROR_INVALID_HANDLE;\n    if(pFindData == NULL)\n        dwErrCode = ERROR_INVALID_PARAMETER;\n\n    // Supply default mask, if needed\n    if(szMask == NULL || szMask[0] == 0)\n        szMask = \"*\";\n\n    // Init the search structure and search handle\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // Allocate the search handle\n        pSearch = new TCascSearch(hs, szListFile, szMask);\n        if(pSearch == NULL)\n            dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n    }\n\n    // Perform search\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        if(!DoStorageSearch(pSearch, pFindData))\n            dwErrCode = ERROR_NO_MORE_FILES;\n    }\n\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        delete pSearch;\n        pSearch = (TCascSearch *)INVALID_HANDLE_VALUE;\n    }\n\n    return (HANDLE)pSearch;\n}\n\nbool WINAPI CascFindNextFile(\n    HANDLE hFind,\n    PCASC_FIND_DATA pFindData)\n{\n    TCascSearch * pSearch;\n\n    pSearch = TCascSearch::IsValid(hFind);\n    if(pSearch == NULL || pFindData == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // Perform search\n    return DoStorageSearch(pSearch, pFindData);\n}\n\nbool WINAPI CascFindClose(HANDLE hFind)\n{\n    TCascSearch * pSearch;\n\n    pSearch = TCascSearch::IsValid(hFind);\n    if(pSearch == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    delete pSearch;\n    return true;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascIndexFiles.cpp",
    "content": "/*****************************************************************************/\n/* CascIndexFiles.cpp                     Copyright (c) Ladislav Zezula 2019 */\n/*---------------------------------------------------------------------------*/\n/* Index file support                                                        */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 23.05.19  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local variables\n\nstatic LPCTSTR szAllowedHexChars = _T(\"0123456789aAbBcCdDeEfF\");\nstatic LPCTSTR szIndexFormat_V1 = _T(\"data.i%x%x\");\nstatic LPCTSTR szIndexFormat_V2 = _T(\"%02x%08x.idx\");\n\n// Limit for \"orphaned\" items - those that are in index files, but are not in ENCODING manifest\n#define CASC_MAX_ORPHANED_ITEMS 0x100\n\ntypedef bool (*EKEY_ENTRY_CALLBACK)(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, LPBYTE pbEKeyEntry);\n\n//-----------------------------------------------------------------------------\n// Local functions\n\n// \"data.iXY\"\nstatic bool IsIndexFileName_V1(LPCTSTR szFileName)\n{\n    // Check if the name looks like a valid index file\n    return (_tcslen(szFileName) == 8 &&\n            _tcsnicmp(szFileName, _T(\"data.i\"), 6) == 0 &&\n            _tcsspn(szFileName + 6, szAllowedHexChars) == 2);\n}\n\nstatic bool IsIndexFileName_V2(LPCTSTR szFileName)\n{\n    // Check if the name looks like a valid index file\n    return (_tcslen(szFileName) == 14 &&\n            _tcsspn(szFileName, _T(\"0123456789aAbBcCdDeEfF\")) == 0x0A &&\n            _tcsicmp(szFileName + 0x0A, _T(\".idx\")) == 0);\n}\n\nstatic bool IndexDirectory_OnFileFound(\n    LPCTSTR szFileName,\n    void * pvContext)\n{\n    TCascStorage * hs = (TCascStorage *)pvContext;\n    PCASC_INDEX pIndexFile;\n    DWORD IndexVersion = 0;\n    DWORD IndexValue = 0;\n\n    // Auto-detect the format of the index file name\n    if(hs->szIndexFormat == NULL)\n    {\n        if(IsIndexFileName_V2(szFileName))\n            hs->szIndexFormat = szIndexFormat_V2;\n        else if(IsIndexFileName_V1(szFileName))\n            hs->szIndexFormat = szIndexFormat_V1;\n        else\n            return false;\n    }\n\n    if(hs->szIndexFormat == szIndexFormat_V2)\n    {\n        // Check the index file name format\n        if(!IsIndexFileName_V2(szFileName))\n            return false;\n\n        // Get the main index from the first two digits\n        if(ConvertStringToInt(szFileName + 0, 2, IndexValue) != ERROR_SUCCESS)\n            return false;\n        if(ConvertStringToInt(szFileName + 2, 8, IndexVersion) != ERROR_SUCCESS)\n            return false;\n    }\n    else if(hs->szIndexFormat == szIndexFormat_V1)\n    {\n        // Check the index file name format\n        if(!IsIndexFileName_V1(szFileName))\n            return false;\n\n        // Get the main index from the first two digits\n        if(ConvertStringToInt(szFileName + 6, 1, IndexValue) != ERROR_SUCCESS)\n            return false;\n        if(ConvertStringToInt(szFileName + 7, 1, IndexVersion) != ERROR_SUCCESS)\n            return false;\n    }\n    else\n    {\n        // Should never happen\n        assert(false);\n        return false;\n    }\n\n    // The index value must not be greater than 0x0F\n    if(IndexValue >= CASC_INDEX_COUNT)\n        return false;\n    pIndexFile = &hs->IndexFiles[IndexValue];\n\n    // If the new subindex is greater than the previous one, use this one instead\n    if(IndexVersion > pIndexFile->NewSubIndex)\n    {\n        pIndexFile->OldSubIndex = pIndexFile->NewSubIndex;\n        pIndexFile->NewSubIndex = IndexVersion;\n    }\n    else if(IndexVersion > pIndexFile->OldSubIndex)\n    {\n        pIndexFile->OldSubIndex = IndexVersion;\n    }\n\n    // Note: WoW6 only keeps last two index files\n    // Any additional index files are deleted at this point\n    return true;\n}\n\nstatic LPTSTR CreateIndexFileName(TCascStorage * hs, DWORD IndexValue, DWORD IndexVersion)\n{\n    TCHAR szFullName[MAX_PATH];\n    TCHAR szPlainName[0x40];\n\n    // Sanity checks\n    assert(hs->szIndexFormat != NULL);\n    assert(hs->szIndexPath != NULL);\n    assert(IndexValue <= 0x0F);\n\n    // Create the full path\n    CascStrPrintf(szPlainName, _countof(szPlainName), hs->szIndexFormat, IndexValue, IndexVersion);\n    CombinePath(szFullName, _countof(szFullName), hs->szIndexPath, szPlainName, NULL);\n\n    // Return allocated path\n    return CascNewStr(szFullName);\n}\n\nstatic void SaveFileOffsetBitsAndEKeyLength(TCascStorage * hs, BYTE FileOffsetBits, BYTE EKeyLength)\n{\n    if(hs->FileOffsetBits == 0)\n        hs->FileOffsetBits = FileOffsetBits;\n    assert(hs->FileOffsetBits == FileOffsetBits);\n\n    if(hs->EKeyLength == 0)\n        hs->EKeyLength = EKeyLength;\n    assert(hs->EKeyLength == EKeyLength);\n}\n\n// Verifies a guarded block - data availability and checksum match\nstatic LPBYTE CaptureGuardedBlock1(LPBYTE pbFileData, LPBYTE pbFileEnd)\n{\n    PFILE_INDEX_GUARDED_BLOCK pBlock = (PFILE_INDEX_GUARDED_BLOCK)pbFileData;\n\n    // Check the guarded block\n    if((pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK)) >= pbFileEnd)\n        return NULL;\n    if((pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK) + pBlock->BlockSize) > pbFileEnd)\n        return NULL;\n    \n    // Verify the hash\n    if(hashlittle(pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK), pBlock->BlockSize, 0) != pBlock->BlockHash)\n        return NULL;\n\n    // Give the output\n    return (LPBYTE)(pBlock + 1);\n}\n\n// Second method of checking a guarded block; hash is calculated entry-by-entry.\n// Unfortunately, due to implementation in hashlittle2(), we cannot calculate the hash of a continuous block\nstatic LPBYTE CaptureGuardedBlock2(LPBYTE pbFileData, LPBYTE pbFileEnd, size_t EntryLength, PDWORD PtrBlockSize = NULL)\n{\n    PFILE_INDEX_GUARDED_BLOCK pBlock = (PFILE_INDEX_GUARDED_BLOCK)pbFileData;\n    LPBYTE pbEntryPtr;\n    size_t EntryCount;\n    unsigned int HashBlizzGet = 0;\n    unsigned int HashHigh = 0;\n    unsigned int HashLow = 0;\n\n    // Check the guarded block. There must be enough bytes to contain FILE_INDEX_GUARDED_BLOCK\n    // and also the block length must not be NULL\n    if ((pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK)) >= pbFileEnd)\n        return NULL;\n    if (pBlock->BlockSize == 0 || (pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK) + pBlock->BlockSize) > pbFileEnd)\n        return NULL;\n\n    //\n    // Verify the hash from the Blizzard Downloader\n    //\n\n    pbEntryPtr = pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK);\n    EntryCount = pBlock->BlockSize / EntryLength;\n    for (size_t i = 0; i < EntryCount; i++)\n    {\n        hashlittle2(pbEntryPtr, EntryLength, &HashHigh, &HashLow);\n        pbEntryPtr += EntryLength;\n    }\n\n    // Verify hash\n    if (HashHigh == pBlock->BlockHash)\n    {\n        // Give the output\n        if (PtrBlockSize != NULL)\n            PtrBlockSize[0] = pBlock->BlockSize;\n        return (LPBYTE)(pBlock + 1);\n    }\n\n    //\n    // Verify the hash from the Blizzget tool, which calculates the hash differently\n    // https://github.com/d07RiV/blizzget/blob/master/src/ngdp.cpp\n    // Function void DataStorage::writeIndex()\n    //\n\n    pbEntryPtr = pbFileData + sizeof(FILE_INDEX_GUARDED_BLOCK);\n    EntryCount = pBlock->BlockSize / EntryLength;\n    for (size_t i = 0; i < EntryCount; i++)\n    {\n        HashBlizzGet = hashlittle(pbEntryPtr, EntryLength, HashBlizzGet);\n        pbEntryPtr += EntryLength;\n    }\n\n    // Verify hash\n    if (HashBlizzGet == pBlock->BlockHash)\n    {\n        // Give the output\n        if (PtrBlockSize != NULL)\n            PtrBlockSize[0] = pBlock->BlockSize;\n        return (LPBYTE)(pBlock + 1);\n    }\n\n    // Hash mismatch\n    return NULL;\n}\n\n// Third method of checking a guarded block; There is 32-bit hash, followed by EKey entry\n// The hash covers the EKey entry plus one byte\nstatic LPBYTE CaptureGuardedBlock3(LPBYTE pbFileData, LPBYTE pbFileEnd, size_t EntryLength)\n{\n    PDWORD PtrEntryHash = (PDWORD)pbFileData;\n    DWORD EntryHash;\n\n    // Check the guarded block. There must be enough bytes to contain single entry and the hash\n    // Also, the hash must be present\n    if ((pbFileData + sizeof(DWORD) + EntryLength) >= pbFileEnd)\n        return NULL;\n    if (PtrEntryHash[0] == 0)\n        return NULL;\n\n    EntryHash = hashlittle(pbFileData + sizeof(DWORD), EntryLength+1, 0) | 0x80000000;\n    if(EntryHash != PtrEntryHash[0])\n        return NULL;\n\n    // Give the output\n    return (LPBYTE)(PtrEntryHash + 1);\n}\n/*\nstatic bool CaptureIndexEntry(CASC_INDEX_HEADER & InHeader, PCASC_EKEY_ENTRY pEKeyEntry, LPBYTE pbEKeyEntry)\n{\n    // Copy the EKey of the variable length\n    pbEKeyEntry = CaptureEncodedKey(pEKeyEntry->EKey, pbEKeyEntry, InHeader.EKeyLength);\n\n    // Copy the storage offset and encoded size\n    pEKeyEntry->StorageOffset = ConvertBytesToInteger_5(pbEKeyEntry);\n    pEKeyEntry->EncodedSize = ConvertBytesToInteger_4_LE(pbEKeyEntry + InHeader.StorageOffsetLength);\n    pEKeyEntry->Alignment = 0;\n\n    // We ignore items that have EncodedSize of 0x1E\n    return (pEKeyEntry->EncodedSize > FIELD_OFFSET(BLTE_ENCODED_HEADER, Signature));\n}\n\nstatic void InsertCKeyEntry(TCascStorage * hs, CASC_EKEY_ENTRY & EKeyEntry, DWORD Flags)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n\n    // Multiple items with the same EKey in the index files may exist.\n    // Example: \"2018 - New CASC\\00001\", EKey 37 89 16 5b 2d cc 71 c1 25 00 00 00 00 00 00 00\n    // Positions: 0x1D, 0x1E, 0x1F\n    // In that case, we only take the first one into account\n    // BREAK_ON_XKEY3(EKeyEntry.EKey, 0x09, 0xF3, 0xCD);\n\n    // If the item is not there yet, insert a new one\n    if((pCKeyEntry = FindCKeyEntry_EKey(hs, EKeyEntry.EKey)) == NULL)\n    {\n        // Insert a new entry to the array. DO NOT ALLOW enlarge array here\n        pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false);\n        if(pCKeyEntry == NULL)\n            return;\n\n        // Fill-in the information\n        ZeroMemory16(pCKeyEntry->CKey);\n        CopyMemory16(pCKeyEntry->EKey, EKeyEntry.EKey);\n        pCKeyEntry->StorageOffset = EKeyEntry.StorageOffset;\n        pCKeyEntry->TagBitMask = 0;\n        pCKeyEntry->ContentSize = CASC_INVALID_SIZE;\n        pCKeyEntry->EncodedSize = EKeyEntry.EncodedSize;\n        pCKeyEntry->Flags = CASC_CE_HAS_EKEY | CASC_CE_HAS_EKEY_PARTIAL;\n        pCKeyEntry->RefCount = 0;\n        pCKeyEntry->SpanCount = 1;\n        pCKeyEntry->Priority = 0;\n\n        // Insert the item to the EKey table\n        hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey);\n    }\n    else\n    {\n        // The entry already exists. True e.g. for ENCODING.\n        // Only copy the storage offset and sizes if not available yet\n        if(pCKeyEntry->StorageOffset == CASC_INVALID_OFFS64)\n        {\n            pCKeyEntry->StorageOffset = EKeyEntry.StorageOffset;\n            pCKeyEntry->EncodedSize = EKeyEntry.EncodedSize;\n        }\n    }\n\n    // Add the extra flag\n    pCKeyEntry->Flags |= Flags;\n}\n*/\nstatic DWORD LoadIndexItems(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbEKeyEntry, LPBYTE pbEKeyEnd)\n{\n    size_t EntryLength = InHeader.EntryLength;\n\n    while((pbEKeyEntry + EntryLength) <= pbEKeyEnd)\n    {\n        // ENCODING for Starcraft II Beta\n        BREAK_ON_XKEY3(pbEKeyEntry, 0x8b, 0x0d, 0x9a);\n\n        if(!PfnEKeyEntry(hs, InHeader, pbEKeyEntry))\n            return ERROR_INDEX_PARSING_DONE;\n\n        pbEKeyEntry += EntryLength;\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD CaptureIndexHeader_V1(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, size_t cbFileData, DWORD BucketIndex)\n{\n    PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pbFileData;\n    LPBYTE pbKeyEntries;\n    LPBYTE pbFileEnd = pbFileData + cbFileData;\n    size_t cbKeyEntries;\n    DWORD HeaderHash;\n\n    // Check the available size. Note that the index file can be just a header.\n    if((pbFileData + sizeof(FILE_INDEX_HEADER_V1)) > pbFileEnd)\n        return ERROR_BAD_FORMAT;\n    if(pIndexHeader->IndexVersion != 0x05 || pIndexHeader->BucketIndex != (BYTE)BucketIndex || pIndexHeader->field_8 == 0)\n        return ERROR_BAD_FORMAT;\n    if(pIndexHeader->EncodedSizeLength != 0x04 || pIndexHeader->StorageOffsetLength != 0x05 || pIndexHeader->EKeyLength != 0x09)\n        return ERROR_NOT_SUPPORTED;\n\n    // Verify the header hash\n    HeaderHash = pIndexHeader->HeaderHash;\n    pIndexHeader->HeaderHash = 0;\n    if(hashlittle(pbFileData, sizeof(FILE_INDEX_HEADER_V1), 0) != HeaderHash)\n        return ERROR_BAD_FORMAT;\n\n    // Return the header hash back\n    pIndexHeader->HeaderHash = HeaderHash;\n\n    // Copy the fields\n    InHeader.IndexVersion        = pIndexHeader->IndexVersion;\n    InHeader.BucketIndex         = pIndexHeader->BucketIndex;\n    InHeader.StorageOffsetLength = pIndexHeader->StorageOffsetLength;\n    InHeader.EncodedSizeLength   = pIndexHeader->EncodedSizeLength;\n    InHeader.EKeyLength          = pIndexHeader->EKeyLength;\n    InHeader.FileOffsetBits      = pIndexHeader->FileOffsetBits;\n    InHeader.Alignment           = 0;\n    InHeader.SegmentSize         = pIndexHeader->SegmentSize;\n\n    // Determine the size of the header\n    InHeader.HeaderLength = sizeof(FILE_INDEX_HEADER_V1);\n    InHeader.HeaderPadding = 0;\n    InHeader.EntryLength = pIndexHeader->EKeyLength + pIndexHeader->StorageOffsetLength + pIndexHeader->EncodedSizeLength;\n    InHeader.EKeyCount = pIndexHeader->EKeyCount1 + pIndexHeader->EKeyCount2;\n\n    // Verify the entries hash - 1st block\n    pbKeyEntries = pbFileData + InHeader.HeaderLength;\n    cbKeyEntries = pIndexHeader->EKeyCount1 * InHeader.EntryLength;\n    if((pbKeyEntries + cbKeyEntries) > pbFileEnd)\n        return ERROR_FILE_CORRUPT;\n    if(hashlittle(pbKeyEntries, cbKeyEntries, 0) != pIndexHeader->KeysHash1)\n        return ERROR_FILE_CORRUPT;\n\n    // Verify the entries hash - 2nd block\n    pbKeyEntries = pbKeyEntries + cbKeyEntries;\n    cbKeyEntries = pIndexHeader->EKeyCount2 * InHeader.EntryLength;\n    if((pbKeyEntries + cbKeyEntries) > pbFileEnd)\n        return ERROR_FILE_CORRUPT;\n    if(hashlittle(pbKeyEntries, cbKeyEntries, 0) != pIndexHeader->KeysHash2)\n        return ERROR_FILE_CORRUPT;\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD CaptureIndexHeader_V2(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, size_t cbFileData, DWORD BucketIndex)\n{\n    PFILE_INDEX_HEADER_V2 pIndexHeader;\n    LPBYTE pbFileEnd = pbFileData + cbFileData;\n\n    // Check for guarded block\n    if((pbFileData = CaptureGuardedBlock1(pbFileData, pbFileEnd)) == NULL)\n        return ERROR_FILE_CORRUPT;\n    pIndexHeader = (PFILE_INDEX_HEADER_V2)pbFileData;\n\n    // Verify the content of the index header\n    if(pIndexHeader->IndexVersion != 0x07 || pIndexHeader->BucketIndex != (BYTE)BucketIndex || pIndexHeader->ExtraBytes != 0x00)\n        return ERROR_BAD_FORMAT;\n    if(pIndexHeader->EncodedSizeLength != 0x04 || pIndexHeader->StorageOffsetLength != 0x05 || pIndexHeader->EKeyLength != 0x09)\n        return ERROR_BAD_FORMAT;\n\n    // Capture the values from the index header\n    InHeader.IndexVersion        = pIndexHeader->IndexVersion;\n    InHeader.BucketIndex         = pIndexHeader->BucketIndex;\n    InHeader.StorageOffsetLength = pIndexHeader->StorageOffsetLength;\n    InHeader.EncodedSizeLength   = pIndexHeader->EncodedSizeLength;\n    InHeader.EKeyLength          = pIndexHeader->EKeyLength;\n    InHeader.FileOffsetBits      = pIndexHeader->FileOffsetBits;\n    InHeader.Alignment           = 0;\n    InHeader.SegmentSize         = pIndexHeader->SegmentSize;\n\n    // Supply the lengths\n    InHeader.HeaderLength = sizeof(FILE_INDEX_GUARDED_BLOCK) + sizeof(FILE_INDEX_HEADER_V2);\n    InHeader.HeaderPadding = 8;\n    InHeader.EntryLength = pIndexHeader->EKeyLength + pIndexHeader->StorageOffsetLength + pIndexHeader->EncodedSizeLength;\n    InHeader.EKeyCount = 0;\n    return ERROR_SUCCESS;\n}    \n\nstatic DWORD LoadIndexFile_V1(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbFileData, size_t cbFileData)\n{\n    LPBYTE pbEKeyEntries = pbFileData + InHeader.HeaderLength + InHeader.HeaderPadding;\n\n    // Remember the values from the index header\n    SaveFileOffsetBitsAndEKeyLength(hs, InHeader.FileOffsetBits, InHeader.EKeyLength);\n\n    // Load the entries from a continuous array\n    return LoadIndexItems(hs, InHeader, PfnEKeyEntry, pbEKeyEntries, pbFileData + cbFileData);\n}\n\nstatic DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbFileData, size_t cbFileData)\n{\n    LPBYTE pbEKeyEntry;\n    LPBYTE pbFileEnd = pbFileData + cbFileData;\n    LPBYTE pbFilePtr = pbFileData + InHeader.HeaderLength + InHeader.HeaderPadding;\n    size_t EKeyEntriesLength;\n    DWORD BlockSize = 0;\n    DWORD dwErrCode = ERROR_NOT_SUPPORTED;\n\n    // Remember the values from the index header\n    SaveFileOffsetBitsAndEKeyLength(hs, InHeader.FileOffsetBits, InHeader.EKeyLength);\n\n    // Get the pointer to the first block of EKey entries\n    if((pbEKeyEntry = CaptureGuardedBlock2(pbFilePtr, pbFileEnd, InHeader.EntryLength, &BlockSize)) != NULL)\n    {\n        // Supply the number of EKey entries\n        InHeader.HeaderPadding += sizeof(FILE_INDEX_GUARDED_BLOCK);\n\n        // Load the continuous array of EKeys\n        return LoadIndexItems(hs, InHeader, PfnEKeyEntry, pbEKeyEntry, pbEKeyEntry + BlockSize);\n    }\n\n    // Get the pointer to the second block of EKey entries.\n    // They are alway at the position aligned to 4096\n    EKeyEntriesLength = pbFileEnd - pbFilePtr;\n    if(EKeyEntriesLength >= 0x7800)\n    {\n        LPBYTE pbStartPage = pbFileData + 0x1000;\n        LPBYTE pbEndPage = pbStartPage + FILE_INDEX_PAGE_SIZE;\n        size_t AlignedLength = ALIGN_TO_SIZE(InHeader.EntryLength, 4);\n\n        // Parse the chunks with the EKey entries\n        while(pbStartPage < pbFileEnd)\n        {\n            pbEKeyEntry = pbStartPage;\n            \n            while(pbEKeyEntry < pbEndPage)\n            {\n                // Check the EKey entry protected by 32-bit hash\n                if((pbEKeyEntry = CaptureGuardedBlock3(pbEKeyEntry, pbEndPage, InHeader.EntryLength)) == NULL)\n                    break;\n\n                // CASC\\\\0001: Encoding\n                //BREAK_ON_XKEY3(pbEKeyEntry, 0xbc, 0xe8, 0x23);\n\n                // Call the EKey entry callback\n                if(!PfnEKeyEntry(hs, InHeader, pbEKeyEntry))\n                    return ERROR_INDEX_PARSING_DONE;\n\n                pbEKeyEntry += AlignedLength;\n            }\n\n            // Move to the next chunk\n            pbStartPage += FILE_INDEX_PAGE_SIZE;\n        }\n        dwErrCode = ERROR_SUCCESS;\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD LoadIndexFile(TCascStorage * hs, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbFileData, size_t cbFileData, DWORD BucketIndex)\n{\n    CASC_INDEX_HEADER InHeader;\n\n    // Check for CASC version 2\n    if(CaptureIndexHeader_V2(InHeader, pbFileData, cbFileData, BucketIndex) == ERROR_SUCCESS)\n        return LoadIndexFile_V2(hs, InHeader, PfnEKeyEntry, pbFileData, cbFileData);\n\n    // Check for CASC index version 1\n    if(CaptureIndexHeader_V1(InHeader, pbFileData, cbFileData, BucketIndex) == ERROR_SUCCESS)\n        return LoadIndexFile_V1(hs, InHeader, PfnEKeyEntry, pbFileData, cbFileData);\n\n    // Should never happen\n    assert(false);\n    return ERROR_BAD_FORMAT;\n}\n\n// Checks the EKey entry for EKey of the ENCODING manifest\nstatic bool InsertEncodingEKeyToMap(TCascStorage * hs, CASC_INDEX_HEADER &, LPBYTE pbEKeyEntry)\n{\n    hs->IndexEKeyMap.InsertObject(pbEKeyEntry, pbEKeyEntry);\n    return true;\n}\n\nstatic DWORD ProcessLocalIndexFiles(TCascStorage * hs, EKEY_ENTRY_CALLBACK PfnEKeyEntry, DWORD dwIndexCount)\n{\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Load each index file\n    for(DWORD i = 0; i < dwIndexCount; i++)\n    {\n        CASC_INDEX & IndexFile = hs->IndexFiles[i];\n\n        // Inform the user about what we are doing\n        if(InvokeProgressCallback(hs, \"Loading index files\", NULL, i, dwIndexCount))\n        {\n            dwErrCode = ERROR_CANCELLED;\n            break;\n        }\n\n        // Load the index file\n        if((dwErrCode = LoadIndexFile(hs, PfnEKeyEntry, IndexFile.pbFileData, IndexFile.cbFileData, i)) != ERROR_SUCCESS)\n            break;\n    }\n\n    // Swallow the \"done parsing\" error\n    if(dwErrCode == ERROR_INDEX_PARSING_DONE)\n        dwErrCode = ERROR_SUCCESS;\n\n    // Remember the number of files that are present locally\n    hs->LocalFiles = hs->CKeyArray.ItemCount();\n    return dwErrCode;\n}\n\nstatic DWORD LoadLocalIndexFiles(TCascStorage * hs)\n{\n    ULONGLONG TotalSize = 0;\n    DWORD dwIndexCount = 0;\n    DWORD dwErrCode;\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading index files\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Perform the directory scan\n    if((dwErrCode = ScanIndexDirectory(hs->szIndexPath, IndexDirectory_OnFileFound, hs)) == ERROR_SUCCESS)\n    {\n        // If no index file was found, we cannot load anything\n        if(hs->szIndexFormat == NULL)\n            return ERROR_FILE_NOT_FOUND;\n\n        // Load each index file\n        for(DWORD i = 0; i < CASC_INDEX_COUNT; i++)\n        {\n            CASC_INDEX & IndexFile = hs->IndexFiles[i];\n            DWORD cbFileData = 0;\n\n            // Create the file name\n            if((IndexFile.szFileName = CreateIndexFileName(hs, i, IndexFile.NewSubIndex)) == NULL)\n                return ERROR_NOT_ENOUGH_MEMORY;\n\n            // WoW6 actually reads THE ENTIRE file to memory. Verified on Mac build (x64).\n            if((IndexFile.pbFileData = LoadFileToMemory(IndexFile.szFileName, &cbFileData)) == NULL)\n            {\n                // Storages downloaded by Blizzget tool don't have all index files present\n                if((dwErrCode = GetCascError()) == ERROR_FILE_NOT_FOUND)\n                {\n                    dwErrCode = ERROR_SUCCESS;\n                    break;\n                }\n\n                return dwErrCode;\n            }\n\n            // Add to the total size of the index files\n            IndexFile.cbFileData = cbFileData;\n            TotalSize += cbFileData;\n            dwIndexCount++;\n        }\n\n        // Build the map of EKey -> IndexEKeyEntry\n        dwErrCode = hs->IndexEKeyMap.Create((size_t)(TotalSize / sizeof(FILE_EKEY_ENTRY)), CASC_EKEY_SIZE, 0);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            dwErrCode = ProcessLocalIndexFiles(hs, InsertEncodingEKeyToMap, dwIndexCount);\n        }\n    }\n\n    return dwErrCode;\n}\n\n//-----------------------------------------------------------------------------\n// Online index files\n// https://wowdev.wiki/TACT#CDN_File_Organization\n\nstatic DWORD CaptureArcIndexFooter(CASC_ARCINDEX_FOOTER & InFooter, LPBYTE pbIndexFile, DWORD cbIndexFile)\n{\n    FILE_INDEX_FOOTER<0x08> * pFooter08;\n    BYTE checksum_data[0x40] = { 0 };\n    BYTE md5_hash[MD5_HASH_SIZE];\n    DWORD checksum_data_length;\n\n    // Clear the entire structure\n    memset(&InFooter, 0, sizeof(CASC_ARCINDEX_FOOTER));\n\n    // Check the variant for checksum == 0x08\n    pFooter08 = (FILE_INDEX_FOOTER<0x08> *)(pbIndexFile + cbIndexFile - sizeof(FILE_INDEX_FOOTER<0x08>));\n    if (pFooter08->Version == 1 && pFooter08->Reserved[0] == 0 && pFooter08->Reserved[1] == 0 && pFooter08->FooterHashBytes == 8)\n    {\n        // Copy the entire structure\n        memcpy(InFooter.TocHash, pFooter08->TocHash, MD5_HASH_SIZE);\n        memcpy(InFooter.FooterHash, pFooter08->FooterHash, pFooter08->FooterHashBytes);\n        InFooter.Version = pFooter08->Version;\n        InFooter.OffsetBytes = pFooter08->OffsetBytes;\n        InFooter.SizeBytes = pFooter08->SizeBytes;\n        InFooter.EKeyLength = pFooter08->EKeyLength;\n        InFooter.FooterHashBytes = pFooter08->FooterHashBytes;\n        InFooter.PageLength = pFooter08->PageSizeKB << 10;\n        InFooter.ItemLength = pFooter08->EKeyLength + pFooter08->OffsetBytes + pFooter08->SizeBytes;\n        InFooter.FooterLength = sizeof(FILE_INDEX_FOOTER<0x08>);\n        InFooter.ElementCount = ConvertBytesToInteger_4_LE(pFooter08->ElementCount);\n\n        // Verify the hash. FooterHash needs to be cleared in order to calculate footer hash properly\n        checksum_data_length = FIELD_OFFSET(FILE_INDEX_FOOTER<0x08>, FooterHash) - FIELD_OFFSET(FILE_INDEX_FOOTER<0x08>, Version);\n        memcpy(checksum_data, &pFooter08->Version, checksum_data_length);\n        CascCalculateDataBlockHash(checksum_data, sizeof(FILE_INDEX_FOOTER<0x08>) - MD5_HASH_SIZE, md5_hash);\n        if(!memcmp(md5_hash, InFooter.FooterHash, InFooter.FooterHashBytes))\n            return ERROR_SUCCESS;\n    }\n\n    assert(false);\n    return ERROR_BAD_FORMAT;\n}\n\nstatic DWORD CaptureIndexEntry(CASC_ARCINDEX_FOOTER  & InFooter, CASC_EKEY_ENTRY & EKeyEntry, LPBYTE pbIndexPage, LPBYTE pbIndexPageEnd, size_t nArchive)\n{\n    ULONGLONG StorageOffset = nArchive;\n    ULONGLONG ArchiveOffset;\n\n    // If there enough bytes for one entry/\n    if ((pbIndexPage + InFooter.ItemLength) > pbIndexPageEnd)\n        return ERROR_BAD_FORMAT;\n\n    // Capture the EKey (variable length)\n    pbIndexPage = CaptureEncodedKey(EKeyEntry.EKey, pbIndexPage, InFooter.EKeyLength);\n\n    // Copy the archive offset\n    ArchiveOffset = ConvertBytesToInteger_X(pbIndexPage + InFooter.SizeBytes, InFooter.OffsetBytes);\n    if (ArchiveOffset >= 0x10000000)\n        return ERROR_BAD_FORMAT;\n\n    // Capture the storage offset and encoded size\n    EKeyEntry.StorageOffset = (StorageOffset << (InFooter.OffsetBytes * 8)) | ArchiveOffset;\n    EKeyEntry.EncodedSize = ConvertBytesToInteger_X(pbIndexPage, InFooter.SizeBytes);\n    EKeyEntry.Alignment = 0;\n\n    // Is there a valid hash?\n    return CascIsValidMD5(EKeyEntry.EKey) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n}\n\nstatic DWORD VerifyIndexSize(CASC_ARCINDEX_FOOTER  & InFooter, LPBYTE pbIndexFile, size_t cbIndexFile, LPBYTE * PtrIndexEnd)\n{\n    size_t nPageCount;\n\n    // Set the new length (without the footer)\n    cbIndexFile = cbIndexFile - InFooter.FooterLength;\n    nPageCount = cbIndexFile / (InFooter.PageLength + MD5_HASH_SIZE);\n\n    // There must be equal or more pages\n    if(((InFooter.PageLength + MD5_HASH_SIZE) * nPageCount) > cbIndexFile)\n        return ERROR_BAD_FORMAT;\n\n    // Return the end-of-index\n    nPageCount = cbIndexFile / (InFooter.PageLength + MD5_HASH_SIZE);\n    PtrIndexEnd[0] = pbIndexFile + (nPageCount * InFooter.PageLength);\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD LoadArchiveIndexPage(TCascStorage * hs, CASC_ARCINDEX_FOOTER & InFooter, LPBYTE pbIndexPage, LPBYTE pbIndexPageEnd, size_t nArchive)\n{\n    CASC_EKEY_ENTRY EKeyEntry;\n    DWORD dwErrCode;\n\n    while (pbIndexPage <= pbIndexPageEnd)\n    {\n        // Capture the index entry\n        dwErrCode = CaptureIndexEntry(InFooter, EKeyEntry, pbIndexPage, pbIndexPageEnd, nArchive);\n        if (dwErrCode != ERROR_SUCCESS)\n            break;\n\n        // Insert a new entry to the index array\n        if((hs->IndexArray.Insert(&EKeyEntry, 1)) == NULL)\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        // Move to the next entry\n        pbIndexPage += InFooter.ItemLength;\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD LoadArchiveIndexFile(TCascStorage * hs, LPBYTE pbIndexFile, DWORD cbIndexFile, size_t nArchive)\n{\n    CASC_ARCINDEX_FOOTER InFooter;\n    LPBYTE pbIndexEnd = NULL;\n    DWORD dwErrCode;\n\n    // Validate and capture the footer\n    dwErrCode = CaptureArcIndexFooter(InFooter, pbIndexFile, cbIndexFile);\n    if (dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Remember the file offset and EKey length\n    SaveFileOffsetBitsAndEKeyLength(hs, InFooter.OffsetBytes * 8, InFooter.EKeyLength);\n\n    // Verify the size of the index file\n    dwErrCode = VerifyIndexSize(InFooter, pbIndexFile, cbIndexFile, &pbIndexEnd);\n    if (dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Parse all pages\n    while (pbIndexFile < pbIndexEnd)\n    {\n        // Load the entire page\n        dwErrCode = LoadArchiveIndexPage(hs, InFooter, pbIndexFile, pbIndexFile + InFooter.PageLength, nArchive);\n        if (dwErrCode != ERROR_SUCCESS)\n            break;\n\n        // Move to the next page\n        pbIndexFile += InFooter.PageLength;\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD BuildMapOfArchiveIndices(TCascStorage * hs)\n{\n    PCASC_EKEY_ENTRY pEKeyEntry;\n    size_t nItemCount = hs->IndexArray.ItemCount();\n    DWORD dwErrCode;\n\n    // Create the map\n    dwErrCode = hs->IndexMap.Create(nItemCount, MD5_HASH_SIZE, FIELD_OFFSET(CASC_EKEY_ENTRY, EKey));\n    if (dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Insert all items\n    for(size_t i = 0; i < nItemCount; i++)\n    {\n        pEKeyEntry = (PCASC_EKEY_ENTRY)hs->IndexArray.ItemAt(i);\n        if (pEKeyEntry != NULL)\n        {\n            if (!hs->IndexMap.InsertObject(pEKeyEntry, pEKeyEntry->EKey))\n            {\n                return ERROR_NOT_ENOUGH_MEMORY;\n            }\n        }\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD LoadArchiveIndexFiles(TCascStorage * hs)\n{\n    LPBYTE pbFileData;\n    TCHAR szLocalPath[MAX_PATH];\n    DWORD cbFileData = 0;\n    size_t nArchiveCount = (hs->ArchivesKey.cbData / MD5_HASH_SIZE);\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Create the array object for the indices\n    dwErrCode = hs->IndexArray.Create(sizeof(CASC_EKEY_ENTRY), 0x10000);\n    if (dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Load all the indices\n    for (size_t i = 0; i < nArchiveCount; i++)\n    {\n        CASC_CDN_DOWNLOAD CdnsInfo = {0};\n        LPBYTE pbIndexHash = hs->ArchivesKey.pbData + (i * MD5_HASH_SIZE);\n\n        // Inform the user about what we are doing\n        if(InvokeProgressCallback(hs, \"Downloading archive indexes\", NULL, (DWORD)(i), (DWORD)(nArchiveCount)))\n        {\n            dwErrCode = ERROR_CANCELLED;\n            break;\n        }\n\n        // Prepare the download structure for \"%CDNS_HOST%/%CDNS_PATH%/##/##/EKey\" file\n        CdnsInfo.szCdnsPath = hs->szCdnPath;\n        CdnsInfo.szPathType = _T(\"data\");\n        CdnsInfo.pbEKey = pbIndexHash;\n        CdnsInfo.szExtension = _T(\".index\");\n        CdnsInfo.szLocalPath = szLocalPath;\n        CdnsInfo.ccLocalPath = _countof(szLocalPath);\n        dwErrCode = DownloadFileFromCDN(hs, CdnsInfo);\n\n        // Load and parse the archive index\n        if (dwErrCode == ERROR_SUCCESS)\n        {\n            // Load the index file to memory\n            pbFileData = LoadFileToMemory(szLocalPath, &cbFileData);\n            if (pbFileData && cbFileData)\n            {\n                dwErrCode = LoadArchiveIndexFile(hs, pbFileData, cbFileData, i);\n                CASC_FREE(pbFileData);\n            }\n        }\n\n        // Break if an error\n        if (dwErrCode != ERROR_SUCCESS)\n            break;\n    }\n\n    // Build map of EKey -> CASC_EKEY_ENTRY\n    if (dwErrCode == ERROR_SUCCESS)\n        dwErrCode = BuildMapOfArchiveIndices(hs);\n    return dwErrCode;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nbool CopyEKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    LPBYTE pbEKeyEntry = (LPBYTE)hs->IndexEKeyMap.FindObject(pCKeyEntry->EKey);\n\n    // Don't do this on online storages\n    if(!(hs->dwFeatures & CASC_FEATURE_ONLINE))\n    {\n        // If the file was found, then copy the content to the CKey entry\n        pbEKeyEntry = (LPBYTE)hs->IndexEKeyMap.FindObject(pCKeyEntry->EKey);\n        if(pbEKeyEntry == NULL)\n            return false;\n\n        pCKeyEntry->StorageOffset = ConvertBytesToInteger_5(pbEKeyEntry + hs->EKeyLength);\n        pCKeyEntry->EncodedSize = ConvertBytesToInteger_4_LE(pbEKeyEntry + hs->EKeyLength + 5);\n        pCKeyEntry->Flags |= CASC_CE_FILE_IS_LOCAL;\n    }\n\n    return true;\n}\n\nDWORD LoadIndexFiles(TCascStorage * hs)\n{\n    // For local storages, load the index files from the disk\n    // For online storages, load the index files from the cache / internet\n    if(hs->dwFeatures & CASC_FEATURE_ONLINE)\n    {\n        return LoadArchiveIndexFiles(hs);\n    }\n    else\n    {\n        return LoadLocalIndexFiles(hs);\n    }\n}\n\nvoid FreeIndexFiles(TCascStorage * hs)\n{\n    // Free the map of EKey -> Index Ekey item\n    hs->IndexEKeyMap.Free();\n\n    // Free all loaded index files\n    for(size_t i = 0; i < CASC_INDEX_COUNT; i++)\n    {\n        CASC_INDEX & IndexFile = hs->IndexFiles[i];\n\n        // Free the file data\n        CASC_FREE(IndexFile.pbFileData);\n        IndexFile.cbFileData = 0;\n\n        // Free the file name\n        CASC_FREE(IndexFile.szFileName);\n    }\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascLib.h",
    "content": "/*****************************************************************************/\n/* CascLib.h                              Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* CascLib library v 1.00                                                    */\n/*                                                                           */\n/* Author : Ladislav Zezula                                                  */\n/* E-mail : ladik@zezula.net                                                 */\n/* WWW    : http://www.zezula.net                                            */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __CASCLIB_H__\n#define __CASCLIB_H__\n\n#ifdef _MSC_VER\n#pragma warning(disable:4668)                   // 'XXX' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'\n#pragma warning(disable:4820)       // 'XXX' : '2' bytes padding added after data member 'XXX::yyy'\n#endif\n\n#include \"CascPort.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//-----------------------------------------------------------------------------\n// Use the apropriate library\n//\n// The library type is encoded in the library name as the following\n// CascLibXYZ.lib\n//\n//  X - D for Debug version, R for Release version\n//  Y - A for ANSI version, U for Unicode version\n//  Z - S for static-linked CRT library, D for dynamic CRT library (dll)\n//\n\n#if defined(_MSC_VER) && !defined(__CASCLIB_SELF__) && !defined(CASCLIB_NO_AUTO_LINK_LIBRARY)\n  #ifndef WDK_BUILD\n    #ifdef _DEBUG                                 // DEBUG VERSIONS\n      #ifndef _UNICODE\n        #ifdef _DLL\n          #pragma comment(lib, \"CascLibDAD.lib\")  // Debug Ansi CRT-DLL version\n        #else\n          #pragma comment(lib, \"CascLibDAS.lib\")  // Debug Ansi CRT-LIB version\n        #endif\n      #else\n        #ifdef _DLL\n          #pragma comment(lib, \"CascLibDUD.lib\")  // Debug Unicode CRT-DLL version\n        #else\n          #pragma comment(lib, \"CascLibDUS.lib\")  // Debug Unicode CRT-LIB version\n        #endif\n      #endif\n    #else                                         // RELEASE VERSIONS\n      #ifndef _UNICODE\n        #ifdef _DLL\n          #pragma comment(lib, \"CascLibRAD.lib\")  // Release Ansi CRT-DLL version\n        #else\n          #pragma comment(lib, \"CascLibRAS.lib\")  // Release Ansi CRT-LIB version\n        #endif\n      #else\n        #ifdef _DLL\n          #pragma comment(lib, \"CascLibRUD.lib\")  // Release Unicode CRT-DLL version\n        #else\n          #pragma comment(lib, \"CascLibRUS.lib\")  // Release Unicode CRT-LIB version\n        #endif\n      #endif\n    #endif\n  #endif\n#endif\n\n//-----------------------------------------------------------------------------\n// Defines\n\n#define CASCLIB_VERSION                 0x0210  // CascLib version - integral (2.1)\n#define CASCLIB_VERSION_STRING           \"2.1\"  // CascLib version - string\n\n// Values for CascOpenFile\n#define CASC_OPEN_BY_NAME           0x00000000  // Open the file by name. This is the default value\n#define CASC_OPEN_BY_CKEY           0x00000001  // The name is just the content key; skip ROOT file processing\n#define CASC_OPEN_BY_EKEY           0x00000002  // The name is just the encoded key; skip ROOT file processing\n#define CASC_OPEN_BY_FILEID         0x00000003  // The name is CASC_FILE_DATA_ID(FileDataId)\n#define CASC_OPEN_TYPE_MASK         0x0000000F  // The mask which gets open type from the dwFlags\n#define CASC_OPEN_FLAGS_MASK        0xFFFFFFF0  // The mask which gets open type from the dwFlags\n#define CASC_STRICT_DATA_CHECK      0x00000010  // Verify all data read from a file\n#define CASC_OVERCOME_ENCRYPTED     0x00000020  // When CascReadFile encounters a block encrypted with a key that is missing, the block is filled with zeros and returned as success\n\n#define CASC_LOCALE_ALL             0xFFFFFFFF\n#define CASC_LOCALE_ALL_WOW         0x0001F3F6  // All except enCN and enTW\n#define CASC_LOCALE_NONE            0x00000000\n#define CASC_LOCALE_UNKNOWN1        0x00000001\n#define CASC_LOCALE_ENUS            0x00000002\n#define CASC_LOCALE_KOKR            0x00000004\n#define CASC_LOCALE_RESERVED        0x00000008\n#define CASC_LOCALE_FRFR            0x00000010\n#define CASC_LOCALE_DEDE            0x00000020\n#define CASC_LOCALE_ZHCN            0x00000040\n#define CASC_LOCALE_ESES            0x00000080\n#define CASC_LOCALE_ZHTW            0x00000100\n#define CASC_LOCALE_ENGB            0x00000200\n#define CASC_LOCALE_ENCN            0x00000400\n#define CASC_LOCALE_ENTW            0x00000800\n#define CASC_LOCALE_ESMX            0x00001000\n#define CASC_LOCALE_RURU            0x00002000\n#define CASC_LOCALE_PTBR            0x00004000\n#define CASC_LOCALE_ITIT            0x00008000\n#define CASC_LOCALE_PTPT            0x00010000\n\n// Content flags on WoW\n#define CASC_CFLAG_LOAD_ON_WINDOWS        0x08\n#define CASC_CFLAG_LOAD_ON_MAC            0x10\n#define CASC_CFLAG_LOW_VIOLENCE           0x80\n#define CASC_CFLAG_DONT_LOAD             0x100\n#define CASC_CFLAG_NO_NAME_HASH     0x10000000\n#define CASC_CFLAG_BUNDLE           0x40000000\n#define CASC_CFLAG_NO_COMPRESSION   0x80000000\n\n#ifndef MD5_HASH_SIZE\n#define MD5_HASH_SIZE                     0x10\n#define MD5_STRING_SIZE                   0x20\n#endif\n\n// Return value for CascGetFileSize and CascSetFilePointer\n#define CASC_INVALID_INDEX          0xFFFFFFFF\n#define CASC_INVALID_SIZE           0xFFFFFFFF\n#define CASC_INVALID_POS            0xFFFFFFFF\n#define CASC_INVALID_ID             0xFFFFFFFF\n#define CASC_INVALID_OFFS64         0xFFFFFFFFFFFFFFFF\n#define CASC_INVALID_SIZE64         0xFFFFFFFFFFFFFFFF\n\n// Flags for CASC_STORAGE_FEATURES::dwFeatures\n#define CASC_FEATURE_FILE_NAMES     0x00000001  // File names are supported by the storage\n#define CASC_FEATURE_ROOT_CKEY      0x00000002  // Present if the storage's ROOT returns CKey\n#define CASC_FEATURE_TAGS           0x00000004  // Tags are supported by the storage\n#define CASC_FEATURE_FNAME_HASHES   0x00000008  // The storage contains file name hashes on ALL files\n#define CASC_FEATURE_FNAME_HASHES_OPTIONAL 0x00000010  // The storage contains file name hashes for SOME files\n#define CASC_FEATURE_FILE_DATA_IDS  0x00000020  // The storage indexes files by FileDataId\n#define CASC_FEATURE_LOCALE_FLAGS   0x00000040  // Locale flags are supported\n#define CASC_FEATURE_CONTENT_FLAGS  0x00000080  // Content flags are supported\n#define CASC_FEATURE_ONLINE         0x00000100  // The storage is an online storage\n\n// Macro to convert FileDataId to the argument of CascOpenFile\n#define CASC_FILE_DATA_ID(FileDataId) ((LPCSTR)(size_t)FileDataId)\n#define CASC_FILE_DATA_ID_FROM_STRING(szFileName)  ((DWORD)(size_t)szFileName)\n\n// Maximum length of encryption key\n#define CASC_KEY_LENGTH 0x10\n\n//-----------------------------------------------------------------------------\n// Structures\n\ntypedef enum _CASC_STORAGE_INFO_CLASS\n{\n    // Returns the number of local files in the storage. Note that files\n    // can exist under different names, so the total number of files in the archive\n    // can be higher than the value returned by this info class\n    CascStorageLocalFileCount,\n\n    // Returns the total file count, including the offline files\n    CascStorageTotalFileCount,\n\n\n    CascStorageFeatures,                        // Returns the features flag\n    CascStorageInstalledLocales,                // Not supported\n    CascStorageProduct,                         // Gives CASC_STORAGE_PRODUCT\n    CascStorageTags,                            // Gives CASC_STORAGE_TAGS structure\n    CascStoragePathProduct,                     // Gives Path:Product into a LPTSTR buffer\n    CascStorageInfoClassMax\n\n} CASC_STORAGE_INFO_CLASS, *PCASC_STORAGE_INFO_CLASS;\n\ntypedef enum _CASC_FILE_INFO_CLASS\n{\n    CascFileContentKey,\n    CascFileEncodedKey,\n    CascFileFullInfo,                           // Gives CASC_FILE_FULL_INFO structure\n    CascFileSpanInfo,                           // Gives CASC_FILE_SPAN_INFO structure for each file span\n    CascFileInfoClassMax\n} CASC_FILE_INFO_CLASS, *PCASC_FILE_INFO_CLASS;\n\n// CascLib may provide a fake name, constructed from file data id, CKey or EKey.\n// This enum helps to see what name was actually returned\n// Note that any of these names can be passed to CascOpenFile with no extra flags\ntypedef enum _CASC_NAME_TYPE\n{\n    CascNameFull,                               // Fully qualified file name\n    CascNameDataId,                             // Name created from file data id (FILE%08X.dat)\n    CascNameCKey,                               // Name created as string representation of CKey\n    CascNameEKey                                // Name created as string representation of EKey\n} CASC_NAME_TYPE, *PCASC_NAME_TYPE;\n\n// Structure for SFileFindFirstFile and SFileFindNextFile\ntypedef struct _CASC_FIND_DATA\n{\n    // Full name of the found file. In case when this is CKey/EKey,\n    // this will be just string representation of the key stored in 'FileKey'\n    char szFileName[MAX_PATH];\n\n    // Content key. This is present if the CASC_FEATURE_ROOT_CKEY is present\n    BYTE CKey[MD5_HASH_SIZE];\n\n    // Encoded key. This is always present.\n    BYTE EKey[MD5_HASH_SIZE];\n\n    // Tag mask. Only valid if the storage supports tags, otherwise 0\n    ULONGLONG TagBitMask;\n\n    // Size of the file, as retrieved from CKey entry\n    ULONGLONG FileSize;\n\n    // Plain name of the found file. Pointing inside the 'szFileName' array\n    char * szPlainName;\n\n    // File data ID. Only valid if the storage supports file data IDs, otherwise CASC_INVALID_ID\n    DWORD dwFileDataId;\n\n    // Locale flags. Only valid if the storage supports locale flags, otherwise CASC_INVALID_ID\n    DWORD dwLocaleFlags;\n\n    // Content flags. Only valid if the storage supports content flags, otherwise CASC_INVALID_ID\n    DWORD dwContentFlags;\n\n    // Span count\n    DWORD dwSpanCount;\n\n    // If true the file is available locally\n    DWORD bFileAvailable:1;\n\n    // Name type in 'szFileName'. In case the file name is not known,\n    // CascLib can put FileDataId-like name or a string representation of CKey/EKey\n    CASC_NAME_TYPE NameType;\n\n} CASC_FIND_DATA, *PCASC_FIND_DATA;\n\ntypedef struct _CASC_STORAGE_TAG\n{\n    LPCSTR szTagName;                           // Tag name (zero terminated, ANSI)\n    DWORD TagNameLength;                        // Length of the tag name\n    DWORD TagValue;                             // Tag value\n} CASC_STORAGE_TAG, *PCASC_STORAGE_TAG;\n\ntypedef struct _CASC_STORAGE_TAGS\n{\n    size_t TagCount;                            // Number of items in the Tags array\n    size_t Reserved;                            // Reserved for future use\n\n    CASC_STORAGE_TAG Tags[1];                   // Array of CASC tags\n\n} CASC_STORAGE_TAGS, *PCASC_STORAGE_TAGS;\n\ntypedef struct _CASC_STORAGE_PRODUCT\n{\n    char szCodeName[0x1C];                      // Code name of the product (\"wowt\" = \"World of Warcraft PTR\")\n    DWORD BuildNumber;                          // Build number. If zero, then CascLib didn't recognize build number\n\n} CASC_STORAGE_PRODUCT, *PCASC_STORAGE_PRODUCT;\n\ntypedef struct _CASC_FILE_FULL_INFO\n{\n    BYTE CKey[MD5_HASH_SIZE];                   // CKey\n    BYTE EKey[MD5_HASH_SIZE];                   // EKey\n    char  DataFileName[0x10];                   // Plain name of the data file where the file is stored\n    ULONGLONG StorageOffset;                    // Offset of the file over the entire storage\n    ULONGLONG SegmentOffset;                    // Offset of the file in the segment file (\"data.###\")\n    ULONGLONG TagBitMask;                       // Bitmask of tags. Zero if not supported\n    ULONGLONG FileNameHash;                     // Hash of the file name. Zero if not supported\n    ULONGLONG ContentSize;                      // Content size of all spans\n    ULONGLONG EncodedSize;                      // Encoded size of all spans\n    DWORD SegmentIndex;                         // Index of the segment file (aka 0 = \"data.000\")\n    DWORD SpanCount;                            // Number of spans forming the file\n    DWORD FileDataId;                           // File data ID. CASC_INVALID_ID if not supported.\n    DWORD LocaleFlags;                          // Locale flags. CASC_INVALID_ID if not supported.\n    DWORD ContentFlags;                         // Locale flags. CASC_INVALID_ID if not supported\n\n} CASC_FILE_FULL_INFO, *PCASC_FILE_FULL_INFO;\n\ntypedef struct _CASC_FILE_SPAN_INFO\n{\n    BYTE CKey[MD5_HASH_SIZE];                   // Content key of the file span\n    BYTE EKey[MD5_HASH_SIZE];                   // Encoded key of the file span\n    ULONGLONG StartOffset;                      // Starting offset of the file span\n    ULONGLONG EndOffset;                        // Ending offset of the file span\n    DWORD ArchiveIndex;                         // Index of the archive\n    DWORD ArchiveOffs;                          // Offset in the archive\n    DWORD HeaderSize;                           // Size of encoded frame headers\n    DWORD FrameCount;                           // Number of frames in this span\n\n} CASC_FILE_SPAN_INFO, *PCASC_FILE_SPAN_INFO;\n\n//-----------------------------------------------------------------------------\n// Extended version of CascOpenStorage\n\n// Some operations (e.g. opening an online storage) may take long time.\n// This callback allows an application to be notified about loading progress\n// and even cancel the storage loading process\ntypedef bool (WINAPI * PFNPROGRESSCALLBACK)(    // Return 'true' to cancel the loading process\n    void * PtrUserParam,                        // User-specific parameter passed to the callback\n    LPCSTR szWork,                              // Text for the current activity (example: \"Loading \"ENCODING\" file\")\n    LPCSTR szObject,                            // (optional) name of the object tied to the activity (example: index file name)\n    DWORD CurrentValue,                         // (optional) current object being processed\n    DWORD TotalValue                            // (optional) If non-zero, this is the total number of objects to process\n    );\n\n// Some storages support multi-product installation (e.g. World of Warcraft).\n// With this callback, the calling application can specify which storage to open\ntypedef bool (WINAPI * PFNPRODUCTCALLBACK)(     // Return 'true' to cancel the loading process\n    void * PtrUserParam,                        // User-specific parameter passed to the callback\n    LPCSTR * ProductList,                       // Array of product codenames found in the storage\n    size_t ProductCount,                        // Number of products in the ProductList array\n    size_t * PtrSelectedProduct                 // [out] This is the selected product to open. On input, set to 0 (aka the first product)\n    );\n\ntypedef struct _CASC_OPEN_STORAGE_ARGS\n{\n    size_t Size;                                // Length of this structure. Initialize to sizeof(CASC_OPEN_STORAGE_ARGS)\n\n    LPCTSTR szLocalPath;                        // Local:  Path to the storage directory (where \".build.info: is) or any of the sub-path\n                                                // Online: Path to the local storage cache\n\n    LPCTSTR szCodeName;                         // If non-null, this will specify a product in a multi-product local storage\n                                                // Has higher priority than PfnProductCallback (if both specified)\n    LPCTSTR szRegion;                           // If non-null, this will specify a product region.\n\n    PFNPROGRESSCALLBACK PfnProgressCallback;    // Progress callback. If non-NULL, this can inform the caller about state of the opening storage\n    void * PtrProgressParam;                    // Pointer-sized parameter that will be passed to PfnProgressCallback\n    PFNPRODUCTCALLBACK PfnProductCallback;      // Progress callback. If non-NULL, will be called on multi-product storage to select one of the products\n    void * PtrProductParam;                     // Pointer-sized parameter that will be passed to PfnProgressCallback\n\n    DWORD dwLocaleMask;                         // Locale mask to open\n    DWORD dwFlags;                              // Reserved. Set to zero.\n\n    //\n    // Any additional member from here on must be checked for availability using the ExtractVersionedArgument function.\n    // Example:\n    //\n    // LPCTSTR szBuildKey = NULL;\n    // ExtractVersionedArgument(pArgs, offsetof(CASC_OPEN_STORAGE_ARGS, szBuildId), &szBuildKey);\n    //\n\n    LPCTSTR szBuildKey;                         // If non-null, this will specify a build key (aka MD5 of build config that is different that current online version)\n\n} CASC_OPEN_STORAGE_ARGS, *PCASC_OPEN_STORAGE_ARGS;\n\n//-----------------------------------------------------------------------------\n// Functions for storage manipulation\n\nbool  WINAPI CascOpenStorageEx(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs, bool bOnlineStorage, HANDLE * phStorage);\nbool  WINAPI CascOpenStorage(LPCTSTR szParams, DWORD dwLocaleMask, HANDLE * phStorage);\nbool  WINAPI CascOpenOnlineStorage(LPCTSTR szParams, DWORD dwLocaleMask, HANDLE * phStorage);\nbool  WINAPI CascGetStorageInfo(HANDLE hStorage, CASC_STORAGE_INFO_CLASS InfoClass, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded);\nbool  WINAPI CascCloseStorage(HANDLE hStorage);\n\nbool  WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocaleFlags, DWORD dwOpenFlags, HANDLE * PtrFileHandle);\nbool  WINAPI CascOpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle);\nbool  WINAPI CascGetFileInfo(HANDLE hFile, CASC_FILE_INFO_CLASS InfoClass, void * pvFileInfo, size_t cbFileInfo, size_t * pcbLengthNeeded);\nbool  WINAPI CascGetFileSize64(HANDLE hFile, PULONGLONG PtrFileSize);\nbool  WINAPI CascSetFilePointer64(HANDLE hFile, LONGLONG DistanceToMove, PULONGLONG PtrNewPos, DWORD dwMoveMethod);\nbool  WINAPI CascReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, PDWORD pdwRead);\nbool  WINAPI CascCloseFile(HANDLE hFile);\n\nDWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh);\nDWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * PtrFilePosHigh, DWORD dwMoveMethod);\n\nHANDLE WINAPI CascFindFirstFile(HANDLE hStorage, LPCSTR szMask, PCASC_FIND_DATA pFindData, LPCTSTR szListFile);\nbool  WINAPI CascFindNextFile(HANDLE hFind, PCASC_FIND_DATA pFindData);\nbool  WINAPI CascFindClose(HANDLE hFind);\n\nbool   WINAPI CascAddEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPBYTE Key);\nbool   WINAPI CascAddStringEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPCSTR szKey);\nbool   WINAPI CascImportKeysFromString(HANDLE hStorage, LPCSTR szKeyList);\nbool   WINAPI CascImportKeysFromFile(HANDLE hStorage, LPCTSTR szFileName);\nLPBYTE WINAPI CascFindEncryptionKey(HANDLE hStorage, ULONGLONG KeyName);\nbool   WINAPI CascGetNotFoundEncryptionKey(HANDLE hStorage, ULONGLONG * KeyName);\n\n//-----------------------------------------------------------------------------\n// Error code support\n\nvoid SetCascError(DWORD dwErrCode);\nDWORD GetCascError();\n\n#ifdef __cplusplus\n}   // extern \"C\"\n#endif\n\n#endif  // __CASCLIB_H__\n"
  },
  {
    "path": "deps/CascLib/src/CascOpenFile.cpp",
    "content": "/*****************************************************************************/\n/* CascOpenFile.cpp                       Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* System-dependent directory functions for CascLib                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 01.05.14  1.00  Lad  The first version of CascOpenFile.cpp                */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// TCascFile class functions\n\nTCascFile::TCascFile(TCascStorage * ahs, PCASC_CKEY_ENTRY apCKeyEntry)\n{\n    // Reference the storage handle\n    if((hs = ahs) != NULL)\n        hs->AddRef();\n    ClassName = CASC_MAGIC_FILE;\n\n    FilePointer = 0;\n    pCKeyEntry = apCKeyEntry;\n    SpanCount = (pCKeyEntry->SpanCount != 0) ? pCKeyEntry->SpanCount : 1;\n    bVerifyIntegrity = false;\n    bDownloadFileIf = false;\n    bCloseFileStream = false;\n    bFreeCKeyEntries = false;\n\n    // Allocate the array of file spans\n    if((pFileSpan = CASC_ALLOC_ZERO<CASC_FILE_SPAN>(SpanCount)) != NULL)\n    {\n        InitFileSpans(pFileSpan, SpanCount);\n        InitCacheStrategy();\n    }\n}\n\nTCascFile::~TCascFile()\n{\n    // Free all stuff related to file spans\n    if (pFileSpan != NULL)\n    {\n        PCASC_FILE_SPAN pSpanPtr = pFileSpan;\n\n        for(DWORD i = 0; i < SpanCount; i++, pSpanPtr++)\n        {\n            // Close the span file stream if this is a local file\n            if(bCloseFileStream)\n                FileStream_Close(pSpanPtr->pStream);\n            pSpanPtr->pStream = NULL;\n\n            // Free the span frames\n            CASC_FREE(pSpanPtr->pFrames);\n        }\n\n        CASC_FREE(pFileSpan);\n    }\n\n    // Free the CKey entries, if needed\n    if(pCKeyEntry && bFreeCKeyEntries)\n        delete [] pCKeyEntry;\n    pCKeyEntry = NULL;\n\n    // Free the file cache\n    CASC_FREE(pbFileCache);\n\n    // Close (dereference) the archive handle\n    if(hs != NULL)\n        hs = hs->Release();\n    ClassName = 0;\n}\n\nDWORD TCascFile::OpenFileSpans(LPCTSTR szSpanList)\n{\n    TFileStream * pStream;\n    ULONGLONG FileSize = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    for(DWORD i = 0; i < SpanCount; i++)\n    {\n        // Open the file span\n        pFileSpan[i].pStream = pStream = FileStream_OpenFile(szSpanList, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT);\n        if(pFileSpan[i].pStream == NULL)\n        {\n            dwErrCode = GetCascError();\n            break;\n        }\n\n        // If succeeded, we assign the span to the \n        FileStream_GetSize(pStream, &FileSize);\n        if((FileSize >> 0x1E) != 0)\n        {\n            dwErrCode = ERROR_NOT_SUPPORTED;\n            break;\n        }\n\n        pCKeyEntry[i].EncodedSize = (DWORD)FileSize;\n    }\n\n    // Free the so-far-opened files\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        for(DWORD i = 0; i < SpanCount; i++)\n        {\n            if(pFileSpan[i].pStream != NULL)\n                FileStream_Close(pFileSpan[i].pStream);\n            pFileSpan[i].pStream = NULL;\n        }\n    }\n\n    return dwErrCode;\n}\n\nvoid TCascFile::InitFileSpans(PCASC_FILE_SPAN pSpans, DWORD dwSpanCount)\n{\n    ULONGLONG FileOffsetBits = 30;\n    ULONGLONG FileOffsetMask = 0;\n    ULONGLONG FileOffset = 0;\n\n    // Initialize the file sizes. Note that if any of the spans has invalid size,\n    // the entire file size will be set to CASC_INVALID_SIZE64.\n    GetFileSpanInfo(pCKeyEntry, &ContentSize, &EncodedSize);\n\n    // Resolve the file offset bits and file offset mask\n    if(hs != NULL)\n        FileOffsetBits = hs->FileOffsetBits;\n    FileOffsetMask = ((ULONGLONG)1 << FileOffsetBits) - 1;\n\n    // Add all span sizes\n    for(DWORD i = 0; i < dwSpanCount; i++, pSpans++)\n    {\n        // Put the archive index and archive offset\n        pSpans->ArchiveIndex = (DWORD)(pCKeyEntry[i].StorageOffset >> FileOffsetBits);\n        pSpans->ArchiveOffs = (DWORD)(pCKeyEntry[i].StorageOffset & FileOffsetMask);\n\n        // Add to the total encoded size\n        if(ContentSize != CASC_INVALID_SIZE64)\n        {\n            pSpans->StartOffset = FileOffset;\n            FileOffset = FileOffset + pCKeyEntry[i].ContentSize;\n            pSpans->EndOffset = FileOffset;\n        }\n    }\n}\n\nvoid TCascFile::InitCacheStrategy()\n{\n    CacheStrategy = CascCacheLastFrame;\n    FileCacheStart = FileCacheEnd = 0;\n    pbFileCache = NULL;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nstatic size_t GetSpanFileCount(LPTSTR szSpanList)\n{\n    LPTSTR szSpanPtr = szSpanList;\n    size_t nSpanCount = 1;\n\n    while(szSpanPtr[0] != 0)\n    {\n        // End of a file?\n        if(szSpanPtr[0] == ';' && szSpanPtr[1] != 0)\n        {\n            szSpanPtr[0] = 0;\n            nSpanCount++;\n        }\n\n        szSpanPtr++;\n    }\n\n    // Place an additional zero to make the list terminated by double EOS\n    szSpanPtr[1] = 0;\n    return nSpanCount;\n}\n\nPCASC_CKEY_ENTRY FindCKeyEntry_CKey(TCascStorage * hs, LPBYTE pbCKey, PDWORD PtrIndex)\n{\n    return (PCASC_CKEY_ENTRY)hs->CKeyMap.FindObject(pbCKey, PtrIndex);\n}\n\nPCASC_CKEY_ENTRY FindCKeyEntry_EKey(TCascStorage * hs, LPBYTE pbEKey, PDWORD PtrIndex)\n{\n    return (PCASC_CKEY_ENTRY)hs->EKeyMap.FindObject(pbEKey, PtrIndex);\n}\n\nbool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD dwOpenFlags, HANDLE * PtrFileHandle)\n{\n    TCascFile * hf = NULL;\n    DWORD dwErrCode = ERROR_FILE_NOT_FOUND;\n\n    // If the CKey entry is NULL, we consider the file non-existant\n    if(pCKeyEntry != NULL)\n    {\n        // Create the file handle structure\n        if((hf = new TCascFile(hs, pCKeyEntry)) != NULL)\n        {\n            hf->bVerifyIntegrity   = (dwOpenFlags & CASC_STRICT_DATA_CHECK)  ? true : false;\n            hf->bDownloadFileIf    = (hs->dwFeatures & CASC_FEATURE_ONLINE)  ? true : false;\n            hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false;\n            dwErrCode = ERROR_SUCCESS;\n        }\n        else\n        {\n            dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n        }\n    }\n\n    // Give the output parameter, no matter what\n    PtrFileHandle[0] = (HANDLE)hf;\n\n    // Handle last error\n    if(dwErrCode != ERROR_SUCCESS)\n        SetCascError(dwErrCode);\n    return (dwErrCode == ERROR_SUCCESS);\n}\n\nbool OpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n    TCascFile * hf = NULL;\n    LPTSTR szSpanList;\n    size_t nSpanCount;\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // Create a copy of the file name. It is actually a file name list,\n    // separated by comma (for supporting multi-span files)\n    if((szSpanList = CascNewStr(szFileName, 1)) != NULL)\n    {\n        // Calculate the span count\n        if((nSpanCount = GetSpanFileCount(szSpanList)) != 0 || nSpanCount > 0xFF)\n        {\n            // Allocate CKey array for the file. Each entry describes one file span\n            if((pCKeyEntry = new CASC_CKEY_ENTRY[nSpanCount]) != NULL)\n            {\n                // Prepare the span count to the first item\n                pCKeyEntry->SpanCount = (BYTE)nSpanCount;\n\n                // Prepare the archive offset in each CKey entry\n                for(size_t i = 0; i < nSpanCount; i++)\n                    pCKeyEntry[i].StorageOffset = 0;\n\n                // Create an instance of the TCascFile\n                if((hf = new TCascFile(NULL, pCKeyEntry)) != NULL)\n                {\n                    // Prepare the structure\n                    hf->bVerifyIntegrity   = (dwOpenFlags & CASC_STRICT_DATA_CHECK)  ? true : false;\n                    hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false;\n                    hf->bCloseFileStream = true;\n\n                    // Open all local file spans\n                    dwErrCode = hf->OpenFileSpans(szSpanList);\n                    if(dwErrCode != ERROR_SUCCESS)\n                    {\n                        delete hf;\n                        hf = NULL;\n                    }\n                }\n            }\n        }\n        else\n        {\n            dwErrCode = ERROR_INVALID_PARAMETER;\n        }\n\n        delete [] szSpanList;\n    }\n\n    // Give the output parameter, no matter what\n    PtrFileHandle[0] = (HANDLE)hf;\n\n    // Handle last error\n    if(dwErrCode != ERROR_SUCCESS)\n        SetCascError(dwErrCode);\n    return (dwErrCode == ERROR_SUCCESS);\n}\n\nbool SetCacheStrategy(HANDLE hFile, CSTRTG CacheStrategy)\n{\n    TCascFile * hf;\n\n    // Validate the file handle\n    if((hf = TCascFile::IsValid(hFile)) != NULL)\n    {\n        // The cache must not be initialized yet\n        if(hf->pbFileCache == NULL)\n        {\n            hf->CacheStrategy = CacheStrategy;\n            return true;\n        }\n    }\n\n    // Failed. This should never happen\n    assert(false);\n    return false;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nbool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocaleFlags, DWORD dwOpenFlags, HANDLE * PtrFileHandle)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = NULL;\n    TCascStorage * hs;\n    const char * szFileName;\n    DWORD FileDataId = CASC_INVALID_ID;\n    BYTE CKeyEKeyBuffer[MD5_HASH_SIZE];\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // This parameter is not used\n    CASCLIB_UNUSED(dwLocaleFlags);\n\n    // Validate the storage handle\n    hs = TCascStorage::IsValid(hStorage);\n    if(hs == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // Validate the other parameters\n    if(PtrFileHandle == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // Retrieve the CKey/EKey from the file name in different modes\n    switch(dwOpenFlags & CASC_OPEN_TYPE_MASK)\n    {\n        case CASC_OPEN_BY_NAME:\n\n            // The 'pvFileName' must be zero terminated ANSI file name\n            szFileName = (const char *)pvFileName;\n            if(szFileName == NULL || szFileName[0] == 0)\n            {\n                SetCascError(ERROR_INVALID_PARAMETER);\n                return false;\n            }\n\n            // The first chance: Try to find the file by name (using the root handler)\n            pCKeyEntry = hs->pRootHandler->GetFile(hs, szFileName);\n            if(pCKeyEntry != NULL)\n                break;\n\n            // Second chance: If the file name is actually a file data id, we convert it to file data ID\n            if(IsFileDataIdName(szFileName, FileDataId))\n            {\n                pCKeyEntry = hs->pRootHandler->GetFile(hs, FileDataId);\n                if(pCKeyEntry != NULL)\n                    break;\n            }\n\n            // Third chance: If the file name is a string representation of CKey/EKey, we try to query for CKey\n            if(IsFileCKeyEKeyName(szFileName, CKeyEKeyBuffer))\n            {\n                pCKeyEntry = FindCKeyEntry_CKey(hs, CKeyEKeyBuffer);\n                if(pCKeyEntry != NULL)\n                    break;\n\n                pCKeyEntry = FindCKeyEntry_EKey(hs, CKeyEKeyBuffer);\n                if(pCKeyEntry != NULL)\n                    break;\n            }\n\n            SetCascError(ERROR_FILE_NOT_FOUND);\n            return false;\n\n        case CASC_OPEN_BY_CKEY:\n\n            // The 'pvFileName' must be a pointer to 16-byte CKey or EKey\n            if(pvFileName == NULL)\n            {\n                SetCascError(ERROR_INVALID_PARAMETER);\n                return false;\n            }\n\n            // Search the CKey map in order to find the CKey entry\n            pCKeyEntry = FindCKeyEntry_CKey(hs, (LPBYTE)pvFileName);\n            break;\n\n        case CASC_OPEN_BY_EKEY:\n\n            // The 'pvFileName' must be a pointer to 16-byte CKey or EKey\n            if(pvFileName == NULL)\n            {\n                SetCascError(ERROR_INVALID_PARAMETER);\n                return false;\n            }\n\n            // Search the CKey map in order to find the CKey entry\n            pCKeyEntry = FindCKeyEntry_EKey(hs, (LPBYTE)pvFileName);\n            break;\n\n        case CASC_OPEN_BY_FILEID:\n\n            // Retrieve the file CKey/EKey\n            pCKeyEntry = hs->pRootHandler->GetFile(hs, CASC_FILE_DATA_ID_FROM_STRING(pvFileName));\n            break;\n\n        default:\n\n            // Unknown open mode\n            dwErrCode = ERROR_INVALID_PARAMETER;\n            break;\n    }\n\n    // Perform the open operation\n    return OpenFileByCKeyEntry(hs, pCKeyEntry, dwOpenFlags, PtrFileHandle);\n}\n\nbool WINAPI CascOpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle)\n{\n    // Verify parameters\n    if(szFileName == NULL || szFileName[0] == 0 || PtrFileHandle == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    return OpenLocalFile(szFileName, dwOpenFlags, PtrFileHandle);\n}\n\nbool WINAPI CascCloseFile(HANDLE hFile)\n{\n    TCascFile * hf;\n\n    hf = TCascFile::IsValid(hFile);\n    if (hf != NULL)\n    {\n        delete hf;\n        return true;\n    }\n\n    SetCascError(ERROR_INVALID_HANDLE);\n    return false;\n}\n\n"
  },
  {
    "path": "deps/CascLib/src/CascOpenStorage.cpp",
    "content": "/*****************************************************************************/\n/* CascOpenStorage.cpp                    Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Storage functions for CASC                                                */\n/* Note: WoW6 offsets refer to WoW.exe 6.0.3.19116 (32-bit)                  */\n/* SHA1: c10e9ffb7d040a37a356b96042657e1a0c95c0dd                            */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of CascOpenStorage.cpp             */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n#ifdef INTERLOCKED_NOT_SUPPORTED\n#pragma error Interlocked operations are not supported on this architecture. Multi-threaded access to CASC storages will not work properly.\n#endif\n\n//-----------------------------------------------------------------------------\n// Local defines\n\n// Limit for \"additional\" items in CKey table\n#define CASC_MAX_EXTRA_ITEMS 0x40\n\n//-----------------------------------------------------------------------------\n// DEBUG functions\n\n#define CHECKED_KEY {0x00, 0x00, 0x0F, 0x84}\n\n#if defined(_DEBUG) && defined(CHECKED_KEY)\n\ninline bool CheckForXKey(LPBYTE XKey)\n{\n    BYTE CheckedKey[] = CHECKED_KEY;\n\n    for(size_t i = 0; i < _countof(CheckedKey); i++)\n    {\n        if(XKey[i] != CheckedKey[i])\n            return false;\n    }\n\n    return true;\n}\n#define BREAK_ON_WATCHED(XKey)  if(CheckForXKey((LPBYTE)XKey))  { __debugbreak(); }\n\n#else\n\n#define BREAK_ON_WATCHED(XKey)  { /* NOTHING */ }\n\n#endif\n\n//-----------------------------------------------------------------------------\n// TCascStorage class functions\n\nTCascStorage::TCascStorage()\n{\n    // Prepare the base storage parameters\n    ClassName = CASC_MAGIC_STORAGE;\n    pRootHandler = NULL;\n    dwRefCount = 1;\n\n    szRootPath = szDataPath = szIndexPath = szBuildFile = szCdnServers = szCdnPath = szCodeName = NULL;\n    szIndexFormat = NULL;\n    szRegion = NULL;\n    szBuildKey = NULL;\n\n    memset(DataFiles, 0, sizeof(DataFiles));\n    memset(IndexFiles, 0, sizeof(IndexFiles));\n    CascInitLock(StorageLock);\n    dwDefaultLocale = 0;\n    dwBuildNumber = 0;\n    dwFeatures = 0;\n    BuildFileType = CascBuildNone;\n\n    LastFailKeyName = 0;\n    LocalFiles = TotalFiles = EKeyEntries = EKeyLength = FileOffsetBits = 0;\n    pArgs = NULL;\n}\n\nTCascStorage::~TCascStorage()\n{\n    // Free the root handler\n    if(pRootHandler != NULL)\n        delete pRootHandler;\n    pRootHandler = NULL;\n\n    // Close all data files\n    for(size_t i = 0; i < CASC_MAX_DATA_FILES; i++)\n    {\n        FileStream_Close(DataFiles[i]);\n        DataFiles[i] = NULL;\n    }\n\n    // Cleanup space occupied by index files\n    FreeIndexFiles(this);\n\n    // Cleanup the lock\n    CascFreeLock(StorageLock);\n\n    // Free the file paths\n    CASC_FREE(szDataPath);\n    CASC_FREE(szRootPath);\n    CASC_FREE(szBuildFile);\n    CASC_FREE(szIndexPath);\n    CASC_FREE(szCdnServers);\n    CASC_FREE(szCdnPath);\n    CASC_FREE(szCodeName);\n    CASC_FREE(szRegion);\n    CASC_FREE(szBuildKey);\n\n    // Free the blobs\n    FreeCascBlob(&CdnConfigKey);\n    FreeCascBlob(&CdnBuildKey);\n    \n    FreeCascBlob(&ArchiveGroup);\n    FreeCascBlob(&ArchivesKey);\n    FreeCascBlob(&PatchArchivesKey);\n    FreeCascBlob(&PatchArchivesGroup);\n    FreeCascBlob(&BuildFiles);\n    ClassName = 0;\n}\n\nTCascStorage * TCascStorage::AddRef()\n{\n    // Need this to be atomic to make multi-threaded file opens work\n    CascInterlockedIncrement(&dwRefCount);\n    return this;\n}\n\nTCascStorage * TCascStorage::Release()\n{\n    // If the reference count reached zero, we close the archive\n    // Need this to be atomic to make multi-threaded file opens work\n    if(CascInterlockedDecrement(&dwRefCount) == 0)\n    {\n        // Release all references in the socket cache\n        if(dwFeatures & CASC_FEATURE_ONLINE)\n            sockets_set_caching(false);\n\n        // Delete the object and return NULL\n        delete this;\n        return NULL;\n    }\n\n    return this;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nvoid * ProbeOutputBuffer(void * pvBuffer, size_t cbLength, size_t cbMinLength, size_t * pcbLengthNeeded)\n{\n    // Verify the output length\n    if(cbLength < cbMinLength)\n    {\n        SetCascError(ERROR_INSUFFICIENT_BUFFER);\n        pvBuffer = NULL;\n    }\n\n    // Give the output length and return result\n    if(pcbLengthNeeded != NULL)\n        pcbLengthNeeded[0] = cbMinLength;\n    return pvBuffer;\n}\n\nstatic LPTSTR CheckForIndexDirectory(TCascStorage * hs, LPCTSTR szSubDir)\n{\n    TCHAR szIndexPath[MAX_PATH];\n\n    // Combine the index path\n    CombinePath(szIndexPath, _countof(szIndexPath), hs->szDataPath, szSubDir, NULL);\n\n    // Check whether the path exists\n    if(!DirectoryExists(szIndexPath))\n        return NULL;\n\n    return CascNewStr(szIndexPath);\n}\n\n// Inserts an entry from the text build file\nstatic PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, CASC_CKEY_ENTRY & CKeyEntry)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = NULL;\n\n    // Stop on file-of-interest\n    BREAK_ON_WATCHED(CKeyEntry.EKey);\n\n    // Skip entries without any key\n    if(CKeyEntry.Flags & (CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY))\n    {\n        // Check if there is an existing entry\n        if((pCKeyEntry = FindCKeyEntry_CKey(hs, CKeyEntry.CKey)) == NULL)\n        {\n            // Insert a new entry to the array. DO NOT ALLOW enlarge array here\n            pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false);\n            if(pCKeyEntry == NULL)\n                return NULL;\n\n            // Fill in the item\n            memcpy(pCKeyEntry, &CKeyEntry, sizeof(CASC_CKEY_ENTRY));\n\n            // If we have CKey present, insert it to the CKey map\n            if(CKeyEntry.Flags & CASC_CE_HAS_CKEY)\n                hs->CKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->CKey);\n\n            // If we have EKey present, insert it to the EKey map\n            if(CKeyEntry.Flags & CASC_CE_HAS_EKEY)\n                hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey);\n        }\n        else\n        {\n            if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE)\n                pCKeyEntry->ContentSize = CKeyEntry.ContentSize;\n            if(pCKeyEntry->EncodedSize == CASC_INVALID_SIZE)\n                pCKeyEntry->EncodedSize = CKeyEntry.EncodedSize;\n        }\n    }\n\n    return pCKeyEntry;\n}\n\n// Inserts an entry from ENCODING\nstatic PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, PFILE_CKEY_ENTRY pFileEntry)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n\n    // Stop on file-of-interest\n    BREAK_ON_WATCHED(pFileEntry->EKey);\n\n    // Insert a new entry to the array. DO NOT ALLOW enlarge array here\n    pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false);\n    if(pCKeyEntry != NULL)\n    {\n        // Initialize the entry\n        CopyMemory16(pCKeyEntry->CKey, pFileEntry->CKey);\n        CopyMemory16(pCKeyEntry->EKey, pFileEntry->EKey);\n        pCKeyEntry->StorageOffset = CASC_INVALID_OFFS64;\n        pCKeyEntry->TagBitMask = 0;\n        pCKeyEntry->ContentSize = ConvertBytesToInteger_4(pFileEntry->ContentSize);\n        pCKeyEntry->EncodedSize = CASC_INVALID_SIZE;\n        pCKeyEntry->Flags = CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY | CASC_CE_IN_ENCODING;\n        pCKeyEntry->RefCount = 0;\n        pCKeyEntry->SpanCount = 1;\n        pCKeyEntry->Priority = 0;\n\n        // Copy the information from index files to the CKey entry\n        CopyEKeyEntry(hs, pCKeyEntry);\n\n        // Insert the item into both maps\n        hs->CKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->CKey);\n        hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey);\n    }\n    else\n    {\n        assert(false);\n    }\n\n    return pCKeyEntry;\n}\n\n// Inserts an entry from DOWNLOAD\nstatic PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, CASC_DOWNLOAD_ENTRY & DlEntry)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n\n    // Stop on file-of-interest\n    BREAK_ON_WATCHED(DlEntry.EKey);\n\n    // Check whether the entry is already there\n    if((pCKeyEntry = FindCKeyEntry_EKey(hs, DlEntry.EKey)) == NULL)\n    {\n        // Insert dummy CKey entry to the array. DO NOT allow to enlarge the array\n        pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false);\n        if(pCKeyEntry == NULL)\n        {\n            assert(false);\n            return NULL;\n        }\n\n        // Copy the entry\n        ZeroMemory16(pCKeyEntry->CKey);\n        CopyMemory16(pCKeyEntry->EKey, DlEntry.EKey);\n        pCKeyEntry->StorageOffset = CASC_INVALID_OFFS64;\n        pCKeyEntry->TagBitMask = 0;\n        pCKeyEntry->ContentSize = CASC_INVALID_SIZE;\n        pCKeyEntry->EncodedSize = (DWORD)DlEntry.EncodedSize;\n        pCKeyEntry->Flags = CASC_CE_HAS_EKEY | CASC_CE_IN_DOWNLOAD;\n        pCKeyEntry->RefCount = 0;\n        pCKeyEntry->SpanCount = 1;\n\n        // Copy the information from index files to the CKey entry\n        CopyEKeyEntry(hs, pCKeyEntry);\n\n        // Insert the entry to the map. Only insert it to the EKey map, as there is no CKey present\n        hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey);\n    }\n    else\n    {\n        // Copy the EKey if we only have partial one\n        if(pCKeyEntry->Flags & CASC_CE_HAS_EKEY_PARTIAL)\n            CopyMemory16(pCKeyEntry->EKey, DlEntry.EKey);\n\n        // Supply the encoded size, if unknown yet\n        if(pCKeyEntry->EncodedSize == CASC_INVALID_SIZE)\n            pCKeyEntry->EncodedSize = (DWORD)DlEntry.EncodedSize;\n        pCKeyEntry->Flags = (pCKeyEntry->Flags & ~CASC_CE_HAS_EKEY_PARTIAL) | CASC_CE_IN_DOWNLOAD;\n    }\n\n    // Supply the rest\n    pCKeyEntry->Priority = DlEntry.Priority;\n    return pCKeyEntry;\n}\n\nstatic DWORD CopyBuildFileItemsToCKeyArray(TCascStorage * hs)\n{\n    // Insert the well-known files\n//  InsertCKeyEntry(hs, hs->EncodingCKey);\n    InsertCKeyEntry(hs, hs->DownloadCKey);\n    InsertCKeyEntry(hs, hs->InstallCKey);\n    InsertCKeyEntry(hs, hs->PatchFile);\n    InsertCKeyEntry(hs, hs->RootFile);\n    InsertCKeyEntry(hs, hs->SizeFile);\n    InsertCKeyEntry(hs, hs->VfsRoot);\n\n    // Insert all VFS roots\n    for(size_t i = 0; i < hs->VfsRootList.ItemCount(); i++)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry = (PCASC_CKEY_ENTRY)hs->VfsRootList.ItemAt(i);\n        InsertCKeyEntry(hs, *pCKeyEntry);\n    }\n\n    return ERROR_SUCCESS;\n}\n\n// Estimate the total number of files, so we won't have to re-allocate arrays and maps\n// and thus speed-up storage loading. In theory, we could guess the file count by\n// measuring size of ENCODING or DOWNLOAD manifests.\nstatic size_t GetEstimatedNumberOfFiles(TCascStorage * hs)\n{\n    size_t nNumberOfFiles1 = 0;\n    size_t nNumberOfFiles2 = 0;\n\n    // If we know the size of DOWNLOAD at this point, we estimate number of files from it.\n    // Size of one entry in DOWNLOAD is at least 22 bytes. This is the most reliable method.\n    // However, for some online storages (\"agent\"), this is a very small value\n    if(hs->DownloadCKey.ContentSize != CASC_INVALID_SIZE)\n        nNumberOfFiles1 = (hs->DownloadCKey.ContentSize / sizeof(FILE_DOWNLOAD_ENTRY)) + CASC_MAX_EXTRA_ITEMS;\n\n    // If we know the size of ENCODING at this point, we estimate number of files from it.\n    // Size of one entry in ENCODING is at least 38 bytes. This method fails on storages\n    // with TVFS file system, as ENCODING only contains a small subset of file.\n    // Fortunately, all known TVFS-based storages have \"download-size\" present\n    if(hs->EncodingCKey.ContentSize != CASC_INVALID_SIZE)\n        nNumberOfFiles2 = (hs->EncodingCKey.ContentSize / sizeof(FILE_CKEY_ENTRY)) + CASC_MAX_EXTRA_ITEMS;\n\n    // Do we know any of them?\n    if(nNumberOfFiles1 || nNumberOfFiles2)\n        return CASCLIB_MAX(nNumberOfFiles1, nNumberOfFiles2);\n\n    // Older storages (HOTS before 39445, WoW before 19116) don't state sizes of ENCODING\n    // and DOWNLOAD in the Build Config files. Solution: Assume there is max 1M of files\n    return 1000000;\n}\n\nstatic DWORD InitCKeyArray(TCascStorage * hs)\n{\n    size_t nNumberOfFiles = GetEstimatedNumberOfFiles(hs);\n    DWORD dwErrCode;\n\n    //\n    // Allocate array and map of CKey entries\n    //\n\n    // Create the array of CKey items\n    dwErrCode = hs->CKeyArray.Create(sizeof(CASC_CKEY_ENTRY), nNumberOfFiles);\n    if(dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Create the map CKey -> CASC_CKEY_ENTRY\n    dwErrCode = hs->CKeyMap.Create(nNumberOfFiles, MD5_HASH_SIZE, FIELD_OFFSET(CASC_CKEY_ENTRY, CKey));\n    if(dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    // Create the map CKey -> CASC_CKEY_ENTRY. Note that TVFS root references files\n    // using 9-byte EKey, so cut the search EKey length to 9 bytes\n    dwErrCode = hs->EKeyMap.Create(nNumberOfFiles, CASC_EKEY_SIZE, FIELD_OFFSET(CASC_CKEY_ENTRY, EKey));\n    if(dwErrCode != ERROR_SUCCESS)\n        return dwErrCode;\n\n    return ERROR_SUCCESS;\n}\n\nint CaptureEncodingHeader(CASC_ENCODING_HEADER & EnHeader, LPBYTE pbFileData, size_t cbFileData)\n{\n    PFILE_ENCODING_HEADER pFileHeader = (PFILE_ENCODING_HEADER)pbFileData;\n\n    // Check the signature ('EN') and version\n    if(cbFileData < sizeof(FILE_ENCODING_HEADER) || pFileHeader->Magic != FILE_MAGIC_ENCODING || pFileHeader->Version != 0x01)\n        return ERROR_BAD_FORMAT;\n\n    // Note that we don't support CKey and EKey sizes other than 0x10 in the ENCODING file\n    if(pFileHeader->CKeyLength != MD5_HASH_SIZE || pFileHeader->EKeyLength != MD5_HASH_SIZE)\n        return ERROR_BAD_FORMAT;\n\n    EnHeader.Magic = pFileHeader->Magic;\n    EnHeader.Version = pFileHeader->Version;\n    EnHeader.CKeyLength = pFileHeader->CKeyLength;\n    EnHeader.EKeyLength = pFileHeader->EKeyLength;\n    EnHeader.CKeyPageCount = ConvertBytesToInteger_4(pFileHeader->CKeyPageCount);\n    EnHeader.CKeyPageSize = ConvertBytesToInteger_2(pFileHeader->CKeyPageSize) * 1024;\n    EnHeader.EKeyPageCount = ConvertBytesToInteger_4(pFileHeader->EKeyPageCount);\n    EnHeader.EKeyPageSize = ConvertBytesToInteger_2(pFileHeader->EKeyPageSize) * 1024;\n    EnHeader.ESpecBlockSize = ConvertBytesToInteger_4(pFileHeader->ESpecBlockSize);\n    return ERROR_SUCCESS;\n}\n\nstatic int LoadEncodingCKeyPage(TCascStorage * hs, CASC_ENCODING_HEADER & EnHeader, LPBYTE pbPageBegin, LPBYTE pbEndOfPage)\n{\n    PFILE_CKEY_ENTRY pFileEntry;\n    LPBYTE pbFileEntry = pbPageBegin;\n\n    // Sanity checks\n    assert(hs->CKeyMap.IsInitialized());\n    assert(hs->EKeyMap.IsInitialized());\n\n    // Parse all encoding entries\n    while(pbFileEntry < pbEndOfPage)\n    {\n        // Get pointer to the encoding entry\n        pFileEntry = (PFILE_CKEY_ENTRY)pbFileEntry;\n        if(pFileEntry->EKeyCount == 0)\n            break;\n\n        // Example of a file entry with multiple EKeys: \n        // Overwatch build 24919, CKey: 0e 90 94 fa d2 cb 85 ac d0 7c ea 09 f9 c5 ba 00 \n//      BREAKIF(pFileEntry->EKeyCount > 1);\n//      BREAK_ON_XKEY3(pFileEntry->CKey, 0x34, 0x82, 0x1f);\n\n        // Insert the entry to the central CKey table\n        InsertCKeyEntry(hs, pFileEntry);\n\n        // Move to the next encoding entry\n        pbFileEntry = pbFileEntry + 2 + 4 + EnHeader.CKeyLength + (pFileEntry->EKeyCount * EnHeader.EKeyLength);\n    }\n    return ERROR_SUCCESS;\n}\n\nstatic int LoadEncodingManifest(TCascStorage * hs)\n{\n    CASC_CKEY_ENTRY & CKeyEntry = hs->EncodingCKey;\n    LPBYTE pbEncodingFile;\n    DWORD cbEncodingFile = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading ENCODING manifest\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Fill-in the information from the index entry and insert it to the file tree\n    if(!CopyEKeyEntry(hs, &CKeyEntry))\n        return ERROR_FILE_NOT_FOUND;\n    InsertCKeyEntry(hs, CKeyEntry);\n\n    // Load the entire encoding file to memory\n    pbEncodingFile = LoadInternalFileToMemory(hs, &hs->EncodingCKey, &cbEncodingFile);\n    if(pbEncodingFile != NULL && cbEncodingFile != 0)\n    {\n        CASC_ENCODING_HEADER EnHeader;\n\n        // Capture the header of the ENCODING file\n        dwErrCode = CaptureEncodingHeader(EnHeader, pbEncodingFile, cbEncodingFile);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Get the CKey page header and the first page\n            PFILE_CKEY_PAGE pPageHeader = (PFILE_CKEY_PAGE)(pbEncodingFile + sizeof(FILE_ENCODING_HEADER) + EnHeader.ESpecBlockSize);\n            LPBYTE pbCKeyPage = (LPBYTE)(pPageHeader + EnHeader.CKeyPageCount);\n\n            // Go through all CKey pages and verify them\n            for(DWORD i = 0; i < EnHeader.CKeyPageCount; i++)\n            {\n                // Check if there is enough space in the buffer\n                if((pbCKeyPage + EnHeader.CKeyPageSize) > (pbEncodingFile + cbEncodingFile))\n                {\n                    dwErrCode = ERROR_FILE_CORRUPT;\n                    break;\n                }\n\n                // Check the hash of the entire segment\n                // Note that verifying takes considerable time of the storage loading\n//              if(!VerifyDataBlockHash(pbCKeyPage, EnHeader.CKeyPageSize, pEncodingSegment->SegmentHash))\n//              {\n//                  dwErrCode = ERROR_FILE_CORRUPT;\n//                  break;\n//              }\n\n                // Check if the CKey matches with the expected first value\n                if(memcmp(((PFILE_CKEY_ENTRY)pbCKeyPage)->CKey, pPageHeader[i].FirstKey, MD5_HASH_SIZE))\n                {\n                    dwErrCode = ERROR_FILE_CORRUPT;\n                    break;\n                }\n\n                // Load the entire page of CKey entries.\n                // This operation will never fail, because all memory is already pre-allocated\n                dwErrCode = LoadEncodingCKeyPage(hs, EnHeader, pbCKeyPage, pbCKeyPage + EnHeader.CKeyPageSize);\n                if(dwErrCode != ERROR_SUCCESS)\n                    break;\n\n                // Move to the next CKey page\n                pbCKeyPage += EnHeader.CKeyPageSize;\n            }\n        }\n\n        // All CKey->EKey entries from the text build files need to be copied to the CKey array\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            dwErrCode = CopyBuildFileItemsToCKeyArray(hs);\n        }\n\n        // Free the loaded ENCODING file\n        CASC_FREE(pbEncodingFile);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\nsize_t GetTagBitmapLength(LPBYTE pbFilePtr, LPBYTE pbFileEnd, DWORD EntryCount)\n{\n    size_t nBitmapLength;\n\n    nBitmapLength = (EntryCount / 8) + ((EntryCount & 0x07) ? 1 : 0);\n    if ((pbFilePtr + nBitmapLength) > pbFileEnd)\n        nBitmapLength = (pbFileEnd - pbFilePtr);\n\n    return nBitmapLength;\n}\n\nint CaptureDownloadHeader(CASC_DOWNLOAD_HEADER & DlHeader, LPBYTE pbFileData, size_t cbFileData)\n{\n    PFILE_DOWNLOAD_HEADER pFileHeader = (PFILE_DOWNLOAD_HEADER)pbFileData;\n\n    // Check the signature ('DL') and version\n    if(cbFileData < sizeof(FILE_DOWNLOAD_HEADER) || pFileHeader->Magic != FILE_MAGIC_DOWNLOAD || pFileHeader->Version > 3)\n        return ERROR_BAD_FORMAT;\n\n    // Note that we don't support CKey sizes greater than 0x10 in the DOWNLOAD file\n    if(pFileHeader->EKeyLength > MD5_HASH_SIZE)\n        return ERROR_BAD_FORMAT;\n\n    // Capture the header version 1\n    memset(&DlHeader, 0, sizeof(CASC_DOWNLOAD_HEADER));\n    DlHeader.Magic = pFileHeader->Magic;\n    DlHeader.Version = pFileHeader->Version;\n    DlHeader.EKeyLength = pFileHeader->EKeyLength;\n    DlHeader.EntryHasChecksum = pFileHeader->EntryHasChecksum;\n    DlHeader.EntryCount = ConvertBytesToInteger_4(pFileHeader->EntryCount);\n    DlHeader.TagCount = ConvertBytesToInteger_2(pFileHeader->TagCount);\n    DlHeader.HeaderLength = FIELD_OFFSET(FILE_DOWNLOAD_HEADER, FlagByteSize);\n    DlHeader.EntryLength = DlHeader.EKeyLength + 5 + 1 + (DlHeader.EntryHasChecksum ? 4 : 0);\n\n    // Capture header version 2\n    if (pFileHeader->Version >= 2)\n    {\n        DlHeader.FlagByteSize = pFileHeader->FlagByteSize;\n        DlHeader.HeaderLength = FIELD_OFFSET(FILE_DOWNLOAD_HEADER, BasePriority);\n        DlHeader.EntryLength += DlHeader.FlagByteSize;\n\n        // Capture header version 3\n        if (pFileHeader->Version >= 3)\n        {\n            DlHeader.BasePriority = pFileHeader->BasePriority;\n            DlHeader.HeaderLength = sizeof(FILE_DOWNLOAD_HEADER);\n        }\n    }\n\n    return ERROR_SUCCESS;\n}\n\nint CaptureDownloadEntry(CASC_DOWNLOAD_HEADER & DlHeader, CASC_DOWNLOAD_ENTRY & DlEntry, LPBYTE pbFilePtr, LPBYTE pbFileEnd)\n{\n    // Check the range\n    if((pbFilePtr + DlHeader.EntryLength) >= pbFileEnd)\n        return ERROR_BAD_FORMAT;\n    memset(&DlEntry, 0, sizeof(CASC_DOWNLOAD_ENTRY));\n\n    // Copy the EKey\n    memcpy(DlEntry.EKey, pbFilePtr, DlHeader.EKeyLength);\n    pbFilePtr += DlHeader.EKeyLength;\n\n    // Convert the file size\n    DlEntry.EncodedSize = ConvertBytesToInteger_5(pbFilePtr);\n    pbFilePtr += 5;\n\n    // Copy the file priority\n    DlEntry.Priority = pbFilePtr[0];\n    pbFilePtr++;\n\n    // Copy the checksum\n    if(DlHeader.EntryHasChecksum)\n    {\n        DlEntry.Checksum = ConvertBytesToInteger_4(pbFilePtr);\n        pbFilePtr += 4;\n    }\n\n    // Copy the flags\n    DlEntry.Flags = ConvertBytesToInteger_X(pbFilePtr, DlHeader.FlagByteSize);\n    return ERROR_SUCCESS;\n}\n\nint CaptureDownloadTag(CASC_DOWNLOAD_HEADER & DlHeader, CASC_TAG_ENTRY1 & DlTag, LPBYTE pbFilePtr, LPBYTE pbFileEnd)\n{\n    LPBYTE pbSaveFilePtr = pbFilePtr;\n\n    // Prepare the tag structure\n    memset(&DlTag, 0, sizeof(CASC_TAG_ENTRY1));\n    DlTag.szTagName = (const char *)pbFilePtr;\n\n    // Skip the tag string\n    while(pbFilePtr < pbFileEnd && pbFilePtr[0] != 0)\n        pbFilePtr++;\n    if(pbFilePtr >= pbFileEnd)\n        return ERROR_BAD_FORMAT;\n    \n    // Save the length of the tag name\n    DlTag.NameLength = (pbFilePtr - pbSaveFilePtr);\n    pbFilePtr++;\n\n    // Get the tag value\n    if((pbFilePtr + sizeof(DWORD)) > pbFileEnd)\n        return ERROR_BAD_FORMAT;\n    DlTag.TagValue = ConvertBytesToInteger_2(pbFilePtr);\n    pbFilePtr += 2;\n\n    // Get the bitmap\n    DlTag.Bitmap = pbFilePtr;\n\n    // Get the bitmap length.\n    // If the bitmap is last in the list and it's shorter than declared, we make it shorter\n    DlTag.BitmapLength = GetTagBitmapLength(pbFilePtr, pbFileEnd, DlHeader.EntryCount);\n    \n    // Get the entry length\n    DlTag.TagLength = (pbFilePtr - pbSaveFilePtr) + DlTag.BitmapLength;\n    return ERROR_SUCCESS;\n}\n\nstatic int LoadDownloadManifest(TCascStorage * hs, CASC_DOWNLOAD_HEADER & DlHeader, LPBYTE pbFileData, LPBYTE pbFileEnd)\n{\n    PCASC_TAG_ENTRY1 TagArray = NULL;\n    LPBYTE pbEntries = pbFileData + DlHeader.HeaderLength;\n    LPBYTE pbEntry = pbEntries;\n    LPBYTE pbTags = pbEntries + DlHeader.EntryLength * DlHeader.EntryCount;\n    LPBYTE pbTag = pbTags;\n    size_t nMaxNameLength = 0;\n    size_t nTagEntryLengh = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Does the storage support tags?\n    if(DlHeader.TagCount != 0)\n    {\n        // Remember that we support tags\n        hs->dwFeatures |= CASC_FEATURE_TAGS;\n\n        // Allocate space for the tag array\n        TagArray = CASC_ALLOC<CASC_TAG_ENTRY1>(DlHeader.TagCount);\n        if(TagArray != NULL)\n        {\n            // Get the longest tag name\n            for(DWORD i = 0; i < DlHeader.TagCount; i++)\n            {\n                if(CaptureDownloadTag(DlHeader, TagArray[i], pbTag, pbFileEnd) == ERROR_SUCCESS)\n                    nMaxNameLength = CASCLIB_MAX(nMaxNameLength, TagArray[i].NameLength);\n                pbTag = pbTag + TagArray[i].TagLength;\n            }\n\n            // Determine the tag entry length\n            nTagEntryLengh = FIELD_OFFSET(CASC_TAG_ENTRY2, szTagName) + nMaxNameLength;\n            nTagEntryLengh = ALIGN_TO_SIZE(nTagEntryLengh, 8);\n\n            // Load the tags into array in the storage structure\n            dwErrCode = hs->TagsArray.Create(nTagEntryLengh, DlHeader.TagCount);\n            if(dwErrCode == ERROR_SUCCESS)\n            {\n                // Convert the array of CASC_DOWNLOAD_TAG1 to array of CASC_DOWNLOAD_TAG2\n                for(DWORD i = 0; i < DlHeader.TagCount; i++)\n                {\n                    PCASC_TAG_ENTRY1 pSourceTag = &TagArray[i];\n                    PCASC_TAG_ENTRY2 pTargetTag;\n\n                    // Insert the tag to the array\n                    pTargetTag = (PCASC_TAG_ENTRY2)hs->TagsArray.Insert(1);\n                    if(pTargetTag == NULL)\n                    {\n                        dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n                        break;\n                    }\n\n                    // Copy the tag structure\n                    memset(pTargetTag, 0, nTagEntryLengh);\n                    memcpy(pTargetTag->szTagName, pSourceTag->szTagName, pSourceTag->NameLength);\n                    pTargetTag->NameLength = pSourceTag->NameLength;\n                    pTargetTag->TagValue = pSourceTag->TagValue;\n                }\n            }\n        }\n        else\n        {\n            dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n        }\n    }\n\n    // Now parse all entries. For each entry, mark the corresponding tag bit in the EKey table\n    for(DWORD i = 0; i < DlHeader.EntryCount; i++)\n    {\n        CASC_DOWNLOAD_ENTRY DlEntry;\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        ULONGLONG TagBit = 1;\n        size_t BitMaskOffset = (i / 8);\n        size_t TagItemCount = hs->TagsArray.ItemCount();\n        BYTE BitMaskBit = 0x80 >> (i % 8);\n\n        // Capture the download entry\n        if(CaptureDownloadEntry(DlHeader, DlEntry, pbEntry, pbFileEnd) != ERROR_SUCCESS)\n            break;\n\n        // COD4: zone/base.xpak\n        //BREAK_ON_XKEY3(DlEntry.EKey, 0xa5, 0x00, 0x16);\n\n        // Insert the entry to the central CKey table\n        if((pCKeyEntry = InsertCKeyEntry(hs, DlEntry)) != NULL)\n        {\n            // Supply the tag bits\n            for(size_t j = 0; j < TagItemCount; j++)\n            {\n                // Set the bit in the entry, if the tag for it is present\n                if((BitMaskOffset < TagArray[j].BitmapLength) && (TagArray[j].Bitmap[BitMaskOffset] & BitMaskBit))\n                    pCKeyEntry->TagBitMask |= TagBit;\n\n                // Move to the next bit\n                TagBit <<= 1;\n            }\n        }\n\n        // Move to the next entry\n        pbEntry += DlHeader.EntryLength;\n    }\n\n    // Free the tag array, if any\n    CASC_FREE(TagArray);\n\n    // Remember the total file count\n    hs->TotalFiles = hs->CKeyArray.ItemCount();\n    return dwErrCode;\n}\n\nstatic int LoadDownloadManifest(TCascStorage * hs)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = FindCKeyEntry_CKey(hs, hs->DownloadCKey.CKey);\n    LPBYTE pbDownloadFile = NULL;\n    DWORD cbDownloadFile = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading DOWNLOAD manifest\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Load the entire DOWNLOAD file to memory\n    pbDownloadFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbDownloadFile);\n    if(pbDownloadFile != NULL && cbDownloadFile != 0)\n    {\n        CASC_DOWNLOAD_HEADER DlHeader;\n\n        // Capture the header of the DOWNLOAD file\n        dwErrCode = CaptureDownloadHeader(DlHeader, pbDownloadFile, cbDownloadFile);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Parse the entire download manifest\n            dwErrCode = LoadDownloadManifest(hs, DlHeader, pbDownloadFile, pbDownloadFile + cbDownloadFile); \n        }\n\n        // Free the loaded manifest\n        CASC_FREE(pbDownloadFile);\n    }\n\n    // If the DOWNLOAD manifest is not present, we won't abort the downloading process.\n    return dwErrCode;\n}\n\n//-----------------------------------------------------------------------------\n// INSTALL manifest. This is a replacement for ROOT, if loading ROOT fails\n// https://wowdev.wiki/TACT#Install_manifest\n\nstatic int LoadInstallManifest(TCascStorage * hs)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = FindCKeyEntry_CKey(hs, hs->InstallCKey.CKey);\n    LPBYTE pbInstallFile = NULL;\n    DWORD cbInstallFile = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading INSTALL manifest\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Load the entire DOWNLOAD file to memory\n    pbInstallFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbInstallFile);\n    if (pbInstallFile != NULL && cbInstallFile != 0)\n    {\n        dwErrCode = RootHandler_CreateInstall(hs, pbInstallFile, cbInstallFile);\n        CASC_FREE(pbInstallFile);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\nstatic bool InsertWellKnownFile(TCascStorage * hs, const char * szFileName, CASC_CKEY_ENTRY & FakeCKeyEntry, DWORD dwFlags = 0)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = NULL;\n\n    // We need to find the CKey entry in the central array\n    if(FakeCKeyEntry.Flags & CASC_CE_HAS_CKEY)\n    {\n        // Did we find anything?\n        pCKeyEntry = FindCKeyEntry_CKey(hs, FakeCKeyEntry.CKey);\n        if(pCKeyEntry != NULL)\n        {\n            // Insert the key to the root handler. Note that the file can already be referenced\n            // (\"index\" vs \"vfs-root\" in Warcraft III storages)\n            hs->pRootHandler->Insert(szFileName, pCKeyEntry);\n\n            // Copy some flags\n            pCKeyEntry->Flags |= (dwFlags | CASC_CE_IN_BUILD);\n            return true;\n        }\n    }\n\n    // Special case: the PATCH file is usually not in any indices.\n    // It's also never locally available\n    if((dwFlags & CASC_CE_FILE_PATCH) && (hs->dwFeatures & CASC_FEATURE_ONLINE))\n    {\n        // Get or insert the PATCH entry\n        pCKeyEntry = InsertCKeyEntry(hs, FakeCKeyEntry);\n        if(pCKeyEntry != NULL)\n        {\n            hs->pRootHandler->Insert(szFileName, pCKeyEntry);\n            pCKeyEntry->Flags |= (dwFlags | CASC_CE_IN_BUILD);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic int LoadBuildManifest(TCascStorage * hs, DWORD dwLocaleMask)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n    PDWORD FileSignature;\n    LPBYTE pbRootFile = NULL;\n    DWORD cbRootFile = 0;\n    DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n    // Sanity checks\n    assert(hs->CKeyMap.IsInitialized() == true);\n    assert(hs->pRootHandler == NULL);\n\n    // Inform the user about what we are doing\n    if(InvokeProgressCallback(hs, \"Loading ROOT manifest\", NULL, 0, 0))\n        return ERROR_CANCELLED;\n\n    // Locale: The default parameter is 0 - in that case, we load all locales\n    dwLocaleMask = (dwLocaleMask != 0) ? dwLocaleMask : 0xFFFFFFFF;\n\n    // Prioritize the VFS root over legacy ROOT file\n    pCKeyEntry = (hs->VfsRoot.ContentSize != CASC_INVALID_SIZE) ? &hs->VfsRoot : &hs->RootFile;\n    pCKeyEntry = FindCKeyEntry_CKey(hs, pCKeyEntry->CKey);\n\n    // Load the entire ROOT file to memory\n    pbRootFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbRootFile);\n    if(pbRootFile != NULL)\n    {\n        // Ignore ROOT files that contain just a MD5 hash\n        if(cbRootFile > MD5_STRING_SIZE)\n        {\n            // Check the type of the ROOT file\n            FileSignature = (PDWORD)pbRootFile;\n            switch(FileSignature[0])\n            {\n                case CASC_MNDX_ROOT_SIGNATURE:\n                    dwErrCode = RootHandler_CreateMNDX(hs, pbRootFile, cbRootFile);\n                    break;\n\n                case CASC_DIABLO3_ROOT_SIGNATURE:\n                    dwErrCode = RootHandler_CreateDiablo3(hs, pbRootFile, cbRootFile);\n                    break;\n\n                case CASC_TVFS_ROOT_SIGNATURE:\n                    dwErrCode = RootHandler_CreateTVFS(hs, pbRootFile, cbRootFile);\n                    break;\n\n                case CASC_WOW82_ROOT_SIGNATURE:\n                    dwErrCode = RootHandler_CreateWoW(hs, pbRootFile, cbRootFile, dwLocaleMask);\n                    break;\n\n                default:\n\n                    //\n                    // Each of these handler creators must verify their format first.\n                    // If the format was not recognized, they need to return ERROR_BAD_FORMAT\n                    //\n\n                    dwErrCode = RootHandler_CreateOverwatch(hs, pbRootFile, cbRootFile);\n                    if(dwErrCode == ERROR_BAD_FORMAT)\n                    {\n                        dwErrCode = RootHandler_CreateStarcraft1(hs, pbRootFile, cbRootFile);\n                        if(dwErrCode == ERROR_BAD_FORMAT)\n                        {\n                            dwErrCode = RootHandler_CreateWoW(hs, pbRootFile, cbRootFile, dwLocaleMask);\n                        }\n                    }\n                    break;\n            }\n        }\n\n        // Free the root file\n        CASC_FREE(pbRootFile);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD GetStorageTotalFileCount(TCascStorage * hs)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry;\n    size_t nItemCount = hs->CKeyArray.ItemCount();\n    DWORD TotalFileCount = 0;\n\n    for(size_t i = 0; i < nItemCount; i++)\n    {\n        if((pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.ItemAt(i)) != NULL)\n        {\n            if(pCKeyEntry->IsFile())\n            {\n                // If there is zero or one file name reference, we count the item as one file.\n                // If there is more than 1 name reference, we count the file as many times as number of references\n                DWORD RefCount = (pCKeyEntry->RefCount > 0) ? pCKeyEntry->RefCount : 1;\n\n                // Add the number of references to the total file count\n                TotalFileCount += RefCount;\n            }\n        }\n    }\n\n    return TotalFileCount;\n}\n\nstatic bool GetStorageProduct(TCascStorage * hs, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded)\n{\n    PCASC_STORAGE_PRODUCT pProductInfo;\n\n    // Verify whether we have enough space in the buffer\n    pProductInfo = (PCASC_STORAGE_PRODUCT)ProbeOutputBuffer(pvStorageInfo, cbStorageInfo, sizeof(CASC_STORAGE_PRODUCT), pcbLengthNeeded);\n    if(pProductInfo != NULL)\n    {\n        // Clear the entire structure\n        memset(pProductInfo, 0, sizeof(CASC_STORAGE_PRODUCT));\n\n        // Copy the product code name and build number\n        if(hs->szCodeName != NULL)\n            CascStrCopy(pProductInfo->szCodeName, _countof(pProductInfo->szCodeName), hs->szCodeName);\n        pProductInfo->BuildNumber = hs->dwBuildNumber;\n    }\n\n    return (pProductInfo != NULL);\n}\n\nstatic bool GetStorageTags(TCascStorage * hs, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded)\n{\n    PCASC_STORAGE_TAGS pTags;\n    PCASC_TAG_ENTRY2 pTag;\n    char * szNameBuffer;\n    size_t cbMinLength;\n\n    // Does the storage support tags?\n    if(hs->TagsArray.IsInitialized() == false)\n    {\n        SetCascError(ERROR_NOT_SUPPORTED);\n        return false;\n    }\n\n    // Calculate the length of the tags\n    cbMinLength = FIELD_OFFSET(CASC_STORAGE_TAGS, Tags) + hs->TagsArray.ItemCount() * sizeof(CASC_STORAGE_TAG);\n    szNameBuffer = (char *)pvStorageInfo + cbMinLength;\n\n    // Also include the tag length\n    for(size_t i = 0; i < hs->TagsArray.ItemCount(); i++)\n    {\n        pTag = (PCASC_TAG_ENTRY2)hs->TagsArray.ItemAt(i);\n        cbMinLength = cbMinLength + pTag->NameLength + 1;\n    }\n\n    // Verify whether we have enough space in the buffer\n    pTags = (PCASC_STORAGE_TAGS)ProbeOutputBuffer(pvStorageInfo, cbStorageInfo, cbMinLength, pcbLengthNeeded);\n    if(pTags != NULL)\n    {\n        // Fill the output structure\n        pTags->TagCount = hs->TagsArray.ItemCount();\n        pTags->Reserved = 0;\n\n        // Copy the tags\n        for(size_t i = 0; i < hs->TagsArray.ItemCount(); i++)\n        {\n            // Get the source tag\n            pTag = (PCASC_TAG_ENTRY2)hs->TagsArray.ItemAt(i);\n\n            // Fill the target tag\n            pTags->Tags[i].szTagName = szNameBuffer;\n            pTags->Tags[i].TagNameLength = (DWORD)pTag->NameLength;\n            pTags->Tags[i].TagValue = pTag->TagValue;\n\n            // Copy the tag name\n            memcpy(szNameBuffer, pTag->szTagName, pTag->NameLength);\n            szNameBuffer[pTag->NameLength] = 0;\n            szNameBuffer = szNameBuffer + pTag->NameLength + 1;\n        }\n    }\n\n    return (pTags != NULL);\n}\n\nstatic bool GetStoragePathProduct(TCascStorage * hs, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded)\n{\n    LPTSTR szBuffer = (LPTSTR)pvStorageInfo;\n    size_t nMaxChars = cbStorageInfo / sizeof(TCHAR);\n    size_t nLength;\n\n    // Calculate the length needed\n    nLength = _tcslen(hs->szRootPath);\n    if(hs->szCodeName != NULL)\n        nLength = nLength + 1 + _tcslen(hs->szCodeName);\n    if(hs->szRegion != NULL)\n        nLength = nLength + 1 + strlen(hs->szRegion);\n    nLength++;\n\n    // Verify whether we have enough space in the buffer\n    szBuffer = (LPTSTR)ProbeOutputBuffer(pvStorageInfo, cbStorageInfo, (nLength * sizeof(TCHAR)), pcbLengthNeeded);\n    if(szBuffer != NULL)\n    {\n        LPTSTR szBufferEnd = szBuffer + nMaxChars;\n\n        // Copy the storage path\n        CascStrCopy(szBuffer, (szBufferEnd - szBuffer), hs->szRootPath);\n        szBuffer += _tcslen(hs->szRootPath);\n\n        // Append the product code name, if any\n        if(hs->szCodeName != NULL)\n        {\n            *szBuffer++ = _T(':');\n            CascStrCopy(szBuffer, (szBufferEnd - szBuffer), hs->szCodeName);\n            szBuffer += _tcslen(hs->szCodeName);\n        }\n\n        // Append the product region, if any\n        if(hs->szRegion != NULL)\n        {\n            *szBuffer++ = _T(':');\n            CascStrCopy(szBuffer, (szBufferEnd - szBuffer), hs->szRegion);\n        }\n    }\n\n    return (szBuffer != NULL);\n}\n\nstatic DWORD InitializeLocalDirectories(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)\n{\n    LPTSTR szWorkPath;\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // Find the root directory of the storage. The root directory\n    // is the one with \".build.info\" or \".build.db\".\n    szWorkPath = CascNewStr(pArgs->szLocalPath);\n    if(szWorkPath != NULL)\n    {\n        // Get the length and go up until we find the \".build.info\" or \".build.db\"\n        for(;;)\n        {\n            // Is this a game directory?\n            dwErrCode = CheckGameDirectory(hs, szWorkPath);\n            if(dwErrCode == ERROR_SUCCESS)\n            {\n                dwErrCode = ERROR_SUCCESS;\n                break;\n            }\n\n            // Cut one path part\n            if(!CutLastPathPart(szWorkPath))\n            {\n                dwErrCode = ERROR_FILE_NOT_FOUND;\n                break;\n            }\n        }\n\n        // Find the index directory\n        if (dwErrCode == ERROR_SUCCESS)\n        {\n            // First, check for more common \"data\" subdirectory\n            if ((hs->szIndexPath = CheckForIndexDirectory(hs, _T(\"data\"))) != NULL)\n                dwErrCode = ERROR_SUCCESS;\n\n            // Second, try the \"darch\" subdirectory (older builds of HOTS - Alpha)\n            else if ((hs->szIndexPath = CheckForIndexDirectory(hs, _T(\"darch\"))) != NULL)\n                dwErrCode = ERROR_SUCCESS;\n\n            else\n                dwErrCode = ERROR_FILE_NOT_FOUND;\n        }\n\n        // Free the work path buffer\n        CASC_FREE(szWorkPath);\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD InitializeOnlineDirectories(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)\n{\n    // Create the root path\n    hs->szRootPath = CascNewStr(pArgs->szLocalPath);\n    if (hs->szRootPath != NULL)\n    {\n        hs->BuildFileType = CascVersionsDb;\n        hs->dwFeatures |= CASC_FEATURE_ONLINE;\n        return ERROR_SUCCESS;\n    }\n\n    return ERROR_NOT_ENOUGH_MEMORY;\n}\n\nstatic DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)\n{\n    LPCTSTR szCodeName = NULL;\n    LPCTSTR szRegion = NULL;\n    LPCTSTR szBuildKey = NULL;\n    DWORD dwLocaleMask = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Pass the argument array to the storage\n    hs->pArgs = pArgs;\n\n    // Extract optional arguments\n    ExtractVersionedArgument(pArgs, FIELD_OFFSET(CASC_OPEN_STORAGE_ARGS, dwLocaleMask), &dwLocaleMask);\n    \n    // Extract the product code name\n    if(ExtractVersionedArgument(pArgs, FIELD_OFFSET(CASC_OPEN_STORAGE_ARGS, szCodeName), &szCodeName) && szCodeName != NULL)\n        hs->szCodeName = CascNewStr(szCodeName);\n\n    // Extract the region (optional)\n    if(ExtractVersionedArgument(pArgs, FIELD_OFFSET(CASC_OPEN_STORAGE_ARGS, szRegion), &szRegion) && szRegion != NULL)\n        hs->szRegion = CascNewStrT2A(szRegion);\n\n    // Extract the build key (optional)\n    if(ExtractVersionedArgument(pArgs, FIELD_OFFSET(CASC_OPEN_STORAGE_ARGS, szBuildKey), &szBuildKey) && szBuildKey != NULL)\n        hs->szBuildKey = CascNewStrT2A(szBuildKey);\n\n    // Special handling to online storages\n    if(hs->dwFeatures & CASC_FEATURE_ONLINE)\n    {\n        // Enable caching of the sockets. This will add references\n        // to all existing and all future sockets\n        sockets_set_caching(true);\n\n        // For online storages, we need to load CDN servers\n        dwErrCode = LoadCdnsFile(hs);\n    }\n\n    // Now, load the main storage file \".build.info\" (or \".build.db\" in old storages) \n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = LoadBuildInfo(hs);\n    }\n\n    // If the .build.info OR .build.db file has been loaded,\n    // proceed with loading the CDN config file\n    if (dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = LoadCdnConfigFile(hs);\n        if(dwErrCode != ERROR_SUCCESS && (hs->dwFeatures & CASC_FEATURE_ONLINE) == 0)\n            dwErrCode = ERROR_SUCCESS;\n    }\n\n    // Proceed with loading the CDN build file\n    if (dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = LoadCdnBuildFile(hs);\n    }\n\n    // Create the array of CKey entries. Each entry represents a file in the storage\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = InitCKeyArray(hs);\n    }\n\n    // Pre-load the local index files\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = LoadIndexFiles(hs);\n    }\n\n    // Load the ENCODING manifest\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = LoadEncodingManifest(hs);\n    }\n\n    // We need to load the DOWNLOAD manifest\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = LoadDownloadManifest(hs);\n    }\n\n    // Load the build manifest (\"ROOT\" file)\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // For WoW storages, multiple files are present in the storage (same name, same file data ID, different locale).\n        // Failing to select storage on them will lead to the first-in-order file in the list being loaded.\n        // Example: WoW build 32144, file: DBFilesClient\\Achievement.db2, file data ID: 1260179\n        // Locales: koKR frFR deDE zhCN esES zhTW enUS&enGB esMX ruRU itIT ptBT&ptPT (in order of appearance in the build manifest)\n        if(dwLocaleMask == 0)\n        {\n            dwLocaleMask = hs->dwDefaultLocale;\n        }\n\n        // Continue loading the manifest\n        dwErrCode = LoadBuildManifest(hs, dwLocaleMask);\n        if (dwErrCode != ERROR_SUCCESS)\n        {\n            // If we fail to load the ROOT file, we take the file names from the INSTALL manifest\n            dwErrCode = LoadInstallManifest(hs);\n        }\n    }\n\n    // Insert entries for files with well-known names. Their CKeys are in the BUILD file\n    // See https://wowdev.wiki/TACT#Encoding_table for their list\n    if (dwErrCode == ERROR_SUCCESS)\n    {\n        InsertWellKnownFile(hs, \"ENCODING\", hs->EncodingCKey);\n        InsertWellKnownFile(hs, \"DOWNLOAD\", hs->DownloadCKey);\n        InsertWellKnownFile(hs, \"INSTALL\", hs->InstallCKey);\n        InsertWellKnownFile(hs, \"PATCH\", hs->PatchFile, CASC_CE_FILE_PATCH);\n        InsertWellKnownFile(hs, \"ROOT\", hs->RootFile);\n        InsertWellKnownFile(hs, \"SIZE\", hs->SizeFile);\n\n        // Also reset the total file count. CascGetStorageInfo will update it on next call\n        hs->TotalFiles = 0;\n    }\n\n    // Load the encryption keys\n    if (dwErrCode == ERROR_SUCCESS)\n    {\n        dwErrCode = CascLoadEncryptionKeys(hs);\n    }\n\n    // Cleanup and exit\n    FreeIndexFiles(hs);\n    hs->pArgs = NULL;\n    return dwErrCode;\n}\n\nstatic LPTSTR ParseOpenParams(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs)\n{\n    LPTSTR szParamsCopy;\n\n    // The 'szParams' must not be empty\n    if(szParams == NULL || pArgs == NULL || szParams[0] == 0)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return NULL;\n    }\n\n    // The 'pArgs' must be valid but must not contain 'szLocalPath', 'szCodeName' or 'szRegion'\n    if(pArgs->szLocalPath != NULL || pArgs->szCodeName != NULL || pArgs->szRegion != NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return NULL;\n    }\n\n    // Make a copy of the parameters so we can temper with them\n    if((szParamsCopy = CascNewStr(szParams)) != NULL)\n    {\n        LPTSTR szPlainName = (LPTSTR)GetPlainFileName(szParamsCopy);\n        LPTSTR szSeparator;\n\n        // The local path is always set\n        pArgs->szLocalPath = szParamsCopy;\n        pArgs->szCodeName = NULL;\n        pArgs->szRegion = NULL;\n        pArgs->szBuildKey = NULL;\n\n        // Find the first \":\". This will indicate the end of local path and also begin of product code\n        if((szSeparator = _tcschr(szPlainName, _T(':'))) != NULL)\n        {\n            // The found string is a product code name\n            pArgs->szCodeName = szSeparator + 1;\n            szSeparator[0] = 0;\n\n            // Try again. If found, it is a product region\n            if((szSeparator = _tcschr(szSeparator + 1, _T(':'))) != NULL)\n            {\n                pArgs->szRegion = szSeparator + 1;\n                szSeparator[0] = 0;\n\n                // Try again. If found, it is a build key (MD5 of a build file)\n                if((szSeparator = _tcschr(szSeparator + 1, _T(':'))) != NULL)\n                {\n                    pArgs->szBuildKey = szSeparator + 1;\n                    szSeparator[0] = 0;\n                }\n            }\n        }\n    }\n    else\n    {\n        SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n    }\n\n    return szParamsCopy;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nbool WINAPI CascOpenStorageEx(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs, bool bOnlineStorage, HANDLE * phStorage)\n{\n    CASC_OPEN_STORAGE_ARGS LocalArgs = {sizeof(CASC_OPEN_STORAGE_ARGS)};\n    TCascStorage * hs;\n    LPTSTR szParamsCopy = NULL;\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // The storage path[+product[+region]] must either be passed in szParams or in pArgs. Not both.\n    // It is allowed to pass NULL as pArgs if the szParams is not NULL\n    if(szParams != NULL)\n    {\n        if(pArgs == NULL)\n            pArgs = &LocalArgs;\n\n        szParamsCopy = ParseOpenParams(szParams, pArgs);\n        if(szParamsCopy == NULL)\n            return false;\n    }\n    else\n    {\n        // The arguments and the local path must be entered\n        if(pArgs == NULL || pArgs->szLocalPath == NULL || pArgs->szLocalPath[0] == 0)\n        {\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return false;\n        }\n    }\n\n    // Allocate the storage structure\n    if((hs = new TCascStorage()) != NULL)\n    {\n        // Setup the directories\n        dwErrCode = (bOnlineStorage) ? InitializeOnlineDirectories(hs, pArgs) : InitializeLocalDirectories(hs, pArgs);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Perform the entire storage loading\n            dwErrCode = LoadCascStorage(hs, pArgs);\n        }\n\n        // Free the storage structure on fail\n        if(dwErrCode != ERROR_SUCCESS)\n        {\n            hs = hs->Release();\n        }\n    }\n\n    // Give the output parameter to the caller\n    CASC_FREE(szParamsCopy);\n    *phStorage = (HANDLE)hs;\n\n    // Return the result\n    if(dwErrCode != ERROR_SUCCESS)\n        SetCascError(dwErrCode);\n    return (dwErrCode == ERROR_SUCCESS);\n}\n\n// szParams: \"LocalPath:CodeName\", e.g. \"C:\\\\Games\\\\World of Warcraft:wowt\"\n// * LocalPath: Local folder, where the online file will be cached.\n// * CodeName: Product code name, e.g. \"agent\" for Battle.net Agent. More info: https://wowdev.wiki/TACT#Products\nbool WINAPI CascOpenStorage(LPCTSTR szParams, DWORD dwLocaleMask, HANDLE * phStorage)\n{\n    CASC_OPEN_STORAGE_ARGS OpenArgs = {sizeof(CASC_OPEN_STORAGE_ARGS)};\n\n    OpenArgs.dwLocaleMask = dwLocaleMask;\n    return CascOpenStorageEx(szParams, &OpenArgs, false, phStorage);\n}\n\n// Allows to browse an online CDN storage\n// szParams: \"CachePath:CodeName:Region\", e.g. \"C:\\\\Cache:wowt:us\"\n// * CachePath: Local folder, where the online file will be cached.\n// * CodeName: Product code name, e.g. \"agent\" for Battle.net Agent. More info: https://wowdev.wiki/TACT#Products\n// * Region: The region (or subvariant) of the product. Corresponds to the first column of the \"versions\" file.\nbool WINAPI CascOpenOnlineStorage(LPCTSTR szParams, DWORD dwLocaleMask, HANDLE * phStorage)\n{\n    CASC_OPEN_STORAGE_ARGS OpenArgs = {sizeof(CASC_OPEN_STORAGE_ARGS)};\n\n    OpenArgs.dwLocaleMask = dwLocaleMask;\n    return CascOpenStorageEx(szParams, &OpenArgs, true, phStorage);\n}\n\nbool WINAPI CascGetStorageInfo(\n    HANDLE hStorage,\n    CASC_STORAGE_INFO_CLASS InfoClass,\n    void * pvStorageInfo,\n    size_t cbStorageInfo,\n    size_t * pcbLengthNeeded)\n{\n    TCascStorage * hs;\n    PDWORD PtrOutputValue;\n    DWORD dwInfoValue = 0;\n\n    // Verify the storage handle\n    hs = TCascStorage::IsValid(hStorage);\n    if(hs == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // Differentiate between info classes\n    switch(InfoClass)\n    {\n        case CascStorageLocalFileCount:\n            dwInfoValue = (DWORD)hs->LocalFiles;\n            break;\n\n        case CascStorageTotalFileCount:\n            if(hs->TotalFiles == 0)\n                hs->TotalFiles = GetStorageTotalFileCount(hs);\n            dwInfoValue = (DWORD)hs->TotalFiles;\n            break;\n\n        case CascStorageFeatures:\n            dwInfoValue = hs->dwFeatures | hs->pRootHandler->GetFeatures();\n            break;\n\n        case CascStorageInstalledLocales:\n            dwInfoValue = hs->dwDefaultLocale;\n            break;\n\n        case CascStorageProduct:\n            return GetStorageProduct(hs, pvStorageInfo, cbStorageInfo, pcbLengthNeeded);\n\n        case CascStorageTags:\n            return GetStorageTags(hs, pvStorageInfo, cbStorageInfo, pcbLengthNeeded);\n\n        case CascStoragePathProduct:\n            return GetStoragePathProduct(hs, pvStorageInfo, cbStorageInfo, pcbLengthNeeded);\n\n        default:\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return false;\n    }\n\n    //\n    // Default: return a 32-bit unsigned value\n    //\n\n    PtrOutputValue = (PDWORD)ProbeOutputBuffer(pvStorageInfo, cbStorageInfo, sizeof(DWORD), pcbLengthNeeded);\n    if(PtrOutputValue != NULL)\n        PtrOutputValue[0] = dwInfoValue;\n    return (PtrOutputValue != NULL);\n}\n\nbool WINAPI CascCloseStorage(HANDLE hStorage)\n{\n    TCascStorage * hs;\n\n    // Verify the storage handle\n    hs = TCascStorage::IsValid(hStorage);\n    if(hs == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // Only free the storage if the reference count reaches 0\n    hs->Release();\n    return true;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascPort.h",
    "content": "/*****************************************************************************/\n/* CascPort.h                             Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Portability module for the CascLib library. Contains a wrapper symbols    */\n/* to make the compilation under Linux work                                  */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __CASCPORT_H__\n#define __CASCPORT_H__\n\n#ifndef __cplusplus\n    #include <stdbool.h>\n#endif\n\n//-----------------------------------------------------------------------------\n// Defines for Windows\n\n#if !defined(CASCLIB_PLATFORM_DEFINED) && (defined(_WIN32) || defined(_WIN64))\n\n  // In MSVC 8.0, there are some functions declared as deprecated.\n  #define _CRT_SECURE_NO_DEPRECATE\n  #define _CRT_NON_CONFORMING_SWPRINTFS\n\n  #ifndef WIN32_LEAN_AND_MEAN\n    #define WIN32_LEAN_AND_MEAN\n  #endif\n\n  // Suppress definitions of `min` and `max` macros by <windows.h>:\n  #define NOMINMAX 1\n\n  #include <tchar.h>\n  #include <assert.h>\n  #include <ctype.h>\n  #include <io.h>\n  #include <stdio.h>\n  #include <stdlib.h>\n  #include <direct.h>\n  #include <malloc.h>\n  #include <windows.h>\n  #include <ws2tcpip.h>\n  #include <strsafe.h>\n\n  #define CASCLIB_PLATFORM_LITTLE_ENDIAN\n\n  #pragma intrinsic(memset, memcmp, memcpy)     // Make these functions intrinsic (inline)\n\n  #define URL_SEP_CHAR              '/'\n  #define PATH_SEP_CHAR             '\\\\'\n  #define PATH_SEP_STRING           \"\\\\\"\n\n  #define CASCLIB_PLATFORM_WINDOWS\n  #define CASCLIB_PLATFORM_DEFINED              // The platform is known now\n\n#endif\n\n#ifndef FIELD_OFFSET\n#define FIELD_OFFSET(type, field)    ((LONG)(size_t)&(((type *)0)->field))\n#endif\n\n//-----------------------------------------------------------------------------\n// Defines for Mac\n\n#if !defined(CASCLIB_PLATFORM_DEFINED) && defined(__APPLE__)  // Mac BSD API\n\n  // Macintosh\n  #include <sys/types.h>\n  #include <sys/stat.h>\n  #include <sys/socket.h>\n  #include <sys/mman.h>\n  #include <fcntl.h>\n  #include <dirent.h>\n  #include <unistd.h>\n  #include <stddef.h>\n  #include <stdint.h>\n  #include <stdlib.h>\n  #include <stdio.h>\n  #include <stdarg.h>\n  #include <string.h>\n  #include <ctype.h>\n  #include <wchar.h>\n  #include <cassert>\n  #include <errno.h>\n  #include <pthread.h>\n  #include <netdb.h>\n\n  // Support for PowerPC on Max OS X\n  #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1)\n    #include <stdint.h>\n    #include <CoreFoundation/CFByteOrder.h>\n  #endif\n\n  #define    PKEXPORT\n\n  #ifndef __SYS_ZLIB\n    #define    __SYS_ZLIB\n  #endif\n\n  #ifndef __BIG_ENDIAN__\n    #define CASCLIB_PLATFORM_LITTLE_ENDIAN\n  #endif\n\n  #define URL_SEP_CHAR              '/'\n  #define PATH_SEP_CHAR             '/'\n  #define PATH_SEP_STRING           \"/\"\n\n  typedef int SOCKET;\n\n  #define CASCLIB_PLATFORM_MAC\n  #define CASCLIB_PLATFORM_DEFINED          // The platform is known now\n\n#endif\n\n//-----------------------------------------------------------------------------\n// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin*\n\n#if !defined(CASCLIB_PLATFORM_DEFINED)\n  #include <sys/types.h>\n  #include <sys/stat.h>\n  #include <sys/socket.h>\n  #include <sys/mman.h>\n  #include <fcntl.h>\n  #include <dirent.h>\n  #include <unistd.h>\n  #include <stddef.h>\n  #include <stdint.h>\n  #include <stdlib.h>\n  #include <stdio.h>\n  #include <stdarg.h>\n  #include <string.h>\n  #include <ctype.h>\n  #include <wchar.h>\n  #include <assert.h>\n  #include <errno.h>\n  #include <pthread.h>\n  #include <netdb.h>\n\n  #define URL_SEP_CHAR              '/'\n  #define PATH_SEP_CHAR             '/'\n  #define PATH_SEP_STRING           \"/\"\n\n  typedef int SOCKET;\n\n  #define CASCLIB_PLATFORM_LITTLE_ENDIAN\n  #define CASCLIB_PLATFORM_LINUX\n  #define CASCLIB_PLATFORM_DEFINED\n\n#endif\n\n//-----------------------------------------------------------------------------\n// Definition of Windows-specific types for non-Windows platforms\n\n#ifndef CASCLIB_PLATFORM_WINDOWS\n\n  // Typedefs for ANSI C\n  typedef unsigned char  BYTE;\n  typedef unsigned short USHORT;\n  typedef int            LONG;\n  typedef unsigned int   DWORD;\n  typedef long long      LONGLONG;\n  typedef signed long long LONGLONG;\n  typedef signed long long *PLONGLONG;\n  typedef unsigned long long ULONGLONG;\n  typedef unsigned long long *PULONGLONG;\n  typedef void         * HANDLE;\n  typedef char           TCHAR;\n  typedef unsigned int   LCID;\n  typedef LONG         * PLONG;\n  typedef DWORD        * PDWORD;\n  typedef BYTE         * LPBYTE;\n  typedef char         * LPSTR;\n  typedef const char   * LPCSTR;\n  typedef TCHAR        * LPTSTR;\n  typedef const TCHAR  * LPCTSTR;\n\n  #ifndef __LP64__\n    #define _LZMA_UINT32_IS_ULONG\n  #endif\n\n  // Some Windows-specific defines\n  #ifndef MAX_PATH\n    #define MAX_PATH 1024\n  #endif\n\n  #define WINAPI\n\n  #define FILE_BEGIN    SEEK_SET\n  #define FILE_CURRENT  SEEK_CUR\n  #define FILE_END      SEEK_END\n\n  #define INVALID_HANDLE_VALUE ((HANDLE)-1)\n\n  #define _T(x)     x\n  #define _tcslen   strlen\n  #define _tcscat   strcat\n  #define _tcschr   strchr\n  #define _tcsrchr  strrchr\n  #define _tcsstr   strstr\n  #define _tcsspn   strspn\n  #define _tcsncmp  strncmp\n  #define _tprintf  printf\n  #define _tremove  remove\n  #define _taccess  access\n  #define _access   access\n\n  #define _stricmp  strcasecmp\n  #define _strnicmp strncasecmp\n  #define _tcsicmp  strcasecmp\n  #define _tcsnicmp strncasecmp\n\n  #define closesocket close\n\n#endif // !CASCLIB_PLATFORM_WINDOWS\n\n// 64-bit calls are supplied by \"normal\" calls on Mac\n#if defined(CASCLIB_PLATFORM_MAC)\n  #define stat64  stat\n  #define fstat64 fstat\n  #define lseek64 lseek\n  #define ftruncate64 ftruncate\n  #define off64_t off_t\n  #define O_LARGEFILE 0\n#endif\n\n// Platform-specific error codes for UNIX-based platforms\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n  #define ERROR_SUCCESS                  0\n  #define ERROR_FILE_NOT_FOUND           ENOENT\n  #define ERROR_PATH_NOT_FOUND           ENOENT\n  #define ERROR_ACCESS_DENIED            EPERM\n  #define ERROR_INVALID_HANDLE           EBADF\n  #define ERROR_NOT_ENOUGH_MEMORY        ENOMEM\n  #define ERROR_NOT_SUPPORTED            ENOTSUP\n  #define ERROR_INVALID_PARAMETER        EINVAL\n  #define ERROR_DISK_FULL                ENOSPC\n  #define ERROR_ALREADY_EXISTS           EEXIST\n  #define ERROR_INSUFFICIENT_BUFFER      ENOBUFS\n  #define ERROR_BAD_FORMAT               1000       // No such error code under Linux\n  #define ERROR_NO_MORE_FILES            1001       // No such error code under Linux\n  #define ERROR_HANDLE_EOF               1002       // No such error code under Linux\n  #define ERROR_CAN_NOT_COMPLETE         1003       // No such error code under Linux\n  #define ERROR_FILE_CORRUPT             1004       // No such error code under Linux\n  #define ERROR_FILE_ENCRYPTED           1005       // Returned by encrypted stream when can't find file key\n  #define ERROR_FILE_TOO_LARGE           1006       // No such error code under Linux\n  #define ERROR_ARITHMETIC_OVERFLOW      1007       // The string value is too large to fit in the given type\n  #define ERROR_NETWORK_NOT_AVAILABLE    1008       // Cannot connect to the internet\n#endif\n\n#ifndef ERROR_FILE_INCOMPLETE\n#define ERROR_FILE_INCOMPLETE            1006       // The required file part is missing\n#endif\n\n#ifndef ERROR_FILE_OFFLINE\n#define ERROR_FILE_OFFLINE               1007       // The file is not available in the local storage\n#endif\n\n#ifndef ERROR_BUFFER_OVERFLOW\n#define ERROR_BUFFER_OVERFLOW            1008\n#endif\n\n#ifndef ERROR_CANCELLED\n#define ERROR_CANCELLED                  1009\n#endif\n\n#ifndef ERROR_INDEX_PARSING_DONE\n#define ERROR_INDEX_PARSING_DONE         1010\n#endif\n\n#ifndef _countof\n#define _countof(x)   (sizeof(x) / sizeof(x[0]))\n#endif\n\n//-----------------------------------------------------------------------------\n// Swapping functions\n\n#ifdef CASCLIB_PLATFORM_LITTLE_ENDIAN\n    #define    BSWAP_INT16_UNSIGNED(a)          (a)\n    #define    BSWAP_INT16_SIGNED(a)            (a)\n    #define    BSWAP_INT32_UNSIGNED(a)          (a)\n    #define    BSWAP_INT32_SIGNED(a)            (a)\n    #define    BSWAP_INT64_SIGNED(a)            (a)\n    #define    BSWAP_INT64_UNSIGNED(a)          (a)\n    #define    BSWAP_ARRAY16_UNSIGNED(a,b)      {}\n    #define    BSWAP_ARRAY32_UNSIGNED(a,b)      {}\n    #define    BSWAP_ARRAY64_UNSIGNED(a,b)      {}\n#else\n\n#ifdef __cplusplus\n  extern \"C\" {\n#endif\n    int16_t  SwapInt16(uint16_t);\n    uint16_t SwapUInt16(uint16_t);\n    int32_t  SwapInt32(uint32_t);\n    uint32_t SwapUInt32(uint32_t);\n    int64_t  SwapInt64(uint64_t);\n    uint64_t SwapUInt64(uint64_t);\n    void ConvertUInt16Buffer(void * ptr, size_t length);\n    void ConvertUInt32Buffer(void * ptr, size_t length);\n    void ConvertUInt64Buffer(void * ptr, size_t length);\n#ifdef __cplusplus\n  }\n#endif\n    #define    BSWAP_INT16_SIGNED(a)            SwapInt16((a))\n    #define    BSWAP_INT16_UNSIGNED(a)          SwapUInt16((a))\n    #define    BSWAP_INT32_SIGNED(a)            SwapInt32((a))\n    #define    BSWAP_INT32_UNSIGNED(a)          SwapUInt32((a))\n    #define    BSWAP_INT64_SIGNED(a)            SwapInt64((a))\n    #define    BSWAP_INT64_UNSIGNED(a)          SwapUInt64((a))\n    #define    BSWAP_ARRAY16_UNSIGNED(a,b)      ConvertUInt16Buffer((a),(b))\n    #define    BSWAP_ARRAY32_UNSIGNED(a,b)      ConvertUInt32Buffer((a),(b))\n    #define    BSWAP_ARRAY64_UNSIGNED(a,b)      ConvertUInt64Buffer((a),(b))\n#endif\n\n//-----------------------------------------------------------------------------\n// Interlocked operations\n\ninline DWORD CascInterlockedIncrement(DWORD * PtrValue)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    return (DWORD)InterlockedIncrement((LONG *)(PtrValue));\n#elif defined(__GNUC__)\n    return __sync_add_and_fetch(PtrValue, 1);\n#else\n    #define INTERLOCKED_NOT_SUPPORTED\n    return ++(*PtrValue);\n#endif\n}\n\ninline DWORD CascInterlockedDecrement(DWORD * PtrValue)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    return (DWORD)InterlockedDecrement((LONG *)(PtrValue));\n#elif defined(__GNUC__)\n    return __sync_sub_and_fetch(PtrValue, 1);\n#else\n    return --(*PtrValue);\n#endif\n}\n\n//-----------------------------------------------------------------------------\n// Lock functions\n\n#ifdef CASCLIB_PLATFORM_WINDOWS\n\ntypedef RTL_CRITICAL_SECTION CASC_LOCK;\n#define CascInitLock(Lock)      InitializeCriticalSection(&Lock);\n#define CascFreeLock(Lock)      DeleteCriticalSection(&Lock);\n#define CascLock(Lock)          EnterCriticalSection(&Lock);\n#define CascUnlock(Lock)        LeaveCriticalSection(&Lock);\n\n#else\n\ntypedef pthread_mutex_t CASC_LOCK;\n#define CascInitLock(Lock)      pthread_mutex_init(&Lock, NULL);\n#define CascFreeLock(Lock)      pthread_mutex_destroy(&Lock);\n#define CascLock(Lock)          pthread_mutex_lock(&Lock);\n#define CascUnlock(Lock)        pthread_mutex_unlock(&Lock);\n\n#endif\n\n//-----------------------------------------------------------------------------\n// Forbidden functions, do not use\n\n#ifdef __CASCLIB_SELF__\n#define strcpy  UNSAFE_DO_NOT_USE_STRCPY\n#define strcat  UNSAFE_DO_NOT_USE_STRCAT\n#define sprintf UNSAFE_DO_NOT_USE_SPRINTF\n#endif\n\n#endif // __CASCPORT_H__\n"
  },
  {
    "path": "deps/CascLib/src/CascReadFile.cpp",
    "content": "/****************************************************************************/\n/* CascOpenFile.cpp                       Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* System-dependent directory functions for CascLib                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 01.05.14  1.00  Lad  The first version of CascOpenFile.cpp                */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nstatic DWORD GetStreamEncodedSize(TFileStream * pStream)\n{\n    ULONGLONG FileSize = 0;\n\n    FileStream_GetSize(pStream, &FileSize);\n    assert((FileSize >> 32) == 0);\n\n    return (DWORD)(FileSize);\n}\n\nstatic DWORD OpenDataStream(TCascFile * hf, PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry, bool bDownloadFileIf)\n{\n    TCascStorage * hs = hf->hs;\n    TFileStream * pStream = NULL;\n    TCHAR szCachePath[MAX_PATH];\n    TCHAR szDataFile[MAX_PATH];\n    TCHAR szPlainName[0x80];\n    DWORD dwErrCode;\n\n    // If the file is available locally, we rely on data files.\n    // If not, we download the file and open the stream\n    if(pCKeyEntry->Flags & CASC_CE_FILE_IS_LOCAL)\n    {\n        DWORD dwArchiveIndex = pFileSpan->ArchiveIndex;\n\n        // Lock the storage to make the operation thread-safe\n        CascLock(hs->StorageLock);\n\n        // If the data archive is not open yet, open it now.\n        if(hs->DataFiles[dwArchiveIndex] == NULL)\n        {\n            // Prepare the name of the data file\n            CascStrPrintf(szPlainName, _countof(szPlainName), _T(\"data.%03u\"), dwArchiveIndex);\n            CombinePath(szDataFile, _countof(szDataFile), hs->szIndexPath, szPlainName, NULL);\n\n            // Open the data stream with read+write sharing to prevent Battle.net agent\n            // detecting a corruption and redownloading the entire package\n            pStream = FileStream_OpenFile(szDataFile, STREAM_FLAG_READ_ONLY | STREAM_FLAG_WRITE_SHARE | STREAM_PROVIDER_FLAT | STREAM_FLAG_FILL_MISSING | BASE_PROVIDER_FILE);\n            hs->DataFiles[dwArchiveIndex] = pStream;\n        }\n\n        // Unlock the storage\n        CascUnlock(hs->StorageLock);\n\n        // Return error or success\n        pFileSpan->pStream = hs->DataFiles[dwArchiveIndex];\n        return (pFileSpan->pStream != NULL) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;\n    }\n    else\n    {\n        if(bDownloadFileIf)\n        {\n            CASC_CDN_DOWNLOAD CdnsInfo = {0};\n            LPCTSTR szPathType = (pCKeyEntry->Flags & CASC_CE_FILE_PATCH) ? _T(\"patch\") : _T(\"data\");\n\n            // Prepare the download structure for \"%CDNS_HOST%/%CDNS_PATH%/##/##/EKey\" file\n            CdnsInfo.szCdnsPath = hs->szCdnPath;\n            CdnsInfo.szPathType = szPathType;\n            CdnsInfo.pbEKey = pCKeyEntry->EKey;\n            CdnsInfo.szLocalPath = szCachePath;\n            CdnsInfo.ccLocalPath = _countof(szCachePath);\n\n            // Download the file from CDN\n            dwErrCode = DownloadFileFromCDN(hs, CdnsInfo);\n            if(dwErrCode == ERROR_SUCCESS)\n            {\n                pStream = FileStream_OpenFile(szCachePath, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT);\n                if(pStream != NULL)\n                {\n                    // Initialize information about the position and size of the file in archive\n                    // On loose files, their position is zero and encoded size is length of the file\n                    if(CdnsInfo.pbArchiveKey != NULL)\n                    {\n                        // Archive position\n                        pFileSpan->ArchiveIndex = CdnsInfo.ArchiveIndex;\n                        pFileSpan->ArchiveOffs = (DWORD)CdnsInfo.ArchiveOffs;\n\n                        // Encoded size\n                        if(pCKeyEntry->EncodedSize == CASC_INVALID_SIZE)\n                            pCKeyEntry->EncodedSize = CdnsInfo.EncodedSize;\n                        assert(pCKeyEntry->EncodedSize == CdnsInfo.EncodedSize);\n                    }\n                    else\n                    {\n                        // Archive position\n                        pFileSpan->ArchiveIndex = 0;\n                        pFileSpan->ArchiveOffs = 0;\n\n                        // Encoded size\n                        if(pCKeyEntry->EncodedSize == CASC_INVALID_SIZE)\n                            pCKeyEntry->EncodedSize = GetStreamEncodedSize(pStream);\n                        assert(pCKeyEntry->EncodedSize == GetStreamEncodedSize(pStream));\n                    }\n\n                    // We need to close the file stream after we're done\n                    pFileSpan->pStream = pStream;\n                    hf->bCloseFileStream = true;\n                    return ERROR_SUCCESS;\n                }\n            }\n        }\n\n        return ERROR_FILE_OFFLINE;\n    }\n}\n\n#ifdef _DEBUG\nstatic unsigned int table_16C57A8[0x10] =\n{\n    0x049396B8, 0x72A82A9B, 0xEE626CCA, 0x9917754F,\n    0x15DE40B1, 0xF5A8A9B6, 0x421EAC7E, 0xA9D55C9A,\n    0x317FD40C, 0x04FAF80D, 0x3D6BE971, 0x52933CFD,\n    0x27F64B7D, 0xC6F5C11B, 0xD5757E3A, 0x6C388745\n};\n\n// Obtained from Agent.exe v 2.15.0.6296 (d14ec9d9a1b396a42964b05f40ea55f37eae5478d550c07ebb6cb09e50968d62)\n// Note the \"Checksum\" value probably won't match with older game versions.\nstatic void VerifyHeaderSpan(PBLTE_ENCODED_HEADER pBlteHeader, ULONGLONG HeaderOffset)\n{\n    LPBYTE pbBlteHeader = (LPBYTE)pBlteHeader;\n    DWORD dwInt32;\n    BYTE EncodedOffset[4] = { 0 };\n    BYTE HashedHeader[4] = { 0 };\n    BYTE JenkinsHash[4];\n    BYTE Checksum[4];\n    size_t i, j;\n\n    // Seems to be hardcoded to zero\n    assert(pBlteHeader->field_15 == 0);\n\n    // Calculate the Jenkins hash and write it to the header\n    dwInt32 = hashlittle(pbBlteHeader, FIELD_OFFSET(BLTE_ENCODED_HEADER, JenkinsHash), 0x3D6BE971);\n    ConvertIntegerToBytes_4_LE(dwInt32, JenkinsHash);\n//  assert(memcmp(pBlteHeader->JenkinsHash, JenkinsHash, sizeof(JenkinsHash)) == 0);\n\n    // Encode the lower 32-bits of the offset\n    dwInt32 = (DWORD)(HeaderOffset + FIELD_OFFSET(BLTE_ENCODED_HEADER, Signature));\n    dwInt32 = table_16C57A8[dwInt32 & 0x0F] ^ dwInt32;\n    ConvertIntegerToBytes_4_LE(dwInt32, EncodedOffset);\n\n    // Calculate checksum of the so-far filled structure\n    for (i = 0; i < FIELD_OFFSET(BLTE_ENCODED_HEADER, Checksum); i++)\n        HashedHeader[i & 3] ^= pbBlteHeader[i];\n\n    // XOR the two values together to get the final checksum.\n    for (j = 0; j < 4; j++, i++)\n        Checksum[j] = HashedHeader[i & 3] ^ EncodedOffset[i & 3];\n//  assert(memcmp(pBlteHeader->Checksum, Checksum, sizeof(Checksum)) == 0);\n}\n#endif\n\nstatic DWORD ParseBlteHeader(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry, ULONGLONG HeaderOffset, LPBYTE pbEncodedBuffer, size_t cbEncodedBuffer, size_t * pcbHeaderSize)\n{\n    PBLTE_ENCODED_HEADER pEncodedHeader = (PBLTE_ENCODED_HEADER)pbEncodedBuffer;\n    PBLTE_HEADER pBlteHeader = (PBLTE_HEADER)pbEncodedBuffer;\n    DWORD ExpectedHeaderSize;\n    DWORD ExHeaderSize = 0;\n    DWORD HeaderSize;\n    DWORD FrameCount = 0;\n\n    CASCLIB_UNUSED(HeaderOffset);\n\n    // On files within storage segments (\"data.###\"), there is BLTE_ENCODED_HEADER\n    // On local files, there is just PBLTE_HEADER\n    if(ConvertBytesToInteger_4_LE(pBlteHeader->Signature) != BLTE_HEADER_SIGNATURE)\n    {\n        // There must be at least some bytes\n        if (cbEncodedBuffer < FIELD_OFFSET(BLTE_ENCODED_HEADER, MustBe0F))\n            return ERROR_BAD_FORMAT;\n        if (pEncodedHeader->EncodedSize != pCKeyEntry->EncodedSize)\n            return ERROR_BAD_FORMAT;\n\n#ifdef _DEBUG\n        // Not really needed, it's here just for explanation of what the values mean\n        //assert(memcmp(pCKeyEntry->EKey, pEncodedHeader->EKey.Value, MD5_HASH_SIZE) == 0);\n        VerifyHeaderSpan(pEncodedHeader, HeaderOffset);\n#endif\n        // Capture the EKey\n        ExHeaderSize = FIELD_OFFSET(BLTE_ENCODED_HEADER, Signature);\n        pBlteHeader = (PBLTE_HEADER)(pbEncodedBuffer + ExHeaderSize);\n    }\n\n    // Verify the signature\n    if(ConvertBytesToInteger_4_LE(pBlteHeader->Signature) != BLTE_HEADER_SIGNATURE)\n        return ERROR_BAD_FORMAT;\n\n    // Capture the header size. If this is non-zero, then array\n    // of chunk headers follow. Otherwise, the file is just one chunk\n    HeaderSize = ConvertBytesToInteger_4(pBlteHeader->HeaderSize);\n    if (HeaderSize != 0)\n    {\n        if (pBlteHeader->MustBe0F != 0x0F)\n            return ERROR_BAD_FORMAT;\n        \n        // Verify the header size\n        FrameCount = ConvertBytesToInteger_3(pBlteHeader->FrameCount);\n        ExpectedHeaderSize = 0x0C + FrameCount * sizeof(BLTE_FRAME);\n        if (ExpectedHeaderSize != HeaderSize)\n            return ERROR_BAD_FORMAT;\n\n        // Give the values\n        pcbHeaderSize[0] = ExHeaderSize + FIELD_OFFSET(BLTE_HEADER, MustBe0F) + sizeof(DWORD);\n    }\n    else\n    {\n        pcbHeaderSize[0] = ExHeaderSize + FIELD_OFFSET(BLTE_HEADER, MustBe0F);\n    }\n\n    // Give the frame count\n    pFileSpan->FrameCount = FrameCount;\n    return ERROR_SUCCESS;\n}\n\nstatic LPBYTE ReadMissingHeaderData(PCASC_FILE_SPAN pFileSpan, ULONGLONG DataFileOffset, LPBYTE pbEncodedBuffer, size_t cbEncodedBuffer, size_t cbTotalHeaderSize)\n{\n    LPBYTE pbNewBuffer;\n\n    // Reallocate the buffer\n    pbNewBuffer = CASC_REALLOC(BYTE, pbEncodedBuffer, cbTotalHeaderSize);\n    if (pbNewBuffer != NULL)\n    {\n        // Load the missing data\n        DataFileOffset += cbEncodedBuffer;\n        if (FileStream_Read(pFileSpan->pStream, &DataFileOffset, pbNewBuffer + cbEncodedBuffer, (DWORD)(cbTotalHeaderSize - cbEncodedBuffer)))\n        {\n            return pbNewBuffer;\n        }\n    }\n\n    // If anything failed, we free the original buffer and return NULL;\n    CASC_FREE(pbEncodedBuffer);\n    return NULL;\n}\n\nstatic LPBYTE CaptureBlteFileFrame(CASC_FILE_FRAME & Frame, LPBYTE pbFramePtr, LPBYTE pbFrameEnd)\n{\n    PBLTE_FRAME pFileFrame = (PBLTE_FRAME)pbFramePtr;\n\n    // Check whether we have enough data ready\n    if((pbFramePtr + sizeof(BLTE_FRAME)) > pbFrameEnd)\n        return NULL;\n\n    Frame.FrameHash   = pFileFrame->FrameHash;\n    Frame.ContentSize = ConvertBytesToInteger_4(pFileFrame->ContentSize);\n    Frame.EncodedSize = ConvertBytesToInteger_4(pFileFrame->EncodedSize);\n    return pbFramePtr + sizeof(BLTE_FRAME);\n}\n\nstatic DWORD LoadSpanFrames(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry, ULONGLONG DataFileOffset, LPBYTE pbFramePtr, LPBYTE pbFrameEnd, size_t cbHeaderSize)\n{\n    PCASC_FILE_FRAME pFrames = NULL;\n    DWORD ContentSize = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    assert(pFileSpan != NULL);\n    assert(pFileSpan->pStream != NULL);\n    assert(pFileSpan->pFrames == NULL);\n\n    if (pFileSpan->FrameCount != 0)\n    {\n        // Move the raw archive offset\n        DataFileOffset += (pFileSpan->FrameCount * sizeof(BLTE_FRAME));\n\n        // Allocate array of file frames\n        pFrames = CASC_ALLOC<CASC_FILE_FRAME>(pFileSpan->FrameCount);\n        if (pFrames != NULL)\n        {\n            // Copy the frames to the file structure\n            for (DWORD i = 0; i < pFileSpan->FrameCount; i++)\n            {\n                CASC_FILE_FRAME & Frame = pFrames[i];\n\n                // Capture the single BLTE frame\n                pbFramePtr = CaptureBlteFileFrame(Frame, pbFramePtr, pbFrameEnd);\n                if(pbFramePtr == NULL)\n                {\n                    dwErrCode = ERROR_BAD_FORMAT;\n                    break;\n                }\n\n                // Fill-in the file range of the frame\n                Frame.StartOffset = pFileSpan->StartOffset + ContentSize;\n                Frame.EndOffset = Frame.StartOffset + Frame.ContentSize;\n                ContentSize += Frame.ContentSize;\n\n                // Fill-in the archive range of the frame\n                assert((DataFileOffset + Frame.EncodedSize) > DataFileOffset);\n                Frame.DataFileOffset = DataFileOffset;\n                DataFileOffset += Frame.EncodedSize;\n            }\n\n            // Save the content size of the file\n            if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE)\n            {\n                pCKeyEntry->ContentSize = ContentSize;\n            }\n        }\n        else\n        {\n            dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n        }\n    }\n    else\n    {\n        // Allocate single \"dummy\" frame\n        pFrames = CASC_ALLOC<CASC_FILE_FRAME>(1);\n        if (pFrames != NULL)\n        {\n            // Fill the single frame\n            memset(&pFrames->FrameHash, 0, sizeof(CONTENT_KEY));\n            pFrames->StartOffset = pFileSpan->StartOffset;\n            pFrames->EndOffset = pFileSpan->EndOffset;\n            pFrames->DataFileOffset = DataFileOffset;\n            pFrames->EncodedSize = (DWORD)(pCKeyEntry->EncodedSize - cbHeaderSize);\n            pFrames->ContentSize = pCKeyEntry->ContentSize;\n\n            // Save the number of file frames\n            pFileSpan->FrameCount = 1;\n        }\n        else\n        {\n            dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n        }\n    }\n\n    // Free the frame array on error\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        pFileSpan->FrameCount = 0;\n        CASC_FREE(pFrames);\n    }\n\n    pFileSpan->pFrames = pFrames;\n    return dwErrCode;\n}\n\nstatic DWORD LoadSpanFramesForPlainFile(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    PCASC_FILE_FRAME pFrames;\n\n    // Allocate single \"dummy\" frame\n    pFrames = CASC_ALLOC<CASC_FILE_FRAME>(1);\n    if (pFrames != NULL)\n    {\n        // Setup the size\n        pFileSpan->EndOffset = pFileSpan->StartOffset + pCKeyEntry->ContentSize;\n        pCKeyEntry->Flags |= CASC_CE_PLAIN_DATA;\n\n        // Fill the single frame\n        memset(&pFrames->FrameHash, 0, sizeof(CONTENT_KEY));\n        pFrames->StartOffset = pFileSpan->StartOffset;\n        pFrames->EndOffset = pFrames->StartOffset + pCKeyEntry->ContentSize;\n        pFrames->DataFileOffset = 0;\n        pFrames->EncodedSize = pCKeyEntry->EncodedSize;\n        pFrames->ContentSize = pCKeyEntry->ContentSize;\n\n        // Save the number of file frames\n        pFileSpan->FrameCount = 1;\n        pFileSpan->pFrames = pFrames;\n        return ERROR_SUCCESS;\n    }\n\n    return ERROR_NOT_ENOUGH_MEMORY;\n}\n\nstatic DWORD LoadEncodedHeaderAndSpanFrames(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    LPBYTE pbEncodedBuffer;\n    size_t cbEncodedBuffer = MAX_ENCODED_HEADER;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Should only be called when the file frames are NOT loaded\n    assert(pFileSpan->pFrames == NULL);\n    assert(pFileSpan->FrameCount == 0);\n\n    // Allocate the initial buffer for the encoded headers\n    pbEncodedBuffer = CASC_ALLOC<BYTE>(MAX_ENCODED_HEADER);\n    if (pbEncodedBuffer != NULL)\n    {\n        ULONGLONG ReadOffset = pFileSpan->ArchiveOffs;\n        size_t cbTotalHeaderSize;\n        size_t cbHeaderSize = 0;\n\n        // At this point, we expect encoded size to be known\n        assert(pCKeyEntry->EncodedSize != CASC_INVALID_SIZE);\n\n        // Do not read more than encoded size\n        cbEncodedBuffer = CASCLIB_MIN(cbEncodedBuffer, pCKeyEntry->EncodedSize);\n\n        // Load the entire (eventual) header area. This is faster than doing\n        // two read operations in a row. Read as much as possible. If the file is cut,\n        // the FileStream will pad it with zeros\n        if (FileStream_Read(pFileSpan->pStream, &ReadOffset, pbEncodedBuffer, (DWORD)cbEncodedBuffer))\n        {\n            // Parse the BLTE header\n            dwErrCode = ParseBlteHeader(pFileSpan, pCKeyEntry, ReadOffset, pbEncodedBuffer, cbEncodedBuffer, &cbHeaderSize);\n            if (dwErrCode == ERROR_SUCCESS)\n            {\n                // If the headers are larger than the initial read size, we read the missing data\n                pFileSpan->HeaderSize = (DWORD)(cbTotalHeaderSize = cbHeaderSize + (pFileSpan->FrameCount * sizeof(BLTE_FRAME)));\n                if (cbTotalHeaderSize > cbEncodedBuffer)\n                {\n                    pbEncodedBuffer = ReadMissingHeaderData(pFileSpan, ReadOffset, pbEncodedBuffer, cbEncodedBuffer, cbTotalHeaderSize);\n                    if (pbEncodedBuffer == NULL)\n                        dwErrCode = GetCascError();\n                    cbEncodedBuffer = cbTotalHeaderSize;\n                }\n\n                // Load the array of frame headers\n                if (dwErrCode == ERROR_SUCCESS)\n                {\n                    assert((ReadOffset + cbHeaderSize) > ReadOffset);\n                    dwErrCode = LoadSpanFrames(pFileSpan, pCKeyEntry, ReadOffset + cbHeaderSize, pbEncodedBuffer + cbHeaderSize, pbEncodedBuffer + cbEncodedBuffer, cbHeaderSize);\n                }\n            }\n            else\n            {\n                // Special treatment for plain files (\"PATCH\"): If the content size and encoded size\n                // are equal, we will create a single fake frame\n                if(pCKeyEntry->EncodedSize == pCKeyEntry->ContentSize)\n                {\n                    dwErrCode = LoadSpanFramesForPlainFile(pFileSpan, pCKeyEntry);\n                }\n            }\n        }\n        else\n        {\n            dwErrCode = ERROR_FILE_CORRUPT;\n        }\n\n        // Free the frame buffer\n        CASC_FREE(pbEncodedBuffer);\n    }\n    else\n    {\n        dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD LoadSpanFrames(TCascFile * hf, PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Sanity check\n    assert(pFileSpan->pFrames == NULL);\n\n    // Make sure that the data stream is open for that span\n    if(pFileSpan->pStream == NULL)\n    {\n        dwErrCode = OpenDataStream(hf, pFileSpan, pCKeyEntry, hf->bDownloadFileIf);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n    }\n\n    // Make sure we have header area loaded\n    return LoadEncodedHeaderAndSpanFrames(pFileSpan, pCKeyEntry);\n}\n\n// Loads all file spans to memory\nstatic DWORD LoadFileSpanFrames(TCascFile * hf)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = hf->pCKeyEntry;\n    PCASC_FILE_SPAN pFileSpan = hf->pFileSpan;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // If the ContentSize/EncodedSize is still unknown, we need to get it from the file frames\n    if(hf->ContentSize == CASC_INVALID_SIZE64 || hf->EncodedSize == CASC_INVALID_SIZE64)\n    {\n        // Set initially to zero\n        hf->ContentSize = 0;\n        hf->EncodedSize = 0;\n\n        // Load file frames for all spans\n        for(DWORD i = 0; i < hf->SpanCount; i++, pCKeyEntry++, pFileSpan++)\n        {\n            // Init the range of the file span\n            pFileSpan->StartOffset = hf->ContentSize;\n            pFileSpan->EndOffset = hf->ContentSize;\n\n            // Load the frames of the file span\n            dwErrCode = LoadSpanFrames(hf, pFileSpan, pCKeyEntry);\n            if(dwErrCode != ERROR_SUCCESS)\n                break;\n\n            hf->ContentSize += pCKeyEntry->ContentSize;\n            hf->EncodedSize += pCKeyEntry->EncodedSize;\n            pFileSpan->EndOffset = hf->ContentSize;\n        }\n    }\n    else\n    {\n        // Load file frames for all spans\n        for(DWORD i = 0; i < hf->SpanCount; i++, pCKeyEntry++, pFileSpan++)\n        {\n            // Load the frames of the file span\n            dwErrCode = LoadSpanFrames(hf, pFileSpan, pCKeyEntry);\n            if(dwErrCode != ERROR_SUCCESS)\n                break;\n        }\n    }\n\n    return dwErrCode;\n}\n\nstatic DWORD EnsureFileSpanFramesLoaded(TCascFile * hf)\n{\n    DWORD dwErrCode;\n\n    if(hf->ContentSize == CASC_INVALID_SIZE64 || hf->pFileSpan->pFrames == NULL)\n    {\n        // Load all frames of all file spans\n        dwErrCode = LoadFileSpanFrames(hf);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Now the content size must be known\n        if(hf->ContentSize == CASC_INVALID_SIZE64)\n            return ERROR_CAN_NOT_COMPLETE;\n    }\n\n    return ERROR_SUCCESS;\n}\n\nstatic DWORD DecodeFileFrame(\n    TCascFile * hf,\n    PCASC_CKEY_ENTRY pCKeyEntry,\n    PCASC_FILE_FRAME pFrame,\n    LPBYTE pbEncoded,\n    LPBYTE pbDecoded,\n    DWORD FrameIndex)\n{\n    TCascStorage * hs = hf->hs;\n    LPBYTE pbWorkBuffer = NULL;\n    DWORD cbDecodedExpected = 0;\n    DWORD cbWorkBuffer = 0;\n    DWORD dwStepCount = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n    DWORD cbEncoded = pFrame->EncodedSize;\n    DWORD cbDecoded = pFrame->ContentSize;\n    bool bWorkComplete = false;\n\n    //if(pFrame->EncodedSize == 0xda001)\n    //{\n    //    FILE * fp = fopen(\"E:\\\\frame-da001-002.dat\", \"wb\");\n    //    fwrite(pbEncoded, 1, pFrame->EncodedSize, fp);\n    //    fclose(fp);\n    //}\n\n    // If this is a file span with plain data, just copy the data\n    if(pCKeyEntry->Flags & CASC_CE_PLAIN_DATA)\n    {\n        assert(pCKeyEntry->ContentSize == pCKeyEntry->EncodedSize);\n        assert(pCKeyEntry->ContentSize == pFrame->ContentSize);\n        assert(pFrame->ContentSize == pFrame->EncodedSize);\n        memcpy(pbDecoded, pbEncoded, pCKeyEntry->ContentSize);\n        return ERROR_SUCCESS;\n    }\n\n    // Shall we verify the frame integrity?\n    if(hf->bVerifyIntegrity)\n    {\n        if(!CascVerifyDataBlockHash(pbEncoded, pFrame->EncodedSize, pFrame->FrameHash.Value))\n            return ERROR_FILE_CORRUPT;\n    }\n\n    // Perform the loop\n    while(bWorkComplete == false)\n    {\n        // There should never be a 3rd step\n        assert(dwStepCount < 2);\n\n        // Perform the operation specific by the first byte\n        switch(pbEncoded[0])\n        {\n            case 'E':   // Encrypted files\n                \n                // The work buffer should not have been allocated by any step\n                assert(pbWorkBuffer == NULL && cbWorkBuffer == 0);\n\n                // Allocate temporary buffer to decrypt into\n                // Example storage: \"2016 - WoW/23420\", File: \"4ee6bc9c6564227f1748abd0b088e950\"\n                pbWorkBuffer = CASC_ALLOC<BYTE>(cbEncoded - 1);\n                cbWorkBuffer = cbEncoded - 1;\n                if(pbWorkBuffer == NULL)\n                    return ERROR_NOT_ENOUGH_MEMORY;\n\n                // Decrypt the stream to the work buffer\n                dwErrCode = CascDecrypt(hs, pbWorkBuffer, &cbWorkBuffer, pbEncoded + 1, cbEncoded - 1, FrameIndex);\n                if(dwErrCode != ERROR_SUCCESS)\n                {\n                    bWorkComplete = true;\n                    break;\n                }\n\n                // When encrypted, there is always one more step after this.\n                // Setup the work buffer as input buffer for the next operation\n                pbEncoded = pbWorkBuffer;\n                cbEncoded = cbWorkBuffer;\n                break;\n\n            case 'Z':   // ZLIB compressed files\n                \n                // If we decompressed less than expected, we simply fill the rest with zeros\n                // Example: INSTALL file from the TACT CASC storage\n                cbDecodedExpected = cbDecoded;\n                dwErrCode = CascDecompress(pbDecoded, &cbDecoded, pbEncoded + 1, cbEncoded - 1);\n\n                // We exactly know what the output buffer size will be.\n                // If the uncompressed data is smaller, fill the rest with zeros\n                if(cbDecoded < cbDecodedExpected)\n                    memset(pbDecoded + cbDecoded, 0, (cbDecodedExpected - cbDecoded));\n                bWorkComplete = true;\n                break;\n\n            case 'N':   // Normal stored files\n                dwErrCode = CascDirectCopy(pbDecoded, &cbDecoded, pbEncoded + 1, cbEncoded - 1);\n                bWorkComplete = true;\n                break;\n\n            case 'F':   // Recursive frames (not supported)\n            default:    // Unrecognized. Could be a plain file data\n                dwErrCode = ERROR_NOT_SUPPORTED;\n                bWorkComplete = true;\n                assert(false);\n                break;\n        }\n\n        // Increment the step count\n        dwStepCount++;\n    }\n\n    // Some people find it handy to extract data from partially encrypted file,\n    // even at the cost of producing corrupt files.\n    // We overcome missing decryption key by zeroing the encrypted portions\n    if(dwErrCode == ERROR_FILE_ENCRYPTED && hf->bOvercomeEncrypted)\n    {\n        memset(pbDecoded, 0, cbDecoded);\n        dwErrCode = ERROR_SUCCESS;\n    }\n\n    // Free the temporary buffer\n    CASC_FREE(pbWorkBuffer);\n    return dwErrCode;\n}\n\nstatic bool GetFileFullInfo(TCascFile * hf, void * pvFileInfo, size_t cbFileInfo, size_t * pcbLengthNeeded)\n{\n    PCASC_FILE_FULL_INFO pFileInfo;\n    PCASC_CKEY_ENTRY pCKeyEntry = hf->pCKeyEntry;\n    TCascStorage * hs = hf->hs;\n    DWORD dwErrCode;\n\n    // Make sure that the file spans are loaded\n    dwErrCode = EnsureFileSpanFramesLoaded(hf);\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        SetCascError(dwErrCode);\n        return false;\n    }\n\n    // Verify whether we have enough space in the buffer\n    pFileInfo = (PCASC_FILE_FULL_INFO)ProbeOutputBuffer(pvFileInfo, cbFileInfo, sizeof(CASC_FILE_FULL_INFO), pcbLengthNeeded);\n    if(pFileInfo != NULL)\n    {\n        // Reset the entire structure\n        CopyMemory16(pFileInfo->CKey, pCKeyEntry->CKey);\n        CopyMemory16(pFileInfo->EKey, pCKeyEntry->EKey);\n        pFileInfo->FileDataId = CASC_INVALID_ID;\n        pFileInfo->LocaleFlags = CASC_INVALID_ID;\n        pFileInfo->ContentFlags = CASC_INVALID_ID;\n\n        // Supply information not depending on root\n        CascStrPrintf(pFileInfo->DataFileName, _countof(pFileInfo->DataFileName), \"data.%03u\", hf->pFileSpan->ArchiveIndex);\n        pFileInfo->StorageOffset = pCKeyEntry->StorageOffset;\n        pFileInfo->SegmentOffset = hf->pFileSpan->ArchiveOffs;\n        pFileInfo->FileNameHash = 0;\n        pFileInfo->TagBitMask = pCKeyEntry->TagBitMask;\n        pFileInfo->ContentSize = hf->ContentSize;\n        pFileInfo->EncodedSize = hf->EncodedSize;\n        pFileInfo->SegmentIndex = hf->pFileSpan->ArchiveIndex;\n        pFileInfo->SpanCount = hf->SpanCount;\n\n        // Supply the root-specific information\n        hs->pRootHandler->GetInfo(pCKeyEntry, pFileInfo);\n    }\n\n    return (pFileInfo != NULL);\n}\n\nstatic bool GetFileSpanInfo(TCascFile * hf, void * pvFileInfo, size_t cbFileInfo, size_t * pcbLengthNeeded)\n{\n    PCASC_FILE_SPAN_INFO pFileInfo;\n    PCASC_FILE_SPAN pFileSpan = hf->pFileSpan;\n    PCASC_CKEY_ENTRY pCKeyEntry = hf->pCKeyEntry;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Make sure that the file spans are loaded\n    dwErrCode = EnsureFileSpanFramesLoaded(hf);\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        SetCascError(dwErrCode);\n        return false;\n    }\n\n    // Verify whether we have enough space in the buffer\n    pFileInfo = (PCASC_FILE_SPAN_INFO)ProbeOutputBuffer(pvFileInfo, cbFileInfo, sizeof(CASC_FILE_SPAN_INFO) * hf->SpanCount, pcbLengthNeeded);\n    if(pFileInfo != NULL)\n    {\n        // Copy all file spans\n        for(DWORD i = 0; i < hf->SpanCount; i++, pFileInfo++, pFileSpan++, pCKeyEntry++)\n        {\n            CopyMemory16(pFileInfo->CKey, pCKeyEntry->CKey);\n            CopyMemory16(pFileInfo->EKey, pCKeyEntry->EKey);\n            pFileInfo->StartOffset = pFileSpan->StartOffset;\n            pFileInfo->EndOffset = pFileSpan->EndOffset;\n            pFileInfo->ArchiveIndex = pFileSpan->ArchiveIndex;\n            pFileInfo->ArchiveOffs = pFileSpan->ArchiveOffs;\n            pFileInfo->HeaderSize = pFileSpan->HeaderSize;\n            pFileInfo->FrameCount = pFileSpan->FrameCount;\n        }\n    }\n\n    return (pFileInfo != NULL);\n}\n\n\n// Reads the file data from cache. Returns the number of bytes read\nstatic DWORD ReadFile_Cache(TCascFile * hf, LPBYTE pbBuffer, ULONGLONG StartOffset, ULONGLONG EndOffset)\n{\n    // Is there a file cache at all?\n    if(hf->pbFileCache != NULL && hf->FileCacheStart <= StartOffset && StartOffset < hf->FileCacheEnd)\n    {\n        LPBYTE pbStartBlock = hf->pbFileCache + (size_t)(StartOffset - hf->FileCacheStart);\n\n        // Can we handle the entire request from the cache?\n        if(EndOffset <= hf->FileCacheEnd)\n        {\n            DWORD dwBytesToCopy = (DWORD)(EndOffset - StartOffset);\n\n            memcpy(pbBuffer, pbStartBlock, dwBytesToCopy);\n            return dwBytesToCopy;\n        }\n\n        // We copy as much bytes as available. The rest is handled by normal read\n        else\n        {\n            DWORD dwBytesToCopy = (DWORD)(hf->FileCacheEnd - StartOffset);\n\n            memcpy(pbBuffer, pbStartBlock, dwBytesToCopy);\n            return dwBytesToCopy;\n        }\n    }\n\n    // Can't handle the request from the cache\n    return 0;\n}\n\n// No cache at all. The entire file will be read directly to the user buffer\nstatic DWORD ReadFile_WholeFile(TCascFile * hf, LPBYTE pbBuffer)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = hf->pCKeyEntry;\n    PCASC_FILE_SPAN pFileSpan = hf->pFileSpan;\n    LPBYTE pbSaveBuffer = pbBuffer;\n    LPBYTE pbEncoded;\n    LPBYTE pbEncodedPtr;\n    DWORD dwErrCode;\n\n    for(DWORD SpanIndex = 0; SpanIndex < hf->SpanCount; SpanIndex++, pCKeyEntry++, pFileSpan++)\n    {\n        ULONGLONG ByteOffset = pFileSpan->ArchiveOffs + pFileSpan->HeaderSize;\n        DWORD EncodedSize = pCKeyEntry->EncodedSize - pFileSpan->HeaderSize;\n\n        // Allocate the buffer for the entire encoded span \n        pbEncodedPtr = pbEncoded = CASC_ALLOC<BYTE>(EncodedSize);\n        if(pbEncoded == NULL)\n        {\n            SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n            return 0;\n        }\n\n        // Load the encoded buffer\n        if(FileStream_Read(pFileSpan->pStream, &ByteOffset, pbEncoded, EncodedSize))\n        {\n            PCASC_FILE_FRAME pFileFrame = pFileSpan->pFrames;\n\n            for(DWORD FrameIndex = 0; FrameIndex < pFileSpan->FrameCount; FrameIndex++, pFileFrame++)\n            {\n                // Decode the file frame\n                dwErrCode = DecodeFileFrame(hf, pCKeyEntry, pFileFrame, pbEncodedPtr, pbBuffer, FrameIndex);\n                if(dwErrCode != ERROR_SUCCESS)\n                    break;\n\n                // Move pointers\n                pbEncodedPtr += pFileFrame->EncodedSize;\n                pbBuffer += pFileFrame->ContentSize;\n            }\n        }\n\n        CASC_FREE(pbEncoded);\n    }\n\n    // Give the amount of bytes read\n    return (DWORD)(pbBuffer - pbSaveBuffer);\n}\n\nstatic DWORD ReadFile_FrameCached(TCascFile * hf, LPBYTE pbBuffer, ULONGLONG StartOffset, ULONGLONG EndOffset)\n{\n    PCASC_CKEY_ENTRY pCKeyEntry = hf->pCKeyEntry;\n    PCASC_FILE_SPAN pFileSpan = hf->pFileSpan;\n    PCASC_FILE_FRAME pFileFrame = NULL;\n    LPBYTE pbSaveBuffer = pbBuffer;\n    LPBYTE pbEncoded = NULL;\n    LPBYTE pbDecoded = NULL;\n    DWORD dwBytesRead = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n    bool bNeedFreeDecoded = true;\n\n    // Parse all file spans\n    for(DWORD SpanIndex = 0; SpanIndex < hf->SpanCount; SpanIndex++, pCKeyEntry++, pFileSpan++)\n    {\n        if(pFileSpan->StartOffset <= StartOffset && StartOffset < pFileSpan->EndOffset)\n        {\n            for(DWORD FrameIndex = 0; FrameIndex < pFileSpan->FrameCount; FrameIndex++)\n            {\n                // Get the current file frame\n                pFileFrame = pFileSpan->pFrames + FrameIndex;\n\n                // Check the frame byte range\n                if(pFileFrame->StartOffset <= StartOffset && StartOffset < pFileFrame->EndOffset)\n                {\n                    // Check bytes read overflow\n                    if((dwBytesRead + pFileFrame->ContentSize) < dwBytesRead)\n                    {\n                        SetCascError(ERROR_BUFFER_OVERFLOW);\n                        return 0;\n                    }\n\n                    // Pick the buffer for decoded data. If we are going to read the entire frame,\n                    // there is a little chance that the caller will read the same file range again\n                    // So we can as well just unpack the entire frame into the output buffer\n                    if(pFileFrame->StartOffset < StartOffset || EndOffset < pFileFrame->EndOffset)\n                    {\n                        if((pbDecoded = CASC_ALLOC<BYTE>(pFileFrame->ContentSize)) == NULL)\n                        {\n                            SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n                            return 0;\n                        }\n                        bNeedFreeDecoded = true;\n                    }\n                    else\n                    {\n                        bNeedFreeDecoded = false;\n                        pbDecoded = pbBuffer;\n                    }\n\n                    // Allocate the encoded frame\n                    if((pbEncoded = CASC_ALLOC<BYTE>(pFileFrame->EncodedSize)) == NULL)\n                    {\n                        CASC_FREE(pbDecoded);\n                        SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n                        return 0;\n                    }\n\n                    // Load the frame to the encoded buffer\n                    if(FileStream_Read(pFileSpan->pStream, &pFileFrame->DataFileOffset, pbEncoded, pFileFrame->EncodedSize))\n                    {\n                        ULONGLONG EndOfCopy = CASCLIB_MIN(pFileFrame->EndOffset, EndOffset);\n                        DWORD dwBytesToCopy = (DWORD)(EndOfCopy - StartOffset);\n\n                        // Decode the frame\n                        dwErrCode = DecodeFileFrame(hf, pCKeyEntry, pFileFrame, pbEncoded, pbDecoded, FrameIndex);\n                        if(dwErrCode == ERROR_SUCCESS)\n                        {\n                            // Copy the data\n                            if(pbDecoded != pbBuffer)\n                                memcpy(pbBuffer, pbDecoded + (DWORD)(StartOffset - pFileFrame->StartOffset), dwBytesToCopy);\n                            StartOffset += dwBytesToCopy;\n                            pbBuffer += dwBytesToCopy;\n                        }\n                    }\n\n                    // Free the encoded buffer\n                    CASC_FREE(pbEncoded);\n\n                    // If we are at the end of the read area, break all loops\n                    if(dwErrCode != ERROR_SUCCESS || StartOffset >= EndOffset)\n                        goto __WorkComplete;\n                    if(bNeedFreeDecoded)\n                        CASC_FREE(pbDecoded);\n                }\n            }\n        }\n    }\n\n    __WorkComplete:\n\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // If there is some data left in the frame, we set it as cache\n        if(pFileFrame != NULL && pbDecoded != NULL && EndOffset < pFileFrame->EndOffset)\n        {\n            CASC_FREE(hf->pbFileCache);\n\n            hf->FileCacheStart = pFileFrame->StartOffset;\n            hf->FileCacheEnd = pFileFrame->EndOffset;\n            hf->pbFileCache = pbDecoded;\n            pbDecoded = NULL;\n        }\n    }\n\n    // Final free of the decoded buffer, if needeed\n    if(bNeedFreeDecoded)\n        CASC_FREE(pbDecoded);\n    pbDecoded = NULL;\n\n    // Return the number of bytes read. Always set LastError.\n    SetCascError(dwErrCode);\n    return (DWORD)(pbBuffer - pbSaveBuffer);\n}\n\n// No cache at all. The entire file will be read directly to the user buffer\nstatic DWORD ReadFile_NonCached(TCascFile * hf, LPBYTE pbBuffer, ULONGLONG StartOffset, ULONGLONG EndOffset)\n{\n    // Reading the whole file?\n    if(StartOffset == 0 && EndOffset == hf->ContentSize)\n    {\n        return ReadFile_WholeFile(hf, pbBuffer);\n    }\n\n    // Reading just a part of the file?\n    else\n    {\n        assert(false);\n    }\n\n    return 0;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nbool WINAPI CascGetFileInfo(HANDLE hFile, CASC_FILE_INFO_CLASS InfoClass, void * pvFileInfo, size_t cbFileInfo, size_t * pcbLengthNeeded)\n{\n    TCascFile * hf;\n    LPBYTE pbOutputValue = NULL;\n    LPBYTE pbInfoValue = NULL;\n    size_t cbInfoValue = 0;\n\n    // Validate the file handle\n    if((hf = TCascFile::IsValid(hFile)) == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // Differentiate between info classes\n    switch(InfoClass)\n    {\n        case CascFileContentKey:\n\n            // Do we have content key at all?\n            if(hf->pCKeyEntry == NULL || (hf->pCKeyEntry->Flags & CASC_CE_HAS_CKEY) == 0)\n            {\n                SetCascError(ERROR_NOT_SUPPORTED);\n                return false;\n            }\n\n            // Give the content key\n            pbInfoValue = hf->pCKeyEntry->CKey;\n            cbInfoValue = CASC_CKEY_SIZE;\n            break;\n\n        case CascFileEncodedKey:\n\n            // Do we have content key at all?\n            if(hf->pCKeyEntry == NULL || (hf->pCKeyEntry->Flags & CASC_CE_HAS_EKEY) == 0)\n            {\n                SetCascError(ERROR_NOT_SUPPORTED);\n                return false;\n            }\n\n            // Give the content key\n            pbInfoValue = hf->pCKeyEntry->EKey;\n            cbInfoValue = CASC_CKEY_SIZE;\n            break;\n\n        case CascFileFullInfo:\n            return GetFileFullInfo(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded);\n\n        case CascFileSpanInfo:\n            return GetFileSpanInfo(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded);\n\n        default:\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return false;\n    }\n\n    // Sanity check\n    assert(pbInfoValue != NULL);\n    assert(cbInfoValue != 0);\n\n    // Give the result\n    pbOutputValue = (LPBYTE)ProbeOutputBuffer(pvFileInfo, cbFileInfo, cbInfoValue, pcbLengthNeeded);\n    if(pbOutputValue != NULL)\n        memcpy(pbOutputValue, pbInfoValue, cbInfoValue);\n    return (pbOutputValue != NULL);\n}\n\n//\n// THE FILE SIZE PROBLEM\n//\n// There are members called \"FileSize\" in many CASC-related structure\n// For various files, these variables have different meaning.\n//\n// Storage      FileName  FileSize     FrameSum    HdrArea     CKeyEntry   EKeyEntry   RootEntry\n// -----------  --------  ----------   --------    --------    ----------  ----------  ----------\n// HotS(29049)  ENCODING  0x0024BA45 - 0x0024b98a  0x0024BA45  n/a         0x0024BA45  n/a\n// HotS(29049)  ROOT      0x00193340 - 0x00193340  0x0010db65  0x00193340  0x0010db65  n/a\n// HotS(29049)  (other)   0x00001080 - 0x00001080  0x000008eb  0x00001080  0x000008eb  0x00001080\n//                                                             \n// WoW(18888)   ENCODING  0x030d487b - 0x030dee79  0x030d487b  n/a         0x030d487b  n/a\n// WoW(18888)   ROOT      0x016a9800 - n/a         0x0131313d  0x016a9800  0x0131313d  n/a\n// WoW(18888)   (other)   0x000007d0 - 0x000007d0  0x00000397  0x000007d0  0x00000397  n/a\n//\n\nbool WINAPI CascGetFileSize64(HANDLE hFile, PULONGLONG PtrFileSize)\n{\n    TCascFile * hf;\n    DWORD dwErrCode;\n\n    // Validate the file handle\n    if((hf = TCascFile::IsValid(hFile)) == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // Validate the file pointer\n    if(PtrFileSize == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // ENCODING on older storages: Content size is not present in the BUILD file\n    // For that reason, we need to query the content size from the file frames\n    dwErrCode = EnsureFileSpanFramesLoaded(hf);\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        SetCascError(dwErrCode);\n        return false;\n    }\n\n    // Give the file size to the caller\n    PtrFileSize[0] = hf->ContentSize;\n    return true;\n}\n\nDWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD PtrFileSizeHigh)\n{\n    ULONGLONG FileSize = 0;\n\n    // Retrieve the 64-bit file size\n    if(!CascGetFileSize64(hFile, &FileSize))\n        return CASC_INVALID_SIZE;\n\n    // Give the file size to the caller\n    if(PtrFileSizeHigh != NULL)\n        PtrFileSizeHigh[0] = (DWORD)(FileSize >> 32);\n    return (DWORD)(FileSize);\n}\n\nbool WINAPI CascSetFilePointer64(HANDLE hFile, LONGLONG DistanceToMove, PULONGLONG PtrNewPos, DWORD dwMoveMethod)\n{\n    ULONGLONG FilePosition;\n    TCascFile * hf;\n\n    // If the hFile is not a valid file handle, return an error.\n    hf = TCascFile::IsValid(hFile);\n    if(hf == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // Get the relative point where to move from\n    switch(dwMoveMethod)\n    {\n        case FILE_BEGIN:\n            FilePosition = 0;\n            break;\n\n        case FILE_CURRENT:\n            FilePosition = hf->FilePointer;\n            break;\n\n        case FILE_END:\n            FilePosition = hf->ContentSize;\n            break;\n\n        default:\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return false;\n    }\n\n    // Now calculate the new file pointer\n    if(DistanceToMove >= 0)\n    {\n        // Do not allow the file pointer to overflow 64-bit range\n        if((FilePosition + DistanceToMove) < FilePosition)\n        {\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return false;\n        }\n\n        // Do not allow the file pointer to overflow the file size\n        if((FilePosition = FilePosition + DistanceToMove) > hf->ContentSize)\n            FilePosition = hf->ContentSize;\n        hf->FilePointer = FilePosition;\n    }\n    else\n    {\n        // Do not allow the file pointer to underflow 64-bit range\n        if((FilePosition + DistanceToMove) > FilePosition)\n        {\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return false;\n        }\n\n        // Do not allow the file pointer to move to negative values\n        if((LONGLONG)(FilePosition = FilePosition + DistanceToMove) < 0)\n            FilePosition = 0;\n        hf->FilePointer = FilePosition;\n    }\n\n    // Give the result size to the caller\n    if(PtrNewPos != NULL)\n        PtrNewPos[0] = hf->FilePointer;\n    return true;\n}\n\nDWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * PtrFilePosHigh, DWORD dwMoveMethod)\n{\n    ULONGLONG NewPos = 0;\n    LONGLONG DistanceToMove;\n    \n    // Assemble the 64-bit distance to move\n    DistanceToMove = (PtrFilePosHigh != NULL) ? MAKE_OFFSET64(PtrFilePosHigh[0], lFilePos) : (LONGLONG)(LONG)lFilePos;\n\n    // Set the file offset\n    if(!CascSetFilePointer64(hFile, DistanceToMove, &NewPos, dwMoveMethod))\n        return CASC_INVALID_POS;\n\n    // Give the result to the caller\n    if(PtrFilePosHigh != NULL)\n        PtrFilePosHigh[0] = (LONG)(NewPos >> 32);\n    return (DWORD)(NewPos);\n}\n\nbool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDWORD PtrBytesRead)\n{\n    ULONGLONG SaveFilePointer;\n    ULONGLONG StartOffset;\n    ULONGLONG EndOffset;\n    TCascFile * hf;\n    LPBYTE pbBuffer = (LPBYTE)pvBuffer;\n    DWORD dwBytesRead1 = 0;     // From cache\n    DWORD dwBytesRead2 = 0;     // From file\n    DWORD dwErrCode;\n\n    // The buffer must be valid\n    if(pvBuffer == NULL)\n    {\n        SetCascError(ERROR_INVALID_PARAMETER);\n        return false;\n    }\n\n    // Validate the file handle\n    if((hf = TCascFile::IsValid(hFile)) == NULL)\n    {\n        SetCascError(ERROR_INVALID_HANDLE);\n        return false;\n    }\n\n    // If we don't have file frames loaded, we need to do it now.\n    // Need to do it before file range check, as the file size may be unknown at this point\n    dwErrCode = EnsureFileSpanFramesLoaded(hf);\n    if(dwErrCode != ERROR_SUCCESS)\n    {\n        SetCascError(dwErrCode);\n        return false;\n    }\n\n    // If the file position is at or beyond end of file, do nothing\n    SaveFilePointer = StartOffset = hf->FilePointer;\n    if(StartOffset >= hf->ContentSize)\n    {\n        if (PtrBytesRead != NULL)\n            PtrBytesRead[0] = 0;\n        return true;\n    }\n\n    // If the read area goes beyond end of the file, cut the number of bytes to read\n    EndOffset = StartOffset + dwBytesToRead;\n    if(EndOffset > hf->ContentSize)\n    {\n        EndOffset = hf->ContentSize;\n    }\n\n    // Can we handle the request (at least partially) from the cache?\n    if((dwBytesRead1 = ReadFile_Cache(hf, pbBuffer, StartOffset, EndOffset)) != 0)\n    {\n        // Move pointers\n        StartOffset = StartOffset + dwBytesRead1;\n        pbBuffer += dwBytesRead1;\n\n        // Has the read request been fully satisfied?\n        if(StartOffset == EndOffset)\n        {\n            if(PtrBytesRead != NULL)\n                PtrBytesRead[0] = dwBytesRead1;\n            hf->FilePointer = EndOffset;\n            return true;\n        }\n    }\n\n    // Perform the cache-strategy-specific read\n    switch(hf->CacheStrategy)\n    {\n        // No caching at all. The entire file will be read directly to the user buffer\n        // Used for loading internal files, where we need to read the whole file\n        case CascCacheNothing:  \n            dwBytesRead2 = ReadFile_NonCached(hf, pbBuffer, StartOffset, EndOffset);\n            break;\n\n        // Read as many frames as we can. The last loaded frame, if not read entirely,\n        // will stay in the cache - We expect the next read to continue from that offset.\n        case CascCacheLastFrame:\n            dwBytesRead2 = ReadFile_FrameCached(hf, pbBuffer, StartOffset, EndOffset);\n            break;\n    }\n\n    // If the second-stage-read failed, we invalidate the entire operation and return 0 bytes read\n    if(dwBytesRead2 != 0)\n    {\n        // Give the result to the caller\n        if(PtrBytesRead != NULL)\n            PtrBytesRead[0] = (dwBytesRead1 + dwBytesRead2);\n        hf->FilePointer = StartOffset + dwBytesRead2;\n        return true;\n    }\n    else\n    {\n        // Give the result to the caller\n        if(PtrBytesRead != NULL)\n            PtrBytesRead[0] = 0;\n        hf->FilePointer = SaveFilePointer;\n        \n        // If 0 bytes were requested, it's actually a success\n        return (dwBytesToRead == 0);\n    }\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_Diablo3.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_Diablo3.cpp               Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Support for loading Diablo 3 ROOT file                                    */\n/* Note: D3 offsets refer to Diablo III.exe 2.2.0.30013 (32-bit)             */\n/* SHA1: e4f17eca8aad8dde70870bf932ac3f5b85f17a1f                            */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 04.03.15  1.00  Lad  The first version of CascRootFile_Diablo3.cpp        */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local structures\n\n#define DIABLO3_SUBDIR_SIGNATURE   0xEAF1FE87\n#define DIABLO3_PACKAGES_SIGNATURE 0xAABB0002\n#define DIABLO3_MAX_SUBDIRS        0x20\n#define DIABLO3_MAX_ASSETS         70               // Maximum possible number of assets\n#define DIABLO3_MAX_ROOT_FOLDERS   0x20             // Maximum count of root directory named entries\n\n// On-disk structure for a file given by file number\ntypedef struct _DIABLO3_ASSET_ENTRY\n{\n    CONTENT_KEY CKey;                              // Content key for the file\n    DWORD FileIndex;                               // File index\n} DIABLO3_ASSET_ENTRY, *PDIABLO3_ASSET_ENTRY;\n\n// On-disk structure for a file given by file number and suffix\ntypedef struct _DIABLO3_ASSETIDX_ENTRY\n{\n    CONTENT_KEY CKey;                              // Content key for the file\n    DWORD FileIndex;                               // File index\n    DWORD SubIndex;                                // File subindex, like \"SoundBank\\3D Ambience\\0000.smp\"\n} DIABLO3_ASSETIDX_ENTRY, *PDIABLO3_ASSETIDX_ENTRY;\n\n// In-memory structure of the named entry\ntypedef struct _DIABLO3_NAMED_ENTRY\n{\n    PCONTENT_KEY pCKey;                             // Pointer to the content key\n    const char * szFileName;                        // Pointer to the zero-terminated file name\n    const char * szFileEnd;                         // Position of the zero terminator (aka end of the file name)\n} DIABLO3_NAMED_ENTRY, *PDIABLO3_NAMED_ENTRY;\n\n// On-disk structure of CoreToc.dat header\ntypedef struct _DIABLO3_CORE_TOC_HEADER\n{\n    DWORD EntryCounts[DIABLO3_MAX_ASSETS];          // Array of number of entries (files) for each asset\n    DWORD EntryOffsets[DIABLO3_MAX_ASSETS];         // Array of offsets of each DIABLO3_CORE_TOC_ENTRY, relative to data after header\n    DWORD Unknowns[DIABLO3_MAX_ASSETS];             // Unknown\n    DWORD Alignment;\n} DIABLO3_CORE_TOC_HEADER, *PDIABLO3_CORE_TOC_HEADER;\n\n// On-disk structure of the entry in CoreToc.dat\ntypedef struct _DIABLO3_CORE_TOC_ENTRY\n{\n    DWORD AssetIndex;                               // Index of the Diablo3 asset (aka directory)\n    DWORD FileIndex;                                // File index\n    DWORD NameOffset;                               // Offset of the plain file name\n\n} DIABLO3_CORE_TOC_ENTRY, *PDIABLO3_CORE_TOC_ENTRY;\n\n// In-memory structure of parsed directory data\ntypedef struct _DIABLO3_DIRECTORY\n{\n    LPBYTE pbDirectoryData;                         // The begin of the directory data block\n    LPBYTE pbDirectoryEnd;                          // The end of the directory data block\n    LPBYTE pbAssetEntries;                          // Pointer to asset entries without subitem number. Example: \"SoundBank\\SoundFile.smp\"\n    LPBYTE pbAssetIdxEntries;                       // Pointer to asset entries with subitem number\n    LPBYTE pbNamedEntries;                          // Pointer to named entries. These are for files with arbitrary names, and they do not belong to an asset\n    DWORD dwAssetEntries;                           // Number of asset entries without subitem number\n    DWORD dwAssetIdxEntries;\n    DWORD dwNamedEntries;\n    DWORD dwNodeIndex;                              // Index of file node for this folder\n} DIABLO3_DIRECTORY, *PDIABLO3_DIRECTORY;\n\n// Structure for conversion DirectoryID -> Directory name\ntypedef struct _DIABLO3_ASSET_INFO\n{\n    const char * szDirectoryName;                   // Directory name\n    const char * szExtension;\n\n} DIABLO3_ASSET_INFO;\ntypedef const DIABLO3_ASSET_INFO * PDIABLO3_ASSET_INFO;\n\n//-----------------------------------------------------------------------------\n// Local variables\n\nstatic const DIABLO3_ASSET_INFO Assets[] =\n{\n//   DIR-NAME               EXTENSION\n//   ==========             =========\n    {NULL,                  NULL},         // 0x00\n    {\"Actor\",               \"acr\"},        // 0x01\n    {\"Adventure\",           \"adv\"},        // 0x02\n    {NULL,                  NULL},         // 0x03\n    {NULL,                  NULL},         // 0x04\n    {\"AmbientSound\",        \"ams\"},        // 0x05\n    {\"Anim\",                \"ani\"},        // 0x06\n    {\"Anim2D\",              \"an2\"},        // 0x07\n    {\"AnimSet\",             \"ans\"},        // 0x08\n    {\"Appearance\",          \"app\"},        // 0x09\n    {NULL,                  NULL},         // 0x0A\n    {\"Cloth\",               \"clt\"},        // 0x0B\n    {\"Conversation\",        \"cnv\"},        // 0x0C\n    {NULL,                  NULL},         // 0x0D\n    {\"EffectGroup\",         \"efg\"},        // 0x0E\n    {\"Encounter\",           \"enc\"},        // 0x0F\n    {NULL,                  NULL},         // 0x10\n    {\"Explosion\",           \"xpl\"},        // 0x11\n    {NULL,                  NULL},         // 0x12\n    {\"Font\",                \"fnt\"},        // 0x13\n    {\"GameBalance\",         \"gam\"},        // 0x14\n    {\"Globals\",             \"glo\"},        // 0x15\n    {\"LevelArea\",           \"lvl\"},        // 0x16\n    {\"Light\",               \"lit\"},        // 0x17\n    {\"MarkerSet\",           \"mrk\"},        // 0x18\n    {\"Monster\",             \"mon\"},        // 0x19\n    {\"Observer\",            \"obs\"},        // 0x1A\n    {\"Particle\",            \"prt\"},        // 0x1B\n    {\"Physics\",             \"phy\"},        // 0x1C\n    {\"Power\",               \"pow\"},        // 0x1D\n    {NULL,                  NULL},         // 0x1E\n    {\"Quest\",               \"qst\"},        // 0x1F\n    {\"Rope\",                \"rop\"},        // 0x20\n    {\"Scene\",               \"scn\"},        // 0x21\n    {\"SceneGroup\",          \"scg\"},        // 0x22\n    {NULL,                  NULL},         // 0x23\n    {\"ShaderMap\",           \"shm\"},        // 0x24\n    {\"Shaders\",             \"shd\"},        // 0x25\n    {\"Shakes\",              \"shk\"},        // 0x26\n    {\"SkillKit\",            \"skl\"},        // 0x27\n    {\"Sound\",               \"snd\"},        // 0x28\n    {\"SoundBank\",           \"sbk\"},        // 0x29\n    {\"StringList\",          \"stl\"},        // 0x2A\n    {\"Surface\",             \"srf\"},        // 0x2B\n    {\"Textures\",            \"tex\"},        // 0x2C\n    {\"Trail\",               \"trl\"},        // 0x2D\n    {\"UI\",                  \"ui\"},         // 0x2E\n    {\"Weather\",             \"wth\"},        // 0x2F\n    {\"Worlds\",              \"wrl\"},        // 0x30\n    {\"Recipe\",              \"rcp\"},        // 0x31\n    {NULL,                  NULL},         // 0x32\n    {\"Condition\",           \"cnd\"},        // 0x33\n    {NULL,                  NULL},         // 0x34\n    {NULL,                  NULL},         // 0x35\n    {NULL,                  NULL},         // 0x36\n    {NULL,                  NULL},         // 0x37\n    {\"Act\",                 \"act\"},        // 0x38\n    {\"Material\",            \"mat\"},        // 0x39\n    {\"QuestRange\",          \"qsr\"},        // 0x3A\n    {\"Lore\",                \"lor\"},        // 0x3B\n    {\"Reverb\",              \"rev\"},        // 0x3C\n    {\"PhysMesh\",            \"phm\"},        // 0x3D\n    {\"Music\",               \"mus\"},        // 0x3E\n    {\"Tutorial\",            \"tut\"},        // 0x3F\n    {\"BossEncounter\",       \"bos\"},        // 0x40\n    {NULL,                  NULL},         // 0x41\n    {\"Accolade\",            \"aco\"},        // 0x42\n};\n\n#define DIABLO3_ASSET_COUNT (sizeof(Assets) / sizeof(Assets[0]))\n\n//-----------------------------------------------------------------------------\n// Handler definitions for Diablo3 root file\n\nstruct TDiabloRoot : public TFileTreeRoot\n{\n    public:\n\n    TDiabloRoot() : TFileTreeRoot(0)\n    {\n        memset(RootFolders, 0, sizeof(RootFolders));\n        pFileIndices = NULL;\n        pbCoreTocFile = NULL;\n        pbCoreTocData = NULL;\n        nFileIndices = 0;\n        cbCoreTocFile = 0;\n\n        // Map for searching a real file extension\n        memset(&PackagesMap, 0, sizeof(CASC_MAP));\n        pbPackagesDat = NULL;\n        cbPackagesDat = 0;\n\n        // We have file names and return CKey as result of search\n        dwFeatures |= (CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY);\n    }\n\n    ~TDiabloRoot()\n    {\n        FreeLoadingStuff();\n    }\n\n    PDIABLO3_ASSET_INFO GetAssetInfo(DWORD dwAssetIndex)\n    {\n        if(dwAssetIndex < DIABLO3_ASSET_COUNT && Assets[dwAssetIndex].szDirectoryName != NULL)\n            return &Assets[dwAssetIndex];\n        return NULL;\n    }\n\n    char * FindPackageName(const char * szAssetName, const char * szPlainName)\n    {\n        char szFileName[MAX_PATH+1];\n        size_t nLength;\n\n        // Construct the name without extension and find it in the map\n        nLength = CascStrPrintf(szFileName, _countof(szFileName), \"%s\\\\%s\", szAssetName, szPlainName);\n        return (char *)PackagesMap.FindString(szFileName, szFileName + nLength);\n    }\n\n    LPBYTE LoadFileToMemory(TCascStorage * hs, const char * szFileName, DWORD * pcbFileData)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        LPBYTE pbFileData = NULL;\n\n        // Try to find CKey for the file\n        pCKeyEntry = GetFile(hs, szFileName);\n        if(pCKeyEntry != NULL)\n            pbFileData = LoadInternalFileToMemory(hs, pCKeyEntry, pcbFileData);\n\n        return pbFileData;\n    }\n\n    static LPBYTE CaptureDirectoryData(\n        DIABLO3_DIRECTORY & DirHeader,\n        LPBYTE pbDirectory,\n        DWORD cbDirectory)\n    {\n        LPBYTE pbDirectoryData = pbDirectory;\n        LPBYTE pbDataEnd = pbDirectory + cbDirectory;\n        DWORD Signature = 0;\n\n        //\n        // Structure of a Diablo3 directory header\n        // 1) Signature (4 bytes)\n        // 2) Number of DIABLO3_ASSET_ENTRY entries (4 bytes)\n        // 3) Array of DIABLO3_ASSET_ENTRY entries\n        // 4) Number of DIABLO3_ASSETIDX_ENTRY entries (4 bytes)\n        // 5) Array of DIABLO3_ASSETIDX_ENTRY entries\n        // 6) Number of DIABLO3_NAMED_ENTRY entries (4 bytes)\n        // 7) Array of DIABLO3_NAMED_ENTRY entries\n        //\n\n        // Prepare the header signature\n        memset(&DirHeader, 0, sizeof(DIABLO3_DIRECTORY));\n\n        // Get the header signature\n        pbDirectory = CaptureInteger32(pbDirectory, pbDataEnd, &Signature);\n        if((pbDirectory == NULL) || (Signature != CASC_DIABLO3_ROOT_SIGNATURE && Signature != DIABLO3_SUBDIR_SIGNATURE))\n            return NULL;\n\n        // Subdirectories have extra two arrays\n        if(Signature == DIABLO3_SUBDIR_SIGNATURE)\n        {\n            // Capture the number of DIABLO3_ASSET_ENTRY items\n            pbDirectory = CaptureInteger32(pbDirectory, pbDataEnd, &DirHeader.dwAssetEntries);\n            if(pbDirectory == NULL)\n                return NULL;\n\n            // Capture the array of DIABLO3_ASSET_ENTRY\n            pbDirectory = CaptureArray(pbDirectory, pbDataEnd, &DirHeader.pbAssetEntries, DIABLO3_ASSET_ENTRY, DirHeader.dwAssetEntries);\n            if(pbDirectory == NULL)\n                return NULL;\n\n            // Capture the number of DIABLO3_ASSETIDX_ENTRY items\n            pbDirectory = CaptureInteger32(pbDirectory, pbDataEnd, &DirHeader.dwAssetIdxEntries);\n            if(pbDirectory == NULL)\n                return NULL;\n\n            // Capture the array of DIABLO3_ASSETIDX_ENTRY\n            pbDirectory = CaptureArray(pbDirectory, pbDataEnd, &DirHeader.pbAssetIdxEntries, DIABLO3_ASSETIDX_ENTRY, DirHeader.dwAssetIdxEntries);\n            if(pbDirectory == NULL)\n                return NULL;\n        }\n\n        // Capture the number of DIABLO3_NAMED_ENTRY array\n        pbDirectory = CaptureInteger32(pbDirectory, pbDataEnd, &DirHeader.dwNamedEntries);\n        if(pbDirectory == NULL)\n            return NULL;\n\n        // Note: Do not capture the array here. We will do that later,\n        // when we will be parsing the directory\n        DirHeader.pbNamedEntries = pbDirectory;\n\n        // Put the directory range\n        DirHeader.pbDirectoryData = pbDirectoryData;\n        DirHeader.pbDirectoryEnd = pbDirectoryData + cbDirectory;\n        return pbDirectory;\n    }\n\n    LPBYTE CaptureCoreTocHeader(\n        PDIABLO3_CORE_TOC_HEADER * PtrHeader,\n        PDWORD PtrMaxIndex,\n        LPBYTE pbDataPtr,\n        LPBYTE pbDataEnd)\n    {\n        PDIABLO3_CORE_TOC_HEADER pTocHeader = (PDIABLO3_CORE_TOC_HEADER)pbDataPtr;\n        DWORD dwMaxFileIndex = 0;\n\n        // Check the space for header\n        if((pbDataPtr + sizeof(DIABLO3_CORE_TOC_HEADER)) > pbDataEnd)\n            return NULL;\n        pbDataPtr += sizeof(DIABLO3_CORE_TOC_HEADER);\n\n        // Verify all asset arrays\n        for(size_t i = 0; i < DIABLO3_MAX_ASSETS; i++)\n        {\n            PDIABLO3_CORE_TOC_ENTRY pTocEntry = (PDIABLO3_CORE_TOC_ENTRY)(pbDataPtr + pTocHeader->EntryOffsets[i]);\n            DWORD EntryOffset = pTocHeader->EntryOffsets[i];\n            DWORD EntryCount = pTocHeader->EntryCounts[i];\n\n            // Verify file range\n            if((pbDataPtr + EntryOffset + EntryCount * sizeof(DIABLO3_CORE_TOC_ENTRY)) > pbDataEnd)\n                return NULL;\n\n            // Find out the entry with the maximum index\n            for(DWORD n = 0; n < EntryCount; n++)\n            {\n                if(pTocEntry->FileIndex >= dwMaxFileIndex)\n                    dwMaxFileIndex = pTocEntry->FileIndex;\n                pTocEntry++;\n            }\n        }\n\n        // Give data and return\n        PtrMaxIndex[0] = dwMaxFileIndex;\n        PtrHeader[0] = pTocHeader;\n        return pbDataPtr;\n    }\n\n    LPBYTE CaptureNamedEntry(\n        LPBYTE pbDataPtr,\n        LPBYTE pbDataEnd,\n        PDIABLO3_NAMED_ENTRY pEntry)\n    {\n        // Capture the content key\n        pbDataPtr = CaptureContentKey(pbDataPtr, pbDataEnd, &pEntry->pCKey);\n        if(pbDataPtr == NULL)\n            return NULL;\n\n        // Capture file name. Must be ASCIIZ file name\n        pEntry->szFileName = (const char *)pbDataPtr;\n        while(pbDataPtr < pbDataEnd && pbDataPtr[0] != 0)\n            pbDataPtr++;\n\n        // Did we find a zero char?\n        if(pbDataPtr < pbDataEnd && pbDataPtr[0] == 0)\n        {\n            pEntry->szFileEnd = (const char *)pbDataPtr;\n            return pbDataPtr + 1;\n        }\n\n        return NULL;\n    }\n\n    int LoadDirectoryFile(TCascStorage * hs, DIABLO3_DIRECTORY & DirHeader, PCASC_CKEY_ENTRY pCKeyEntry)\n    {\n        LPBYTE pbData;\n        DWORD cbData = 0;\n\n        // Load the n-th folder\n        pbData = LoadInternalFileToMemory(hs, pCKeyEntry, &cbData);\n        if(pbData && cbData)\n        {\n            if(CaptureDirectoryData(DirHeader, pbData, cbData) == NULL)\n            {\n                // Clear the directory\n                CASC_FREE(pbData);\n                return ERROR_BAD_FORMAT;\n            }\n        }\n        return ERROR_SUCCESS;\n    }\n\n    bool CreateAssetFileName(\n        CASC_PATH<char> & PathBuffer,\n        DWORD FileIndex,\n        DWORD SubIndex)\n    {\n        PDIABLO3_CORE_TOC_ENTRY pTocEntry;\n        PDIABLO3_ASSET_INFO pAssetInfo;\n        LPCSTR szPackageName = NULL;\n        LPCSTR szPlainName;\n        LPCSTR szFormat;\n        char szBuffer[MAX_PATH];\n\n        // Find and check the entry\n        pTocEntry = pFileIndices + FileIndex;\n        if(pTocEntry->FileIndex == FileIndex)\n        {\n            // Retrieve the asset information\n            szPlainName = (LPCSTR)(pbCoreTocData + pTocEntry->NameOffset);\n            pAssetInfo = GetAssetInfo(pTocEntry->AssetIndex);\n\n            // Construct the file name, up to the extension. Don't include the '.'\n            szFormat = (SubIndex != CASC_INVALID_INDEX) ? \"%s\\\\%04u\" : \"%s\";\n            CascStrPrintf(szBuffer, _countof(szBuffer), szFormat, szPlainName, SubIndex);\n\n            // Try to fixup the file extension from the package name.\n            // File extensions are not predictable because for subitems,\n            // they are not always equal to the main items:\n            //\n            //  SoundBank\\3D Ambience.sbk\n            //  SoundBank\\3D Ambience\\0000.smp\n            //  SoundBank\\3D Ambience\\0002.smp\n            //  ...\n            //  SoundBank\\Angel.sbk\n            //  SoundBank\\Angel\\0000.fsb\n            //  SoundBank\\Angel\\0002.fsb\n            //\n            // We use the Base\\Data_D3\\PC\\Misc\\Packages.dat for real file extensions, where possible\n            //\n\n            if(pAssetInfo != NULL)\n            {\n                // Retrieve the asset name\n                szPackageName = FindPackageName(pAssetInfo->szDirectoryName, szBuffer);\n                if(szPackageName != NULL)\n                {\n                    PathBuffer.AppendString(szPackageName, false);\n                    return true;\n                }\n\n                // Append the directory name\n                PathBuffer.AppendString(pAssetInfo->szDirectoryName, false);\n            }\n            else\n            {\n                // Append generic name \"Asset##\" and continue\n                PathBuffer.AppendString(\"Asset\", false);\n                PathBuffer.AppendChar((char)('0' + (pTocEntry->AssetIndex / 10)));\n                PathBuffer.AppendChar((char)('0' + (pTocEntry->AssetIndex % 10)));\n            }\n\n            // Append the content of the buffer\n            PathBuffer.AppendString(szBuffer, true);\n\n            // If we have an extension, use it. Otherwise, supply \"a##\"\n            if(pAssetInfo != NULL && pAssetInfo->szExtension != NULL)\n            {\n                PathBuffer.AppendChar('.');\n                PathBuffer.AppendString(pAssetInfo->szExtension, false);\n            }\n            else\n            {\n                CascStrPrintf(szBuffer, _countof(szBuffer), \".a%02u\", pTocEntry->AssetIndex);\n                PathBuffer.AppendString(szBuffer, false);\n            }\n            return true;\n        }\n\n        return false;\n    }\n\n    // Parse the asset entries\n    DWORD ParseAssetEntries(\n        TCascStorage * hs,\n        DIABLO3_DIRECTORY & Directory,\n        CASC_PATH<char> & PathBuffer)\n    {\n        PDIABLO3_ASSET_ENTRY pEntry = (PDIABLO3_ASSET_ENTRY)Directory.pbAssetEntries;\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        size_t nSavePos = PathBuffer.Save();\n        DWORD dwEntries = Directory.dwAssetEntries;\n\n        // Do nothing if there is no entries\n        if(pEntry != NULL && dwEntries != 0)\n        {\n            // Insert all asset entries to the file tree\n            for(DWORD i = 0; i < dwEntries; i++, pEntry++)\n            {\n                pCKeyEntry = FindCKeyEntry_CKey(hs, pEntry->CKey.Value);\n                if(pCKeyEntry != NULL)\n                {\n                    // Construct the full path name of the entry\n                    if(CreateAssetFileName(PathBuffer, pEntry->FileIndex, CASC_INVALID_INDEX))\n                    {\n                        // Insert the entry to the file tree\n                        FileTree.InsertByName(pCKeyEntry, PathBuffer);\n                    }\n\n                    // Restore the path buffer position\n                    PathBuffer.Restore(nSavePos);\n                }\n            }\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    DWORD ParseAssetAndIdxEntries(\n        TCascStorage * hs,\n        DIABLO3_DIRECTORY & Directory,\n        CASC_PATH<char> & PathBuffer)\n    {\n        PDIABLO3_ASSETIDX_ENTRY pEntry = (PDIABLO3_ASSETIDX_ENTRY)Directory.pbAssetIdxEntries;\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        size_t nSavePos = PathBuffer.Save();\n        DWORD dwEntries = Directory.dwAssetIdxEntries;\n\n        // Do nothing if there is no entries\n        if(pEntry != NULL && dwEntries != 0)\n        {\n            // Insert all asset entries to the file tree\n            for(DWORD i = 0; i < dwEntries; i++, pEntry++)\n            {\n                pCKeyEntry = FindCKeyEntry_CKey(hs, pEntry->CKey.Value);\n                if(pCKeyEntry != NULL)\n                {\n                    // Construct the full path name of the entry\n                    if(CreateAssetFileName(PathBuffer, pEntry->FileIndex, pEntry->SubIndex))\n                    {\n                        // Insert the entry to the file tree\n//                      fprintf(fp, \"%08u %04u %s\\n\", pEntry->FileIndex, pEntry->SubIndex, PathBuffer.szBegin);\n                        FileTree.InsertByName(pCKeyEntry, PathBuffer);\n                    }\n\n                    // Restore the path buffer position\n                    PathBuffer.Restore(nSavePos);\n                }\n            }\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    // Parse the named entries of all folders\n    DWORD ParseDirectory_Phase1(\n        TCascStorage * hs, \n        DIABLO3_DIRECTORY & Directory,\n        CASC_PATH<char> & PathBuffer,\n        bool bIsRootDirectory)\n    {\n        DIABLO3_NAMED_ENTRY NamedEntry;\n        size_t nFolderIndex = 0;\n        size_t nSavePos = PathBuffer.Save();\n        DWORD dwErrCode = ERROR_SUCCESS;\n\n        // Do nothing if there is no named headers\n        if(Directory.pbNamedEntries && Directory.dwNamedEntries)\n        {\n            PCASC_CKEY_ENTRY pCKeyEntry;\n            PCASC_FILE_NODE pFileNode;\n            LPBYTE pbDataPtr = Directory.pbNamedEntries;\n            LPBYTE pbDataEnd = Directory.pbDirectoryEnd;\n            DWORD dwNodeIndex;\n\n            // Parse all entries\n            while(pbDataPtr < pbDataEnd)\n            {\n                // Capture the named entry\n                pbDataPtr = CaptureNamedEntry(pbDataPtr, pbDataEnd, &NamedEntry);\n                if(pbDataPtr == NULL)\n                    return ERROR_BAD_FORMAT;\n\n                // Append the path fragment to the total path\n                PathBuffer.AppendStringN(NamedEntry.szFileName, (NamedEntry.szFileEnd - NamedEntry.szFileName), true);\n\n                // Check whether the file exists in the storage\n                pCKeyEntry = FindCKeyEntry_CKey(hs, NamedEntry.pCKey->Value);\n                if(pCKeyEntry != NULL)\n                {\n                    // Create file node belonging to this folder\n                    pFileNode = FileTree.InsertByName(pCKeyEntry, PathBuffer);\n                    dwNodeIndex = (DWORD)FileTree.IndexOf(pFileNode);\n\n                    // If we are parsing root folder, we also need to load the data of the sub-folder file\n                    if(bIsRootDirectory)\n                    {\n                        // Mark the node as directory\n                        pCKeyEntry->Flags |= CASC_CE_FOLDER_ENTRY;\n                        pFileNode->Flags |= CFN_FLAG_FOLDER;\n\n                        // Load the sub-directory file\n                        dwErrCode = LoadDirectoryFile(hs, RootFolders[nFolderIndex], pCKeyEntry);\n                        if(dwErrCode != ERROR_SUCCESS)\n                            return dwErrCode;\n\n                        // Parse the sub-directory file\n                        dwErrCode = ParseDirectory_Phase1(hs, RootFolders[nFolderIndex], PathBuffer, false);\n                        if(dwErrCode != ERROR_SUCCESS)\n                            return dwErrCode;\n\n                        // Also save the item pointer and increment the folder index\n                        RootFolders[nFolderIndex].dwNodeIndex = dwNodeIndex;\n                        nFolderIndex++;\n                    }\n\n                    // Restore the path pointer\n                    PathBuffer.Restore(nSavePos);\n                }\n            }\n        }\n\n        return dwErrCode;\n    }\n\n    // Parse the nameless entries of all folders\n    int ParseDirectory_Phase2(TCascStorage * hs)\n    {\n        CASC_PATH<char> PathBuffer;\n        char szBuffer[MAX_PATH];\n\n        // Parse each root subdirectory\n        for(size_t i = 0; i < DIABLO3_MAX_ROOT_FOLDERS; i++)\n        {\n            // Is this root folder loaded?\n            if(RootFolders[i].pbDirectoryData != NULL)\n            {\n                // Retrieve the parent name\n                if(RootFolders[i].dwNodeIndex != 0)\n                {\n                    FileTree.PathAt(szBuffer, _countof(szBuffer), RootFolders[i].dwNodeIndex);\n                    PathBuffer.SetPathRoot(szBuffer);\n                }\n\n                // Array of DIABLO3_ASSET_ENTRY entries.\n                // These are for files belonging to an asset, without subitem number.\n                // Example: \"SoundBank\\SoundFile.smp\"\n                ParseAssetEntries(hs, RootFolders[i], PathBuffer);\n\n                // Array of DIABLO3_ASSETIDX_ENTRY entries.\n                // These are for files belonging to an asset, with a subitem number.\n                // Example: \"SoundBank\\SoundFile\\0001.smp\"\n                ParseAssetAndIdxEntries(hs, RootFolders[i], PathBuffer);\n            }\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    // Creates an array of DIABLO3_CORE_TOC_ENTRY entries indexed by FileIndex\n    // Used as lookup table when we have FileIndex and need Asset+PlainName\n    DWORD CreateMapOfFileIndices(TCascStorage * hs, const char * szFileName)\n    {\n        PDIABLO3_CORE_TOC_HEADER pTocHeader = NULL;\n        LPBYTE pbCoreTocPtr = pbCoreTocFile;\n        DWORD dwMaxFileIndex = 0;\n        DWORD dwErrCode = ERROR_CAN_NOT_COMPLETE;\n\n        // Load the entire file to memory\n        pbCoreTocFile = pbCoreTocPtr = LoadFileToMemory(hs, szFileName, &cbCoreTocFile);\n        if(pbCoreTocFile && cbCoreTocFile)\n        {\n            LPBYTE pbCoreTocEnd = pbCoreTocFile + cbCoreTocFile;\n\n            // Capture the header\n            if((pbCoreTocPtr = CaptureCoreTocHeader(&pTocHeader, &dwMaxFileIndex, pbCoreTocPtr, pbCoreTocEnd)) == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // If there are no indices, return NULL\n            if(dwMaxFileIndex == 0)\n                return ERROR_SUCCESS;\n\n            // Allocate and populate the array of DIABLO3_CORE_TOC_ENTRYs\n            pFileIndices = CASC_ALLOC<DIABLO3_CORE_TOC_ENTRY>(dwMaxFileIndex + 1);\n            if(pFileIndices != NULL)\n            {\n                // Initialize all entries to invalid\n                memset(pFileIndices, 0xFF, (dwMaxFileIndex + 1) * sizeof(DIABLO3_CORE_TOC_ENTRY));\n\n                // Populate the linear array with the file indices\n                for(size_t i = 0; i < DIABLO3_MAX_ASSETS; i++)\n                {\n                    PDIABLO3_CORE_TOC_ENTRY pTocEntry = (PDIABLO3_CORE_TOC_ENTRY)(pbCoreTocPtr + pTocHeader->EntryOffsets[i]);\n                    LPBYTE pbCoreTocNames = (LPBYTE)(pTocEntry + pTocHeader->EntryCounts[i]);\n\n                    // Setup the entries\n                    for(DWORD n = 0; n < pTocHeader->EntryCounts[i]; n++)\n                    {\n                        DWORD dwFileIndex = pTocEntry->FileIndex;\n\n                        pFileIndices[dwFileIndex].AssetIndex = pTocEntry->AssetIndex;\n                        pFileIndices[dwFileIndex].FileIndex  = pTocEntry->FileIndex;\n                        pFileIndices[dwFileIndex].NameOffset = (DWORD)(pbCoreTocNames - pbCoreTocPtr) + pTocEntry->NameOffset;\n                        pTocEntry++;\n                    }\n                }\n\n                // Save the file to the root handler\n                pbCoreTocData = pbCoreTocPtr;\n                nFileIndices = dwMaxFileIndex;\n                dwErrCode = ERROR_SUCCESS;\n            }\n        }\n        return dwErrCode;\n    }\n\n    // Packages.dat contains a list of full file names (without locale prefix).\n    // They are not sorted, nor they correspond to file IDs.\n    // Does the sort order mean something? Perhaps we could use them as listfile?\n    int CreateMapOfRealNames(TCascStorage * hs, const char * szFileName)\n    {\n        DWORD Signature = 0;\n        DWORD NumberOfNames = 0;\n\n        // Load the entire file to memory\n        pbPackagesDat = LoadFileToMemory(hs, szFileName, &cbPackagesDat);\n        if(pbPackagesDat && cbPackagesDat)\n        {\n            LPBYTE pbPackagesPtr = pbPackagesDat;\n            LPBYTE pbPackagesEnd = pbPackagesDat + cbPackagesDat;\n\n            // Get the header. There is just Signature + NumberOfNames\n            if((pbPackagesPtr = CaptureInteger32(pbPackagesPtr, pbPackagesEnd, &Signature)) == NULL)\n                return ERROR_BAD_FORMAT;\n            if((pbPackagesPtr = CaptureInteger32(pbPackagesPtr, pbPackagesEnd, &NumberOfNames)) == NULL)\n                return ERROR_BAD_FORMAT;\n            if(Signature != DIABLO3_PACKAGES_SIGNATURE || NumberOfNames == 0)\n                return ERROR_BAD_FORMAT;\n\n            // Create the map for fast search of the file name\n            if(PackagesMap.Create(NumberOfNames, 0, 0, KeyIsString) == ERROR_SUCCESS)\n            {\n                const char * szPackageName = (const char *)pbPackagesPtr;\n\n                // Go as long as there is something\n                for(DWORD i = 0; i < NumberOfNames; i++)\n                {\n                    // Get the file extension\n                    if((LPBYTE)szPackageName >= pbPackagesEnd)\n                        break;\n\n                    // Insert the file name to the map. The file extension is not included\n                    PackagesMap.InsertString(szPackageName, true);\n                    szPackageName = szPackageName + strlen(szPackageName) + 1;\n                }\n            }\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    DWORD Load(TCascStorage * hs, DIABLO3_DIRECTORY & RootDirectory)\n    {\n        CASC_PATH<char> PathBuffer;\n        DWORD dwErrCode;\n\n        // Always parse the named entries first. They always point to a file.\n        // These are entries with arbitrary names, and they do not belong to an asset\n        dwErrCode = ParseDirectory_Phase1(hs, RootDirectory, PathBuffer, true);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // The asset entries in the ROOT file don't contain file names, but indices.\n            // To convert a file index to a file name, we need to load and parse the \"Base\\\\CoreTOC.dat\" file.\n            dwErrCode = CreateMapOfFileIndices(hs, \"Base\\\\CoreTOC.dat\");\n            if(dwErrCode == ERROR_SUCCESS)\n            {\n                // The file \"Base\\Data_D3\\PC\\Misc\\Packages.dat\" contains the file names\n                // (without level-0 and level-1 directory).\n                // We can use these names for supplying the missing extensions\n                CreateMapOfRealNames(hs, \"Base\\\\Data_D3\\\\PC\\\\Misc\\\\Packages.dat\");\n\n                // Now parse all folders and resolve the full names\n                ParseDirectory_Phase2(hs);\n            }\n\n            // Free all stuff that was used during loading of the ROOT file\n            FreeLoadingStuff();\n        }\n\n        return dwErrCode;\n    }\n\n    void FreeLoadingStuff()\n    {\n        // Free the captured root sub-directories\n        for(size_t i = 0; i < DIABLO3_MAX_SUBDIRS; i++)\n            CASC_FREE(RootFolders[i].pbDirectoryData);\n\n        // Free the package map\n        PackagesMap.Free();\n\n        // Free the array of file indices\n        CASC_FREE(pFileIndices);\n\n        // Free the loaded CoreTOC.dat file\n        CASC_FREE(pbCoreTocFile);\n\n        // Free the loaded Packages.dat file\n        CASC_FREE(pbPackagesDat);\n    }\n\n    // Array of root directory subdirectories\n    DIABLO3_DIRECTORY RootFolders[DIABLO3_MAX_ROOT_FOLDERS];\n\n    // Array of DIABLO3_TOC_ENTRY structures, sorted by the file index\n    // Used for converting FileIndex -> Asset+PlainName during loading\n    PDIABLO3_CORE_TOC_ENTRY pFileIndices;\n    LPBYTE pbCoreTocFile;\n    LPBYTE pbCoreTocData;\n    size_t nFileIndices;\n    DWORD cbCoreTocFile;\n\n    // Map for searching a real file extension\n    CASC_MAP PackagesMap;\n    LPBYTE pbPackagesDat;\n    DWORD cbPackagesDat;\n};\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nDWORD RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)\n{\n    TDiabloRoot * pRootHandler = NULL;\n    DIABLO3_DIRECTORY RootDirectory;\n    DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n    // Verify the header of the ROOT file\n    if(TDiabloRoot::CaptureDirectoryData(RootDirectory, pbRootFile, cbRootFile) != NULL)\n    {\n        // Allocate the root handler object\n        pRootHandler = new TDiabloRoot();\n        if(pRootHandler != NULL)\n        {\n            // Load the root directory. If load failed, we free the object\n            dwErrCode = pRootHandler->Load(hs, RootDirectory);\n            if(dwErrCode != ERROR_SUCCESS)\n            {\n                delete pRootHandler;\n                pRootHandler = NULL;\n            }\n        }\n    }\n\n    // Assign the root directory (or NULL) and return error\n    hs->pRootHandler = pRootHandler;\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_Install.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_Install.cpp               Copyright (c) Ladislav Zezula 2018 */\n/*---------------------------------------------------------------------------*/\n/* Support for ROOT handler based on INSTALL manifest                        */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 21.05.19  1.00  Lad  The first version of CascRootFile_Install.cpp        */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Handler definitions for Starcraft I root file\n\nstruct TRootHandler_Install : public TFileTreeRoot\n{\n    public:\n\n    TRootHandler_Install() : TFileTreeRoot(0)\n    {\n        // We have file names and return CKey as result of search\n        dwFeatures |= (CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY);\n    }\n\n    DWORD Load(TCascStorage * hs, CASC_INSTALL_HEADER InHeader, LPBYTE pbInstallFile, LPBYTE pbInstallEnd)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        const char * szString;\n        size_t nBitmapLength;\n        size_t nFileCount = InHeader.EntryCount;\n\n        // Skip the header\n        pbInstallFile += InHeader.HeaderLength;\n\n        // Skip the tags\n        for (DWORD i = 0; i < InHeader.TagCount; i++)\n        {\n            szString = (const char *)pbInstallFile;\n            nBitmapLength = GetTagBitmapLength(pbInstallFile, pbInstallEnd, InHeader.EntryCount);\n            pbInstallFile = pbInstallFile + strlen(szString) + 1 + sizeof(USHORT) + nBitmapLength;\n        }\n\n        // Load the names and insert them to the root handler\n        while(nFileCount > 0 && pbInstallFile < pbInstallEnd)\n        {\n            // File Name and CKey\n            szString = (const char *)pbInstallFile;\n            pbInstallFile += strlen(szString) + 1;\n\n            // Verify whether it is a known entry\n            pCKeyEntry = FindCKeyEntry_CKey(hs, pbInstallFile);\n            pbInstallFile += MD5_HASH_SIZE + sizeof(DWORD);\n\n            // Insert the FileName+CKey to the file tree\n            if (pCKeyEntry != NULL)\n                FileTree.InsertByName(pCKeyEntry, szString);\n            nFileCount--;\n        }\n\n        return ERROR_SUCCESS;\n    }\n};\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nDWORD CaptureInstallHeader(CASC_INSTALL_HEADER & InHeader, LPBYTE pbFileData, size_t cbFileData)\n{\n    PFILE_INSTALL_HEADER pFileHeader = (PFILE_INSTALL_HEADER)pbFileData;\n\n    // Check the signature ('DL') and version\n    if (cbFileData < sizeof(FILE_INSTALL_HEADER) || pFileHeader->Magic != FILE_MAGIC_INSTALL || pFileHeader->Version != 1)\n        return ERROR_BAD_FORMAT;\n\n    // Note that we don't support CKey sizes greater than 0x10 in the INSTALL file\n    if (pFileHeader->EKeyLength > MD5_HASH_SIZE)\n        return ERROR_BAD_FORMAT;\n\n    // Capture the header version 1\n    memset(&InHeader, 0, sizeof(CASC_INSTALL_HEADER));\n    InHeader.Magic = pFileHeader->Magic;\n    InHeader.Version = pFileHeader->Version;\n    InHeader.EKeyLength = pFileHeader->EKeyLength;\n    InHeader.TagCount = ConvertBytesToInteger_2(pFileHeader->TagCount);\n    InHeader.EntryCount = ConvertBytesToInteger_4(pFileHeader->EntryCount);\n    InHeader.HeaderLength = sizeof(FILE_INSTALL_HEADER);\n    return ERROR_SUCCESS;\n}\n\nDWORD RootHandler_CreateInstall(TCascStorage * hs, LPBYTE pbInstallFile, DWORD cbInstallFile)\n{\n    CASC_INSTALL_HEADER InHeader;\n    TRootHandler_Install * pRootHandler = NULL;\n    DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n    // Capture the header of the DOWNLOAD file\n    dwErrCode = CaptureInstallHeader(InHeader, pbInstallFile, cbInstallFile);\n    if (dwErrCode == ERROR_SUCCESS)\n    {\n        // Allocate the root handler object\n        pRootHandler = new TRootHandler_Install();\n        if (pRootHandler != NULL)\n        {\n            // Parse the entire install manifest\n            dwErrCode = pRootHandler->Load(hs, InHeader, pbInstallFile, pbInstallFile + cbInstallFile);\n            hs->pRootHandler = pRootHandler;\n        }\n    }\n\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_MNDX.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_MNDX.cpp                  Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Common functions for CascLib                                              */\n/* Note: \"HOTS\" refers to Play.exe, v2.5.0.29049 (Heroes of the Storm Alpha) */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 18.05.14  1.00  Lad  The first version of CascRootFile_MNDX.cpp           */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local defines\n\n#define MNDX_MAR_SIGNATURE 0x0052414d           // 'MAR\\0'\n#define MAR_PACKAGE_NAMES           0           // MAR with package names only\n#define MAR_STRIPPED_NAMES          1           // MAR with names where packages were stripped\n#define MAR_FULL_NAMES              2           // MAR with full file names\n#define MAR_COUNT                   3           // Maximum of 3 MAR files are supported\n\n#define MNDX_SEARCH_INITIALIZING    0\n#define MNDX_SEARCH_SEARCHING       2\n#define MNDX_SEARCH_FINISHED        4\n\n#define MNDX_MAX_ENTRIES(type)  (0xFFFFFFFF / sizeof(type))\n\n#define MNDX_INVALID_SIZE_T        ((size_t)(-1))\n\n#define MNDX_LAST_CKEY_ENTRY       0x80000000\n\n//-----------------------------------------------------------------------------\n// Local structures\n\ntypedef union _SETBITS\n{\n    struct\n    {\n        DWORD Lower08 : 8;                          // Number of set bits in the lower 1 byte\n        DWORD Lower16 : 8;                          // Number of set bits in the lower 2 bytes\n        DWORD Lower24 : 8;                          // Number of set bits in the lower 3 bytes\n        DWORD Lower32 : 8;                          // Number of set bits in the 32-bit integer\n    } u;\n\n    DWORD SetBitsAll;                               // The total set bits mask\n\n} SETBITS, *PSETBITS;\n\ntypedef struct _HASH_ENTRY\n{\n    DWORD NodeIndex;                                // Index of the path node\n    DWORD NextIndex;                                // ID of the first subnode in the hash table\n\n    union\n    {\n        DWORD FragmentOffset;                       // Offset of the path fragment in the TPathFragmentTable\n        DWORD ChildTableIndex;                      // Starting search index for the child database (if child database is present)\n        char SingleChar;                            // If the upper 24 bits of the FragmentOffset is 0xFFFFFFFF, this single character\n    };\n                                                    // Otherwise --> Offset to the name fragment table\n} HASH_ENTRY, *PHASH_ENTRY;\n\ntypedef struct _FILE_MNDX_HEADER\n{\n    DWORD Signature;                                // 'MNDX'\n    DWORD HeaderVersion;                            // Must be <= 2\n    DWORD FormatVersion;\n\n} FILE_MNDX_HEADER, *PFILE_MNDX_HEADER;\n\ntypedef struct _MNDX_PACKAGE\n{\n    char * szFileName;                              // Pointer to file name\n    size_t nLength;                                 // Length of the file name\n    size_t nIndex;                                  // Package index\n\n} MNDX_PACKAGE, *PMNDX_PACKAGE;\n\n// Root file entry for CASC storages with MNDX root file (Heroes of the Storm)\n// Corresponds to the in-file structure\ntypedef struct _MNDX_CKEY_ENTRY\n{\n    DWORD Flags;                                    // High 8 bits: Flags, low 24 bits: package index\n    BYTE  CKey[MD5_HASH_SIZE];                      // Content key for the file\n    DWORD ContentSize;                              // Uncompressed file size, in bytes\n\n} MNDX_CKEY_ENTRY, *PMNDX_CKEY_ENTRY;\n\ntypedef struct _FILE_MAR_INFO\n{\n    DWORD MarIndex;\n    DWORD MarDataSize;\n    DWORD MarDataSizeHi;\n    DWORD MarDataOffset;\n    DWORD MarDataOffsetHi;\n} FILE_MAR_INFO, *PFILE_MAR_INFO;\n\n//-----------------------------------------------------------------------------\n// Local variables\n\nunsigned char table_1BA1818[0x800] =\n{\n    0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\n    0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,\n    0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02,\n    0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,\n    0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,\n    0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02,\n    0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,\n    0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03,\n    0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03,\n    0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03,\n    0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03,\n    0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,\n    0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\n    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07\n};\n\n//-----------------------------------------------------------------------------\n// Local functions - Number of set bits in an integer\n\n// HOTS: inlined\nstatic SETBITS GetNumberOfSetBits(DWORD Value32)\n{\n    SETBITS SetBits;\n\n    Value32 = ((Value32 >> 1) & 0x55555555) + (Value32 & 0x55555555);\n    Value32 = ((Value32 >> 2) & 0x33333333) + (Value32 & 0x33333333);\n    Value32 = ((Value32 >> 4) & 0x0F0F0F0F) + (Value32 & 0x0F0F0F0F);\n    SetBits.SetBitsAll = Value32 * 0x01010101;\n\n    return SetBits;\n}\n\nstatic DWORD GetNumberOfSetBits32(DWORD Value32)\n{\n    return GetNumberOfSetBits(Value32).u.Lower32;\n}\n\nstatic LPBYTE CaptureData(LPBYTE pbRootPtr, LPBYTE pbRootEnd, void * pvBuffer, size_t cbLength)\n{\n    // Check whether there is enough data in the buffer\n    if((pbRootPtr + cbLength) > pbRootEnd)\n        return NULL;\n\n    // Copy the data\n    memcpy(pvBuffer, pbRootPtr, cbLength);\n    return pbRootPtr + cbLength;\n}\n\n//-----------------------------------------------------------------------------\n// The TPathStop structure\n\nstruct TPathStop\n{\n    TPathStop()\n    {\n        LoBitsIndex = 0;\n        field_4 = 0;\n        Count = 0;\n        HiBitsIndex_PathFragment = CASC_INVALID_INDEX;\n        field_10 = 0xFFFFFFFF;\n    }\n\n    TPathStop(DWORD arg_0, DWORD arg_4, DWORD arg_8)\n    {\n        LoBitsIndex = arg_0;\n        field_4 = arg_4;\n        Count = arg_8;\n        HiBitsIndex_PathFragment = CASC_INVALID_INDEX;\n        field_10 = 0xFFFFFFFF;\n    }\n\n    DWORD LoBitsIndex;\n    DWORD field_4;\n    DWORD Count;\n    DWORD HiBitsIndex_PathFragment;\n    DWORD field_10;\n};\n\n//-----------------------------------------------------------------------------\n// Basic array implementations\n\nclass TByteStream\n{\n    public:\n\n    // HOTS: 01959990\n    TByteStream()\n    {\n        pbByteData = NULL;\n        pvMappedFile = NULL;\n        cbByteData = 0;\n        field_C = 0;\n        hFile = 0;\n        hMap = 0;\n    }\n\n    // HOTS: 19599F0\n    template <typename T>\n    int GetBytes(size_t length, T ** Pointer)\n    {\n        // Is there enough bytes in the array?\n        if(length > cbByteData)\n            return ERROR_BAD_FORMAT;\n\n        // Give the buffer to the caller\n        Pointer[0] = (T *)(pbByteData);\n\n        // Move pointers\n        pbByteData += length;\n        cbByteData -= length;\n        return ERROR_SUCCESS;\n    }\n\n    int CopyBytes(void * value, size_t length)\n    {\n        // Is there enough bytes in the array?\n        if(length > cbByteData)\n            return ERROR_BAD_FORMAT;\n\n        // Give the buffer to the caller\n        memcpy(value, pbByteData, length);\n\n        // Move pointers\n        pbByteData += length;\n        cbByteData -= length;\n        return ERROR_SUCCESS;\n    }\n\n    // HOTS: 1959A60\n    int SkipBytes(size_t cbByteCount)\n    {\n        LPBYTE Pointer;\n\n        return GetBytes<BYTE>(cbByteCount, &Pointer);\n    }\n\n    // HOTS: 1959AF0\n    int SetByteBuffer(LPBYTE pbNewByteData, size_t cbNewByteData)\n    {\n        if(pbNewByteData != NULL || cbNewByteData == 0)\n        {\n            pbByteData = pbNewByteData;\n            cbByteData = cbNewByteData;\n            return ERROR_SUCCESS;\n        }\n\n        return ERROR_INVALID_PARAMETER;\n    }\n\n    // HOTS: 1957160 <DWORD>\n    template <typename T>\n    DWORD GetValue(T & Value)\n    {\n        T * Pointer;\n        DWORD dwErrCode;\n\n        dwErrCode = GetBytes(sizeof(T), (LPBYTE *)(&Pointer));\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        Value = Pointer[0];\n        return ERROR_SUCCESS;\n    }\n\n    // Retrieves the item count in the array\n    template <typename T>\n    DWORD GetArrayItemCount(DWORD & ArraySize, DWORD & ItemCount)\n    {\n        ULONGLONG ByteCount;\n        DWORD dwErrCode;\n\n        // The first 8 bytes is the byte size of the array\n        dwErrCode = GetValue<ULONGLONG>(ByteCount);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Extract the number of bytes\n        if(ByteCount > 0xFFFFFFFF || (ByteCount % sizeof(T)) != 0)\n            return ERROR_BAD_FORMAT;\n\n        // Give the result to the caller\n        ItemCount = (DWORD)(ByteCount / sizeof(T));\n        ArraySize = (DWORD)(ByteCount);\n        return ERROR_SUCCESS;\n    }\n\n    // HOTS: 1957190: <DWORD>\n    // HOTS: 19571E0: <BASEVALS>\n    // HOTS: 1957230: <BYTE>\n    // HOTS: 1957280: <HASH_ENTRY>\n    template <typename T>\n    DWORD GetArray(T ** Pointer, size_t ItemCount)\n    {\n        DWORD dwErrCode = ERROR_SUCCESS;\n\n        // Verify parameters\n        if(Pointer == NULL && ItemCount != 0)\n            return ERROR_INVALID_PARAMETER;\n        if(ItemCount > MNDX_MAX_ENTRIES(T))\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        // Allocate bytes for the array\n        if (Pointer != NULL)\n        {\n            Pointer[0] = CASC_ALLOC<T>(ItemCount);\n            if (Pointer[0] == NULL)\n                return ERROR_NOT_ENOUGH_MEMORY;\n\n            // Get the pointer to the array\n            dwErrCode = CopyBytes(Pointer[0], sizeof(T) * ItemCount);\n        }\n\n        return dwErrCode;\n    }\n\n    LPBYTE pbByteData;\n    void * pvMappedFile;\n    size_t cbByteData;\n    DWORD field_C;\n    HANDLE hFile;\n    HANDLE hMap;\n};\n\n//-----------------------------------------------------------------------------\n// TGenericArray interface/implementation\n\ntemplate <typename T>\nclass TGenericArray\n{\n    public:\n\n    TGenericArray()\n    {\n        ItemArray = NULL;\n        ItemCount = 0;\n        MaxItemCount = 0;\n        bIsValidArray = false;\n    }\n\n    ~TGenericArray()\n    {\n        CASC_FREE(ItemArray);\n    }\n\n    T & operator[] (size_t index)\n    {\n        assert(index < ItemCount);\n        return ItemArray[index];\n    }\n\n    // HOTS: 1957090 (SetDwordsValid)\n    // HOTS: 19570B0 (SetBaseValsValid)\n    // HOTS: 19570D0 (? SetBitsValid ?)\n    // HOTS: 19570F0 (SetPathFragmentsValid)\n    int SetArrayValid()\n    {\n        if(bIsValidArray != 0)\n            return ERROR_ALREADY_EXISTS;\n\n        bIsValidArray = true;\n        return ERROR_SUCCESS;\n    }\n\n    // HOTS: 19575A0 (char)\n    // HOTS: 1957600 (TPathStop)\n    void SetMaxItems(DWORD NewMaxItemCount)\n    {\n        T * OldArray = ItemArray;\n        T * NewArray;\n\n        // Allocate new data buffer\n        NewArray = CASC_ALLOC<T>(NewMaxItemCount);\n        if(NewArray != NULL)\n        {\n            // Copy the old items to the buffer\n            for(size_t i = 0; i < ItemCount; i++)\n            {\n                NewArray[i] = ItemArray[i];\n            }\n        }\n\n        ItemArray = NewArray;\n        MaxItemCount = NewMaxItemCount;\n        CASC_FREE(OldArray);\n    }\n\n    // HOTS: 19575A0 (char)\n    // HOTS: 1957600 (TPathStop)\n    void SetMaxItemsIf(DWORD NewMaxItemCount)\n    {\n        if(NewMaxItemCount > MaxItemCount)\n        {\n            if(MaxItemCount > (NewMaxItemCount / 2))\n            {\n                if(MaxItemCount <= (MNDX_MAX_ENTRIES(T) / 2))\n                    NewMaxItemCount = MaxItemCount + MaxItemCount;\n                else\n                    NewMaxItemCount = MNDX_MAX_ENTRIES(T);\n            }\n\n            SetMaxItems(NewMaxItemCount);\n        }\n    }\n\n    // HOTS: inline  <char>\n    // HOTS: 1958330 <TPathStop>\n    void Insert(T NewItem)\n    {\n        // Make sure we have enough capacity for the new item\n        SetMaxItemsIf(ItemCount + 1);\n\n        // Put the character to the slot that has been reserved\n        ItemArray[ItemCount++] = NewItem;\n    }\n\n    // HOTS: 19583A0 <TPathStop>\n    void GrowArray(DWORD NewItemCount)\n    {\n        DWORD OldMaxItemCount = MaxItemCount;\n\n        // Make sure we have enough capacity for new items\n        SetMaxItemsIf(NewItemCount);\n\n        // Initialize the newly inserted items\n        for(DWORD i = OldMaxItemCount; i < NewItemCount; i++)\n        {\n            ItemArray[i] = T();\n        }\n\n        ItemCount = NewItemCount;\n    }\n\n    // HOTS: 1957440 <DWORD>\n    // HOTS: 19574E0 <BASEVALS>\n    // HOTS: 1957690 <BYTE>\n    // HOTS: 1957700 <HASH_ENTRY>\n    // HOTS: 195A220 <char>\n    // HOTS: 1958580 <TBitStream, DWORD>\n    DWORD LoadFromStream(TByteStream & InStream)\n    {\n        DWORD NumberOfBytes;\n        DWORD dwErrCode;\n\n        // Get and verify the number of items\n        dwErrCode = InStream.GetArrayItemCount<T>(NumberOfBytes, ItemCount);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Get the pointer to the array\n        dwErrCode = InStream.GetArray<T>(&ItemArray, ItemCount);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        return SetArrayValid();\n    }\n\n    T * ItemArray;\n    DWORD ItemCount;                           // Number of items in the array\n    DWORD MaxItemCount;                        // Capacity of the array\n    bool bIsValidArray;\n};\n\nclass TBitEntryArray : public TGenericArray<DWORD>\n{\n    public:\n\n    TBitEntryArray() : TGenericArray()\n    {\n        BitsPerEntry = 0;\n        EntryBitMask = 0;\n        TotalEntries = 0;\n    }\n\n    ~TBitEntryArray()\n    {}\n\n    DWORD GetItem(DWORD EntryIndex)\n    {\n        DWORD dwItemIndex = (EntryIndex * BitsPerEntry) >> 0x05;\n        DWORD dwStartBit = (EntryIndex * BitsPerEntry) & 0x1F;\n        DWORD dwEndBit = dwStartBit + BitsPerEntry;\n        DWORD dwResult;\n\n        // If the end bit index is greater than 32,\n        // we also need to load from the next 32-bit item\n        if(dwEndBit > 0x20)\n        {\n            dwResult = (ItemArray[dwItemIndex + 1] << (0x20 - dwStartBit)) | (ItemArray[dwItemIndex] >> dwStartBit);\n        }\n        else\n        {\n            dwResult = ItemArray[dwItemIndex] >> dwStartBit;\n        }\n\n        // Now we also need to mask the result by the bit mask\n        return dwResult & EntryBitMask;\n    }\n\n    DWORD LoadBitsFromStream(TByteStream & InStream)\n    {\n        ULONGLONG Value64 = 0;\n        DWORD dwErrCode;\n\n        dwErrCode = LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = InStream.GetValue<DWORD>(BitsPerEntry);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n        if(BitsPerEntry > 0x20)\n            return ERROR_BAD_FORMAT;\n\n        dwErrCode = InStream.GetValue<DWORD>(EntryBitMask);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = InStream.GetValue<ULONGLONG>(Value64);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n        if(Value64 > 0xFFFFFFFF)\n            return ERROR_BAD_FORMAT;\n        TotalEntries = (DWORD)Value64;\n\n        assert((BitsPerEntry * TotalEntries) / 32 <= ItemCount);\n        return ERROR_SUCCESS;\n    }\n\n    DWORD BitsPerEntry;\n    DWORD EntryBitMask;\n    DWORD TotalEntries;\n};\n\n//-----------------------------------------------------------------------------\n// TSparseArray functions\n\n#define INDEX_TO_GROUP(val)   (val >> 9)\n#define GROUP_TO_INDEX(grp)   (grp << 9)\n\n// For each 0x200-th bit, this contains information about amount of \"1\" bits \ntypedef struct _BASEVALS\n{\n    DWORD BaseValue200;             // Item value of every 0x200-th item\n\n    DWORD AddValue40 : 7;           // For each 0x40 items (above the base200),\n    DWORD AddValue80 : 8;           // we have extra shortcut to the item value\n    DWORD AddValueC0 : 8;           // that is to be added to BaseValue200\n    DWORD AddValue100 : 9;\n    DWORD AddValue140 : 9;\n    DWORD AddValue180 : 9;\n    DWORD AddValue1C0 : 9;\n\n    DWORD __xalignment : 5;         // Filling\n} BASEVALS, *PBASEVALS;\n\nclass TSparseArray\n{\n    public:\n\n    TSparseArray()\n    {\n        TotalItemCount = 0;\n        ValidItemCount = 0;\n    }\n\n    // HOTS: 1958630\n    DWORD LoadFromStream(TByteStream & InStream)\n    {\n        DWORD total_count = 0;\n        DWORD valid_count = 0;\n        DWORD dwErrCode;\n\n        dwErrCode = ItemBits.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = InStream.GetValue<DWORD>(total_count);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n        dwErrCode = InStream.GetValue<DWORD>(valid_count);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n        if(valid_count > total_count)\n            return ERROR_FILE_CORRUPT;\n\n        TotalItemCount = total_count;\n        ValidItemCount = valid_count;\n\n        dwErrCode = BaseVals.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = IndexToItem0.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = IndexToItem1.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        return ERROR_SUCCESS;\n    }\n\n    // Returns true if the array is empty\n    bool IsEmpty()\n    {\n        return (TotalItemCount == 0);\n    }\n\n    // Returns true if the item at n-th position is present\n    bool IsItemPresent(size_t index)\n    {\n        // (index >> 0x05) gives the DWORD, (1 << (ItemIndex & 0x1F)) gives the bit\n        return (ItemBits[index >> 0x05] & (1 << (index & 0x1F))) ? true : false;\n    }\n\n    // Retrieves the value of the n-th item in the sparse array.\n    // Note that for items that are not present, the value is equal\n    // to the nearest lower present value\n    DWORD GetItemValueAt(size_t index)\n    {\n        BASEVALS & SetBitsCount = BaseVals[index >> 0x09];\n        DWORD IntValue;\n        DWORD BitMask;\n\n        //\n        // Since we don't want to count bits for the entire array,\n        // there are item value shortcuts every 0x200 items,\n        // and then every 0x40 items above the 0x200 base\n        //\n\n        // 1) We have base value for every 0x200-th item\n        IntValue = SetBitsCount.BaseValue200;\n\n        // 2) Add the base value for each 0x40-th item above the 0x200 base\n        switch(((index >> 0x06) & 0x07) - 1)\n        {\n            case 0:     // Add the 1st value (7 bits)\n                IntValue += SetBitsCount.AddValue40;\n                break;\n\n            case 1:     // Add the 2nd value (8 bits)\n                IntValue += SetBitsCount.AddValue80;\n                break;\n\n            case 2:     // Add the 3rd value (8 bits)\n                IntValue += SetBitsCount.AddValueC0;\n                break;\n\n            case 3:     // Add the 4th value (9 bits)\n                IntValue += SetBitsCount.AddValue100;\n                break;\n\n            case 4:     // Add the 5th value (9 bits)\n                IntValue += SetBitsCount.AddValue140;\n                break;\n\n            case 5:     // Add the 6th value (9 bits)\n                IntValue += SetBitsCount.AddValue180;\n                break;\n\n            case 6:     // Add the 7th value (9 bits)\n                IntValue += SetBitsCount.AddValue1C0;\n                break;\n        }\n\n        // 3) Count the bits of the higher DWORD, if the index 0x20 - 0x30 above the 0x200 base\n        if(index & 0x20)\n            IntValue += GetNumberOfSetBits32(ItemBits[(index >> 0x05) - 1]);\n\n        // 4) Count the bits in the current DWORD (masked by bit index mask) \n        BitMask = (1 << (index & 0x1F)) - 1;\n        return IntValue + GetNumberOfSetBits32(ItemBits[index >> 0x05] & BitMask);\n    }\n\n    DWORD FindGroup_Items0(DWORD index)\n    {\n        // Setup the group range to search\n        DWORD minGroup = (IndexToItem0[INDEX_TO_GROUP(index) + 0]) >> 9;\n        DWORD maxGroup = (IndexToItem0[INDEX_TO_GROUP(index) + 1] + 0x1FF) >> 9;\n\n        // Search the groups and find the BASEVALS structure\n        // For spans less than 10 groups, use sequential search, otherwise binary search.\n        if ((maxGroup - minGroup) < 10)\n        {\n            // HOTS: 1959CF7\n            while (index >= GROUP_TO_INDEX(minGroup) - BaseVals[minGroup + 1].BaseValue200 + 0x200)\n            {\n                // HOTS: 1959D14\n                minGroup++;\n            }\n        }\n        else\n        {\n            // HOTS: 1959D2E\n            while ((minGroup + 1) < maxGroup)\n            {\n                // HOTS: 1959D38\n                DWORD middleValue = (maxGroup + minGroup) >> 1;\n\n                if (index < (maxGroup << 0x09) - BaseVals[maxGroup].BaseValue200)\n                {\n                    // HOTS: 01959D4B\n                    maxGroup = middleValue;\n                }\n                else\n                {\n                    // HOTS: 1959D50\n                    minGroup = middleValue;\n                }\n            }\n        }\n\n        return minGroup;\n    }\n\n    DWORD FindGroup_Items1(DWORD index)\n    {\n        DWORD groupIndex = (index >> 0x09);\n        DWORD startValue = IndexToItem1[groupIndex] >> 9;\n        DWORD nextValue = (IndexToItem1[groupIndex + 1] + 0x1FF) >> 9;\n\n        // Find the BASEVALS structure which the start index belongs to\n        // For less than 10 values, use sequential search. Otherwise, use binary search\n        if ((nextValue - startValue) < 10)\n        {\n            // HOTS: 01959F94\n            while (index >= BaseVals[startValue + 1].BaseValue200)\n            {\n                // HOTS: 1959FA3\n                startValue++;\n            }\n        }\n        else\n        {\n            // Binary search (HOTS: 1959FAD)\n            if ((startValue + 1) < nextValue)\n            {\n                // HOTS: 1959FB4\n                DWORD middleValue = (nextValue + startValue) >> 1;\n\n                if (index < BaseVals[middleValue].BaseValue200)\n                {\n                    // HOTS: 1959FC4\n                    nextValue = middleValue;\n                }\n                else\n                {\n                    // HOTS: 1959FC8\n                    startValue = middleValue;\n                }\n            }\n        }\n\n        return startValue;\n    }\n\n    // Returns the value of Item0[index] (HOTS: 1959CB0)\n    DWORD GetItem0(DWORD index)\n    {\n        SETBITS zeroBits;\n        DWORD groupIndex;\n        DWORD dwordIndex;\n        DWORD itemIndex;\n        DWORD bitGroup;\n        DWORD edx = index;\n\n#ifdef _DEBUG\n        //if (TotalItemCount > 0x200)\n        //{\n        //    FILE * fp = fopen(\"e:\\\\Ladik\\\\Appdir\\\\CascLib\\\\doc\\\\mndx-sparse-array.txt\", \"wt\");\n        //    Dump(fp);\n        //    fclose(fp);\n        //}\n#endif\n\n        // If the index is at begin of the group, we just return the start value\n        if ((index & 0x1FF) == 0)\n            return IndexToItem0[INDEX_TO_GROUP(index)];\n\n        // Find the group where the index belongs to\n        groupIndex = FindGroup_Items0(index);\n\n        // HOTS: 1959D5F\n        edx += BaseVals[groupIndex].BaseValue200 - (groupIndex << 0x09);\n        dwordIndex = (groupIndex << 4);\n\n        if (edx < 0x100 - BaseVals[groupIndex].AddValue100)\n        {\n            // HOTS: 1959D8C\n            if (edx < 0x80 - BaseVals[groupIndex].AddValue80)\n            {\n                // HOTS: 01959DA2\n                if (edx >= 0x40 - BaseVals[groupIndex].AddValue40)\n                {\n                    // HOTS: 01959DB7\n                    dwordIndex += 2;\n                    edx = edx + BaseVals[groupIndex].AddValue40 - 0x40;\n                }\n            }\n            else\n            {\n                // HOTS: 1959DC0\n                if (edx < 0xC0 - BaseVals[groupIndex].AddValueC0)\n                {\n                    // HOTS: 1959DD3\n                    dwordIndex += 4;\n                    edx = edx + BaseVals[groupIndex].AddValue80 - 0x80;\n                }\n                else\n                {\n                    // HOTS: 1959DD3\n                    dwordIndex += 6;\n                    edx = edx + BaseVals[groupIndex].AddValueC0 - 0xC0;\n                }\n            }\n        }\n        else\n        {\n            // HOTS: 1959DE8\n            if (edx < 0x180 - BaseVals[groupIndex].AddValue180)\n            {\n                // HOTS: 01959E00\n                if (edx < 0x140 - BaseVals[groupIndex].AddValue140)\n                {\n                    // HOTS: 1959E11\n                    dwordIndex += 8;\n                    edx = edx + BaseVals[groupIndex].AddValue100 - 0x100;\n                }\n                else\n                {\n                    // HOTS: 1959E1D\n                    dwordIndex += 10;\n                    edx = edx + BaseVals[groupIndex].AddValue140 - 0x140;\n                }\n            }\n            else\n            {\n                // HOTS: 1959E29\n                if (edx < 0x1C0 - BaseVals[groupIndex].AddValue1C0)\n                {\n                    // HOTS: 1959E3D\n                    dwordIndex += 12;\n                    edx = edx + BaseVals[groupIndex].AddValue180 - 0x180;\n                }\n                else\n                {\n                    // HOTS: 1959E49\n                    dwordIndex += 14;\n                    edx = edx + BaseVals[groupIndex].AddValue1C0 - 0x1C0;\n                }\n            }\n        }\n\n        // HOTS: 1959E53:\n        // Calculate the number of bits set in the value of \"bitGroup\"\n        bitGroup = ~ItemBits[dwordIndex];\n        zeroBits = GetNumberOfSetBits(bitGroup);\n\n        if (edx >= zeroBits.u.Lower32)\n        {\n            // HOTS: 1959ea4\n            bitGroup = ~ItemBits[++dwordIndex];\n            edx = edx - zeroBits.u.Lower32;\n            zeroBits = GetNumberOfSetBits(bitGroup);\n        }\n\n        // Re-calculate the item index\n        itemIndex = (dwordIndex << 0x05);\n\n        // HOTS: 1959eea\n        if (edx < zeroBits.u.Lower16)\n        {\n            // HOTS: 1959EFC\n            if (edx >= zeroBits.u.Lower08)\n            {\n                // HOTS: 1959F05\n                bitGroup >>= 0x08;\n                itemIndex += 0x08;\n                edx -= zeroBits.u.Lower08;\n            }\n        }\n        else\n        {\n            // HOTS: 1959F0D\n            if (edx < zeroBits.u.Lower24)\n            {\n                // HOTS: 1959F19\n                bitGroup >>= 0x10;\n                itemIndex += 0x10;\n                edx -= zeroBits.u.Lower16;\n            }\n            else\n            {\n                // HOTS: 1959F23\n                bitGroup >>= 0x18;\n                itemIndex += 0x18;\n                edx -= zeroBits.u.Lower24;\n            }\n        }\n\n        // HOTS: 1959f2b\n        edx = edx << 0x08;\n        bitGroup = bitGroup & 0xFF;\n\n        // BUGBUG: Possible buffer overflow here. Happens when dwItemIndex >= 0x9C.\n        // The same happens in Heroes of the Storm (build 29049), so I am not sure\n        // if this is a bug or a case that never happens\n        assert((bitGroup + edx) < sizeof(table_1BA1818));\n        return table_1BA1818[bitGroup + edx] + itemIndex;\n    }\n\n    DWORD GetItem1(DWORD index)\n    {\n        SETBITS setBits;\n        DWORD distFromBase;\n        DWORD groupIndex;\n        DWORD dwordIndex;\n        DWORD itemIndex;\n        DWORD bitGroup;\n\n        // If the index is at begin of the group, we just return the start value\n        if ((index & 0x1FF) == 0)\n            return IndexToItem1[INDEX_TO_GROUP(index)];\n\n        // Find the group where the index belongs to\n        groupIndex = FindGroup_Items1(index);\n\n        // Calculate the base200 dword index (HOTS: 1959FD4)\n        distFromBase = index - BaseVals[groupIndex].BaseValue200;\n        dwordIndex = groupIndex << 0x04;\n\n        // Calculate the dword index including the sub-checkpoint\n        if (distFromBase < BaseVals[groupIndex].AddValue100)\n        {\n            // HOTS: 1959FF1\n            if (distFromBase < BaseVals[groupIndex].AddValue80)\n            {\n                // HOTS: 0195A000\n                if (distFromBase >= BaseVals[groupIndex].AddValue40)\n                {\n                    // HOTS: 195A007\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValue40;\n                    dwordIndex += 2;\n                }\n            }\n            else\n            {\n                // HOTS: 195A00E\n                if (distFromBase < BaseVals[groupIndex].AddValueC0)\n                {\n                    // HOTS: 195A01A\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValue80;\n                    dwordIndex += 4;\n                }\n                else\n                {\n                    // HOTS: 195A01F\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValueC0;\n                    dwordIndex += 6;\n                }\n            }\n        }\n        else\n        {\n            // HOTS: 195A026\n            if (distFromBase < BaseVals[groupIndex].AddValue180)\n            {\n                // HOTS: 195A037\n                if (distFromBase < BaseVals[groupIndex].AddValue140)\n                {\n                    // HOTS: 195A041\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValue100;\n                    dwordIndex += 8;\n                }\n                else\n                {\n                    // HOTS: 195A048\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValue140;\n                    dwordIndex += 10;\n                }\n            }\n            else\n            {\n                // HOTS: 195A04D\n                if (distFromBase < BaseVals[groupIndex].AddValue1C0)\n                {\n                    // HOTS: 195A05A\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValue180;\n                    dwordIndex += 12;\n                }\n                else\n                {\n                    // HOTS: 195A061\n                    distFromBase = distFromBase - BaseVals[groupIndex].AddValue1C0;\n                    dwordIndex += 14;\n                }\n            }\n        }\n\n        // HOTS: 195A066\n        bitGroup = ItemBits[dwordIndex];\n        setBits = GetNumberOfSetBits(bitGroup);\n\n        // Get total number of set bits in the bit group\n        if (distFromBase >= setBits.u.Lower32)\n        {\n            // HOTS: 195A0B2\n            bitGroup = ItemBits[++dwordIndex];\n            distFromBase = distFromBase - setBits.u.Lower32;\n            setBits = GetNumberOfSetBits(bitGroup);\n        }\n\n        // Calculate the item index\n        itemIndex = (dwordIndex << 0x05);\n\n        // Get the number of set bits in the lower word (HOTS: 195A0F6)\n        if (distFromBase < setBits.u.Lower16)\n        {\n            // HOTS: 195A111\n            if (distFromBase >= setBits.u.Lower08)\n            {\n                // HOTS: 195A111\n                itemIndex = itemIndex + 0x08;\n                bitGroup = bitGroup >> 0x08;\n                distFromBase = distFromBase - setBits.u.Lower08;\n            }\n        }\n        else\n        {\n            // HOTS: 195A119\n            if (distFromBase < setBits.u.Lower24)\n            {\n                // HOTS: 195A125\n                bitGroup = bitGroup >> 0x10;\n                itemIndex = itemIndex + 0x10;\n                distFromBase = distFromBase - setBits.u.Lower16;\n            }\n            else\n            {\n                // HOTS: 195A12F\n                bitGroup = bitGroup >> 0x18;\n                itemIndex = itemIndex + 0x18;\n                distFromBase = distFromBase - setBits.u.Lower24;\n            }\n        }\n\n        bitGroup = bitGroup & 0xFF;\n        distFromBase = distFromBase << 0x08;\n\n        // BUGBUG: Potential buffer overflow\n        // Happens in Heroes of the Storm when index == 0x5B\n        assert((bitGroup + distFromBase) < sizeof(table_1BA1818));\n        return table_1BA1818[bitGroup + distFromBase] + itemIndex;\n    }\n\n#ifdef _DEBUG\n    void Dump(FILE * fp)\n    {\n        size_t * ArrayNormal;\n        size_t * ArrayInvert;\n        size_t IndexNormal = 0;\n        size_t IndexInvert = 0;\n\n        // Output numbers of set bits for every 0x200-th item\n        fprintf(fp, \"Number of set bits for every 0x200-th index\\n\"\n                    \"========================================================\\n\"\n                    \"   Index    Base200h  +40  +80  +C0  +100 +140 +180 +1C0\\n\"\n                    \"--------------------------------------------------------\\n\");\n        for (size_t i = 0; i < BaseVals.ItemCount; i++)\n        {\n            fprintf(fp, \"[%08zX]: %08x  %04x %04x %04x %04x %04x %04x %04x\\n\", GROUP_TO_INDEX(i), BaseVals[i].BaseValue200,\n                BaseVals[i].AddValue40,\n                BaseVals[i].AddValue80,\n                BaseVals[i].AddValueC0,\n                BaseVals[i].AddValue100,\n                BaseVals[i].AddValue140,\n                BaseVals[i].AddValue180,\n                BaseVals[i].AddValue1C0);\n        }\n        fprintf(fp, \"\\n\");\n\n        // Output values of Item1 and Item0 for every 0x200-th index\n        fprintf(fp, \"Item0 and Item1 for every 0x200-th index\\n\"\n                    \"========================================\\n\"\n                    \"   Index     Item0    Item1\\n\"\n                    \"-----------------------------\\n\");\n        for (size_t i = 0; i < IndexToItem0.ItemCount; i++)\n        {\n            fprintf(fp, \"[%08zX]: %08x %08x\\n\", GROUP_TO_INDEX(i), IndexToItem0[i], IndexToItem1[i]);\n        }\n        fprintf(fp, \"\\n\");\n\n\n        // Output values of Item1 and Item0 for every index\n        ArrayNormal = new size_t[TotalItemCount];\n        ArrayInvert = new size_t[TotalItemCount];\n        if (ArrayNormal && ArrayInvert)\n        {\n            // Invalidate both arrays\n            memset(ArrayNormal, 0xFF, TotalItemCount * sizeof(size_t));\n            memset(ArrayInvert, 0xFF, TotalItemCount * sizeof(size_t));\n\n            // Load the both arrays\n            for (size_t i = 0; i < TotalItemCount; i++)\n            {\n                if (IsItemPresent(i))\n                    ArrayNormal[IndexNormal++] = i;\n                else\n                    ArrayInvert[IndexInvert++] = i;\n            }\n\n            // Output both arrays\n            fprintf(fp, \"Item0 and Item1 for every index\\n\"\n                        \"========================================\\n\"\n                        \"   Index     Item0    Item1\\n\"\n                        \"-----------------------------\\n\");\n            for (size_t i = 0; i < TotalItemCount; i++)\n            {\n                char NormalValue[0x20];\n                char InvertValue[0x20];\n\n                if (ArrayNormal[i] == MNDX_INVALID_SIZE_T && ArrayInvert[i] == MNDX_INVALID_SIZE_T)\n                    break;\n                fprintf(fp, \"[%08zX]: %8s  %8s\\n\", i, DumpValue(InvertValue, _countof(InvertValue), ArrayInvert[i]), DumpValue(NormalValue, _countof(NormalValue), ArrayNormal[i]));\n            }\n            fprintf(fp, \"\\n\");\n        }\n\n        // Free both arrays\n        delete[] ArrayNormal;\n        delete[] ArrayInvert;\n\n        // Output array of all values\n        fprintf(fp, \"Item List: Index -> Value\\n==========================\\n\");\n        for (size_t i = 0; i < TotalItemCount; i++)\n        {\n            if (IsItemPresent(i))\n            {\n                fprintf(fp, \"[%08zX]: %08x\\n\", i, GetItemValueAt(i));\n            }\n            else\n            {\n                fprintf(fp, \"[%08zX]: NOT PRESENT\\n\", i);\n            }\n        }\n        fprintf(fp, \"\\n\");\n    }\n\n    char * DumpValue(char * szBuffer, size_t cchBuffer, size_t value)\n    {\n        CascStrPrintf(szBuffer, cchBuffer, (value != MNDX_INVALID_SIZE_T) ? \"%08zX\" : \"   -    \", value);\n        return szBuffer;\n    }\n#endif\n\n    TGenericArray<DWORD> ItemBits;              // A bit array for each item. 1 if the item is present.\n    size_t TotalItemCount;                      // Total number of items in the array\n    size_t ValidItemCount;                      // Number of present items in the array\n    TGenericArray<BASEVALS> BaseVals;           // For each 0x200-th item, this contains the number of set bits up to that 0x200-th item\n    TGenericArray<DWORD> IndexToItem0;          // Mapping of index to invert item. An \"invert\" item is an item whose bit in \"ItemBits\" is zero.\n    TGenericArray<DWORD> IndexToItem1;          // Mapping of index to normal item. An \"normal\" item is an item whose bit in \"ItemBits\" is set.\n};\n\n//-----------------------------------------------------------------------------\n// TStruct40 functions\n\nclass TStruct40\n{\n    public:\n\n    TStruct40()\n    {\n        NodeIndex   = 0;\n        ItemCount   = 0;\n        PathLength  = 0;\n        SearchPhase = MNDX_SEARCH_INITIALIZING;\n    }\n\n    // HOTS: 19586B0\n    void BeginSearch()\n    {\n        // HOTS: 19586BD\n        PathBuffer.ItemCount = 0;\n        PathBuffer.SetMaxItemsIf(0x40);\n\n        // HOTS: 19586E1\n        // Set the new item count\n        PathStops.GrowArray(0);\n        PathStops.SetMaxItemsIf(4);\n\n        PathLength = 0;\n        NodeIndex = 0;\n        ItemCount = 0;\n        SearchPhase = MNDX_SEARCH_SEARCHING;\n    }\n\n    DWORD CalcHashValue(const char * szPath)\n    {\n        return (BYTE)(szPath[PathLength]) ^ (NodeIndex << 0x05) ^ NodeIndex;\n    }\n\n    TGenericArray<TPathStop> PathStops;         // Array of path checkpoints\n    TGenericArray<char> PathBuffer;             // Buffer for building a file name\n    DWORD NodeIndex;                            // ID of a path node being searched; starting with 0\n    DWORD PathLength;                           // Length of the path in the PathBuffer\n    DWORD ItemCount;\n    DWORD SearchPhase;                          // 0 = initializing, 2 = searching, 4 = finished\n};\n\n//-----------------------------------------------------------------------------\n// Local functions - TMndxSearch\n\nclass TMndxSearch\n{\n    public:\n\n    // HOTS: 01956EE0\n    TMndxSearch()\n    {\n        szSearchMask = NULL;\n        cchSearchMask = 0;\n        szFoundPath = NULL;\n        cchFoundPath = 0;\n        nIndex = 0;\n    }\n\n    // HOTS: 01956F00\n    ~TMndxSearch()\n    {}\n\n    // HOTS: 01956E70\n    int SetSearchMask(\n        const char * szNewSearchMask,\n        size_t cchNewSearchMask)\n    {\n        if(szSearchMask == NULL && cchSearchMask != 0)\n            return ERROR_INVALID_PARAMETER;\n\n        Struct40.SearchPhase = MNDX_SEARCH_INITIALIZING;\n\n        szSearchMask = szNewSearchMask;\n        cchSearchMask = cchNewSearchMask;\n        return ERROR_SUCCESS;\n    }\n\n    TStruct40 Struct40;\n    const char * szSearchMask;          // Search mask without wildcards\n    size_t cchSearchMask;               // Length of the search mask\n    const char * szFoundPath;           // Found path name\n    size_t cchFoundPath;                // Length of the found path name\n    DWORD nIndex;                       // Index of the file name\n};\n\n//-----------------------------------------------------------------------------\n// TPathFragmentTable class. This class implements table of the path fragments.\n// These path fragments can either by terminated by zeros (ASCIIZ)\n// or can be marked by the external \"PathMarks\" structure\n\nclass TPathFragmentTable\n{\n    public:\n\n    // HOTS: 0195A290\n    TPathFragmentTable()\n    {}\n\n    // HOTS: inlined\n    ~TPathFragmentTable()\n    {}\n\n    // HOTS: 195A180\n    bool ComparePathFragment(TMndxSearch * pSearch, size_t nFragmentOffset)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n\n        // Do we have path fragment separators in an external structure?\n        if(PathMarks.IsEmpty())\n        {\n            // Keep searching as long as the name matches with the fragment\n            while(PathFragments[nFragmentOffset] == pSearch->szSearchMask[pStruct40->PathLength])\n            {\n                // Move to the next character\n                pStruct40->PathLength++;\n                nFragmentOffset++;\n\n                // Is it the end of the fragment or end of the path?\n                if(PathFragments[nFragmentOffset] == 0)\n                    return true;\n                if(pStruct40->PathLength >= pSearch->cchSearchMask)\n                    return false;\n            }\n\n            return false;\n        }\n        else\n        {\n            // Keep searching as long as the name matches with the fragment\n            while(PathFragments[nFragmentOffset] == pSearch->szSearchMask[pStruct40->PathLength])\n            {\n                // Move to the next character\n                pStruct40->PathLength++;\n\n                // Is it the end of the path fragment?\n                if(PathMarks.IsItemPresent(nFragmentOffset++))\n                    return true;\n                if(nFragmentOffset >= pSearch->cchSearchMask)\n                    return false;\n            }\n\n            return false;\n        }\n    }\n\n    // HOTS: 195A3F0\n    void CopyPathFragment(TMndxSearch * pSearch, size_t nFragmentOffset)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n\n        // Do we have path fragment separators in an external structure?\n        if (PathMarks.IsEmpty())\n        {\n            // HOTS: 195A40C\n            while (PathFragments[nFragmentOffset] != 0)\n            {\n                // Insert the character to the path being built\n                pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]);\n            }\n        }\n        else\n        {\n            // HOTS: 195A4B3\n            while(!PathMarks.IsItemPresent(nFragmentOffset))\n            {\n                // Insert the character to the path being built\n                pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]);\n            }\n        }\n    }\n\n    // HOTS: 195A570\n    bool CompareAndCopyPathFragment(TMndxSearch * pSearch, size_t nFragmentOffset)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n\n        // Do we have path fragment separators in an external structure?\n        if(PathMarks.IsEmpty())\n        {\n            // Keep copying as long as we don't reach the end of the search mask\n            while(pStruct40->PathLength < pSearch->cchSearchMask)\n            {\n                // HOTS: 195A5A0\n                if(PathFragments[nFragmentOffset] != pSearch->szSearchMask[pStruct40->PathLength])\n                    return false;\n\n                // HOTS: 195A5B7\n                pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]);\n                pStruct40->PathLength++;\n\n                // If we found the end of the fragment, return success\n                if(PathFragments[nFragmentOffset] == 0)\n                    return true;\n            }\n\n            // HOTS: 195A660\n            // Now we need to copy the rest of the fragment\n            while(PathFragments[nFragmentOffset] != 0)\n            {\n                pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset]);\n                nFragmentOffset++;\n            }\n        }\n        else\n        {\n            // Keep copying as long as we don't reach the end of the search mask\n            while(nFragmentOffset < pSearch->cchSearchMask)\n            {\n                if(PathFragments[nFragmentOffset] != pSearch->szSearchMask[pStruct40->PathLength])\n                    return false;\n\n                pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset]);\n                pStruct40->PathLength++;\n\n                // If we found the end of the fragment, return success\n                if(PathMarks.IsItemPresent(nFragmentOffset++))\n                    return true;\n            }\n\n            // Now we need to copy the rest of the fragment\n            while(!PathMarks.IsItemPresent(nFragmentOffset))\n            {\n                // HOTS: 195A7A6\n                pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]);\n            }\n        }\n\n        return true;\n    }\n\n    // HOTS: 0195A820\n    DWORD LoadFromStream(TByteStream & InStream)\n    {\n        DWORD dwErrCode;\n\n        dwErrCode = PathFragments.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        return PathMarks.LoadFromStream(InStream);\n    }\n\n    TGenericArray<char> PathFragments;\n    TSparseArray PathMarks;\n};\n\n//-----------------------------------------------------------------------------\n// TStruct10 functions\n\nclass TStruct10\n{\n    public:\n\n    TStruct10()\n    {\n        field_0 = 0x03;\n        field_4 = 0x200;\n        field_8 = 0x1000;\n        field_C = 0x20000;\n    }\n\n    // HOTS: 1956FD0\n    int sub_1956FD0(DWORD dwBitMask)\n    {\n        switch(dwBitMask & 0xF80)\n        {\n            case 0x00:\n                field_4 = 0x200;\n                return ERROR_SUCCESS;\n\n            case 0x80:\n                field_4 = 0x80;\n                return ERROR_SUCCESS;\n\n            case 0x100:\n                field_4 = 0x100;\n                return ERROR_SUCCESS;\n\n            case 0x200:\n                field_4 = 0x200;\n                return ERROR_SUCCESS;\n\n            case 0x400:\n                field_4 = 0x400;\n                return ERROR_SUCCESS;\n\n            case 0x800:\n                field_4 = 0x800;\n                return ERROR_SUCCESS;\n        }\n\n        return ERROR_INVALID_PARAMETER;\n    }\n\n    // HOTS: 1957050\n    int sub_1957050(DWORD dwBitMask)\n    {\n        switch(dwBitMask & 0xF0000)\n        {\n            case 0x00:\n                field_C = 0x20000;\n                return ERROR_SUCCESS;\n\n            case 0x10000:\n                field_C = 0x10000;\n                return ERROR_SUCCESS;\n\n            case 0x20000:\n                field_C = 0x20000;\n                return ERROR_SUCCESS;\n        }\n\n        return ERROR_INVALID_PARAMETER;\n    }\n\n    // HOTS: 19572E0\n    DWORD sub_19572E0(DWORD dwBitMask)\n    {\n        DWORD dwSubMask;\n        DWORD dwErrCode;\n\n        if(dwBitMask & 0xFFF00000)\n            return ERROR_INVALID_PARAMETER;\n\n        dwSubMask = dwBitMask & 0x7F;\n        if(dwSubMask)\n            field_0 = dwSubMask;\n\n        dwErrCode = sub_1956FD0(dwBitMask);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwSubMask = dwBitMask & 0xF000;\n        if(dwSubMask == 0 || dwSubMask == 0x1000)\n        {\n            field_8 = 0x1000;\n            return sub_1957050(dwBitMask);\n        }\n\n        if(dwSubMask == 0x2000)\n        {\n            field_8 = 0x2000;\n            return sub_1957050(dwBitMask);\n        }\n\n        return ERROR_INVALID_PARAMETER;\n    }\n\n    // HOTS: 1957800\n    int sub_1957800(DWORD dwBitMask)\n    {\n        return sub_19572E0(dwBitMask);\n    }\n\n    DWORD field_0;\n    DWORD field_4;\n    DWORD field_8;\n    DWORD field_C;\n};\n\n//-----------------------------------------------------------------------------\n// TFileNameDatabase interface/implementation\n\nclass TFileNameDatabase\n{\n    public:\n\n    // HOTS: 01958730\n    TFileNameDatabase()\n    {\n        HashTableMask = 0;\n        field_214 = 0;\n        pChildDB = NULL;\n    }\n\n    ~TFileNameDatabase()\n    {\n        delete pChildDB;\n    }\n\n    // Returns nonzero if the name fragment match is a single-char match\n    bool IsPathFragmentSingleChar(HASH_ENTRY * pHashEntry)\n    {\n        return ((pHashEntry->FragmentOffset & 0xFFFFFF00) == 0xFFFFFF00);\n    }\n\n    // Returns true if the given collision path fragment is a string (aka more than 1 char)\n    bool IsPathFragmentString(size_t index)\n    {\n        return CollisionHiBitsIndexes.IsItemPresent(index);\n    }\n\n    // HOTS: 1957350, inlined\n    DWORD GetPathFragmentOffset1(DWORD index_lobits)\n    {\n        DWORD index_hibits = CollisionHiBitsIndexes.GetItemValueAt(index_lobits);\n\n        return (HiBitsTable.GetItem(index_hibits) << 0x08) | LoBitsTable[index_lobits];\n    }\n\n    // Retrieves fragment_offset/subtable_index of the path fragment, with check for starting value\n    DWORD GetPathFragmentOffset2(DWORD & index_hibits, DWORD index_lobits)\n    {\n        // If the hi-bits index is invalid, we need to get its starting value\n        if (index_hibits == CASC_INVALID_INDEX)\n        {\n/*\n            printf(\"\\n\");\n            for (DWORD i = 0; i < CollisionHiBitsIndexes.TotalItemCount; i++)\n            {\n                if (CollisionHiBitsIndexes.IsItemPresent(i))\n                    printf(\"[%02X] = %02X\\n\", i, CollisionHiBitsIndexes.GetIntValueAt(i));\n                else\n                    printf(\"[%02X] = NOT_PRESENT\\n\", i);\n            }\n*/\n            index_hibits = CollisionHiBitsIndexes.GetItemValueAt(index_lobits);\n        }\n        else\n        {\n            index_hibits++;\n        }\n\n        // Now we use both NodeIndex and HiBits index for retrieving the path fragment index\n        return (HiBitsTable.GetItem(index_hibits) << 0x08) | LoBitsTable[index_lobits];\n    }\n\n    // HOTS: 1956DA0\n    DWORD Load(LPBYTE pbMarData, size_t cbMarData)\n    {\n        TByteStream ByteStream;\n        DWORD dwSignature;\n        DWORD dwErrCode;\n\n        if(pbMarData == NULL && cbMarData != 0)\n            return ERROR_INVALID_PARAMETER;\n\n        dwErrCode = ByteStream.SetByteBuffer(pbMarData, cbMarData);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Get pointer to MAR signature\n            dwErrCode = ByteStream.GetValue<DWORD>(dwSignature);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n\n            // Verify the signature\n            if(dwSignature != MNDX_MAR_SIGNATURE)\n                return ERROR_BAD_FORMAT;\n\n            // HOTS: 1956E11\n            dwErrCode = LoadFromStream(ByteStream);\n        }\n\n        return dwErrCode;\n    }\n\n    // HOTS: 19584B0\n    int SetChildDatabase(TFileNameDatabase * pNewDB)\n    {\n        if(pNewDB != NULL && pChildDB == pNewDB)\n            return ERROR_INVALID_PARAMETER;\n\n        if(pChildDB != NULL)\n            delete pChildDB;\n        pChildDB = pNewDB;\n        return ERROR_SUCCESS;\n    }\n\n    // HOTS: 1957970\n    bool ComparePathFragment(TMndxSearch * pSearch)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n        PHASH_ENTRY pHashEntry;\n        DWORD ColTableIndex;\n        DWORD HiBitsIndex;\n        DWORD NodeIndex;\n\n        // Calculate the item hash from the current char and fragment ID\n        NodeIndex = pStruct40->CalcHashValue(pSearch->szSearchMask) & HashTableMask;\n        pHashEntry = &HashTable[NodeIndex];\n\n        // Does the hash value ID match?\n        if(pHashEntry->NodeIndex == pStruct40->NodeIndex)\n        {\n            // Check if there is single character match\n            if (!IsPathFragmentSingleChar(pHashEntry))\n            {\n                // Check if there is a name fragment match\n                if (pChildDB != NULL)\n                {\n                    if (!pChildDB->ComparePathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex))\n                        return false;\n                }\n                else\n                {\n                    if (!PathFragmentTable.ComparePathFragment(pSearch, pHashEntry->FragmentOffset))\n                        return false;\n                }\n            }\n            else\n            {\n                pStruct40->PathLength++;\n            }\n\n            pStruct40->NodeIndex = pHashEntry->NextIndex;\n            return true;\n        }\n\n        //\n        // Conflict: Multiple node IDs give the same table index\n        //\n\n        // HOTS: 1957A0E\n        ColTableIndex = CollisionTable.GetItem0(pStruct40->NodeIndex) + 1;\n        pStruct40->NodeIndex = (ColTableIndex - pStruct40->NodeIndex - 1);\n        HiBitsIndex = CASC_INVALID_INDEX;\n\n        // HOTS: 1957A41:\n        while(CollisionTable.IsItemPresent(ColTableIndex))\n        {\n            // HOTS: 1957A41\n            // Check if the low 8 bits if the fragment offset contain a single character\n            // or an offset to a name fragment\n            if(IsPathFragmentString(pStruct40->NodeIndex))\n            {\n                DWORD FragmentOffset = GetPathFragmentOffset2(HiBitsIndex, pStruct40->NodeIndex);\n                DWORD SavePathLength = pStruct40->PathLength;       // HOTS: 1957A83\n\n                // Do we have a child database?\n                if(pChildDB != NULL)\n                {\n                    // HOTS: 1957AEC\n                    if(pChildDB->ComparePathFragmentByIndex(pSearch, FragmentOffset))\n                        return true;\n                }\n                else\n                {\n                    // HOTS: 1957AF7\n                    if(PathFragmentTable.ComparePathFragment(pSearch, FragmentOffset))\n                        return true;\n                }\n\n                // HOTS: 1957B0E\n                // If there was partial match with the fragment, end the search\n                if(pStruct40->PathLength != SavePathLength)\n                    return false;\n            }\n            else\n            {\n                // HOTS: 1957B1C\n                if(LoBitsTable[pStruct40->NodeIndex] == pSearch->szSearchMask[pStruct40->PathLength])\n                {\n                    pStruct40->PathLength++;\n                    return true;\n                }\n            }\n\n            // HOTS: 1957B32\n            pStruct40->NodeIndex++;\n            ColTableIndex++;\n        }\n\n        return false;\n    }\n\n    // HOTS: 1957B80\n    bool ComparePathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n        PHASH_ENTRY pHashEntry;\n        DWORD eax;\n\n        // HOTS: 1957B95\n        for (;;)\n        {\n            // Get the hasn table item\n            pHashEntry = &HashTable[TableIndex & HashTableMask];\n\n            // \n            if (TableIndex == pHashEntry->NextIndex)\n            {\n                // HOTS: 01957BB4\n                if (!IsPathFragmentSingleChar(pHashEntry))\n                {\n                    // HOTS: 1957BC7\n                    if (pChildDB != NULL)\n                    {\n                        // HOTS: 1957BD3\n                        if (!pChildDB->ComparePathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex))\n                            return false;\n                    }\n                    else\n                    {\n                        // HOTS: 1957BE0\n                        if (!PathFragmentTable.ComparePathFragment(pSearch, pHashEntry->FragmentOffset))\n                            return false;\n                    }\n                }\n                else\n                {\n                    // HOTS: 1957BEE\n                    if (pSearch->szSearchMask[pStruct40->PathLength] != pHashEntry->SingleChar)\n                        return false;\n                    pStruct40->PathLength++;\n                }\n\n                // HOTS: 1957C05\n                TableIndex = pHashEntry->NodeIndex;\n                if (TableIndex == 0)\n                    return true;\n\n                if (pStruct40->PathLength >= pSearch->cchSearchMask)\n                    return false;\n            }\n            else\n            {\n                // HOTS: 1957C30\n                if (IsPathFragmentString(TableIndex))\n                {\n                    DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex);\n\n                    // HOTS: 1957C4C\n                    if (pChildDB != NULL)\n                    {\n                        // HOTS: 1957C58\n                        if (!pChildDB->ComparePathFragmentByIndex(pSearch, FragmentOffset))\n                            return false;\n                    }\n                    else\n                    {\n                        // HOTS: 1957350\n                        if (!PathFragmentTable.ComparePathFragment(pSearch, FragmentOffset))\n                            return false;\n                    }\n                }\n                else\n                {\n                    // HOTS: 1957C8E\n                    if (LoBitsTable[TableIndex] != pSearch->szSearchMask[pStruct40->PathLength])\n                        return false;\n\n                    pStruct40->PathLength++;\n                }\n\n                // HOTS: 1957CB2\n                if (TableIndex <= field_214)\n                    return true;\n\n                if (pStruct40->PathLength >= pSearch->cchSearchMask)\n                    return false;\n\n                eax = CollisionTable.GetItem1(TableIndex);\n                TableIndex = (eax - TableIndex - 1);\n            }\n        }\n    }\n\n    // HOTS: 1958D70\n    void CopyPathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n        PHASH_ENTRY pHashEntry;\n\n        // HOTS: 1958D84\n        for (;;)\n        {\n            pHashEntry = &HashTable[TableIndex & HashTableMask];\n            if (TableIndex == pHashEntry->NextIndex)\n            {\n                // HOTS: 1958DA6\n                if (!IsPathFragmentSingleChar(pHashEntry))\n                {\n                    // HOTS: 1958DBA\n                    if (pChildDB != NULL)\n                    {\n                        pChildDB->CopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex);\n                    }\n                    else\n                    {\n                        PathFragmentTable.CopyPathFragment(pSearch, pHashEntry->FragmentOffset);\n                    }\n                }\n                else\n                {\n                    // HOTS: 1958DE7\n                    // Insert the low 8 bits to the path being built\n                    pStruct40->PathBuffer.Insert(pHashEntry->SingleChar);\n                }\n\n                // HOTS: 1958E71\n                TableIndex = pHashEntry->NodeIndex;\n                if (TableIndex == 0)\n                    return;\n            }\n            else\n            {\n                // HOTS: 1958E8E\n                if (IsPathFragmentString(TableIndex))\n                {\n                    DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex);\n\n                    // HOTS: 1958EAF\n                    if (pChildDB != NULL)\n                    {\n                        pChildDB->CopyPathFragmentByIndex(pSearch, FragmentOffset);\n                    }\n                    else\n                    {\n                        PathFragmentTable.CopyPathFragment(pSearch, FragmentOffset);\n                    }\n                }\n                else\n                {\n                    // HOTS: 1958F50\n                    // Insert one character to the path being built\n                    pStruct40->PathBuffer.Insert(LoBitsTable[TableIndex]);\n                }\n\n                // HOTS: 1958FDE\n                if (TableIndex <= field_214)\n                    return;\n\n                TableIndex = 0xFFFFFFFF - TableIndex + CollisionTable.GetItem1(TableIndex);\n            }\n        }\n    }\n\n    // HOTS: 1958B00\n    bool CompareAndCopyPathFragment(TMndxSearch * pSearch)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n        PHASH_ENTRY pHashEntry;\n        DWORD HiBitsIndex;\n        DWORD ColTableIndex;\n        DWORD TableIndex;\n/*\n        FILE * fp = fopen(\"E:\\\\PathFragmentTable.txt\", \"wt\");\n        if (fp != NULL)\n        {\n            for (DWORD i = 0; i < HashTable.ItemCount; i++)\n            {\n                FragOffs = HashTable[i].FragOffs;\n                fprintf(fp, \"%02x ('%c') %08X %08X %08X\", i, (0x20 <= i && i < 0x80) ? i : 0x20, HashTable[i].ItemIndex, HashTable[i].NextIndex, FragOffs);\n\n                if(FragOffs != 0x00800000)\n                {\n                    if((FragOffs & 0xFFFFFF00) == 0xFFFFFF00)\n                        fprintf(fp, \" '%c'\", (char)(FragOffs & 0xFF));\n                    else\n                        fprintf(fp, \" %s\", &PathFragmentTable.PathFragments[FragOffs]);\n                }\n                fprintf(fp, \"\\n\");\n            }\n\n            fclose(fp);\n        }\n*/\n        // Calculate the item hash from the current char and fragment ID\n        TableIndex = pStruct40->CalcHashValue(pSearch->szSearchMask) & HashTableMask;\n        pHashEntry = &HashTable[TableIndex];\n\n        // Does the hash value ID match?\n        if(pStruct40->NodeIndex == pHashEntry->NodeIndex)\n        {\n            // If the higher 24 bits are set, then the fragment is just one letter,\n            // contained directly in the table.\n            if(!IsPathFragmentSingleChar(pHashEntry))\n            {\n                // HOTS: 1958B59\n                if (pChildDB != NULL)\n                {\n                    if (!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex))\n                        return false;\n                }\n                else\n                {\n                    if (!PathFragmentTable.CompareAndCopyPathFragment(pSearch, pHashEntry->FragmentOffset))\n                        return false;\n                }\n            }\n            else\n            {\n                // HOTS: 1958B88\n                pStruct40->PathBuffer.Insert(pHashEntry->SingleChar);\n                pStruct40->PathLength++;\n            }\n\n            // HOTS: 1958BCA\n            pStruct40->NodeIndex = pHashEntry->NextIndex;\n            return true;\n        }\n\n        // HOTS: 1958BE5\n        ColTableIndex = CollisionTable.GetItem0(pStruct40->NodeIndex) + 1;\n        pStruct40->NodeIndex = (ColTableIndex - pStruct40->NodeIndex - 1);\n        HiBitsIndex = CASC_INVALID_INDEX;\n\n        // Keep searching while we have a valid collision table entry\n        while(CollisionTable.IsItemPresent(ColTableIndex))\n        {\n            // If we have high bits in the the bit at NodeIndex is set, it means that there is fragment offset\n            // If not, the byte in LoBitsTable is the character\n            if(IsPathFragmentString(pStruct40->NodeIndex))\n            {\n                DWORD FragmentOffset = GetPathFragmentOffset2(HiBitsIndex, pStruct40->NodeIndex);\n                DWORD SavePathLength = pStruct40->PathLength;   // HOTS: 1958C62\n\n                // Do we have a child database?\n                if(pChildDB != NULL)\n                {\n                    // HOTS: 1958CCB\n                    if(pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, FragmentOffset))\n                        return true;\n                }\n                else\n                {\n                    // HOTS: 1958CD6\n                    if(PathFragmentTable.CompareAndCopyPathFragment(pSearch, FragmentOffset))\n                        return true;\n                }\n\n                // HOTS: 1958CED\n                if(SavePathLength != pStruct40->PathLength)\n                    return false;\n            }\n            else\n            {\n                // HOTS: 1958CFB\n                if(LoBitsTable[pStruct40->NodeIndex] == pSearch->szSearchMask[pStruct40->PathLength])\n                {\n                    // HOTS: 1958D11\n                    pStruct40->PathBuffer.Insert(LoBitsTable[pStruct40->NodeIndex]);\n                    pStruct40->PathLength++;\n                    return true;\n                }\n            }\n\n            // HOTS: 1958D11\n            pStruct40->NodeIndex++;\n            ColTableIndex++;\n        }\n\n        return false;\n    }\n\n    // HOTS: 1959010\n    bool CompareAndCopyPathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n        PHASH_ENTRY pHashEntry;\n\n        // HOTS: 1959024\n        for(;;)\n        {\n            pHashEntry = &HashTable[TableIndex & HashTableMask];\n            if(TableIndex == pHashEntry->NextIndex)\n            {\n                // HOTS: 1959047\n                if(!IsPathFragmentSingleChar(pHashEntry))\n                {\n                    // HOTS: 195905A\n                    if(pChildDB != NULL)\n                    {\n                        if(!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex))\n                            return false;\n                    }\n                    else\n                    {\n                        if(!PathFragmentTable.CompareAndCopyPathFragment(pSearch, pHashEntry->FragmentOffset))\n                            return false;\n                    }\n                }\n                else\n                {\n                    // HOTS: 1959092\n                    if(pHashEntry->SingleChar != pSearch->szSearchMask[pStruct40->PathLength])\n                        return false;\n\n                    // Insert the low 8 bits to the path being built\n                    pStruct40->PathBuffer.Insert(pHashEntry->SingleChar);\n                    pStruct40->PathLength++;\n                }\n\n                // HOTS: 195912E\n                TableIndex = pHashEntry->NodeIndex;\n                if(TableIndex == 0)\n                    return true;\n            }\n            else\n            {\n                // HOTS: 1959147\n                if(IsPathFragmentString(TableIndex))\n                {\n                    // HOTS: 195917C\n                    DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex);\n\n                    if(pChildDB != NULL)\n                    {\n                        if(!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, FragmentOffset))\n                            return false;\n                    }\n                    else\n                    {\n                        if(!PathFragmentTable.CompareAndCopyPathFragment(pSearch, FragmentOffset))\n                            return false;\n                    }\n                }\n                else\n                {\n                    // HOTS: 195920E\n                    if(LoBitsTable[TableIndex] != pSearch->szSearchMask[pStruct40->PathLength])\n                        return false;\n\n                    // Insert one character to the path being built\n                    pStruct40->PathBuffer.Insert(LoBitsTable[TableIndex]);\n                    pStruct40->PathLength++;\n                }\n\n                // HOTS: 19592B6\n                if(TableIndex <= field_214)\n                    return true;\n\n                TableIndex = 0xFFFFFFFF - TableIndex + CollisionTable.GetItem1(TableIndex);\n            }\n\n            // HOTS: 19592D5\n            if(pStruct40->PathLength >= pSearch->cchSearchMask)\n                break;\n        }\n\n        CopyPathFragmentByIndex(pSearch, TableIndex);\n        return true;\n    }\n\n    // HOTS: 1959460\n    bool DoSearch(TMndxSearch * pSearch)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n        TPathStop * pPathStop;\n        DWORD edi;\n\n        // Perform action based on the search phase\n        switch (pStruct40->SearchPhase)\n        {\n            case MNDX_SEARCH_INITIALIZING:\n            {\n                // HOTS: 1959489\n                pStruct40->BeginSearch();\n\n                // If the caller passed a part of the search path, we need to find that one\n                while (pStruct40->PathLength < pSearch->cchSearchMask)\n                {\n                    if (!CompareAndCopyPathFragment(pSearch))\n                    {\n                        pStruct40->SearchPhase = MNDX_SEARCH_FINISHED;\n                        return false;\n                    }\n                }\n\n                // HOTS: 19594b0\n                TPathStop PathStop(pStruct40->NodeIndex, 0, pStruct40->PathBuffer.ItemCount);\n                pStruct40->PathStops.Insert(PathStop);\n                pStruct40->ItemCount = 1;\n\n                if (FileNameIndexes.IsItemPresent(pStruct40->NodeIndex))\n                {\n                    pSearch->szFoundPath = &pStruct40->PathBuffer[0];\n                    pSearch->cchFoundPath = pStruct40->PathBuffer.ItemCount;\n                    pSearch->nIndex = FileNameIndexes.GetItemValueAt(pStruct40->NodeIndex);\n                    return true;\n                }\n            }\n            // No break here, go straight to the MNDX_SEARCH_SEARCHING\n\n            case MNDX_SEARCH_SEARCHING:\n            {\n                // HOTS: 1959522\n                for (;;)\n                {\n                    // HOTS: 1959530\n                    if (pStruct40->ItemCount == pStruct40->PathStops.ItemCount)\n                    {\n                        TPathStop * pLastStop;\n                        DWORD ColTableIndex;\n\n                        pLastStop = &pStruct40->PathStops[pStruct40->PathStops.ItemCount - 1];\n\n                        ColTableIndex = CollisionTable.GetItem0(pLastStop->LoBitsIndex) + 1;\n\n                        // Insert a new structure\n                        TPathStop PathStop(ColTableIndex - pLastStop->LoBitsIndex - 1, ColTableIndex, 0);\n                        pStruct40->PathStops.Insert(PathStop);\n                    }\n\n                    // HOTS: 19595BD\n                    pPathStop = &pStruct40->PathStops[pStruct40->ItemCount];\n\n                    // HOTS: 19595CC\n                    if (CollisionTable.IsItemPresent(pPathStop->field_4++))\n                    {\n                        // HOTS: 19595F2\n                        pStruct40->ItemCount++;\n\n                        if (IsPathFragmentString(pPathStop->LoBitsIndex))\n                        {\n                            DWORD FragmentOffset = GetPathFragmentOffset2(pPathStop->HiBitsIndex_PathFragment, pPathStop->LoBitsIndex);\n\n                            // HOTS: 1959630\n                            if (pChildDB != NULL)\n                            {\n                                // HOTS: 1959649\n                                pChildDB->CopyPathFragmentByIndex(pSearch, FragmentOffset);\n                            }\n                            else\n                            {\n                                // HOTS: 1959654\n                                PathFragmentTable.CopyPathFragment(pSearch, FragmentOffset);\n                            }\n                        }\n                        else\n                        {\n                            // HOTS: 1959665\n                            // Insert one character to the path being built\n                            pStruct40->PathBuffer.Insert(LoBitsTable[pPathStop->LoBitsIndex]);\n                        }\n\n                        // HOTS: 19596AE\n                        pPathStop->Count = pStruct40->PathBuffer.ItemCount;\n\n                        // HOTS: 19596b6\n                        if (FileNameIndexes.IsItemPresent(pPathStop->LoBitsIndex))\n                        {\n                            // HOTS: 19596D1\n                            if (pPathStop->field_10 == 0xFFFFFFFF)\n                            {\n                                // HOTS: 19596D9\n                                pPathStop->field_10 = FileNameIndexes.GetItemValueAt(pPathStop->LoBitsIndex);\n                            }\n                            else\n                            {\n                                pPathStop->field_10++;\n                            }\n\n                            // HOTS: 1959755\n                            pSearch->szFoundPath = &pStruct40->PathBuffer[0];\n                            pSearch->cchFoundPath = pStruct40->PathBuffer.ItemCount;\n                            pSearch->nIndex = pPathStop->field_10;\n                            return true;\n                        }\n                    }\n                    else\n                    {\n                        // HOTS: 19596E9\n                        if (pStruct40->ItemCount == 1)\n                        {\n                            pStruct40->SearchPhase = MNDX_SEARCH_FINISHED;\n                            return false;\n                        }\n\n                        // HOTS: 19596F5\n                        pStruct40->PathStops[pStruct40->ItemCount - 1].LoBitsIndex++;\n                        edi = pStruct40->PathStops[pStruct40->ItemCount - 2].Count;\n                        pStruct40->PathBuffer.SetMaxItemsIf(edi);\n\n                        // HOTS: 1959749\n                        pStruct40->PathBuffer.ItemCount = edi;\n                        pStruct40->ItemCount--;\n                    }\n                }\n            }\n\n            case MNDX_SEARCH_FINISHED:\n                break;\n        }\n\n        return false;\n    }\n\n    // HOTS: 1957EF0\n    bool FindFileInDatabase(TMndxSearch * pSearch)\n    {\n        TStruct40 * pStruct40 = &pSearch->Struct40;\n\n        pStruct40->NodeIndex = 0;\n        pStruct40->PathLength = 0;\n        pStruct40->SearchPhase = MNDX_SEARCH_INITIALIZING;\n\n        if(pSearch->cchSearchMask > 0)\n        {\n            while(pStruct40->PathLength < pSearch->cchSearchMask)\n            {\n                // HOTS: 01957F12\n                if(!ComparePathFragment(pSearch))\n                    return false;\n            }\n        }\n\n        // HOTS: 1957F26\n        if(!FileNameIndexes.IsItemPresent(pStruct40->NodeIndex))\n            return false;\n\n        pSearch->szFoundPath   = pSearch->szSearchMask;\n        pSearch->cchFoundPath  = pSearch->cchSearchMask;\n        pSearch->nIndex = FileNameIndexes.GetItemValueAt(pStruct40->NodeIndex);\n        return true;\n    }\n\n    // HOTS: 1959790\n    DWORD LoadFromStream(TByteStream & InStream)\n    {\n        DWORD dwBitMask;\n        DWORD dwErrCode;\n\n        dwErrCode = CollisionTable.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = FileNameIndexes.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = CollisionHiBitsIndexes.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // HOTS: 019597CD\n        dwErrCode = LoBitsTable.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = HiBitsTable.LoadBitsFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // HOTS: 019597F5\n        dwErrCode = PathFragmentTable.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // HOTS: 0195980A\n        if(CollisionHiBitsIndexes.ValidItemCount != 0 && PathFragmentTable.PathFragments.ItemCount == 0)\n        {\n            TFileNameDatabase * pNewDB;\n\n            pNewDB = new TFileNameDatabase;\n            if (pNewDB == NULL)\n                return ERROR_NOT_ENOUGH_MEMORY;\n\n            dwErrCode = SetChildDatabase(pNewDB);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n\n            dwErrCode = pChildDB->LoadFromStream(InStream);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n        }\n\n        // HOTS: 0195986B\n        dwErrCode = HashTable.LoadFromStream(InStream);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        HashTableMask = HashTable.ItemCount - 1;\n\n        dwErrCode = InStream.GetValue<DWORD>(field_214);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        dwErrCode = InStream.GetValue<DWORD>(dwBitMask);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        return Struct10.sub_1957800(dwBitMask);\n    }\n\n    TSparseArray CollisionTable;                // Table of valid collisions, indexed by NodeIndex\n    TSparseArray FileNameIndexes;               // Array of file name indexes\n    TSparseArray CollisionHiBitsIndexes;        // Table of indexes of high bits (above 8 bits) for collisions \n\n    // This pair of arrays serves for fast conversion from node index to FragmentOffset / FragmentChar\n    TGenericArray<BYTE> LoBitsTable;            // Array of lower 8 bits of name fragment offset\n    TBitEntryArray      HiBitsTable;            // Array of upper x bits of name fragment offset\n\n    TPathFragmentTable PathFragmentTable;\n    TFileNameDatabase * pChildDB;\n\n    TGenericArray<HASH_ENTRY> HashTable;         // Hash table for searching name fragments\n\n    DWORD HashTableMask;                        // Mask to get hash table index from hash value\n    DWORD field_214;\n    TStruct10 Struct10;\n};\n\n//-----------------------------------------------------------------------------\n// Local functions - MAR file\n\nclass TMndxMarFile\n{\n    public:\n\n    TMndxMarFile()\n    {\n        pDatabase = NULL;\n        pbMarData = NULL;\n        cbMarData = 0;\n    }\n\n    ~TMndxMarFile()\n    {\n        if(pDatabase != NULL)\n            delete pDatabase;\n        CASC_FREE(pbMarData);\n    }\n\n    // HOTS: 00E94180\n    int LoadRootData(FILE_MAR_INFO & MarInfo, LPBYTE pbRootFile, LPBYTE pbRootEnd)\n    {\n        // Allocate the MAR data\n        pbMarData = CASC_ALLOC<BYTE>(MarInfo.MarDataSize);\n        cbMarData = MarInfo.MarDataSize;\n        if(pbMarData == NULL)\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        // Capture the MAR data\n        if(!CaptureData(pbRootFile + MarInfo.MarDataOffset, pbRootEnd, pbMarData, cbMarData))\n            return ERROR_FILE_CORRUPT;\n\n        // Create the file name database\n        pDatabase = new TFileNameDatabase();\n        if(pDatabase == NULL)\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        return pDatabase->Load(pbMarData, cbMarData);\n    }\n\n    // HOTS: 1956C60\n    DWORD SearchFile(TMndxSearch * pSearch)\n    {\n        DWORD dwErrCode = ERROR_SUCCESS;\n\n        if(pDatabase == NULL)\n            return ERROR_INVALID_PARAMETER;\n\n        if(!pDatabase->FindFileInDatabase(pSearch))\n            dwErrCode = ERROR_FILE_NOT_FOUND;\n\n        return dwErrCode;\n    }\n\n    // HOTS: 1956CE0\n    DWORD DoSearch(TMndxSearch * pSearch, bool * pbFindResult)\n    {\n        DWORD dwErrCode = ERROR_SUCCESS;\n\n        if(pDatabase == NULL)\n            return ERROR_INVALID_PARAMETER;\n\n        *pbFindResult = pDatabase->DoSearch(pSearch);\n        return dwErrCode;\n    }\n\n    // HOTS: 1956D20\n    int GetFileNameCount(size_t * PtrFileNameCount)\n    {\n        if(pDatabase == NULL)\n            return ERROR_INVALID_PARAMETER;\n\n        PtrFileNameCount[0] = pDatabase->FileNameIndexes.ValidItemCount;\n        return ERROR_SUCCESS;\n    }\n\n//  protected:\n    TFileNameDatabase * pDatabase;\n    LPBYTE pbMarData;\n    size_t cbMarData;\n};\n\n//-----------------------------------------------------------------------------\n// Implementation of root file functions\n\ntypedef struct _FILE_MNDX_INFO\n{\n    BYTE  RootFileName[MD5_HASH_SIZE];              // Name (aka MD5) of the root file\n    DWORD HeaderVersion;                            // Must be <= 2\n    DWORD FormatVersion;\n    DWORD field_1C;\n    DWORD field_20;\n    DWORD MarInfoOffset;                            // Offset of the first MAR entry info\n    DWORD MarInfoCount;                             // Number of the MAR info entries\n    DWORD MarInfoSize;                              // Size of the MAR info entry\n    DWORD CKeyEntriesOffset;                        // Offset of the CKey entries, relative to begin of the root file\n    DWORD CKeyEntriesCount;                         // Number of CKeys (files) in the root file\n    DWORD FileNameCount;                            // Number of unique file names. More files with the same name in the different packages can exist\n    DWORD CKeyEntrySize;                            // Size of one CKey root entry\n    TMndxMarFile * MarFiles[MAR_COUNT];             // File name list for the packages\n\n} FILE_MNDX_INFO, *PFILE_MNDX_INFO;\n\nstruct TMndxHandler\n{\n    public:\n\n    //\n    //  Constructor and destructor\n    //\n\n    TMndxHandler()\n    {\n        memset(this, 0, sizeof(TMndxHandler));\n    }\n\n    ~TMndxHandler()\n    {\n        PMNDX_PACKAGE pPackage;\n        size_t i;\n\n        for(i = 0; i < MAR_COUNT; i++)\n            delete MndxInfo.MarFiles[i];\n        CASC_FREE(FileNameIndexToCKeyIndex);\n        pCKeyEntries = NULL;\n\n        for(i = 0; i < Packages.ItemCount(); i++)\n        {\n            pPackage = (PMNDX_PACKAGE)Packages.ItemAt(i);\n            CASC_FREE(pPackage->szFileName);\n        }\n        Packages.Free();\n    }\n\n    //\n    //  Helper functions\n    //\n\n    static LPBYTE CaptureRootHeader(FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootPtr, LPBYTE pbRootEnd)\n    {\n        // Capture the root header\n        pbRootPtr = CaptureData(pbRootPtr, pbRootEnd, &MndxHeader, sizeof(FILE_MNDX_HEADER));\n        if (pbRootPtr == NULL)\n            return NULL;\n\n        // Check signature and version\n        if (MndxHeader.Signature != CASC_MNDX_ROOT_SIGNATURE || MndxHeader.FormatVersion > 2 || MndxHeader.FormatVersion < 1)\n            return NULL;\n\n        // Passed\n        return pbRootPtr + sizeof(FILE_MNDX_HEADER);\n    }\n\n    DWORD LoadPackageNames()\n    {\n        TMndxMarFile * pMarFile = MndxInfo.MarFiles[MAR_PACKAGE_NAMES];\n        TMndxSearch Search;\n        PMNDX_PACKAGE pPackage;\n        size_t nPackageCount = 0x40;\n        bool bFindResult = false;\n        DWORD dwErrCode;\n\n        // Prepare the file name search in the top level directory\n        Search.SetSearchMask(\"\", 0);\n\n        // Allocate initial name list structure\n        pMarFile->GetFileNameCount(&nPackageCount);\n        dwErrCode = Packages.Create<MNDX_PACKAGE>(nPackageCount);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Reset the package array\n        Packages.Reset();\n\n        // Keep searching as long as we find something\n        while(pMarFile->DoSearch(&Search, &bFindResult) == ERROR_SUCCESS && bFindResult)\n        {\n            // Insert new package to the array\n            assert(Search.nIndex < nPackageCount);\n            pPackage = (PMNDX_PACKAGE)Packages.InsertAt(Search.nIndex);\n            if (pPackage != NULL)\n            {\n                // The package mut not be initialized yet\n                assert(pPackage->szFileName == NULL);\n\n                // Allocate space for the file name\n                pPackage->szFileName = CASC_ALLOC<char>(Search.cchFoundPath + 1);\n                if (pPackage->szFileName == NULL)\n                    return ERROR_NOT_ENOUGH_MEMORY;\n\n                // Fill the package structure\n                memcpy(pPackage->szFileName, Search.szFoundPath, Search.cchFoundPath);\n                pPackage->szFileName[Search.cchFoundPath] = 0;\n                pPackage->nLength = Search.cchFoundPath;\n                pPackage->nIndex = Search.nIndex;\n            }\n        }\n\n        // Give the packages to the caller\n        return ERROR_SUCCESS;\n    }\n\n    DWORD Load(const FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootFile, LPBYTE pbRootEnd)\n    {\n        TMndxMarFile * pMarFile;\n        FILE_MAR_INFO MarInfo;\n        size_t nFilePointer = 0;\n        DWORD i;\n        DWORD dwErrCode = ERROR_SUCCESS;\n\n        // Copy the header into the MNDX info\n        MndxInfo.HeaderVersion = MndxHeader.HeaderVersion;\n        MndxInfo.FormatVersion = MndxHeader.FormatVersion;\n        nFilePointer += sizeof(FILE_MNDX_HEADER);\n\n        // Header version 2 has 2 extra fields that we need to load\n        if(MndxInfo.HeaderVersion == 2)\n        {\n            if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MndxInfo.field_1C, sizeof(DWORD) + sizeof(DWORD)))\n                return ERROR_FILE_CORRUPT;\n            nFilePointer += sizeof(DWORD) + sizeof(DWORD);\n        }\n\n        // Load the rest of the file header\n        if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MndxInfo.MarInfoOffset, 0x1C))\n            return ERROR_FILE_CORRUPT;\n\n        // Verify the structure\n        if(MndxInfo.MarInfoCount > MAR_COUNT || MndxInfo.MarInfoSize != sizeof(FILE_MAR_INFO))\n            return ERROR_FILE_CORRUPT;\n\n        // Load all MAR infos\n        for(i = 0; i < MndxInfo.MarInfoCount; i++)\n        {\n            // Capture the n-th MAR info\n            nFilePointer = MndxInfo.MarInfoOffset + (MndxInfo.MarInfoSize * i);\n            if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MarInfo, sizeof(FILE_MAR_INFO)))\n                return ERROR_FILE_CORRUPT;\n\n            // Allocate MAR_FILE structure\n            pMarFile = new TMndxMarFile();\n            if(pMarFile == NULL)\n            {\n                dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n                break;\n            }\n\n            // Create the database from the MAR data\n            dwErrCode = pMarFile->LoadRootData(MarInfo, pbRootFile, pbRootEnd);\n            if(dwErrCode != ERROR_SUCCESS)\n                break;\n\n            // Assign the MAR file to the MNDX info structure\n            MndxInfo.MarFiles[i] = pMarFile;\n        }\n\n        // All three MAR files must be loaded\n        // HOTS: 00E9503B\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            if(MndxInfo.MarFiles[MAR_PACKAGE_NAMES] == NULL || MndxInfo.MarFiles[MAR_STRIPPED_NAMES] == NULL || MndxInfo.MarFiles[MAR_FULL_NAMES] == NULL)\n                dwErrCode = ERROR_BAD_FORMAT;\n            if(MndxInfo.CKeyEntrySize != sizeof(MNDX_CKEY_ENTRY))\n                dwErrCode = ERROR_BAD_FORMAT;\n        }\n\n        // Load the array of Ckey entries. All present files are in the array,\n        // the same names (differentiated by package ID) are groupped together\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            size_t CKeyEntriesSize;\n            size_t FileNameCount = 0;\n\n            pMarFile = MndxInfo.MarFiles[MAR_STRIPPED_NAMES];\n            dwErrCode = ERROR_FILE_CORRUPT;\n\n            // Capture the array of CKey entries\n            if(pMarFile->GetFileNameCount(&FileNameCount) == ERROR_SUCCESS && FileNameCount == MndxInfo.FileNameCount)\n            {\n                CKeyEntriesSize = MndxInfo.CKeyEntriesCount * MndxInfo.CKeyEntrySize;\n                if ((pbRootFile + MndxInfo.CKeyEntriesOffset + CKeyEntriesSize) <= pbRootEnd)\n                {\n                    pCKeyEntries = (PMNDX_CKEY_ENTRY)(pbRootFile + MndxInfo.CKeyEntriesOffset);\n                    dwErrCode = ERROR_SUCCESS;\n                }\n            }\n        }\n\n        // Pick the CKey entries that are the first with a given name\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            assert(MndxInfo.FileNameCount <= MndxInfo.CKeyEntriesCount);\n            FileNameIndexToCKeyIndex = CASC_ALLOC<PMNDX_CKEY_ENTRY>(MndxInfo.FileNameCount + 1);\n            if(FileNameIndexToCKeyIndex != NULL)\n            {\n                PMNDX_CKEY_ENTRY pRootEntry = pCKeyEntries;\n                DWORD nFileNameIndex = 0;\n\n                // The first entry is always beginning of a file name group\n                FileNameIndexToCKeyIndex[nFileNameIndex++] = pRootEntry;\n\n                // Get the remaining file name groups\n                for(i = 0; i < MndxInfo.CKeyEntriesCount; i++, pRootEntry++)\n                {\n                    if (nFileNameIndex > MndxInfo.FileNameCount)\n                        break;\n\n                    if (pRootEntry->Flags & MNDX_LAST_CKEY_ENTRY)\n                    {\n                        FileNameIndexToCKeyIndex[nFileNameIndex++] = pRootEntry + 1;\n                    }\n                }\n\n                // Verify the final number of file names\n                if ((nFileNameIndex - 1) != MndxInfo.FileNameCount)\n                    dwErrCode = ERROR_BAD_FORMAT;\n            }\n            else\n                dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n        }\n\n        // Load the package names from the 0-th MAR file\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            dwErrCode = LoadPackageNames();\n        }\n\n        return dwErrCode;\n    }\n\n    DWORD LoadFileNames(TCascStorage * hs, CASC_FILE_TREE & FileTree)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        PMNDX_CKEY_ENTRY pRootEntry;\n        PMNDX_CKEY_ENTRY pRootEnd = pCKeyEntries + MndxInfo.CKeyEntriesCount;\n        PMNDX_PACKAGE pPackage;\n        TMndxMarFile * pMarFile = MndxInfo.MarFiles[MAR_STRIPPED_NAMES];\n        TMndxSearch Search;\n        char szFileName[MAX_PATH];\n        bool bFindResult = false;\n        DWORD dwErrCode;\n\n        // Setup the search mask\n        Search.SetSearchMask(\"\", 0);\n\n        // Keep searching ad long as we found something\n        while ((dwErrCode = pMarFile->DoSearch(&Search, &bFindResult)) == ERROR_SUCCESS && bFindResult)\n        {\n            // Sanity check\n            assert(Search.cchFoundPath < MAX_PATH);\n\n            // The found file name index must fall into range of file names\n            if (Search.nIndex < MndxInfo.FileNameCount)\n            {\n                // Retrieve the first-in-group CKey entry of that name\n                pRootEntry = FileNameIndexToCKeyIndex[Search.nIndex];\n\n                // Now take all files of that name, prepend their package name and insert to file tree\n                while(pRootEntry < pRootEnd)\n                {\n                    // Find the appropriate CKey entry in the central storage\n                    pCKeyEntry = FindCKeyEntry_CKey(hs, pRootEntry->CKey);\n                    if (pCKeyEntry != NULL)\n                    {\n                        size_t nPackageIndex = pRootEntry->Flags & 0x00FFFFFF;\n\n                        // Retrieve the package for this entry\n                        pPackage = (PMNDX_PACKAGE)Packages.ItemAt(nPackageIndex);\n                        if (pPackage != NULL)\n                        {\n                            // Sanity check\n                            assert(pPackage->nIndex == nPackageIndex);\n\n                            // Merge the package name and file name\n                            MakeFileName(szFileName, _countof(szFileName), pPackage, &Search);\n\n                            // Insert the entry to the file tree\n                            FileTree.InsertByName(pCKeyEntry, szFileName);\n                        }\n                    }\n\n                    // Is this the last-in-group entry?\n                    if (pRootEntry->Flags & MNDX_LAST_CKEY_ENTRY)\n                        break;\n                    pRootEntry++;\n                }\n            }\n        }\n\n        return dwErrCode;\n    }\n\n    //\n    //  Helper functions\n    //\n\n    void MakeFileName(char * szBuffer, size_t cchBuffer, PMNDX_PACKAGE pPackage, TMndxSearch * pSearch)\n    {\n        char * szBufferEnd = szBuffer + cchBuffer - 1;\n\n        // Buffer length check\n        assert((pPackage->nLength + 1 + pSearch->cchFoundPath + 1) < cchBuffer);\n\n        // Copy the package name\n        if ((szBuffer + pPackage->nLength) < szBufferEnd)\n        {\n            memcpy(szBuffer, pPackage->szFileName, pPackage->nLength);\n            szBuffer += pPackage->nLength;\n        }\n\n        // Append slash\n        if ((szBuffer + 1) < szBufferEnd)\n            *szBuffer++ = '/';\n\n        // Append file name\n        if ((szBuffer + pSearch->cchFoundPath) < szBufferEnd)\n        {\n            memcpy(szBuffer, pSearch->szFoundPath, pSearch->cchFoundPath);\n            szBuffer += pSearch->cchFoundPath;\n        }\n\n        szBuffer[0] = 0;\n    }\n\n    protected:\n\n    FILE_MNDX_INFO MndxInfo;\n\n    PMNDX_CKEY_ENTRY * FileNameIndexToCKeyIndex;\n    PMNDX_CKEY_ENTRY pCKeyEntries;\n    CASC_ARRAY Packages;                        // Linear list of present packages\n};\n\n//-----------------------------------------------------------------------------\n// Handler definition for MNDX root file\n\nstruct TRootHandler_MNDX : public TFileTreeRoot\n{\n    public:\n\n    TRootHandler_MNDX() : TFileTreeRoot(0)\n    {\n        // MNDX supports file names and CKeys\n        dwFeatures |= CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY;\n    }\n\n    DWORD Load(TCascStorage * hs, const FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootFile, LPBYTE pbRootEnd)\n    {\n        TMndxHandler Handler;\n        DWORD dwErrCode;\n\n        // Load and parse the entire MNDX structure\n        dwErrCode = Handler.Load(MndxHeader, pbRootFile, pbRootEnd);\n        if (dwErrCode == ERROR_SUCCESS)\n        {\n            // Search all file names and insert them into the file tree\n            dwErrCode = Handler.LoadFileNames(hs, FileTree);\n        }\n\n        return dwErrCode;\n    }\n};\n\n//-----------------------------------------------------------------------------\n// Public functions - MNDX info\n\nDWORD RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)\n{\n    TRootHandler_MNDX * pRootHandler = NULL;\n    FILE_MNDX_HEADER MndxHeader;\n    LPBYTE pbRootEnd = pbRootFile + cbRootFile;\n    DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n    // Verify the header of the ROOT file\n    if(TMndxHandler::CaptureRootHeader(MndxHeader, pbRootFile, pbRootEnd) != NULL)\n    {\n        // Allocate the root handler object\n        pRootHandler = new TRootHandler_MNDX();\n        if(pRootHandler != NULL)\n        {\n            // Load the root directory. If load failed, we free the object\n            dwErrCode = pRootHandler->Load(hs, MndxHeader, pbRootFile, pbRootEnd);\n            if(dwErrCode != ERROR_SUCCESS)\n            {\n                delete pRootHandler;\n                pRootHandler = NULL;\n            }\n        }\n    }\n\n    // Assign the root directory (or NULL) and return error\n    hs->pRootHandler = pRootHandler;\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_OW.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_Text.cpp                  Copyright (c) Ladislav Zezula 2017 */\n/*---------------------------------------------------------------------------*/\n/* Support for loading ROOT files in plain text                              */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 28.10.15  1.00  Lad  The first version of CascRootFile_Text.cpp           */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Structure definitions for CMF files\n\n#define MAX_LINE_ELEMENTS   8\n\ntypedef struct _CMF_HEADER_V3\n{\n    DWORD BuildVersion;\n    DWORD Unknown0;\n    DWORD Unknown1;\n    DWORD Unknown2;\n    DWORD Unknown3;\n    DWORD DataCount;\n    DWORD Unknown4;\n    DWORD EntryCount;\n    DWORD Magic;\n} CMF_HEADER_V3, *PCMF_HEADER_V3;\n\ntypedef struct _CMF_HEADER_V2\n{\n    DWORD BuildVersion;\n    DWORD Unknown0;\n    DWORD Unknown1;\n    DWORD Unknown2;\n    DWORD DataCount;\n    DWORD Unknown3;\n    DWORD EntryCount;\n    DWORD Magic;\n} CMF_HEADER_V2, *PCMF_HEADER_V2;\n\ntypedef struct _CMF_HEADER_V1\n{\n    DWORD BuildVersion;\n    DWORD Unknown0;\n    DWORD DataCount;\n    DWORD Unknown1;\n    DWORD EntryCount;\n    DWORD Magic;\n} CMF_HEADER_V1, *PCMF_HEADER_V1;\n\n//-----------------------------------------------------------------------------\n// Structure definitions for APM files\n\n// In-memory format\ntypedef struct _APM_ENTRY\n{\n    DWORD     Index;\n    ULONGLONG HashA;\n    ULONGLONG HashB;\n} APM_ENTRY, *PAPM_ENTRY;\n\n// On-disk format, size = 0x14\ntypedef struct _APM_ENTRY_V2\n{\n    DWORD     Index;\n    DWORD     HashA_Lo;                     // Must split the hashes in order to make this structure properly aligned\n    DWORD     HashA_Hi;\n    DWORD     HashB_Lo;\n    DWORD     HashB_Hi;\n} APM_ENTRY_V2, *PAPM_ENTRY_V2;\n\n// On-disk format, size = 0x0C\ntypedef struct _APM_ENTRY_V1\n{\n    DWORD     Index;\n    DWORD     HashA_Lo;                     // Must split the hashes in order to make this structure properly aligned\n    DWORD     HashA_Hi;\n} APM_ENTRY_V1, *PAPM_ENTRY_V1;\n\n// In-memory format\ntypedef struct _APM_PACKAGE_ENTRY\n{\n    ULONGLONG PackageGUID;                  // 077 file\n    ULONGLONG Unknown1;\n    DWORD Unknown2;\n    DWORD Unknown3;\n    ULONGLONG Unknown4;\n} APM_PACKAGE_ENTRY, *PAPM_PACKAGE_ENTRY;\n\n// On-disk format\ntypedef struct _APM_PACKAGE_ENTRY_V2\n{\n    ULONGLONG PackageGUID;                  // 077 file\n    ULONGLONG Unknown1;\n    DWORD Unknown2;\n    DWORD Unknown3;\n    ULONGLONG Unknown4;\n} APM_PACKAGE_ENTRY_V2, *PAPM_PACKAGE_ENTRY_V2;\n\n// On-disk format\ntypedef struct _APM_PACKAGE_ENTRY_V1\n{\n    ULONGLONG EntryPointGUID;               // virtual most likely\n    ULONGLONG PrimaryGUID;                  // real\n    ULONGLONG SecondaryGUID;                // real\n    ULONGLONG Key;                          // encryption\n    ULONGLONG PackageGUID;                  // 077 file\n    ULONGLONG Unknown1;\n    DWORD Unknown2;\n} APM_PACKAGE_ENTRY_V1, *PAPM_PACKAGE_ENTRY_V1;\n\ntypedef struct _APM_HEADER_V3\n{\n    ULONGLONG BuildNumber;              // Build number of the game\n    ULONGLONG ZeroValue1;\n    DWORD ZeroValue2;\n    DWORD PackageCount;\n    DWORD ZeroValue3;\n    DWORD EntryCount;\n    DWORD Checksum;\n\n    // Followed by the array of APM_ENTRY (count is in \"EntryCount\")\n    // Followed by the array of APM_PACKAGE (count is in \"PackageCount\")\n\n} APM_HEADER_V3, *PAPM_HEADER_V3;\n\ntypedef struct _APM_HEADER_V2\n{\n    ULONGLONG BuildNumber;              // Build number of the game\n    ULONGLONG ZeroValue1;\n    DWORD PackageCount;\n    DWORD ZeroValue2;\n    DWORD EntryCount;\n    DWORD Checksum;\n\n    // Followed by the array of APM_ENTRY (count is in \"EntryCount\")\n    // Followed by the array of APM_PACKAGE (count is in \"PackageCount\")\n\n} APM_HEADER_V2, *PAPM_HEADER_V2;\n\ntypedef struct _APM_HEADER_V1\n{\n    ULONGLONG BuildNumber;              // Build number of the game\n    DWORD BuildVersion;\n    DWORD PackageCount;\n    DWORD EntryCount;\n    DWORD Checksum;\n\n    // Followed by the array of APM_ENTRY (count is in \"EntryCount\")\n    // Followed by the array of APM_PACKAGE (count is in \"PackageCount\")\n\n} APM_HEADER_V1, *PAPM_HEADER_V1;\n\n//-----------------------------------------------------------------------------\n// Handler classes\n\n/*\nstruct TCmfFile\n{\n    TCmfFile()\n    {\n        memset(this, 0, sizeof(TCmfFile));\n    }\n\n    LPBYTE CaptureHeader(LPBYTE pbCmfData, LPBYTE pbCmfEnd)\n    {\n        DWORD BuildNumber = *(PDWORD)pbCmfData;\n\n        // Check the newest header version\n        if(BuildNumber >= 45104 && BuildNumber != 45214)\n        {\n            PCMF_HEADER_V3 pHeader3 = (PCMF_HEADER_V3)pbCmfData;\n            \n            if ((LPBYTE)(pHeader3 + 1) > pbCmfEnd)\n                return NULL;\n\n            BuildVersion = pHeader3->BuildVersion;\n            DataCount = pHeader3->DataCount;\n            EntryCount = pHeader3->EntryCount;\n            Magic = pHeader3->Magic;\n            return (LPBYTE)(pHeader3 + 1);\n        }\n\n        else if(BuildNumber >= 39028)\n        {\n            // TODO\n            assert(false);\n            return NULL;\n        }\n\n        else\n        {\n            // TODO\n            assert(false);\n            return NULL;\n        }\n    }\n\n    DWORD BuildVersion;\n    DWORD DataCount;\n    DWORD EntryCount;\n    DWORD Magic;\n};\n\nstruct TApmFile\n{\n    TApmFile()\n    {\n        memset(this, 0, sizeof(TApmFile));\n    }\n\n    ~TApmFile()\n    {\n        CASC_FREE(pApmPackages);\n        CASC_FREE(pApmEntries);\n    }\n\n    LPBYTE CaptureHeader(LPBYTE pbApmData, LPBYTE pbApmEnd)\n    {\n        // Check the data size for the largest possible header size\n        if((pbApmData + sizeof(APM_HEADER_V3)) < pbApmEnd)\n        {\n            // Try the version 3\n            PAPM_HEADER_V3 pApmFile3 = (PAPM_HEADER_V3)(pbApmData);\n            if(pApmFile3->ZeroValue1 == 0 && pApmFile3->ZeroValue2 == 0 && pApmFile3->PackageCount && pApmFile3->EntryCount && pApmFile3->Checksum)\n            {\n                BuildNumber  = pApmFile3->BuildNumber;\n                PackageCount = pApmFile3->PackageCount;\n                EntryCount   = pApmFile3->EntryCount;\n                Checksum     = pApmFile3->Checksum;\n                return pbApmData + 0x24;\n            }\n\n            // Try the version 2\n            PAPM_HEADER_V2 pApmFile2 = (PAPM_HEADER_V2)(pbApmData);\n            if(pApmFile2->ZeroValue1 == 0 && pApmFile2->PackageCount && pApmFile2->EntryCount && pApmFile2->Checksum)\n            {\n                BuildNumber  = pApmFile2->BuildNumber;\n                PackageCount = pApmFile2->PackageCount;\n                EntryCount   = pApmFile2->EntryCount;\n                Checksum     = pApmFile2->Checksum;\n                return pbApmData + 0x20;\n            }\n\n            // Try the version 1 (build 24919)\n            PAPM_HEADER_V1 pApmHeader1 = (PAPM_HEADER_V1)(pbApmData);\n            if(pApmHeader1->BuildVersion != 0 && pApmHeader1->PackageCount && pApmHeader1->EntryCount && pApmHeader1->Checksum)\n            {\n                BuildNumber  = pApmHeader1->BuildNumber;\n                PackageCount = pApmHeader1->PackageCount;\n                EntryCount   = pApmHeader1->EntryCount;\n                Checksum     = pApmHeader1->Checksum;\n                return pbApmData + 0x18;\n            }\n        }\n\n        return NULL;\n    }\n\n    LPBYTE CaptureArrayOfEntries(LPBYTE pbArrayOfEntries, LPBYTE pbApmEnd)\n    {\n        // Allocate array of entries\n        pApmEntries = CASC_ALLOC<APM_ENTRY>(EntryCount);\n        if(pApmEntries != NULL)\n        {\n            // The newest format\n            if(BuildNumber > 45104 && BuildNumber != 45214)\n            {\n                PAPM_ENTRY_V2 pEntry2 = (PAPM_ENTRY_V2)pbArrayOfEntries;\n                LPBYTE pbEntriesEnd = (LPBYTE)(pEntry2 + EntryCount);\n\n                if(pbEntriesEnd <= pbApmEnd)\n                {\n                    for(DWORD i = 0; i < EntryCount; i++)\n                    {\n                        pApmEntries[i].Index = pEntry2->Index;\n                        pApmEntries[i].HashA = MAKE_OFFSET64(pEntry2->HashA_Hi, pEntry2->HashA_Lo);\n                        pApmEntries[i].HashB = MAKE_OFFSET64(pEntry2->HashB_Hi, pEntry2->HashB_Lo);\n                    }\n\n                    return pbEntriesEnd;\n                }\n            }\n            else\n            {\n                PAPM_ENTRY_V1 pEntry1 = (PAPM_ENTRY_V1)pbArrayOfEntries;\n                LPBYTE pbEntriesEnd = (LPBYTE)(pEntry1 + EntryCount);\n\n                if(pbEntriesEnd <= pbApmEnd)\n                {\n                    for(DWORD i = 0; i < EntryCount; i++)\n                    {\n                        pApmEntries[i].Index = pEntry1->Index;\n                        pApmEntries[i].HashA = MAKE_OFFSET64(pEntry1->HashA_Hi, pEntry1->HashA_Lo);\n                        pApmEntries[i].HashB = 0;\n                    }\n\n                    return pbEntriesEnd;\n                }\n            }\n        }\n\n        return NULL;\n    }\n\n    LPBYTE CapturePackageEntries(LPBYTE pbArrayOfEntries, LPBYTE pbApmEnd)\n    {\n        // Allocate array of entries\n        pApmPackages = CASC_ALLOC_ZERO<APM_PACKAGE_ENTRY>(PackageCount);\n        if(pApmPackages != NULL)\n        {\n            // The newest format\n            if(BuildNumber > 45104 && BuildNumber != 45214)\n            {\n                PAPM_PACKAGE_ENTRY_V2 pEntry2 = (PAPM_PACKAGE_ENTRY_V2)pbArrayOfEntries;\n                LPBYTE pbEntriesEnd = (LPBYTE)(pEntry2 + PackageCount);\n\n                if(pbEntriesEnd <= pbApmEnd)\n                {\n                    for(DWORD i = 0; i < PackageCount; i++)\n                    {\n                        pApmPackages[i].PackageGUID = pEntry2[i].PackageGUID;\n                        pApmPackages[i].Unknown1 = pEntry2[i].Unknown1;\n                        pApmPackages[i].Unknown2 = pEntry2[i].Unknown2;\n                        pApmPackages[i].Unknown3 = pEntry2[i].Unknown3;\n                        pApmPackages[i].Unknown4 = pEntry2[i].Unknown4;\n                    }\n\n                    return pbEntriesEnd;\n                }\n            }\n            else\n            {\n                PAPM_PACKAGE_ENTRY_V1 pEntry1 = (PAPM_PACKAGE_ENTRY_V1)pbArrayOfEntries;\n                LPBYTE pbEntriesEnd = (LPBYTE)(pEntry1 + PackageCount);\n\n                if(pbEntriesEnd <= pbApmEnd)\n                {\n                    for(DWORD i = 0; i < PackageCount; i++)\n                    {\n                        // TODO!!!\n                        pApmPackages[i].PackageGUID = pEntry1->PackageGUID;\n                    }\n\n                    return pbEntriesEnd;\n                }\n            }\n        }\n\n        return NULL;\n    }\n\n    PAPM_ENTRY pApmEntries;\n    PAPM_PACKAGE_ENTRY pApmPackages;\n    ULONGLONG BuildNumber;\n    DWORD PackageCount;\n    DWORD EntryCount;\n    DWORD Checksum;\n    size_t HeaderSize;\n\n    // Followed by the array of APM_ENTRY (count is in \"EntryCount\")\n    // Followed by the array of APM_PACKAGE (count is in \"PackageCount\")\n\n};\n*/\n\n//-----------------------------------------------------------------------------\n// Handler definition for OVERWATCH root file\n\n//\n// -------------------------------------\n// Overwatch ROOT file (build 24919):\n// -------------------------------------\n// #MD5|CHUNK_ID|FILENAME|INSTALLPATH\n// FE3AD8A77EEF77B383DF4929AED816FD|0|RetailClient/GameClientApp.exe|GameClientApp.exe\n// 5EDDEFECA544B6472C5CD52BE63BC02F|0|RetailClient/Overwatch Launcher.exe|Overwatch Launcher.exe\n// 6DE09F0A67F33F874F2DD8E2AA3B7AAC|0|RetailClient/ca-bundle.crt|ca-bundle.crt\n// 99FE9EB6A4BB20209202F8C7884859D9|0|RetailClient/ortp_x64.dll|ortp_x64.dll\n//\n// -------------------------------------\n// Overwatch ROOT file (build 47161):\n// -------------------------------------\n// #FILEID|MD5|CHUNK_ID|PRIORITY|MPRIORITY|FILENAME|INSTALLPATH\n// RetailClient/Overwatch.exe|807F96661280C07E762A8C129FEBDA6F|0|0|255|RetailClient/Overwatch.exe|Overwatch.exe\n// RetailClient/Overwatch Launcher.exe|5EDDEFECA544B6472C5CD52BE63BC02F|0|0|255|RetailClient/Overwatch Launcher.exe|Overwatch Launcher.exe\n// RetailClient/ortp_x64.dll|7D1B5DEC267480F3E8DAD6B95143A59C|0|0|255|RetailClient/ortp_x64.dll|ortp_x64.dll\n//\n\nstruct TRootHandler_OW : public TFileTreeRoot\n{\n    TRootHandler_OW() : TFileTreeRoot(0)\n    {\n        // We have file names and return CKey as result of search\n        dwFeatures |= (CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY);\n    }\n/*\n    bool IsManifestFolderName(const char * szFileName, const char * szManifestFolder, size_t nLength)\n    {\n        if(!_strnicmp(szFileName, szManifestFolder, nLength))\n        {\n            return (szFileName[nLength] == '\\\\' || szFileName[nLength] == '/');\n        }\n        return false;\n    }\n\n    bool IsApmFileName(const char * szFileName)\n    {\n        const char * szExtension;\n\n        if(IsManifestFolderName(szFileName, \"Manifest\", 8) || IsManifestFolderName(szFileName, \"TactManifest\", 12))\n        {\n            szExtension = GetFileExtension(szFileName);\n            if(!_stricmp(szExtension, \".apm\"))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    DWORD LoadApmFile(TCascStorage * hs, CONTENT_KEY & CKey, const char * szFileName)\n    {\n        TApmFile ApmFile;\n        LPBYTE pbApmData;\n        DWORD cbApmData = 0;\n        DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n        pbApmData = LoadInternalFileToMemory(hs, CKey.Value, CASC_OPEN_BY_CKEY, &cbApmData);\n        if(pbApmData != NULL)\n        {\n            LPBYTE pbApmEnd = pbApmData + cbApmData;\n            LPBYTE pbApmPtr = pbApmData;\n            \n            pbApmPtr = ApmFile.CaptureHeader(pbApmPtr, pbApmEnd);\n            if(pbApmPtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // Read the array of entries\n            pbApmPtr = ApmFile.CaptureArrayOfEntries(pbApmPtr, pbApmEnd);\n            if(pbApmPtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // Read the array of package entries\n            pbApmPtr = ApmFile.CapturePackageEntries(pbApmPtr, pbApmEnd);\n            if(pbApmPtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n            CASC_FREE(pbApmData);\n        }\n\n        return dwErrCode;\n    }\n\n    static DWORD LoadCmfFile(TCascStorage * hs, CONTENT_KEY & CKey, const char * szFileName)\n    {\n        TCmfFile CmfFile;\n        LPBYTE pbCmfData;\n        DWORD cbCmfData = 0;\n        DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n        pbCmfData = LoadInternalFileToMemory(hs, CKey.Value, CASC_OPEN_BY_CKEY, &cbCmfData);\n        if(pbCmfData != NULL)\n        {\n            LPBYTE pbCmfEnd = pbCmfData + cbCmfData;\n            LPBYTE pbCmfPtr = pbCmfData;\n\n            // Capture the CMF header\n            pbCmfPtr = CmfFile.CaptureHeader(pbCmfPtr, pbCmfEnd);\n            if(pbCmfPtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n//          if(CmfFile.Magic >= 0x636D6614)\n//              DecryptCmfFile(\n\n            CASC_FREE(pbCmfData);\n        }\n\n        return dwErrCode;\n    }\n*/\n    int Load(TCascStorage * hs, CASC_CSV & Csv, size_t nFileNameIndex, size_t nCKeyIndex)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n//      size_t ApmFiles[0x80];\n//      size_t nApmFiles = 0;\n        BYTE CKey[MD5_HASH_SIZE];\n\n        CASCLIB_UNUSED(hs);\n\n        // Keep loading every line until there is something\n        while(Csv.LoadNextLine())\n        {\n            const CASC_CSV_COLUMN & FileName = Csv[CSV_ZERO][nFileNameIndex];\n            const CASC_CSV_COLUMN & CKeyStr = Csv[CSV_ZERO][nCKeyIndex];\n\n            // Retrieve the file name and the content key\n            if(FileName.szValue && CKeyStr.szValue && CKeyStr.nLength == MD5_STRING_SIZE)\n            {\n                // Convert the string CKey to binary\n                if(BinaryFromString(CKeyStr.szValue, MD5_STRING_SIZE, CKey) == ERROR_SUCCESS)\n                {\n                    // Find the item in the tree\n                    if((pCKeyEntry = FindCKeyEntry_CKey(hs, CKey)) != NULL)\n                    {\n                        // Insert the file name and the CKey into the tree\n                        FileTree.InsertByName(pCKeyEntry, FileName.szValue);\n\n                        // If the file name is actually an asset, we need to parse that asset and load files in it\n//                      if(IsApmFileName(szFileName))\n//                      {\n//                          ApmFiles[nApmFiles++] = FileTree_IndexOf(&pRootHandler->FileTree, pFileNode1);\n//                      }\n                    }\n                }\n            }\n        }\n/*\n        // Load all CMF+APM files\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            for(size_t i = 0; i < nApmFiles; i++)\n            {\n                char szApmFile[MAX_PATH + 1];\n                char szCmfFile[MAX_PATH + 1];\n\n                // Get the n-th item and its name\n                pFileNode1 = (PCASC_FILE_NODE)FileTree_PathAt(&pRootHandler->FileTree, szApmFile, MAX_PATH, ApmFiles[i]);\n                if(pFileNode1 == NULL)\n                    break;\n\n                if(strcmp(szApmFile, \"TactManifest\\\\Win_SPWin_RDEV_LenUS_EExt.apm\"))\n                    continue;\n\n                // Get the name of thew CMF file\n                CascStrCopy(szCmfFile, _countof(szCmfFile), szApmFile);\n                CascStrCopy((char *)GetFileExtension(szCmfFile), 5, \".cmf\");\n                pFileNode2 = (PCASC_FILE_NODE)FileTree_Find(&pRootHandler->FileTree, szCmfFile);\n                if(pFileNode2 == NULL)\n                    break;\n\n                // Create the map of CMF entries\n                dwErrCode = LoadCmfFile(hs, pFileNode2->CKey, szCmfFile);\n                if(dwErrCode != ERROR_SUCCESS)\n                    break;\n\n            }\n        }\n*/\n        return ERROR_SUCCESS;\n    }\n};\n\n//-----------------------------------------------------------------------------\n// Public functions\n\n// TODO: There is way more files in the Overwatch CASC storage than present in the ROOT file.\nDWORD RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)\n{\n    TRootHandler_OW * pRootHandler = NULL;\n    CASC_CSV Csv(0, true);\n    size_t Indices[2];\n    DWORD dwErrCode;\n\n    // Load the ROOT file\n    dwErrCode = Csv.Load(pbRootFile, cbRootFile);\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // Retrieve the indices of the file name and MD5 columns\n        Indices[0] = Csv.GetColumnIndex(\"FILENAME\");\n        Indices[1] = Csv.GetColumnIndex(\"MD5\");\n\n        // If both indices were found OK, then load the root file\n        if(Indices[0] != CSV_INVALID_INDEX && Indices[1] != CSV_INVALID_INDEX)\n        {\n            pRootHandler = new TRootHandler_OW();\n            if (pRootHandler != NULL)\n            {\n                // Load the root directory. If load failed, we free the object\n                dwErrCode = pRootHandler->Load(hs, Csv, Indices[0], Indices[1]);\n                if (dwErrCode != ERROR_SUCCESS)\n                {\n                    delete pRootHandler;\n                    pRootHandler = NULL;\n                }\n            }\n        }\n        else\n        {\n            dwErrCode = ERROR_BAD_FORMAT;\n        }\n    }\n\n    // Assign the root directory (or NULL) and return error\n    hs->pRootHandler = pRootHandler;\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_TVFS.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_TVFS.cpp                  Copyright (c) Ladislav Zezula 2018 */\n/*---------------------------------------------------------------------------*/\n/* ROOT handler for TACT VFS manifest format (root)                          */\n/* Note: TACT = Trusted Application Content Transfer                         */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 24.05.18  1.00  Lad  The first version of CascRootFile_TVFS.cpp           */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local defines\n\n#define TVFS_FLAG_INCLUDE_CKEY       0x0001         // Include C-key in content file record\n#define TVFS_FLAG_WRITE_SUPPORT      0x0002         // Write support. Include a table of encoding specifiers. This is required for writing files to the underlying storage. This bit is implied by the patch-support bit\n#define TVFS_FLAG_PATCH_SUPPORT      0x0004         // Patch support. Include patch records in the content file records.\n#define TVFS_FLAG_LOWERCASE_MANIFEST 0x0008         // Lowercase manifest. All paths in the path table have been converted to ASCII lowercase (i.e. [A-Z] converted to [a-z])\n\n#define TVFS_PTE_PATH_SEPARATOR_PRE  0x0001         // There is path separator before the name\n#define TVFS_PTE_PATH_SEPARATOR_POST 0x0002         // There is path separator after the name\n#define TVFS_PTE_NODE_VALUE          0x0004         // The NodeValue in path table entry is valid\n\n#define TVFS_FOLDER_NODE            0x80000000      // Highest bit is set if a file node is a folder\n#define TVFS_FOLDER_SIZE_MASK       0x7FFFFFFF      // Mask to get length of the folder\n\n//-----------------------------------------------------------------------------\n// Local structures\n\n// In-memory layout of the TVFS file header\ntypedef struct _TVFS_DIRECTORY_HEADER\n{\n    DWORD Signature;                                // Must be CASC_TVFS_ROOT_SIGNATURE\n    BYTE  FormatVersion;                            // Version of the format. Should be 1.\n    BYTE  HeaderSize;                               // Size of the header, in bytes\n    BYTE  EKeySize;                                 // Size of an E-Key. TACT uses 9-byte E-keys\n    BYTE  PatchKeySize;                             // Size of a patch key. TACT uses 9-byte P-keys\n    DWORD Flags;                                    // Flags. See TVFS_FLAG_XXX\n\n    // Followed by the offset table (variable length)\n    DWORD  PathTableOffset;                         // Offset of the path table\n    DWORD  PathTableSize;                           // Size of the path table\n    DWORD  VfsTableOffset;                          // Offset of the VFS table\n    DWORD  VfsTableSize;                            // Size of the VFS table\n    DWORD  CftTableOffset;                          // Offset of the container file table\n    DWORD  CftTableSize;                            // Size of the container file table\n    USHORT MaxDepth;                                // The maximum depth of the path prefix tree stored in the path table\n    DWORD  EstTableOffset;                          // The offset of the encoding specifier table. Only if the write-support bit is set in the header flag\n    DWORD  EstTableSize;                            // The size of the encoding specifier table. Only if the write-support bit is set in the header flag\n\n    DWORD  CftOffsSize;                             // Byte length of the offset in the Content File Table entry\n    DWORD  EstOffsSize;                             // Byte length of the offset in the Encoding Specifier Table entry\n\n    LPBYTE pbDirectoryData;                         // Pointer to the begin of directory data\n    LPBYTE pbDirectoryEnd;                          // Pointer to the end of directory data\n\n//  LPBYTE pbPathFileTable;                         // Begin and end of the path table\n//  LPBYTE pbPathTableEnd;\n\n//  LPBYTE pbVfsFileTable;                          // Begin and end of the VFS file table\n//  LPBYTE pbVfsTableEnd;\n\n//  LPBYTE pbCftFileTable;                          // Begin and end of the content file table\n//  LPBYTE pbCftTableEnd;\n\n} TVFS_DIRECTORY_HEADER, *PTVFS_DIRECTORY_HEADER;\n\n/*\n// Minimum size of a valid path table entry. 1 byte + 1-byte name + 1 byte + DWORD\n#define TVFS_HEADER_LENGTH FIELD_OFFSET(TVFS_DIRECTORY_HEADER, CftOffsSize)\n\n// Minimum size of a valid path table entry. 1 byte + 1-byte name + 1 byte + DWORD\n#define TVFS_MIN_PATH_ENTRY (1 + 1 + 1 + sizeof(DWORD)) \n\n// Minimum size of the VFS entry (SpanCount + FileOffset + SpanLength + CftOffset)\n#define TVFS_MIN_VFS_ENTRY (1 + sizeof(DWORD) + sizeof(DWORD) + 1)\n\n// Minimum size of the Content File Table entry (CASC_EKEY_SIZE + EncodedSize + ContentSize)\n#define TVFS_MIN_CFT_ENTRY (CASC_EKEY_SIZE + sizeof(DWORD) + sizeof(DWORD))\n\n// Minimum size of the TVFS folder data\n#define TVFS_MIN_FILE_SIZE (TVFS_HEADER_LENGTH + TVFS_MIN_PATH_ENTRY + TVFS_MIN_VFS_ENTRY + TVFS_MIN_CFT_ENTRY)\n\n// Maximum estimated file table. Empirically set to 8 MB, increase if needed.\n#define TVFS_MAX_FILE_SIZE 0x00800000\n*/\n\n// In-memory layout of the path table entry\ntypedef struct _TVFS_PATH_TABLE_ENTRY\n{\n    LPBYTE pbNamePtr;                               // Pointer to the begin of the node name\n    LPBYTE pbNameEnd;                               // Pointer to the end of the file name\n    DWORD NodeFlags;                                // TVFS_PTE_XXX\n    DWORD NodeValue;                                // Node value\n} TVFS_PATH_TABLE_ENTRY, *PTVFS_PATH_TABLE_ENTRY;\n\n//-----------------------------------------------------------------------------\n// Handler definition for TVFS root file\n\n// Structure for the root handler\nstruct TRootHandler_TVFS : public TFileTreeRoot\n{\n    public:\n\n    TRootHandler_TVFS() : TFileTreeRoot(0)\n    {\n        // TVFS supports file names, but DOESN'T support CKeys.\n        dwFeatures |= CASC_FEATURE_FILE_NAMES;\n    }\n\n    // Returns size of \"container file table offset\" field in the VFS.\n    // - If the container file table is larger than 0xffffff bytes, it's 4 bytes\n    // - If the container file table is larger than 0xffff bytes, it's 3 bytes\n    // - If the container file table is larger than 0xff bytes, it's 2 bytes\n    // - If the container file table is smaller than 0xff bytes, it's 1 byte\n    static DWORD GetOffsetFieldSize(DWORD dwTableSize)\n    {\n        if(dwTableSize > 0xffffff)\n            return 4;\n        if(dwTableSize > 0xffff)\n            return 3;\n        if(dwTableSize > 0xff)\n            return 2;\n        return 1;\n    }\n\n    bool PathBuffer_AppendNode(CASC_PATH<char> & PathBuffer, TVFS_PATH_TABLE_ENTRY & PathEntry)\n    {\n        // Append the prefix separator, if needed\n        if (PathEntry.NodeFlags & TVFS_PTE_PATH_SEPARATOR_PRE)\n            PathBuffer.AppendChar('/');\n\n        // Append the name fragment, if any\n        if (PathEntry.pbNameEnd > PathEntry.pbNamePtr)\n            PathBuffer.AppendStringN((const char *)PathEntry.pbNamePtr, (PathEntry.pbNameEnd - PathEntry.pbNamePtr), false);\n\n        // Append the postfix separator, if needed\n        if (PathEntry.NodeFlags & TVFS_PTE_PATH_SEPARATOR_POST)\n            PathBuffer.AppendChar('/');\n\n        return true;\n    }\n\n    static DWORD CaptureDirectoryHeader(TVFS_DIRECTORY_HEADER & DirHeader, LPBYTE pbDataPtr, LPBYTE pbDataEnd)\n    {\n        // Fill the header structure with zeros\n        memset(&DirHeader, 0, sizeof(TVFS_DIRECTORY_HEADER));\n        DirHeader.pbDirectoryData = pbDataPtr;\n        DirHeader.pbDirectoryEnd = pbDataEnd;\n\n        // Capture the signature\n        pbDataPtr = CaptureInteger32(pbDataPtr, pbDataEnd, &DirHeader.Signature);\n        if(pbDataPtr == NULL || DirHeader.Signature != CASC_TVFS_ROOT_SIGNATURE)\n            return ERROR_BAD_FORMAT;\n\n        // Capture the other four integers \n        pbDataPtr = CaptureByteArray(pbDataPtr, pbDataEnd, 4, &DirHeader.FormatVersion);\n        if(pbDataPtr == NULL || DirHeader.FormatVersion != 1 || DirHeader.EKeySize != 9 || DirHeader.PatchKeySize != 9 || DirHeader.HeaderSize < 8)\n            return ERROR_BAD_FORMAT;\n\n        // Capture the rest\n        pbDataPtr = CaptureByteArray(pbDataPtr, pbDataEnd, DirHeader.HeaderSize - FIELD_OFFSET(TVFS_DIRECTORY_HEADER, Flags), (LPBYTE)(&DirHeader.Flags));\n        if(pbDataPtr == NULL)\n            return ERROR_BAD_FORMAT;\n\n        // Swap the header values\n        DirHeader.Flags = ConvertBytesToInteger_4_LE((LPBYTE)(&DirHeader.Flags));\n\n        // Swap the offset table values\n        DirHeader.PathTableOffset = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.PathTableOffset));\n        DirHeader.PathTableSize   = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.PathTableSize));\n        DirHeader.VfsTableOffset  = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.VfsTableOffset));\n        DirHeader.VfsTableSize    = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.VfsTableSize));\n        DirHeader.CftTableOffset  = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.CftTableOffset));\n        DirHeader.CftTableSize    = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.CftTableSize));\n        DirHeader.MaxDepth        = (USHORT)ConvertBytesToInteger_2((LPBYTE)(&DirHeader.MaxDepth));\n        DirHeader.EstTableOffset  = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.EstTableOffset));\n        DirHeader.EstTableSize    = ConvertBytesToInteger_4((LPBYTE)(&DirHeader.EstTableSize));\n\n        // Determine size of file table offsets\n        DirHeader.CftOffsSize = GetOffsetFieldSize(DirHeader.CftTableSize);\n        DirHeader.EstOffsSize = GetOffsetFieldSize(DirHeader.EstTableSize);\n\n        // Capture the path table\n//      DirHeader.pbPathFileTable = pbDirectory + DirHeader.PathTableOffset;\n//      DirHeader.pbPathTableEnd = pbDirectory + DirHeader.PathTableOffset + DirHeader.PathTableSize;\n//      if(DirHeader.pbPathTableEnd > pbDataEnd)\n//          return ERROR_BAD_FORMAT;\n\n        // Capture the VFS file table\n//      DirHeader.pbVfsFileTable = pbDirectory + DirHeader.VfsTableOffset;\n//      DirHeader.pbVfsTableEnd = pbDirectory + DirHeader.VfsTableOffset + DirHeader.VfsTableSize;\n//      if(DirHeader.pbVfsTableEnd > pbDataEnd)\n//          return ERROR_BAD_FORMAT;\n\n        // Capture the container file table\n//      DirHeader.pbCftFileTable = pbDirectory + DirHeader.CftTableOffset;\n//      DirHeader.pbCftTableEnd = pbDirectory + DirHeader.CftTableOffset + DirHeader.CftTableSize;\n//      if(DirHeader.pbCftTableEnd > pbDataEnd)\n//          return ERROR_BAD_FORMAT;\n\n        return ERROR_SUCCESS;\n    }\n\n    LPBYTE CaptureVfsSpanCount(TVFS_DIRECTORY_HEADER & DirHeader, DWORD dwVfsOffset, DWORD & SpanCount)\n    {\n        LPBYTE pbVfsFileTable = DirHeader.pbDirectoryData + DirHeader.VfsTableOffset;\n        LPBYTE pbVfsFileEntry = pbVfsFileTable + dwVfsOffset;\n        LPBYTE pbVfsFileEnd = pbVfsFileTable + DirHeader.VfsTableSize;\n\n        // Get the number of span entries\n        if(!(pbVfsFileTable <= pbVfsFileEntry && pbVfsFileEntry < pbVfsFileEnd))\n            return NULL;\n        SpanCount = *pbVfsFileEntry++;\n\n        // 1 - 224 = valid file, 225-254 = other file, 255 = deleted file\n        // We will ignore all files with unsupported span count\n        return (1 <= SpanCount && SpanCount <= 224) ? pbVfsFileEntry : NULL;\n    }\n\n    LPBYTE CaptureVfsSpanEntries(TVFS_DIRECTORY_HEADER & DirHeader, LPBYTE pbVfsSpanEntry, PCASC_CKEY_ENTRY PtrSpanEntry, size_t SpanCount)\n    {\n        LPBYTE pbCftFileTable;\n        LPBYTE pbCftFileEntry;\n        LPBYTE pbCftFileEnd;\n        LPBYTE pbVfsFileTable = DirHeader.pbDirectoryData + DirHeader.VfsTableOffset;\n        LPBYTE pbVfsFileEnd = pbVfsFileTable + DirHeader.VfsTableSize;\n        size_t ItemSize = sizeof(DWORD) + sizeof(DWORD) + DirHeader.CftOffsSize;\n\n        // Check whether all spans are included in the valid range\n        if(pbVfsSpanEntry < pbVfsFileTable || (pbVfsSpanEntry + (ItemSize * SpanCount)) > pbVfsFileEnd)\n            return NULL;\n\n        // Convert all spans\n        for(size_t i = 0; i < SpanCount; i++)\n        {\n            DWORD dwCftOffset = ConvertBytesToInteger_X(pbVfsSpanEntry + sizeof(DWORD) + sizeof(DWORD), DirHeader.CftOffsSize);\n\n            //\n            // Structure of the span entry:\n            // (4bytes): Offset into the referenced file (big endian)\n            // (4bytes): Size of the span (big endian)\n            // (?bytes): Offset into Container File Table. Length depends on container file table size\n            //\n\n            // Resolve the Container File Table entry\n            pbCftFileTable = DirHeader.pbDirectoryData + DirHeader.CftTableOffset;\n            pbCftFileEntry = pbCftFileTable + dwCftOffset;\n            pbCftFileEnd = pbCftFileTable + DirHeader.CftTableSize;\n\n            // Capture the EKey and the file size\n            if((pbCftFileEntry + DirHeader.EKeySize + sizeof(DWORD)) > pbCftFileEnd)\n                return NULL;\n\n            // Copy the EKey and content size\n            CaptureEncodedKey(PtrSpanEntry->EKey, pbCftFileEntry, DirHeader.EKeySize);\n            PtrSpanEntry->ContentSize  = ConvertBytesToInteger_4(pbVfsSpanEntry + sizeof(DWORD));\n\n            // Move to the next entry\n            pbVfsSpanEntry += ItemSize;\n            PtrSpanEntry++;\n        }\n\n        return pbVfsSpanEntry;\n    }\n\n    //\n    // Structure of the path table entry:\n    // (1byte) 0x00 (optional) - means that there will be prefix path separator\n    // (1byte) File name length\n    // (?byte) File name\n    // (1byte) 0x00 (optional) - means that there will be postfix path separator\n    // (1byte) 0xFF (optional) - node value identifier\n    // (4byte)                 - node value\n    //\n    // Note: The path \"data\\archive\\maps\\file.bmp\" could be cut into nodes like:\n    //                 data\\0 (or data with subdirectory)\n    //                   arc\n    //                     hive\\0\n    //                       maps\\0 (or folder data)\n    //                         file.bmp\n    //\n\n    LPBYTE CapturePathEntry(TVFS_PATH_TABLE_ENTRY & PathEntry, LPBYTE pbPathTablePtr, LPBYTE pbPathTableEnd)\n    {\n        // Reset the path entry structure\n        PathEntry.pbNamePtr = pbPathTablePtr;\n        PathEntry.pbNameEnd = pbPathTablePtr;\n        PathEntry.NodeFlags = 0;\n        PathEntry.NodeValue = 0;\n\n        // Zero before the name means prefix path separator\n        if (pbPathTablePtr < pbPathTableEnd && pbPathTablePtr[0] == 0)\n        {\n            PathEntry.NodeFlags |= TVFS_PTE_PATH_SEPARATOR_PRE;\n            pbPathTablePtr++;\n        }\n\n        // Capture the length of the name fragment\n        if (pbPathTablePtr < pbPathTableEnd && pbPathTablePtr[0] != 0xFF)\n        {\n            // Capture length of the name fragment\n            size_t nLength = *pbPathTablePtr++;\n\n            if ((pbPathTablePtr + nLength) > pbPathTableEnd)\n                return NULL;\n            PathEntry.pbNamePtr = pbPathTablePtr;\n            PathEntry.pbNameEnd = pbPathTablePtr + nLength;\n            pbPathTablePtr += nLength;\n        }\n\n        // Zero after the name means postfix path separator\n        if (pbPathTablePtr < pbPathTableEnd && pbPathTablePtr[0] == 0)\n        {\n            PathEntry.NodeFlags |= TVFS_PTE_PATH_SEPARATOR_POST;\n            pbPathTablePtr++;\n        }\n\n        if (pbPathTablePtr < pbPathTableEnd)\n        {\n            // Check for node value\n            if (pbPathTablePtr[0] == 0xFF)\n            {\n                if ((pbPathTablePtr + 1 + sizeof(DWORD)) > pbPathTableEnd)\n                    return NULL;\n                PathEntry.NodeValue = ConvertBytesToInteger_4(pbPathTablePtr + 1);\n                PathEntry.NodeFlags |= TVFS_PTE_NODE_VALUE;\n                pbPathTablePtr = pbPathTablePtr + 1 + sizeof(DWORD);\n            }\n\n            // Non-0xFF after the name means path separator after\n            else\n            {\n                PathEntry.NodeFlags |= TVFS_PTE_PATH_SEPARATOR_POST;\n                assert(pbPathTablePtr[0] != 0);\n            }\n        }\n\n        return pbPathTablePtr;\n    }\n\n    bool IsVfsFileEKey(TCascStorage * hs, LPBYTE EKey, size_t EKeyLength)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        size_t ItemCount = hs->VfsRootList.ItemCount();\n\n        // Search the array\n        for (size_t i = 0; i < ItemCount; i++)\n        {\n            pCKeyEntry = (PCASC_CKEY_ENTRY)hs->VfsRootList.ItemAt(i);\n            if (pCKeyEntry != NULL)\n            {\n                if (!memcmp(pCKeyEntry->EKey, EKey, EKeyLength))\n                    return true;\n            }\n        }\n\n        // Not found in the VFS list\n        return false;\n    }\n\n    // This function verifies whether a file is actually a sub-directory.\n    // If yes, it contains just another \"TVFS\" virtual file system, just like the ROOT file.\n    DWORD IsVfsSubDirectory(TCascStorage * hs,  TVFS_DIRECTORY_HEADER & DirHeader, TVFS_DIRECTORY_HEADER & SubHeader, LPBYTE EKey, DWORD dwFileSize)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        LPBYTE pbVfsData = NULL;\n        DWORD cbVfsData = dwFileSize;\n        DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n        // Verify whether the EKey is in the list of VFS root files\n        if(IsVfsFileEKey(hs, EKey, DirHeader.EKeySize))\n        {\n            // Locate the CKey entry\n            if((pCKeyEntry = FindCKeyEntry_EKey(hs, EKey)) != NULL)\n            {\n                // Load the entire file into memory\n                pbVfsData = LoadInternalFileToMemory(hs, pCKeyEntry, &cbVfsData);\n                if (pbVfsData && cbVfsData)\n                {\n                    // Capture the file folder. This also serves as test\n                    dwErrCode = CaptureDirectoryHeader(SubHeader, pbVfsData, pbVfsData + cbVfsData);\n                    if (dwErrCode == ERROR_SUCCESS)\n                        return dwErrCode;\n\n                    // Clear the captured header\n                    memset(&SubHeader, 0, sizeof(TVFS_DIRECTORY_HEADER));\n                    CASC_FREE(pbVfsData);\n                }\n            }\n        }\n\n        return dwErrCode;\n    }\n\n    PCASC_CKEY_ENTRY InsertUnknownCKeyEntry(TCascStorage * hs, LPBYTE pbEKey, size_t cbEKey, DWORD ContentSize)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n\n        // Insert a new entry to the array. DO NOT ALLOW enlarge array here\n        pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false);\n        if(pCKeyEntry != NULL)\n        {\n            memset(pCKeyEntry, 0, sizeof(CASC_CKEY_ENTRY));\n            memcpy(pCKeyEntry->EKey, pbEKey, cbEKey);\n            pCKeyEntry->StorageOffset = CASC_INVALID_OFFS64;\n            pCKeyEntry->ContentSize = ContentSize;\n            pCKeyEntry->EncodedSize = CASC_INVALID_SIZE;\n            pCKeyEntry->Flags = CASC_CE_HAS_EKEY | CASC_CE_HAS_EKEY_PARTIAL;\n            pCKeyEntry->SpanCount = 1;\n\n            // Copy the information from index files to the CKey entry\n            CopyEKeyEntry(hs, pCKeyEntry);\n\n            // Insert the item into EKey map\n            hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey);\n        }\n\n        return pCKeyEntry;\n    }\n\n    void InsertRootVfsEntry(TCascStorage * hs, LPBYTE pbCKey, const char * szFormat, size_t nIndex)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        char szFileName[0x20];\n\n        // The CKey entry must exist\n        if((pCKeyEntry = FindCKeyEntry_CKey(hs, pbCKey)) != NULL)\n        {\n            CascStrPrintf(szFileName, _countof(szFileName), szFormat, nIndex);\n            Insert(szFileName, pCKeyEntry);\n        }\n    }\n\n    DWORD ParsePathFileTable(TCascStorage * hs, TVFS_DIRECTORY_HEADER & DirHeader, CASC_PATH<char> & PathBuffer, LPBYTE pbPathTablePtr, LPBYTE pbPathTableEnd)\n    {\n        TVFS_DIRECTORY_HEADER SubHeader;\n        TVFS_PATH_TABLE_ENTRY PathEntry;\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        LPBYTE pbVfsSpanEntry;\n        size_t  nSavePos = PathBuffer.Save();\n        DWORD dwSpanCount;\n        DWORD dwErrCode;\n\n        // Sanity check\n        assert(SpanArray.IsInitialized());\n\n        // Parse the file table\n        while(pbPathTablePtr < pbPathTableEnd)\n        {\n            // Capture the single path table entry\n            pbPathTablePtr = CapturePathEntry(PathEntry, pbPathTablePtr, pbPathTableEnd);\n            if(pbPathTablePtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // Append the node name to the total path. Also add backslash, if it's a folder\n            PathBuffer_AppendNode(PathBuffer, PathEntry);\n\n            // Folder component\n            if (PathEntry.NodeFlags & TVFS_PTE_NODE_VALUE)\n            {\n                // If the TVFS_FOLDER_NODE is set, then the path node is a directory,\n                // with its data immediately following the path node. Lower 31 bits of NodeValue\n                // contain the length of the directory (including the NodeValue!)\n                if (PathEntry.NodeValue & TVFS_FOLDER_NODE)\n                {\n                    LPBYTE pbDirectoryEnd = pbPathTablePtr + (PathEntry.NodeValue & TVFS_FOLDER_SIZE_MASK) - sizeof(DWORD);\n\n                    // Check the available data\n                    assert((PathEntry.NodeValue & TVFS_FOLDER_SIZE_MASK) >= sizeof(DWORD));\n\n                    // Recursively call the folder parser on the same file\n                    dwErrCode = ParsePathFileTable(hs, DirHeader, PathBuffer, pbPathTablePtr, pbDirectoryEnd);\n                    if (dwErrCode != ERROR_SUCCESS)\n                        return dwErrCode;\n\n                    // Skip the directory data\n                    pbPathTablePtr = pbDirectoryEnd;\n                }\n                else\n                {\n                    // Capture the number of VFS spans\n                    pbVfsSpanEntry = CaptureVfsSpanCount(DirHeader, PathEntry.NodeValue, dwSpanCount);\n                    if(pbVfsSpanEntry == NULL)\n                        return ERROR_BAD_FORMAT;\n\n                    // If it's one span, it's either a subdirectory or an entire file\n                    if(dwSpanCount == 1)\n                    {\n                        CASC_CKEY_ENTRY SpanEntry;\n\n                        // Capture the single span entry\n                        pbVfsSpanEntry = CaptureVfsSpanEntries(DirHeader, pbVfsSpanEntry, &SpanEntry, 1);\n                        if(pbVfsSpanEntry == NULL)\n                            return ERROR_FILE_CORRUPT;\n\n                        // Find the CKey entry\n                        pCKeyEntry = FindCKeyEntry_EKey(hs, SpanEntry.EKey);\n                        if(pCKeyEntry == NULL)\n                        {\n                            // Some files are in the ROOT manifest even if they are not in ENCODING and DOWNLOAD.\n                            // Example: \"2018 - New CASC\\00001\", file \"DivideAndConquer.w3m:war3mapMap.blp\"\n                            pCKeyEntry = InsertUnknownCKeyEntry(hs, SpanEntry.EKey, DirHeader.EKeySize, SpanEntry.ContentSize);\n                            if(pCKeyEntry == NULL)\n                            {\n                                return ERROR_NOT_ENOUGH_MEMORY;\n                            }\n                        }\n\n                        // We need to check whether this is another TVFS directory file\n                        if (IsVfsSubDirectory(hs, DirHeader, SubHeader, SpanEntry.EKey, SpanEntry.ContentSize) == ERROR_SUCCESS)\n                        {\n                            // Add colon (':')\n                            PathBuffer.AppendChar(':');\n\n                            // The file content size should already be there\n                            assert(pCKeyEntry->ContentSize == SpanEntry.ContentSize);\n                            FileTree.InsertByName(pCKeyEntry, PathBuffer);\n\n                            // Parse the subdir\n                            ParseDirectoryData(hs, SubHeader, PathBuffer);\n                            CASC_FREE(SubHeader.pbDirectoryData);\n                        }\n                        else\n                        {\n                            // If the content content size is not there, supply it now\n                            if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE)\n                                pCKeyEntry->ContentSize = SpanEntry.ContentSize;\n                            FileTree.InsertByName(pCKeyEntry, PathBuffer);\n                        }\n                    }\n                    else\n                    {\n                        PCASC_CKEY_ENTRY pSpanEntries;\n                        PCASC_FILE_NODE pFileNode;\n                        USHORT RefCount;\n                        bool bFilePresent = true;\n\n                        //\n                        // Need to support multi-span files, possibly lager than 4 GB\n                        // Example: CoD: Black Ops 4, file \"zone/base.xpak\" 0x16 spans, over 15 GB size\n                        //\n\n                        // Allocate buffer for all span entries\n                        pSpanEntries = (PCASC_CKEY_ENTRY)SpanArray.Insert(dwSpanCount);\n                        if(pSpanEntries == NULL)\n                            return ERROR_NOT_ENOUGH_MEMORY;\n\n                        // Capture all span entries\n                        pbVfsSpanEntry = CaptureVfsSpanEntries(DirHeader, pbVfsSpanEntry, pSpanEntries, dwSpanCount);\n                        if(pbVfsSpanEntry == NULL)\n                            return ERROR_FILE_CORRUPT;\n\n                        // Parse all span entries\n                        for(DWORD dwSpanIndex = 0; dwSpanIndex < dwSpanCount; dwSpanIndex++)\n                        {\n                            PCASC_CKEY_ENTRY pSpanEntry = pSpanEntries + dwSpanIndex;\n\n                            // Find the CKey entry\n                            pCKeyEntry = FindCKeyEntry_EKey(hs, pSpanEntries[dwSpanIndex].EKey);\n                            if(pCKeyEntry == NULL)\n                            {\n                                bFilePresent = false;\n                                break;\n                            }\n\n                            // Supply the content size\n                            if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE)\n                                pCKeyEntry->ContentSize = pSpanEntry->ContentSize;\n                            assert(pCKeyEntry->ContentSize == pSpanEntry->ContentSize);\n\n                            // Fill-in the span entry\n                            if(dwSpanIndex == 0)\n                            {\n                                pCKeyEntry->SpanCount = (BYTE)(dwSpanCount);\n                                pCKeyEntry->RefCount++;\n                            }\n                            else\n                            {\n                                // Mark the CKey entry as a file span. Note that a CKey entry\n                                // can actually be both a file span and a standalone file:\n                                // * zone/zm_red.xpak - { zone/zm_red.xpak_1, zone/zm_red.xpak_2, ..., zone/zm_red.xpak_6 }\n                                pCKeyEntry->Flags |= CASC_CE_FILE_SPAN;\n                            }\n\n                            // Copy all from the existing CKey entry\n                            memcpy(pSpanEntry, pCKeyEntry, sizeof(CASC_CKEY_ENTRY));\n                        }\n\n                        // Do nothing if the file is not present locally\n                        if(bFilePresent)\n                        {\n                            // Insert a new file node that will contain pointer to the span entries\n                            RefCount = pSpanEntries->RefCount;\n                            pFileNode = FileTree.InsertByName(pSpanEntries, PathBuffer);\n                            pSpanEntries->RefCount = RefCount;\n\n                            if(pFileNode == NULL)\n                                return ERROR_NOT_ENOUGH_MEMORY;\n                        }\n                    }\n                }\n\n                // Reset the position of the path buffer\n                PathBuffer.Restore(nSavePos);\n            }\n        }\n\n        // Return the total number of entries\n        return ERROR_SUCCESS;\n    }\n\n    DWORD ParseDirectoryData(TCascStorage * hs, TVFS_DIRECTORY_HEADER & DirHeader, CASC_PATH<char> & PathBuffer)\n    {\n        LPBYTE pbRootDirectory = DirHeader.pbDirectoryData + DirHeader.PathTableOffset;\n        LPBYTE pbRootDirPtr = pbRootDirectory;\n        LPBYTE pbRootDirEnd = pbRootDirPtr + DirHeader.PathTableSize;\n        DWORD dwNodeValue = 0;\n\n        // Most usually, there is a root directory in the folder\n        if((pbRootDirPtr + 1 + sizeof(DWORD)) < pbRootDirEnd)\n        {\n            //\n            // The structure of the root directory\n            // -----------------------------------\n            // 1byte   0xFF\n            // 4bytes  NodeValue (BigEndian). The most significant bit is set\n            //          - Lower 31 bits contain length of the directory data, including NodeValue\n            //\n\n            if(pbRootDirPtr[0] == 0xFF)\n            {\n                // Get the NodeValue and check its highest bit\n                if(CaptureInteger32_BE(pbRootDirPtr + 1, pbRootDirEnd, &dwNodeValue) == NULL || (dwNodeValue & TVFS_FOLDER_NODE) == 0)\n                    return ERROR_BAD_FORMAT;\n                \n                // Get the range of the root directory\n                pbRootDirEnd = pbRootDirPtr + 1 + (dwNodeValue & TVFS_FOLDER_SIZE_MASK);\n                pbRootDirPtr = pbRootDirPtr + 1 + sizeof(DWORD);\n\n                // Check the directory\n                if(pbRootDirEnd > (pbRootDirectory + DirHeader.PathTableSize))\n                    return ERROR_BAD_FORMAT;\n            }\n        }\n\n        // Now go parse the path file table\n        return ParsePathFileTable(hs, DirHeader, PathBuffer, pbRootDirPtr, pbRootDirEnd);\n    }\n\n    DWORD Load(TCascStorage * hs, TVFS_DIRECTORY_HEADER & RootHeader)\n    {\n        CASC_PATH<char> PathBuffer;\n        DWORD dwErrCode;\n\n        // Save the length of the key\n        FileTree.SetKeyLength(RootHeader.EKeySize);\n\n        // Initialize the array of span entries\n        dwErrCode = SpanArray.Create(sizeof(CASC_CKEY_ENTRY), 0x100);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // Insert the main VFS root file as named entry\n        InsertRootVfsEntry(hs, hs->VfsRoot.CKey, \"vfs-root\", 0);\n\n        // Insert all VFS roots folders as files\n        //for(size_t i = 0; i < hs->VfsRootList.ItemCount(); i++)\n        //{\n        //    pCKeyEntry = (PCASC_CKEY_ENTRY)hs->VfsRootList.ItemAt(i);\n        //    InsertRootVfsEntry(hs, pCKeyEntry->CKey, \"vfs-%u\", i+1);\n        //}\n\n        // Parse the entire directory data\n        return ParseDirectoryData(hs, RootHeader, PathBuffer);\n    }\n\n    CASC_ARRAY SpanArray;           // Array of CASC_SPAN_ENTRY for all multi-span files\n};\n\n//-----------------------------------------------------------------------------\n// Public functions - TVFS root\n\nDWORD RootHandler_CreateTVFS(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)\n{\n    TRootHandler_TVFS * pRootHandler = NULL;\n    TVFS_DIRECTORY_HEADER RootHeader;\n    DWORD dwErrCode;\n\n    // Capture the entire root directory\n    dwErrCode = TRootHandler_TVFS::CaptureDirectoryHeader(RootHeader, pbRootFile, pbRootFile + cbRootFile);\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // Allocate the root handler object\n        pRootHandler = new TRootHandler_TVFS();\n        if(pRootHandler != NULL)\n        {\n            // Load the root directory. If load failed, we free the object\n            dwErrCode = pRootHandler->Load(hs, RootHeader);\n            if(dwErrCode != ERROR_SUCCESS)\n            {\n                delete pRootHandler;\n                pRootHandler = NULL;\n            }\n        }\n    }\n\n    // Assign the root directory (or NULL) and return error\n    hs->pRootHandler = pRootHandler;\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_Text.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_Text.cpp                  Copyright (c) Ladislav Zezula 2017 */\n/*---------------------------------------------------------------------------*/\n/* Support for generic ROOT handler with mapping of FileName -> CKey         */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 28.10.15  1.00  Lad  The first version of CascRootFile_Text.cpp           */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Handler definitions for Starcraft I root file\n\nstruct TRootHandler_SC1 : public TFileTreeRoot\n{\n    public:\n\n    TRootHandler_SC1() : TFileTreeRoot(0)\n    {\n        // We have file names and return CKey as result of search\n        dwFeatures |= (CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY);\n    }\n\n    static bool IsRootFile(LPBYTE pbRootFile, DWORD cbRootFile)\n    {\n        CASC_CSV Csv(1, false);\n        size_t nColumns;\n        bool bResult = false;\n\n        // Get the first line from the listfile\n        if(Csv.Load(pbRootFile, cbRootFile) == ERROR_SUCCESS)\n        {\n            // There must be 2 or 3 elements\n            nColumns = Csv[CSV_ZERO].GetColumnCount();\n            if (nColumns == 2 || nColumns == 3)\n            {\n                const CASC_CSV_COLUMN & FileName = Csv[CSV_ZERO][CSV_ZERO];\n                const CASC_CSV_COLUMN & CKeyStr = Csv[CSV_ZERO][1];\n\n                bResult = (FileName.szValue && CKeyStr.szValue && CKeyStr.nLength == MD5_STRING_SIZE);\n            }\n        }\n\n        // We need to reset the listfile to the begin position\n        return bResult;\n    }\n\n    DWORD Load(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        CASC_CSV Csv(0, false);\n        BYTE CKey[MD5_HASH_SIZE];\n        DWORD dwErrCode;\n\n        // Parse the ROOT file first in order to see whether we have the correct format\n        dwErrCode = Csv.Load(pbRootFile, cbRootFile);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Parse all lines\n            while(Csv.LoadNextLine())\n            {\n                const CASC_CSV_COLUMN & FileName = Csv[CSV_ZERO][CSV_ZERO];\n                const CASC_CSV_COLUMN & CKeyStr = Csv[CSV_ZERO][1];\n\n                // Convert the CKey to binary\n                if(BinaryFromString(CKeyStr.szValue, MD5_STRING_SIZE, CKey) == ERROR_SUCCESS)\n                {\n                    // Verify whether it is a known entry\n                    if((pCKeyEntry = FindCKeyEntry_CKey(hs, CKey)) != NULL)\n                    {\n                        // Insert the FileName+CKey to the file tree\n                        FileTree.InsertByName(pCKeyEntry, FileName.szValue);\n                    }\n                }\n            }\n        }\n\n        return dwErrCode;\n    }\n};\n\n//-----------------------------------------------------------------------------\n// Public functions\n\n//\n// Starcraft ROOT file is a text file with the following format:\n// HD2/portraits/NBluCrit/NLCFID01.webm|c2795b120592355d45eba9cdc37f691e\n// locales/enUS/Assets/campaign/EXPZerg/Zerg08/staredit/wav/zovtra01.ogg|316b0274bf2dabaa8db60c3ff1270c85\n// locales/zhCN/Assets/sound/terran/ghost/tghdth01.wav|6637ed776bd22089e083b8b0b2c0374c\n//\n\nDWORD RootHandler_CreateStarcraft1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)\n{\n    TRootHandler_SC1 * pRootHandler = NULL;\n    DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n    // Verify whether this looks like a Starcraft I root file\n    if(TRootHandler_SC1::IsRootFile(pbRootFile, cbRootFile))\n    {\n        // Allocate the root handler object\n        pRootHandler = new TRootHandler_SC1();\n        if(pRootHandler != NULL)\n        {\n            // Load the root directory. If load failed, we free the object\n            dwErrCode = pRootHandler->Load(hs, pbRootFile, cbRootFile);\n            if(dwErrCode != ERROR_SUCCESS)\n            {\n                delete pRootHandler;\n                pRootHandler = NULL;\n            }\n        }\n    }\n\n    // Assign the root directory (or NULL) and return error\n    hs->pRootHandler = pRootHandler;\n    return dwErrCode;\n}\n"
  },
  {
    "path": "deps/CascLib/src/CascRootFile_WoW.cpp",
    "content": "/*****************************************************************************/\n/* CascRootFile_WoW.cpp                   Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Storage functions for CASC                                                */\n/* Note: WoW offsets refer to WoW.exe 6.0.3.19116 (32-bit)                   */\n/* SHA1: c10e9ffb7d040a37a356b96042657e1a0c95c0dd                            */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of CascRootFile_WoW.cpp            */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"CascLib.h\"\n#include \"CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local structures\n\n#define ROOT_SEARCH_PHASE_INITIALIZING  0\n#define ROOT_SEARCH_PHASE_LISTFILE      1\n#define ROOT_SEARCH_PHASE_NAMELESS      2\n#define ROOT_SEARCH_PHASE_FINISHED      3\n\n// Known dwRegion values returned from sub_661316 (7.0.3.22210 x86 win), also referred by lua GetCurrentRegion\n#define WOW_REGION_US              0x01\n#define WOW_REGION_KR              0x02\n#define WOW_REGION_EU              0x03\n#define WOW_REGION_TW              0x04\n#define WOW_REGION_CN              0x05\n\ntypedef enum _ROOT_FORMAT\n{\n    RootFormatWoW6x,                            // WoW 6.x - 8.1.x\n    RootFormatWoW82                             // WoW 8.2 or newer\n} ROOT_FORMAT, *PROOT_FORMAT;\n\n// ROOT file header, since 8.2\ntypedef struct _FILE_ROOT_HEADER_82\n{\n    DWORD Signature;                            // Must be CASC_WOW82_ROOT_SIGNATURE\n    DWORD TotalFiles;\n    DWORD FilesWithNameHash;\n} FILE_ROOT_HEADER_82, *PFILE_ROOT_HEADER_82;\n\n// On-disk version of root group. A root group contains a group of file\n// with the same locale and file flags\ntypedef struct _FILE_ROOT_GROUP_HEADER\n{\n    DWORD NumberOfFiles;                        // Number of entries\n    DWORD ContentFlags;\n    DWORD LocaleFlags;                          // File locale mask (CASC_LOCALE_XXX)\n\n    // Followed by a block of file data IDs (count: NumberOfFiles)\n    // Followed by the MD5 and file name hash (count: NumberOfFiles)\n\n} FILE_ROOT_GROUP_HEADER, *PFILE_ROOT_GROUP_HEADER;\n\n// On-disk version of root entry. Only present in versions 6.x - 8.1.xx\n// Each root entry represents one file in the CASC storage\n// In WoW 8.2 and newer, CKey and FileNameHash are split into separate arrays\n// and FileNameHash is optional\ntypedef struct _FILE_ROOT_ENTRY\n{\n    CONTENT_KEY CKey;                           // MD5 of the file\n    ULONGLONG FileNameHash;                     // Jenkins hash of the file name\n\n} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY;\n\ntypedef struct _FILE_ROOT_GROUP\n{\n    FILE_ROOT_GROUP_HEADER Header;\n    PDWORD FileDataIds;                         // Pointer to the array of File Data IDs\n\n    PFILE_ROOT_ENTRY pRootEntries;              // Valid for WoW 6.x - 8.1.x\n    PCONTENT_KEY pCKeyEntries;                  // Valid for WoW 8.2 or newer\n    PULONGLONG pHashes;                         // Valid for WoW 8.2 or newer (optional)\n\n} FILE_ROOT_GROUP, *PFILE_ROOT_GROUP;\n\n//-----------------------------------------------------------------------------\n// TRootHandler_WoW interface / implementation\n\n#define FTREE_FLAGS_WOW (FTREE_FLAG_USE_DATA_ID | FTREE_FLAG_USE_LOCALE_FLAGS | FTREE_FLAG_USE_CONTENT_FLAGS)\n\nstruct TRootHandler_WoW : public TFileTreeRoot\n{\n    public:\n\n    TRootHandler_WoW(ROOT_FORMAT RFormat, DWORD HashlessFileCount) : TFileTreeRoot(FTREE_FLAGS_WOW)\n    {\n        // Turn off the \"we know file names\" bit \n        FileCounterHashless = HashlessFileCount;\n        FileCounter = 0;\n        RootFormat = RFormat;\n\n        // Update the flags based on format\n        switch(RootFormat)\n        {\n            case RootFormatWoW6x:\n                dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_FNAME_HASHES | CASC_FEATURE_FILE_DATA_IDS | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS;\n                break;\n\n            case RootFormatWoW82:\n                dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_FNAME_HASHES_OPTIONAL | CASC_FEATURE_FILE_DATA_IDS | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS;\n                break;\n        }\n    }\n\n    static LPBYTE CaptureRootHeader(FILE_ROOT_HEADER_82 & RootHeader, LPBYTE pbRootPtr, LPBYTE pbRootEnd)\n    {\n        // Validate the root file header\n        if((pbRootPtr + sizeof(FILE_ROOT_HEADER_82)) >= pbRootEnd)\n            return NULL;\n        memcpy(&RootHeader, pbRootPtr, sizeof(FILE_ROOT_HEADER_82));\n\n        // Verify the root file header\n        if(RootHeader.Signature != CASC_WOW82_ROOT_SIGNATURE)\n            return NULL;\n        if(RootHeader.FilesWithNameHash > RootHeader.TotalFiles)\n            return NULL;\n\n        return pbRootPtr + sizeof(FILE_ROOT_HEADER_82);\n    }\n\n    LPBYTE CaptureRootGroup(FILE_ROOT_GROUP & RootGroup, LPBYTE pbRootPtr, LPBYTE pbRootEnd)\n    {\n        // Reset the entire root group structure\n        memset(&RootGroup, 0, sizeof(FILE_ROOT_GROUP));\n\n        // Validate the locale block header\n        if((pbRootPtr + sizeof(FILE_ROOT_GROUP_HEADER)) >= pbRootEnd)\n            return NULL;\n        memcpy(&RootGroup.Header, pbRootPtr, sizeof(FILE_ROOT_GROUP_HEADER));\n        pbRootPtr = pbRootPtr + sizeof(FILE_ROOT_GROUP_HEADER);\n\n        // Validate the array of file data IDs\n        if((pbRootPtr + (sizeof(DWORD) * RootGroup.Header.NumberOfFiles)) >= pbRootEnd)\n            return NULL;\n        RootGroup.FileDataIds = (PDWORD)pbRootPtr;\n        pbRootPtr = pbRootPtr + (sizeof(DWORD) * RootGroup.Header.NumberOfFiles);\n\n        // Add the number of files in this block to the number of files loaded\n        FileCounter += RootGroup.Header.NumberOfFiles;\n\n        // Validate the array of root entries\n        switch(RootFormat)\n        {\n            case RootFormatWoW6x:\n                if((pbRootPtr + (sizeof(FILE_ROOT_ENTRY) * RootGroup.Header.NumberOfFiles)) > pbRootEnd)\n                    return NULL;\n                RootGroup.pRootEntries = (PFILE_ROOT_ENTRY)pbRootPtr;\n\n                // Return the position of the next block\n                return pbRootPtr + (sizeof(FILE_ROOT_ENTRY) * RootGroup.Header.NumberOfFiles);\n\n            case RootFormatWoW82:\n                \n                // Verify the position of array of CONTENT_KEY\n                if((pbRootPtr + (sizeof(CONTENT_KEY) * RootGroup.Header.NumberOfFiles)) > pbRootEnd)\n                    return NULL;\n                RootGroup.pCKeyEntries = (PCONTENT_KEY)pbRootPtr;\n                pbRootPtr = pbRootPtr + (sizeof(CONTENT_KEY) * RootGroup.Header.NumberOfFiles);\n\n                // Also include array of file hashes\n                if(!(RootGroup.Header.ContentFlags & CASC_CFLAG_NO_NAME_HASH))\n                {\n                    if((pbRootPtr + (sizeof(ULONGLONG) * RootGroup.Header.NumberOfFiles)) > pbRootEnd)\n                        return NULL;\n                    RootGroup.pHashes = (PULONGLONG)pbRootPtr;\n                    pbRootPtr = pbRootPtr + (sizeof(ULONGLONG) * RootGroup.Header.NumberOfFiles);\n                }\n\n                return pbRootPtr;\n\n            default:\n                return NULL;\n        }\n    }\n\n    DWORD ParseWowRootFile_AddFiles_6x(TCascStorage * hs, FILE_ROOT_GROUP & RootGroup)\n    {\n        PFILE_ROOT_ENTRY pRootEntry = RootGroup.pRootEntries;\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        DWORD FileDataId = 0;\n\n        // Sanity check\n        assert(RootGroup.pRootEntries != NULL);\n\n        // WoW.exe (build 19116): Blocks with zero files are skipped\n        for(DWORD i = 0; i < RootGroup.Header.NumberOfFiles; i++, pRootEntry++)\n        {\n            // Set the file data ID\n            FileDataId = FileDataId + RootGroup.FileDataIds[i];\n//          BREAKIF(FileDataId == 2823765);\n\n            // Find the item in the central storage. Insert it to the tree\n            if((pCKeyEntry = FindCKeyEntry_CKey(hs, pRootEntry->CKey.Value)) != NULL)\n            {\n                if(pRootEntry->FileNameHash != 0)\n                {\n                    FileTree.InsertByHash(pCKeyEntry, pRootEntry->FileNameHash, FileDataId, RootGroup.Header.LocaleFlags, RootGroup.Header.ContentFlags);\n                }\n                else\n                {\n                    FileTree.InsertById(pCKeyEntry, FileDataId, RootGroup.Header.LocaleFlags, RootGroup.Header.ContentFlags);\n                }\n            }\n\n            // Update the file data ID\n            assert((FileDataId + 1) > FileDataId);\n            FileDataId++;\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    DWORD ParseWowRootFile_AddFiles_82(TCascStorage * hs, FILE_ROOT_GROUP & RootGroup)\n    {\n        PCASC_CKEY_ENTRY pCKeyEntry;\n        PCONTENT_KEY pCKey = RootGroup.pCKeyEntries;\n        DWORD FileDataId = 0;\n\n        // Sanity check\n        assert(RootGroup.pCKeyEntries != NULL);\n\n        // WoW.exe (build 19116): Blocks with zero files are skipped\n        for(DWORD i = 0; i < RootGroup.Header.NumberOfFiles; i++, pCKey++)\n        {\n            // Set the file data ID\n            FileDataId = FileDataId + RootGroup.FileDataIds[i];\n            //printf(\"File Data ID: %u\\n\", FileDataId);\n\n            // Find the item in the central storage. Insert it to the tree\n            if((pCKeyEntry = FindCKeyEntry_CKey(hs, pCKey->Value)) != NULL)\n            {\n                // If we know the file name hash, we're gonna insert it by hash AND file data id.\n                // If we don't know the hash, we're gonna insert it just by file data id.\n                if(RootGroup.pHashes != NULL && RootGroup.pHashes[i] != 0)\n                {\n                    FileTree.InsertByHash(pCKeyEntry, RootGroup.pHashes[i], FileDataId, RootGroup.Header.LocaleFlags, RootGroup.Header.ContentFlags);\n                }\n                else\n                {\n                    FileTree.InsertById(pCKeyEntry, FileDataId, RootGroup.Header.LocaleFlags, RootGroup.Header.ContentFlags);\n                }\n            }\n\n            // Update the file data ID\n            assert((FileDataId + 1) > FileDataId);\n            FileDataId++;\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    DWORD ParseWowRootFile_Level2(\n        TCascStorage * hs,\n        LPBYTE pbRootPtr,\n        LPBYTE pbRootEnd,\n        DWORD dwLocaleMask,\n        BYTE bOverrideLowViolence,\n        BYTE bAudioLocale)\n    {\n        FILE_ROOT_GROUP RootBlock;\n\n        // Reset the total file counter\n        FileCounter = 0;\n\n        // Now parse the root file\n        while(pbRootPtr < pbRootEnd)\n        {\n            //char szMessage[0x100];\n            //StringCchPrintfA(szMessage, _countof(szMessage), \"%p\\n\", (pbRootEnd - pbRootPtr));\n            //OutputDebugStringA(szMessage);\n\n            // Validate the file locale block\n            pbRootPtr = CaptureRootGroup(RootBlock, pbRootPtr, pbRootEnd);\n            if(pbRootPtr == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // WoW.exe (build 19116): Entries with flag 0x100 set are skipped\n            if(RootBlock.Header.ContentFlags & CASC_CFLAG_DONT_LOAD)\n                continue;\n\n            // WoW.exe (build 19116): Entries with flag 0x80 set are skipped if overrideArchive CVAR is set to FALSE (which is by default in non-chinese clients)\n            if((RootBlock.Header.ContentFlags & CASC_CFLAG_LOW_VIOLENCE) && bOverrideLowViolence == 0)\n                continue;\n\n            // WoW.exe (build 19116): Entries with (flags >> 0x1F) not equal to bAudioLocale are skipped\n            if((RootBlock.Header.ContentFlags >> 0x1F) != bAudioLocale)\n                continue;\n\n            // WoW.exe (build 19116): Locales other than defined mask are skipped too\n            if(RootBlock.Header.LocaleFlags != 0 && (RootBlock.Header.LocaleFlags & dwLocaleMask) == 0)\n                continue;\n\n            // Now call the custom function\n            switch(RootFormat)\n            {\n                case RootFormatWoW82:\n                    ParseWowRootFile_AddFiles_82(hs, RootBlock);\n                    break;\n\n                case RootFormatWoW6x:\n                    ParseWowRootFile_AddFiles_6x(hs, RootBlock);\n                    break;\n\n                default:\n                    return ERROR_NOT_SUPPORTED;\n            }\n        }\n\n        return ERROR_SUCCESS;\n    }\n\n    /*\n    #define CASC_LOCALE_BIT_ENUS            0x01\n    #define CASC_LOCALE_BIT_KOKR            0x02\n    #define CASC_LOCALE_BIT_RESERVED        0x03\n    #define CASC_LOCALE_BIT_FRFR            0x04\n    #define CASC_LOCALE_BIT_DEDE            0x05\n    #define CASC_LOCALE_BIT_ZHCN            0x06\n    #define CASC_LOCALE_BIT_ESES            0x07\n    #define CASC_LOCALE_BIT_ZHTW            0x08\n    #define CASC_LOCALE_BIT_ENGB            0x09\n    #define CASC_LOCALE_BIT_ENCN            0x0A\n    #define CASC_LOCALE_BIT_ENTW            0x0B\n    #define CASC_LOCALE_BIT_ESMX            0x0C\n    #define CASC_LOCALE_BIT_RURU            0x0D\n    #define CASC_LOCALE_BIT_PTBR            0x0E\n    #define CASC_LOCALE_BIT_ITIT            0x0F\n    #define CASC_LOCALE_BIT_PTPT            0x10\n\n        // dwLocale is obtained from a WOW_LOCALE_* to CASC_LOCALE_BIT_* mapping (sub_6615D0 in 7.0.3.22210 x86 win)\n        // because (ENUS, ENGB) and (PTBR, PTPT) pairs share the same value on WOW_LOCALE_* enum\n        // dwRegion is used to distinguish them\n        if(dwRegion == WOW_REGION_EU)\n        {\n            // Is this english version of WoW?\n            if(dwLocale == CASC_LOCALE_BIT_ENUS)\n            {\n                LoadWowRootFileLocales(hs, pbRootPtr, cbRootFile, CASC_LOCALE_ENGB, bOverrideArchive, bAudioLocale);\n                LoadWowRootFileLocales(hs, pbRootPtr, cbRootFile, CASC_LOCALE_ENUS, bOverrideArchive, bAudioLocale);\n                return ERROR_SUCCESS;\n            }\n\n            // Is this portuguese version of WoW?\n            if(dwLocale == CASC_LOCALE_BIT_PTBR)\n            {\n                LoadWowRootFileLocales(hs, pbRootPtr, cbRootFile, CASC_LOCALE_PTPT, bOverrideArchive, bAudioLocale);\n                LoadWowRootFileLocales(hs, pbRootPtr, cbRootFile, CASC_LOCALE_PTBR, bOverrideArchive, bAudioLocale);\n            }\n        }\n        else\n            LoadWowRootFileLocales(hs, pbRootPtr, cbRootFile, (1 << dwLocale), bOverrideArchive, bAudioLocale);\n    */\n\n    DWORD ParseWowRootFile_Level1(\n        TCascStorage * hs, \n        LPBYTE pbRootPtr,\n        LPBYTE pbRootEnd,\n        DWORD dwLocaleMask,\n        BYTE bAudioLocale)\n    {\n        DWORD dwErrCode;\n\n        // Load the locale as-is\n        dwErrCode = ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, dwLocaleMask, false, bAudioLocale);\n        if (dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n\n        // If we wanted enGB, we also load enUS for the missing files\n        if(dwLocaleMask == CASC_LOCALE_ENGB)\n            ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, CASC_LOCALE_ENUS, false, bAudioLocale);\n\n        if(dwLocaleMask == CASC_LOCALE_PTPT)\n            ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, CASC_LOCALE_PTBR, false, bAudioLocale);\n\n        return ERROR_SUCCESS;\n    }\n\n    // WoW.exe: 004146C7 (BuildManifest::Load)\n    DWORD Load(TCascStorage * hs, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwLocaleMask)\n    {\n        DWORD dwErrCode;\n\n        dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 0);\n        if (dwErrCode == ERROR_SUCCESS)\n            dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 1);\n\n        return dwErrCode;\n    }\n\n    // Search for files\n    PCASC_CKEY_ENTRY Search(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)\n    {\n        // If we have a listfile, we'll feed the listfile entries to the file tree\n        if(pSearch->pCache != NULL && pSearch->bListFileUsed == false)\n        {\n            PCASC_FILE_NODE pFileNode;\n            ULONGLONG FileNameHash;\n            size_t nLength;\n            DWORD FileDataId = CASC_INVALID_ID;\n            char szFileName[MAX_PATH];\n\n            if(RootFormat == RootFormatWoW82)\n            {\n                // Keep going through the listfile\n                for(;;)\n                {\n                    // Retrieve the next line from the list file. Ignore lines that are too long to fit in the buffer\n                    nLength = ListFile_GetNext(pSearch->pCache, szFileName, _countof(szFileName), &FileDataId);\n                    if(nLength == 0)\n                    {\n                        if(GetCascError() == ERROR_INSUFFICIENT_BUFFER)\n                            continue;\n                        break;\n                    }\n\n                    // Try to find the file node by file data id\n                    pFileNode = FileTree.FindById(FileDataId);\n                    if(pFileNode != NULL && pFileNode->NameLength == 0)\n                    {\n                        FileTree.SetNodeFileName(pFileNode, szFileName);\n                    }\n                }\n            }\n            else\n            {\n                // Keep going through the listfile\n                for(;;)\n                {\n                    // Retrieve the next line from the list file. Ignore lines that are too long to fit in the buffer\n                    nLength = ListFile_GetNextLine(pSearch->pCache, szFileName, _countof(szFileName));\n                    if(nLength == 0)\n                    {\n                        if(GetCascError() == ERROR_INSUFFICIENT_BUFFER)\n                            continue;\n                        break;\n                    }\n\n                    // Calculate the hash of the file name\n                    FileNameHash = CalcFileNameHash(szFileName);\n\n                    // Try to find the file node by file name hash\n                    pFileNode = FileTree.Find(FileNameHash);\n                    if(pFileNode != NULL && pFileNode->NameLength == 0)\n                    {\n                        FileTree.SetNodeFileName(pFileNode, szFileName);\n                    }\n                }\n            }\n            pSearch->bListFileUsed = true;\n        }\n\n        // Let the file tree root give us the file names\n        return TFileTreeRoot::Search(pSearch, pFindData);\n    }\n\n    ROOT_FORMAT RootFormat;                 // Root file format\n    DWORD FileCounterHashless;              // Number of files for which we don't have hash. Meaningless for WoW before 8.2\n    DWORD FileCounter;                      // Counter of loaded files. Only used during loading of ROOT file\n};\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nDWORD RootHandler_CreateWoW(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask)\n{\n    TRootHandler_WoW * pRootHandler = NULL;\n    FILE_ROOT_HEADER_82 RootHeader;\n    ROOT_FORMAT RootFormat = RootFormatWoW6x;\n    LPBYTE pbRootEnd = pbRootFile + cbRootFile;\n    LPBYTE pbRootPtr;\n    DWORD FileCounterHashless = 0;\n    DWORD dwErrCode = ERROR_BAD_FORMAT;\n\n    // Check for the new format (World of Warcraft 8.2, build 30170)\n    pbRootPtr = TRootHandler_WoW::CaptureRootHeader(RootHeader, pbRootFile, pbRootEnd);\n    if(pbRootPtr != NULL)\n    {\n        FileCounterHashless = RootHeader.TotalFiles - RootHeader.FilesWithNameHash;\n        RootFormat = RootFormatWoW82;\n        pbRootFile = pbRootPtr;\n    }\n\n    // Create the WOW handler\n    pRootHandler = new TRootHandler_WoW(RootFormat, FileCounterHashless);\n    if(pRootHandler != NULL)\n    {\n        // Load the root directory. If load failed, we free the object\n        dwErrCode = pRootHandler->Load(hs, pbRootFile, pbRootEnd, dwLocaleMask);\n        if(dwErrCode != ERROR_SUCCESS)\n        {\n            delete pRootHandler;\n            pRootHandler = NULL;\n        }\n    }\n\n    // Assign the root directory (or NULL) and return error\n    hs->pRootHandler = pRootHandler;\n    return dwErrCode;\n}\n\n"
  },
  {
    "path": "deps/CascLib/src/CascStructs.h",
    "content": "/*****************************************************************************/\n/* CascStructs.h                          Copyright (c) Ladislav Zezula 2019 */\n/*---------------------------------------------------------------------------*/\n/* On-disk structures for CASC storages                                      */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 28.04.19  1.00  Lad  The first version of CascStructs.h                   */\n/*****************************************************************************/\n\n#ifndef __CASC_STRUCTS_H__\n#define __CASC_STRUCTS_H__\n\n//-----------------------------------------------------------------------------\n// Common definitions\n\n#define CASC_INDEX_COUNT          0x10              // Number of index files\n#define CASC_CKEY_SIZE            0x10              // Size of the content key\n#define CASC_EKEY_SIZE            0x09              // Size of the encoded key\n#define CASC_MAX_DATA_FILES      0x100              // Maximum number of data files\n\n//-----------------------------------------------------------------------------\n// The index files structures\n\n#define FILE_INDEX_PAGE_SIZE    0x200               // Number of bytes in one page of EKey items\n\n// Structure describing the 32-bit block size and 32-bit Jenkins hash of the block\ntypedef struct _BLOCK_SIZE_AND_HASH\n{\n    DWORD cbBlockSize;\n    DWORD dwBlockHash;\n\n} BLOCK_SIZE_AND_HASH, *PBLOCK_SIZE_AND_HASH;\n\n// Checksum describing a block in the index file (v2)\ntypedef struct _FILE_INDEX_GUARDED_BLOCK\n{\n    DWORD BlockSize;\n    DWORD BlockHash;\n\n} FILE_INDEX_GUARDED_BLOCK, *PFILE_INDEX_GUARDED_BLOCK;\n\n// Structure of the header of the index files version 1\ntypedef struct _FILE_INDEX_HEADER_V1\n{\n    USHORT IndexVersion;                            // Must be 0x05\n    BYTE  BucketIndex;                              // The bucket index of this file; should be the same as the first byte of the hex filename. \n    BYTE  align_3;\n    DWORD field_4;\n    ULONGLONG field_8;\n    ULONGLONG SegmentSize;                          // Size of one data segment (aka data.### file)\n    BYTE  EncodedSizeLength;                        // Length, in bytes, of the EncodedSize in the EKey entry\n    BYTE  StorageOffsetLength;                      // Length, in bytes, of the StorageOffset field in the EKey entry\n    BYTE  EKeyLength;                               // Length of the encoded key (bytes)\n    BYTE  FileOffsetBits;                           // Number of bits of the archive file offset in StorageOffset field. Rest is data segment index\n    DWORD EKeyCount1;\n    DWORD EKeyCount2;\n    DWORD KeysHash1;\n    DWORD KeysHash2;\n    DWORD HeaderHash;\n} FILE_INDEX_HEADER_V1, *PFILE_INDEX_HEADER_V1;\n\ntypedef struct _FILE_INDEX_HEADER_V2\n{\n    USHORT IndexVersion;                            // Must be 0x07\n    BYTE   BucketIndex;                             // The bucket index of this file; should be the same as the first byte of the hex filename. \n    BYTE   ExtraBytes;                              // Unknown; must be 0\n    BYTE   EncodedSizeLength;                       // Length, in bytes, of the EncodedSize in the EKey entry\n    BYTE   StorageOffsetLength;                     // Length, in bytes, of the StorageOffset field in the EKey entry\n    BYTE   EKeyLength;                              // Length of the encoded key (bytes)\n    BYTE   FileOffsetBits;                          // Number of bits of the archive file offset in StorageOffset field. Rest is data segment index\n    ULONGLONG SegmentSize;                          // Size of one data segment (aka data.### file)\n\n} FILE_INDEX_HEADER_V2, *PFILE_INDEX_HEADER_V2;\n\n// The EKey entry from the \".idx\" files. Note that the lengths are optional and controlled by the FILE_INDEX_HEADER_Vx\ntypedef struct _FILE_EKEY_ENTRY\n{\n    BYTE EKey[CASC_EKEY_SIZE];                      // The first 9 bytes of the encoded key\n    BYTE FileOffsetBE[5];                           // Index of data file and offset within (big endian).\n    BYTE EncodedSize[4];                            // Encoded size (big endian). This is the size of encoded header, all file frame headers and all file frames\n} FILE_EKEY_ENTRY, *PFILE_EKEY_ENTRY;\n\n//-----------------------------------------------------------------------------\n// The archive index (md5.index) files structures\n// https://wowdev.wiki/TACT#CDN_File_Organization\n\ntemplate <int CHKSUM_LENGTH>\nstruct FILE_INDEX_FOOTER\n{\n    BYTE TocHash[MD5_HASH_SIZE];                    // Client tries to read with 0x10, then backs off in size when smaller\n    BYTE Version;                                   // Version of the index header\n    BYTE Reserved[2];                               // Length, in bytes, of the file offset field\n    BYTE PageSizeKB;                                // Length, in kilobytes, of the index page\n    BYTE OffsetBytes;                               // Normally 4 for archive indices, 6 for group indices, and 0 for loose file indices\n    BYTE SizeBytes;                                 // Normally 4\n    BYTE EKeyLength;                                // Normally 16\n    BYTE FooterHashBytes;                           // Normally 8, <= 0x10\n    BYTE ElementCount[4];                           // BigEndian in _old_ versions (e.g. 18179)\n    BYTE FooterHash[CHKSUM_LENGTH];\n};\n\n//-----------------------------------------------------------------------------\n// The ENCODING manifest structures\n//\n// The ENCODING file is in the form of:\n// * File header. Fixed length.\n// * Encoding Specification (ESpec) in the string form. Length is stored in FILE_ENCODING_HEADER::ESpecBlockSize\n// https://wowdev.wiki/CASC#Encoding\n// https://wowdev.wiki/TACT#Encoding_table\n//\n\n#define FILE_MAGIC_ENCODING 0x4E45                  // 'EN'\n\n// File header of the ENCODING manifest\ntypedef struct _FILE_ENCODING_HEADER\n{\n    USHORT Magic;                                   // FILE_MAGIC_ENCODING ('EN')\n    BYTE Version;                                   // Expected to be 1 by CascLib\n    BYTE CKeyLength;                                // The content key length in ENCODING file. Usually 0x10\n    BYTE EKeyLength;                                // The encoded key length in ENCODING file. Usually 0x10\n    BYTE CKeyPageSize[2];                           // Size of the CKey page, in KB (big-endian)\n    BYTE EKeyPageSize[2];                           // Size of the EKey page, in KB (big-endian)\n    BYTE CKeyPageCount[4];                          // Number of CKey pages in the table (big endian)\n    BYTE EKeyPageCount[4];                          // Number of EKey pages in the table (big endian)\n    BYTE field_11;                                  // Asserted to be zero by the agent\n    BYTE ESpecBlockSize[4];                         // Size of the ESpec string block\n\n} FILE_ENCODING_HEADER, *PFILE_ENCODING_HEADER;\n\n// Page header of the ENCODING manifest\ntypedef struct _FILE_CKEY_PAGE\n{\n    BYTE FirstKey[MD5_HASH_SIZE];                   // The first CKey/EKey in the segment\n    BYTE SegmentHash[MD5_HASH_SIZE];                // MD5 hash of the entire segment\n\n} FILE_CKEY_PAGE, *PFILE_CKEY_PAGE;\n\n// Single entry in the page\ntypedef struct _FILE_CKEY_ENTRY\n{\n    USHORT EKeyCount;                               // Number of EKeys\n    BYTE ContentSize[4];                            // Content file size (big endian)\n    BYTE CKey[CASC_CKEY_SIZE];                      // Content key. This is MD5 of the file content\n    BYTE EKey[CASC_CKEY_SIZE];                      // Encoded key. This is (trimmed) MD5 hash of the file header, containing MD5 hashes of all the logical blocks of the file\n\n} FILE_CKEY_ENTRY, *PFILE_CKEY_ENTRY;\n\ntypedef struct _FILE_ESPEC_ENTRY\n{\n    BYTE ESpecKey[MD5_HASH_SIZE];                   // The ESpec key of the file\n    BYTE ESpecIndexBE[4];                           // Index of ESPEC entry, assuming zero-terminated strings (big endian)\n    BYTE FileSizeBE[5];                             // Size of the encoded version of the file (big endian)\n\n} FILE_ESPEC_ENTRY, *PFILE_ESPEC_ENTRY;\n\n//-----------------------------------------------------------------------------\n// The DOWNLOAD manifest structures\n//\n// See https://wowdev.wiki/TACT#Download_manifest\n//\n\n#define FILE_MAGIC_DOWNLOAD 0x4C44                  // 'DL'\n\n// File header of the DOWNLOAD manifest\ntypedef struct _FILE_DOWNLOAD_HEADER\n{\n    USHORT Magic;                                   // FILE_MAGIC_DOWNLOAD ('DL')\n    BYTE Version;                                   // Expected to be 1 by CascLib\n    BYTE EKeyLength;                                // The content key length in DOWNLOAD file. Expected to be 0x10\n    BYTE EntryHasChecksum;                          // If nonzero, then the entry has checksum.\n    BYTE EntryCount[4];                             // Number of entries (big-endian)\n    BYTE TagCount[2];                               // Number of tag entries (big endian)\n\n    // Version 2 or newer\n    BYTE FlagByteSize;                              // Number of flag bytes\n\n    // Verion 3 or newer\n    BYTE BasePriority;\n    BYTE Unknown2[3];\n\n} FILE_DOWNLOAD_HEADER, *PFILE_DOWNLOAD_HEADER;\n\ntypedef struct _FILE_DOWNLOAD_ENTRY\n{\n    BYTE EKey[MD5_HASH_SIZE];                       // Encoding key (variable length)\n    BYTE FileSize[5];                               // File size\n    BYTE Priority;\n\n    // DWORD Checksum [optional]\n    // BYTE Flags;\n\n} FILE_DOWNLOAD_ENTRY, *PFILE_DOWNLOAD_ENTRY;\n\n//-----------------------------------------------------------------------------\n// The INSTALL manifest structures\n//\n// See https://wowdev.wiki/TACT#Install_manifest\n//\n\n#define FILE_MAGIC_INSTALL 0x4E49                   // 'IN'\n\n// File header of the INSTALL manifest\ntypedef struct _FILE_INSTALL_HEADER\n{\n    USHORT Magic;                                   // FILE_MAGIC_INSTALL ('DL')\n    BYTE Version;                                   // Expected to be 1 by CascLib\n    BYTE EKeyLength;                                // The content key length in INSTALL file. Expected to be 0x10\n    BYTE TagCount[2];                               // Number of tag entries (big endian)\n    BYTE EntryCount[4];                             // Number of entries (big-endian)\n\n} FILE_INSTALL_HEADER, *PFILE_INSTALL_HEADER;\n\n//-----------------------------------------------------------------------------\n// Data file structures\n\n#define BLTE_HEADER_SIGNATURE   0x45544C42          // 'BLTE' header in the data files\n#define BLTE_HEADER_DELTA       0x1E                // Distance of BLTE header from begin of the header area\n#define MAX_ENCODED_HEADER      0x1000              // Starting size for the frame headers\n\ntypedef struct _BLTE_HEADER\n{\n    BYTE  Signature[4];                             // Must be \"BLTE\"\n    BYTE  HeaderSize[4];                            // Header size in bytes (big endian)\n    BYTE  MustBe0F;                                 // Must be 0x0F. Optional, only if HeaderSize != 0\n    BYTE  FrameCount[3];                            // Frame count (big endian). Optional, only if HeaderSize != 0\n} BLTE_HEADER, *PBLTE_HEADER;\n\ntypedef struct _BLTE_ENCODED_HEADER\n{\n    // Header span.\n    ENCODED_KEY EKey;                               // Encoded key of the data beginning with \"BLTE\" (byte-reversed)\n    DWORD EncodedSize;                              // Encoded size of the data data beginning with \"BLTE\" (little endian)\n    BYTE  field_14;                                 // Seems to be 1 if the header span has no data\n    BYTE  field_15;                                 // Hardcoded to zero (Agent.exe 2.15.0.6296: 01370000->0148E2AA)\n    BYTE  JenkinsHash[4];                           // Jenkins hash (hashlittle2) of the preceding fields (EKey + EncodedSize + field_14 + field_15) (little endian)\n    BYTE  Checksum[4];                              // Checksum of the previous part. See \"VerifyHeaderSpan()\" for more information.\n\n    // BLTE header. Always present.\n    BYTE  Signature[4];                             // Must be \"BLTE\"\n    BYTE  HeaderSize[4];                            // Header size in bytes (big endian)\n    BYTE  MustBe0F;                                 // Must be 0x0F. Optional, only if HeaderSize != 0\n    BYTE  FrameCount[3];                            // Frame count (big endian). Optional, only if HeaderSize != 0\n} BLTE_ENCODED_HEADER, *PBLTE_ENCODED_HEADER;\n\ntypedef struct _BLTE_FRAME\n{\n    BYTE EncodedSize[4];                            // Encoded frame size (big endian)\n    BYTE ContentSize[4];                            // Content frame size (big endian)\n    CONTENT_KEY FrameHash;                          // Hash of the encoded frame\n\n} BLTE_FRAME, *PBLTE_FRAME;\n\n#endif  // __CASC_STRUCTS_H__\n\n"
  },
  {
    "path": "deps/CascLib/src/DllMain.c",
    "content": "/*****************************************************************************/\n/* DllMain.c                              Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Description: DllMain for the CascLib.dll library                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 26.10.15  1.00  Lad  The first version of DllMain.c                       */\n/*****************************************************************************/\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\n//-----------------------------------------------------------------------------\n// DllMain\n\nBOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)\n{\n    UNREFERENCED_PARAMETER(hInst);\n    UNREFERENCED_PARAMETER(dwReason);\n    UNREFERENCED_PARAMETER(lpReserved);\n\n    return TRUE;\n}\n"
  },
  {
    "path": "deps/CascLib/src/DllMain.def",
    "content": ";\n; Export file for Windows\n; Copyright (c) 2015 Ladislav Zezula\n; ladik@zezula.net\n;\n\nLIBRARY CascLib.dll\n\nEXPORTS\n\n    CascOpenStorage\n    CascOpenStorageEx\n    CascOpenOnlineStorage\n    CascGetStorageInfo\n    CascCloseStorage\n\n    CascOpenFile\n    CascOpenLocalFile\n    CascGetFileInfo\n    CascGetFileSize\n    CascGetFileSize64\n    CascSetFilePointer\n    CascSetFilePointer64\n    CascReadFile\n    CascCloseFile\n\n    CascFindFirstFile\n    CascFindNextFile\n    CascFindClose\n\n    CascAddEncryptionKey\n    CascAddStringEncryptionKey\n    CascFindEncryptionKey\n    CascGetNotFoundEncryptionKey\n\n    GetCascError\n    SetCascError\n"
  },
  {
    "path": "deps/CascLib/src/DllMain.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"afxres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// Neutral resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)\nLANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\n#pragma code_page(1250)\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION 1,50,0,205\n PRODUCTVERSION 1,50,0,205\n FILEFLAGSMASK 0x17L\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS 0x4L\n FILETYPE 0x0L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040504b0\"\n        BEGIN\n            VALUE \"Comments\", \"http://www.zezula.net/casc.html\"\n            VALUE \"FileDescription\", \"CascLib library for reading Blizzard CASC storages\"\n            VALUE \"FileVersion\", \"1, 50, 0, 205\"\n            VALUE \"InternalName\", \"CascLib\"\n            VALUE \"LegalCopyright\", \"Copyright (c) 2014 - 2021 Ladislav Zezula\"\n            VALUE \"OriginalFilename\", \"CascLib.dll\"\n            VALUE \"ProductName\", \"CascLib\"\n            VALUE \"ProductVersion\", \"1, 50, 0, 205\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x405, 1200\n    END\nEND\n\n#endif    // Neutral resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n/////////////////////////////////////////////////////////////////////////////\n// Czech (Czech Republic) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY)\nLANGUAGE LANG_CZECH, SUBLANG_DEFAULT\n#pragma code_page(1250)\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n2 TEXTINCLUDE \nBEGIN\n    \"#include \"\"afxres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE \nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n1 TEXTINCLUDE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n#endif    // Czech (Czech Republic) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n\n"
  },
  {
    "path": "deps/CascLib/src/common/Array.h",
    "content": "/*****************************************************************************/\n/* Array.h                                Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Common array implementation                                               */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 30.10.15  1.00  Lad  The first version of DynamicArray.h                  */\n/* 10.08.18  1.00  Lad  CLASS-ified, renamed to Array.h                      */\n/*****************************************************************************/\n\n#ifndef __CASC_ARRAY_H__\n#define __CASC_ARRAY_H__\n\n//-----------------------------------------------------------------------------\n// Structures\n\nclass CASC_ARRAY\n{\n    public:\n\n    CASC_ARRAY()\n    {\n        m_pItemArray = NULL;\n        m_ItemCountMax = 0;\n        m_ItemCount = 0;\n        m_ItemSize = 0;\n    }\n\n    ~CASC_ARRAY()\n    {\n        Free();\n    }\n\n    // Creates an array with a custom element type\n    template<typename TYPE>\n    int Create(size_t ItemCountMax)\n    {\n        return Create(sizeof(TYPE), ItemCountMax);\n    }\n\n    // Creates an array with a custom element size\n    int Create(size_t ItemSize, size_t ItemCountMax)\n    {\n        // Create the array\n        if ((m_pItemArray = CASC_ALLOC<BYTE>(ItemSize * ItemCountMax)) == NULL)\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        m_ItemCountMax = ItemCountMax;\n        m_ItemCount = 0;\n        m_ItemSize = ItemSize;\n        return ERROR_SUCCESS;\n    }\n\n    // Inserts one or more items; returns pointer to the first inserted item\n    void * Insert(size_t NewItemCount, bool bEnlargeAllowed = true)\n    {\n        void * pNewItems;\n\n        // Try to enlarge the buffer, if needed\n        if (!EnlargeArray(m_ItemCount + NewItemCount, bEnlargeAllowed))\n            return NULL;\n        pNewItems = m_pItemArray + (m_ItemCount * m_ItemSize);\n\n        // Increment the size of the array\n        m_ItemCount += NewItemCount;\n\n        // Return pointer to the new item\n        return pNewItems;\n    }\n\n    // Inserts one or more items; returns pointer to the first inserted item\n    void * Insert(const void * NewItems, size_t NewItemCount, bool bEnlargeAllowed = true)\n    {\n        void * pNewItem = Insert(NewItemCount, bEnlargeAllowed);\n\n        // Copy the item(s) to the array, if any\n        if (pNewItem && NewItems)\n            memcpy(pNewItem, NewItems, (NewItemCount * m_ItemSize));\n        return pNewItem;\n    }\n\n    // Returns an item at a given index\n    void * ItemAt(size_t ItemIndex)\n    {\n        return (ItemIndex < m_ItemCount) ? (m_pItemArray + (ItemIndex * m_ItemSize)) : NULL;\n    }\n\n    void * LastItem()\n    {\n        return m_pItemArray + (m_ItemCount * m_ItemSize);\n    }\n\n    // Inserts an item at a given index. If there is not enough items in the array,\n    // the array will be enlarged. Should any gaps to be created, the function will zero them\n    void * InsertAt(size_t ItemIndex)\n    {\n        LPBYTE pbLastItem;\n        LPBYTE pbNewItem;\n\n        // Make sure we have array large enough\n        if(!EnlargeArray(ItemIndex + 1, true))\n            return NULL;\n        \n        // Get the items range\n        pbLastItem = m_pItemArray + (m_ItemCount * m_ItemSize);\n        pbNewItem = m_pItemArray + (ItemIndex * m_ItemSize);\n        m_ItemCount = CASCLIB_MAX(m_ItemCount, ItemIndex+1);\n\n        // If we inserted an item past the current end, we need to clear the items in-between\n        if (pbNewItem > pbLastItem)\n        {\n            memset(pbLastItem, 0, (pbNewItem - pbLastItem));\n            m_ItemCount = ItemIndex + 1;\n        }\n\n        return pbNewItem;\n    }\n\n    // Returns index of an item\n    size_t IndexOf(const void * pItem)\n    {\n        LPBYTE pbItem = (LPBYTE)pItem;\n\n        assert((m_pItemArray <= pbItem) && (pbItem <= m_pItemArray + (m_ItemCount * m_ItemSize)));\n        assert(((pbItem - m_pItemArray) % m_ItemSize) == 0);\n\n        return ((pbItem - m_pItemArray) / m_ItemSize);\n     }\n\n    void * ItemArray()\n    {\n        return m_pItemArray;\n    }\n\n    size_t ItemCount()\n    {\n        return m_ItemCount;\n    }\n\n    size_t ItemCountMax()\n    {\n        return m_ItemCountMax;\n    }\n\n    size_t ItemSize()\n    {\n        return m_ItemSize;\n    }\n\n    bool IsInitialized()\n    {\n        return (m_pItemArray && m_ItemCountMax);\n    }\n\n    // Invalidates the entire array, but keeps memory allocated\n    void Reset()\n    {\n        memset(m_pItemArray, 0, m_ItemCountMax * m_ItemSize);\n        m_ItemCount = 0;\n    }\n\n    // Frees the array\n    void Free()\n    {\n        CASC_FREE(m_pItemArray);\n        m_ItemCountMax = m_ItemCount = m_ItemSize = 0;\n    }\n\n    protected:\n\n    bool EnlargeArray(size_t NewItemCount, bool bEnlargeAllowed)\n    {\n        LPBYTE NewItemArray;\n        size_t ItemCountMax;\n\n        // We expect the array to be already allocated\n        assert(m_pItemArray != NULL);\n        assert(m_ItemCountMax != 0);\n\n        // Shall we enlarge the table?\n        if (NewItemCount > m_ItemCountMax)\n        {\n            // Deny enlarge if not allowed\n            if(bEnlargeAllowed == false)\n                return false;\n\n            // Calculate new table size\n            ItemCountMax = m_ItemCountMax;\n            while (ItemCountMax < NewItemCount)\n                ItemCountMax = ItemCountMax << 1;\n\n            // Allocate new table\n            NewItemArray = CASC_REALLOC(BYTE, m_pItemArray, (ItemCountMax * m_ItemSize));\n            if (NewItemArray == NULL)\n                return false;\n\n            // Set the new table size\n            m_ItemCountMax = ItemCountMax;\n            m_pItemArray = NewItemArray;\n        }\n\n        return true;\n    }\n\n    LPBYTE m_pItemArray;                        // Pointer to item array\n    size_t m_ItemCountMax;                      // Maximum item count\n    size_t m_ItemCount;                         // Current item count\n    size_t m_ItemSize;                          // Size of an item\n};\n\n#endif // __CASC_ARRAY__\n"
  },
  {
    "path": "deps/CascLib/src/common/Common.cpp",
    "content": "/*****************************************************************************/\n/* CascCommon.cpp                         Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Common functions for CascLib                                              */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of CascCommon.cpp                  */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Conversion to uppercase/lowercase\n\n// Converts ASCII characters to lowercase\n// Converts backslash (0x5C) to normal slash (0x2F)\nunsigned char AsciiToLowerTable_Slash[256] =\n{\n    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,\n    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,\n    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,\n    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,\n    0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,\n    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,\n    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,\n    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,\n    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,\n    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,\n    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,\n    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,\n    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,\n    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,\n    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,\n    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF\n};\n\n// Converts ASCII characters to uppercase\n// Converts slash (0x2F) to backslash (0x5C)\nunsigned char AsciiToUpperTable_BkSlash[256] =\n{\n    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,\n    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,\n    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C,\n    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,\n    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,\n    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,\n    0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,\n    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,\n    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,\n    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,\n    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,\n    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,\n    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,\n    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,\n    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,\n    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF\n};\n\n// Converts ASCII characters to hexa digit\nunsigned char AsciiToHexTable[128] =\n{\n    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n};\n\nunsigned char IntToHexChar[] = \"0123456789abcdef\";\n\n//-----------------------------------------------------------------------------\n// GetCascError/SetCascError support for non-Windows platform\n\nstatic DWORD dwLastError = ERROR_SUCCESS;\n\nDWORD GetCascError()\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    return GetLastError();\n#else\n    return dwLastError;\n#endif\n}\n\nvoid SetCascError(DWORD dwErrCode)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    SetLastError(dwErrCode);\n#endif\n    dwLastError = dwErrCode;\n}\n\n//-----------------------------------------------------------------------------\n// Linear data stream manipulation\n\nLPBYTE CaptureInteger16_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue)\n{\n    // Is there enough data?\n    if((pbDataPtr + sizeof(USHORT)) > pbDataEnd)\n        return NULL;\n\n    // Convert data from Little endian to \n    PtrValue[0] = ConvertBytesToInteger_2(pbDataPtr);\n\n    // Return the pointer to data following after the integer\n    return pbDataPtr + sizeof(USHORT);\n}\n\nLPBYTE CaptureInteger32(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue)\n{\n    // Is there enough data?\n    if((pbDataPtr + sizeof(DWORD)) > pbDataEnd)\n        return NULL;\n\n    // Give data\n    PtrValue[0] = *(PDWORD)pbDataPtr;\n\n    // Return the pointer to data following after the integer\n    return pbDataPtr + sizeof(DWORD);\n}\n\nLPBYTE CaptureInteger32_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue)\n{\n    // Is there enough data?\n    if((pbDataPtr + sizeof(DWORD)) > pbDataEnd)\n        return NULL;\n\n    // Convert data from Little endian to \n    PtrValue[0] = ConvertBytesToInteger_4(pbDataPtr);\n\n    // Return the pointer to data following after the integer\n    return pbDataPtr + sizeof(DWORD);\n}\n\nLPBYTE CaptureByteArray(LPBYTE pbDataPtr, LPBYTE pbDataEnd, size_t nLength, LPBYTE pbOutput)\n{\n    // Is there enough data?\n    if((pbDataPtr + nLength) > pbDataEnd)\n        return NULL;\n\n    // Give data\n    memcpy(pbOutput, pbDataPtr, nLength);\n\n    // Return the pointer to data following after the integer\n    return pbDataPtr + nLength;\n}\n\nLPBYTE CaptureContentKey(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PCONTENT_KEY * PtrCKey)\n{\n    // Is there enough data?\n    if((pbDataPtr + sizeof(CONTENT_KEY)) > pbDataEnd)\n        return NULL;\n\n    // Give data\n    PtrCKey[0] = (PCONTENT_KEY)pbDataPtr;\n\n    // Return the pointer to data following after the integer\n    return pbDataPtr + sizeof(CONTENT_KEY);\n}\n\nLPBYTE CaptureEncodedKey(LPBYTE pbEKey, LPBYTE pbData, BYTE EKeyLength)\n{\n    // Two usual lengths of EKey\n    assert(EKeyLength == 0x09 || EKeyLength == 0x10);\n\n    // Copy the first 0x09 bytes\n    if(EKeyLength >= 0x09)\n    {\n        pbEKey[0x00] = pbData[0x00];\n        pbEKey[0x01] = pbData[0x01];\n        pbEKey[0x02] = pbData[0x02];\n        pbEKey[0x03] = pbData[0x03];\n        pbEKey[0x04] = pbData[0x04];\n        pbEKey[0x05] = pbData[0x05];\n        pbEKey[0x06] = pbData[0x06];\n        pbEKey[0x07] = pbData[0x07];\n        pbEKey[0x08] = pbData[0x08];\n\n        if(EKeyLength == 0x10)\n        {\n            pbEKey[0x09] = pbData[0x09];\n            pbEKey[0x0A] = pbData[0x0A];\n            pbEKey[0x0B] = pbData[0x0B];\n            pbEKey[0x0C] = pbData[0x0C];\n            pbEKey[0x0D] = pbData[0x0D];\n            pbEKey[0x0E] = pbData[0x0E];\n            pbEKey[0x0F] = pbData[0x0F];\n        }\n        else\n        {\n            pbEKey[0x09] = 0;\n            pbEKey[0x0A] = 0;\n            pbEKey[0x0B] = 0;\n            pbEKey[0x0C] = 0;\n            pbEKey[0x0D] = 0;\n            pbEKey[0x0E] = 0;\n            pbEKey[0x0F] = 0;\n        }\n    }\n\n    return pbData + EKeyLength;\n}\n\nLPBYTE CaptureArray_(LPBYTE pbDataPtr, LPBYTE pbDataEnd, LPBYTE * PtrArray, size_t ItemSize, size_t ItemCount)\n{\n    size_t ArraySize = ItemSize * ItemCount;\n\n    // Is there enough data?\n    if((pbDataPtr + ArraySize) > pbDataEnd)\n        return NULL;\n\n    // Give data\n    PtrArray[0] = pbDataPtr;\n\n    // Return the pointer to data following after the array\n    return pbDataPtr + ArraySize;\n}\n\n//-----------------------------------------------------------------------------\n// String copying and conversion\n\nvoid CascStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_t cchSource)\n{\n    size_t cchToCopy;\n\n    if (cchTarget > 0)\n    {\n        // Make sure we know the length\n        if (cchSource == -1)\n            cchSource = strlen(szSource);\n        cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource);\n\n        // Copy the string\n        memcpy(szTarget, szSource, cchToCopy);\n        szTarget[cchToCopy] = 0;\n    }\n}\n\nvoid CascStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource)\n{\n    size_t cchToCopy;\n\n    if (cchTarget > 0)\n    {\n        // Make sure we know the length\n        if (cchSource == -1)\n            cchSource = wcslen(szSource);\n        cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource);\n\n        wcstombs(szTarget, szSource, cchToCopy);\n        szTarget[cchToCopy] = 0;\n    }\n}\n\nvoid CascStrCopy(wchar_t * szTarget, size_t cchTarget, const char * szSource, size_t cchSource)\n{\n    size_t cchToCopy;\n\n    if (cchTarget > 0)\n    {\n        // Make sure we know the length\n        if (cchSource == -1)\n            cchSource = strlen(szSource);\n        cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource);\n\n        mbstowcs(szTarget, szSource, cchToCopy);\n        szTarget[cchToCopy] = 0;\n    }\n}\n\nvoid CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource)\n{\n    size_t cchToCopy;\n\n    if (cchTarget > 0)\n    {\n        // Make sure we know the length\n        if (cchSource == -1)\n            cchSource = wcslen(szSource);\n        cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource);\n\n        memcpy(szTarget, szSource, cchToCopy * sizeof(wchar_t));\n        szTarget[cchToCopy] = 0;\n    }\n}\n\n//-----------------------------------------------------------------------------\n// Safe version of s(w)printf\n\nsize_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...)\n{\n    char * buffend;\n    va_list argList;\n\n    // Start the argument list\n    va_start(argList, format);\n    \n#ifdef CASCLIB_PLATFORM_WINDOWS\n    StringCchVPrintfExA(buffer, nCount, &buffend, NULL, 0, format, argList);\n//  buffend = buffer + vsnprintf(buffer, nCount, format, argList);\n#else\n    buffend = buffer + vsnprintf(buffer, nCount, format, argList);\n#endif\n    \n    // End the argument list\n    va_end(argList);\n    return (buffend - buffer);\n}\n\nsize_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...)\n{\n    wchar_t * buffend;\n    va_list argList;\n\n    // Start the argument list\n    va_start(argList, format);\n\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    StringCchVPrintfExW(buffer, nCount, &buffend, NULL, 0, format, argList);\n//  buffend = buffer + vswprintf(buffer, nCount, format, argList);\n#else\n    buffend = buffer + vswprintf(buffer, nCount, format, argList);\n#endif\n\n    // End the argument list\n    va_end(argList);\n    return (buffend - buffer);\n}\n\n//-----------------------------------------------------------------------------\n// String allocation\n\nchar * CascNewStr(const char * szString, size_t nCharsToReserve)\n{\n    char * szNewString = NULL;\n    size_t nLength;\n\n    if(szString != NULL)\n    {\n        nLength = strlen(szString);\n        szNewString = CASC_ALLOC<char>(nLength + nCharsToReserve + 1);\n        if(szNewString != NULL)\n        {\n            memcpy(szNewString, szString, nLength);\n            szNewString[nLength] = 0;\n        }\n    }\n\n    return szNewString;\n}\n\nwchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve)\n{\n    wchar_t * szNewString = NULL;\n    size_t nLength;\n\n    if(szString != NULL)\n    {\n        nLength = wcslen(szString);\n        szNewString = CASC_ALLOC<wchar_t>(nLength + nCharsToReserve + 1);\n        if(szNewString != NULL)\n        {\n            memcpy(szNewString, szString, nLength * sizeof(wchar_t));\n            szNewString[nLength] = 0;\n        }\n    }\n\n    return szNewString;\n}\n\nLPSTR CascNewStrT2A(LPCTSTR szString, size_t nCharsToReserve)\n{\n    LPSTR szNewString = NULL;\n    size_t nLength;\n\n    if(szString != NULL)\n    {\n        nLength = _tcslen(szString);\n        szNewString = CASC_ALLOC<char>(nLength + nCharsToReserve + 1);\n        if(szNewString != NULL)\n        {\n            CascStrCopy(szNewString, nLength + nCharsToReserve + 1, szString, nLength);\n//          szNewString[nLength] = 0;\n        }\n    }\n\n    return szNewString;\n}\n\nLPTSTR CascNewStrA2T(LPCSTR szString, size_t nCharsToReserve)\n{\n    LPTSTR szNewString = NULL;\n    size_t nLength;\n\n    if(szString != NULL)\n    {\n        nLength = strlen(szString);\n        szNewString = CASC_ALLOC<TCHAR>(nLength + nCharsToReserve + 1);\n        if(szNewString != NULL)\n        {\n            CascStrCopy(szNewString, nLength + nCharsToReserve + 1, szString, nLength);\n//          szNewString[nLength] = 0;\n        }\n    }\n\n    return szNewString;\n}\n\n//-----------------------------------------------------------------------------\n// String merging\n\nLPTSTR GetLastPathPart(LPTSTR szWorkPath)\n{\n    size_t nLength = _tcslen(szWorkPath);\n\n    // Go one character back\n    if(nLength > 0)\n        nLength--;\n\n    // Cut ending (back)slashes, if any\n    while(nLength > 0 && (szWorkPath[nLength] == _T('\\\\') || szWorkPath[nLength] == _T('/')))\n        nLength--;\n\n    // Cut the last path part\n    while(nLength > 0)\n    {\n        // End of path?\n        if(szWorkPath[nLength] == _T('\\\\') || szWorkPath[nLength] == _T('/'))\n        {\n            return szWorkPath + nLength;\n        }\n\n        // Go one character back\n        nLength--;\n    }\n\n    return NULL;\n}\n\nbool CutLastPathPart(LPTSTR szWorkPath)\n{\n    // Get the last part of the path\n    szWorkPath = GetLastPathPart(szWorkPath);\n    if(szWorkPath == NULL)\n        return false;\n\n    szWorkPath[0] = 0;\n    return true;\n}\n\nsize_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, va_list argList)\n{\n    CASC_PATH<TCHAR> Path(PATH_SEP_CHAR);\n    LPCTSTR szFragment;\n    bool bWithSeparator = false;\n\n    // Combine all parts of the path here\n    while((szFragment = va_arg(argList, LPTSTR)) != NULL)\n    {\n        Path.AppendString(szFragment, bWithSeparator);\n        bWithSeparator = true;\n    }\n\n    return Path.Copy(szBuffer, nMaxChars);\n}\n\nsize_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, ...)\n{\n    va_list argList;\n    size_t nLength;\n\n    va_start(argList, nMaxChars);\n    nLength = CombinePath(szBuffer, nMaxChars, argList);\n    va_end(argList);\n\n    return nLength;\n}\n\nsize_t NormalizeFileName(const unsigned char * NormTable, char * szNormName, const char * szFileName, size_t cchMaxChars)\n{\n    char * szNormNameEnd = szNormName + cchMaxChars;\n    size_t i;\n\n    // Normalize the file name: ToLower + BackSlashToSlash\n    for(i = 0; szFileName[0] != 0 && szNormName < szNormNameEnd; i++)\n        *szNormName++ = NormTable[*szFileName++];\n\n    // Terminate the string\n    szNormName[0] = 0;\n    return i;\n}\n\nsize_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars)\n{\n    return NormalizeFileName(AsciiToUpperTable_BkSlash, szNormName, szFileName, cchMaxChars);\n}\n\nsize_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars)\n{\n    return NormalizeFileName(AsciiToLowerTable_Slash, szNormName, szFileName, cchMaxChars);\n}\n\nULONGLONG CalcNormNameHash(const char * szNormName, size_t nLength)\n{\n    uint32_t dwHashHigh = 0;\n    uint32_t dwHashLow = 0;\n\n    // Calculate the HASH value of the normalized file name\n    hashlittle2(szNormName, nLength, &dwHashHigh, &dwHashLow);\n    return ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow;\n}\n\nULONGLONG CalcFileNameHash(const char * szFileName)\n{\n    char szNormName[MAX_PATH+1];\n    size_t nLength;\n\n    // Normalize the file name - convert to uppercase, slashes to backslashes\n    nLength = NormalizeFileName_UpperBkSlash(szNormName, szFileName, MAX_PATH);\n\n    // Calculate hash from the normalized name\n    return CalcNormNameHash(szNormName, nLength);\n}\n\n//-----------------------------------------------------------------------------\n// File name utilities\n\nbool IsFileDataIdName(const char * szFileName, DWORD & FileDataId)\n{\n    const char * szFilePtr;\n    BYTE BinaryValue[4];\n\n    // If the file name begins with \"File\", then a decimal file data ID must follow\n    if(!strncmp(szFileName, \"File\", 4))\n    {\n        DWORD Accumulator = 0;\n\n        for(szFilePtr = szFileName + 4; szFilePtr[0] != 0 && szFilePtr[0] != '.'; szFilePtr++)\n        {\n            if(!('0' <= szFilePtr[0] && szFilePtr[0] <= '9'))\n                return false;\n            Accumulator = (Accumulator * 10) + (szFilePtr[0] - '0');\n        }\n\n        if(szFilePtr[0] == '.' || szFilePtr[0] == 0)\n        {\n            FileDataId = Accumulator;\n            return true;\n        }\n    }\n\n    // If the file name begins with \"FILE\", then a hexadecimal file data ID must follow\n    if(!strncmp(szFileName, \"FILE\", 4) && strlen(szFileName) >= 0x0C)\n    {\n        // Convert the hexadecimal number to integer\n        if(BinaryFromString(szFileName+4, 8, BinaryValue) == ERROR_SUCCESS)\n        {\n            // Must be followed by an extension or end-of-string\n            if(szFileName[0x0C] == 0 || szFileName[0x0C] == '.')\n            {\n                FileDataId = ConvertBytesToInteger_4(BinaryValue);\n                return (FileDataId != CASC_INVALID_ID);\n            }\n        }\n    }\n\n    return false;\n}\n\nbool IsFileCKeyEKeyName(const char * szFileName, LPBYTE PtrKeyBuffer)\n{\n    size_t nLength = strlen(szFileName);\n\n    if(nLength == MD5_STRING_SIZE)\n    {\n        if(BinaryFromString(szFileName, MD5_STRING_SIZE, PtrKeyBuffer) == ERROR_SUCCESS)\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool CascCheckWildCard(const char * szString, const char * szWildCard)\n{\n    const char * szWildCardPtr;\n\n    while(szWildCard && szWildCard[0])\n    {\n        // If there is '?' in the wildcard, we skip one char\n        while(szWildCard[0] == '?')\n        {\n            if(szString[0] == 0)\n                return false;\n\n            szWildCard++;\n            szString++;\n        }\n\n        // Handle '*'\n        szWildCardPtr = szWildCard;\n        if(szWildCardPtr[0] != 0)\n        {\n            if(szWildCardPtr[0] == '*')\n            {\n                while(szWildCardPtr[0] == '*')\n                    szWildCardPtr++;\n\n                if(szWildCardPtr[0] == 0)\n                    return true;\n\n                if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] == AsciiToUpperTable_BkSlash[szString[0]])\n                {\n                    if(CascCheckWildCard(szString, szWildCardPtr))\n                        return true;\n                }\n            }\n            else\n            {\n                if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] != AsciiToUpperTable_BkSlash[szString[0]])\n                    return false;\n\n                szWildCard = szWildCardPtr + 1;\n            }\n\n            if(szString[0] == 0)\n                return false;\n            szString++;\n        }\n        else\n        {\n            return (szString[0] == 0) ? true : false;\n        }\n    }\n    return true;\n}\n\n//-----------------------------------------------------------------------------\n// Hashing functions\n\nbool CascIsValidMD5(LPBYTE pbMd5)\n{\n    PDWORD Int32Array = (PDWORD)pbMd5;\n\n    // The MD5 is considered invalid if it is zeroed\n    return (Int32Array[0] | Int32Array[1] | Int32Array[2] | Int32Array[3]) ? true : false;\n}\n\nbool CascVerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5)\n{\n    MD5_CTX md5_ctx;\n    BYTE md5_digest[MD5_HASH_SIZE];\n\n    // Don't verify the block if the MD5 is not valid.\n    if(!CascIsValidMD5(expected_md5))\n        return true;\n\n    // Calculate the MD5 of the data block\n    MD5_Init(&md5_ctx);\n    MD5_Update(&md5_ctx, pvDataBlock, cbDataBlock);\n    MD5_Final(md5_digest, &md5_ctx);\n\n    // Does the MD5's match?\n    return (memcmp(md5_digest, expected_md5, MD5_HASH_SIZE) == 0);\n}\n\nvoid CascCalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash)\n{\n    MD5_CTX md5_ctx;\n\n    MD5_Init(&md5_ctx);\n    MD5_Update(&md5_ctx, pvDataBlock, cbDataBlock);\n    MD5_Final(md5_hash, &md5_ctx);\n}\n"
  },
  {
    "path": "deps/CascLib/src/common/Common.h",
    "content": "/*****************************************************************************/\n/* CascCommon.h                           Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Common functions for CascLib                                              */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of CascCommon.h                    */\n/*****************************************************************************/\n\n#ifndef __COMMON_H__\n#define __COMMON_H__\n\n//-----------------------------------------------------------------------------\n// Common macros\n\n// Macro for building 64-bit file offset from two 32-bit\n#define MAKE_OFFSET64(hi, lo)      (((ULONGLONG)hi << 32) | (ULONGLONG)lo)\n\n#ifndef ALIGN_TO_SIZE\n#define ALIGN_TO_SIZE(x, a)   (((x) + (a)-1) & ~((a)-1))\n#endif\n\n// Prevent problems with CRT \"min\" and \"max\" functions,\n// as they are not defined on all platforms\n#define CASCLIB_MIN(a, b) ((a < b) ? a : b)\n#define CASCLIB_MAX(a, b) ((a > b) ? a : b)\n#define CASCLIB_UNUSED(p) ((void)(p))\n\n//-----------------------------------------------------------------------------\n// Common structures\n\n// Structure for static content key (CKey) and encoded key (EKey)\n// The CKey is a MD5 hash of the file data.\n// The EKey is (shortened) MD5 hash of the file header, which contains MD5 hashes of all the logical blocks of the file.\ntypedef struct _CONTENT_KEY\n{\n    BYTE Value[MD5_HASH_SIZE];                      // MD5 of the file\n\n} CONTENT_KEY, *PCONTENT_KEY, ENCODED_KEY, *PENCODED_KEY;\n\n//-----------------------------------------------------------------------------\n// EKey entry, captured from index files of all types. This structure\n// is somewhat less memory consuming than CASC_CKEY_ENTRY\n\ntypedef struct _CASC_EKEY_ENTRY\n{\n    BYTE EKey[MD5_HASH_SIZE];                       // Encoded key. Length depends on TCascStorage::EKeyLength\n    ULONGLONG StorageOffset;                        // Offset of the encoded file in archive.\n                                                    // Lower (TCascStorage::FileOffsetBits) bits are archive offset.\n                                                    // Upper bits are archive index\n    DWORD EncodedSize;                              // Encoded size\n    DWORD Alignment;                                // Alignment to 8-byte boundary. Reserved for future use\n} CASC_EKEY_ENTRY, *PCASC_EKEY_ENTRY;\n\n//-----------------------------------------------------------------------------\n// Basic structure used by all CascLib objects to describe a single entry\n// in the CASC storage. Each entry represents one physical file\n// in the storage. Note that the file may be present under several file names.\n\n// Flags for CASC_CKEY_ENTRY::Flags\n#define CASC_CE_FILE_IS_LOCAL      0x00000001       // The file is available locally. Keep this flag to have value of 1\n#define CASC_CE_HAS_CKEY           0x00000002       // The CKey is present in the entry\n#define CASC_CE_HAS_EKEY           0x00000004       // The EKey is present, at least partial one\n#define CASC_CE_HAS_EKEY_PARTIAL   0x00000008       // The EKey is only partial, padded by zeros. Always used with CASC_CE_HAS_EKEY\n#define CASC_CE_IN_ENCODING        0x00000010       // Present in the ENCODING manifest\n#define CASC_CE_IN_DOWNLOAD        0x00000020       // Present in the DOWNLOAD manifest\n#define CASC_CE_IN_BUILD           0x00000040       // Present in the BUILD (text) manifest\n#define CASC_CE_IN_ARCHIVE         0x00000080       // File is stored in an archive (for online storages)\n#define CASC_CE_FOLDER_ENTRY       0x00000100       // This CKey entry is a folder\n#define CASC_CE_FILE_SPAN          0x00000200       // This CKey entry is a follow-up file span\n#define CASC_CE_FILE_PATCH         0x00000400       // The file is in PATCH subfolder in remote storage\n#define CASC_CE_PLAIN_DATA         0x00000800       // The file data is not BLTE encoded, but in plain format\n\n// In-memory representation of a single entry. \nstruct CASC_CKEY_ENTRY\n{\n    CASC_CKEY_ENTRY()\n    {\n        Init();\n    }\n\n    void Init(void)\n    {\n        memset(this, 0, sizeof(CASC_CKEY_ENTRY));\n        StorageOffset = CASC_INVALID_OFFS64;\n        EncodedSize = CASC_INVALID_SIZE;\n        ContentSize = CASC_INVALID_SIZE;\n        SpanCount = 1;\n    }\n\n    bool IsFile()\n    {\n        // Must not be a folder entry\n        if((Flags & CASC_CE_FOLDER_ENTRY) == 0)\n        {\n            // There can be entries that are both file span or the standalone file\n            // * zone/zm_red.xpak - { zone/zm_red.xpak_1, zone/zm_red.xpak_2, ..., zone/zm_red.xpak_6 }\n            if(RefCount != 0)\n                return true;\n\n            // To include the file, it must either be present in ENCODING, DOWNLOAD or in BUILD file\n            if(((Flags & CASC_CE_FILE_SPAN) == 0) && (Flags & (CASC_CE_IN_ENCODING | CASC_CE_IN_DOWNLOAD | CASC_CE_IN_BUILD)))\n                return true;\n        }\n        return false;\n    }\n\n    BYTE CKey[MD5_HASH_SIZE];                       // Content key of the full length\n    BYTE EKey[MD5_HASH_SIZE];                       // Encoded key of the full length\n    ULONGLONG StorageOffset;                        // Linear offset over the entire storage. 0 if not present\n    ULONGLONG TagBitMask;                           // Bitmap for the tags. 0 ig tags are not supported\n    DWORD ContentSize;                              // Content size of the file\n    DWORD EncodedSize;                              // Encoded size of the file\n    DWORD Flags;                                    // See CASC_CE_XXX\n    USHORT RefCount;                                // This is the number of file names referencing this entry\n    BYTE SpanCount;                                 // Number of spans for the file\n    BYTE Priority;                                  // Download priority\n};\ntypedef CASC_CKEY_ENTRY *PCASC_CKEY_ENTRY;\n\n//-----------------------------------------------------------------------------\n// Conversion tables\n\nextern unsigned char AsciiToLowerTable_Slash[256];\nextern unsigned char AsciiToUpperTable_BkSlash[256];\nextern unsigned char AsciiToHexTable[0x80];\nextern unsigned char IntToHexChar[];\n\n//-----------------------------------------------------------------------------\n// Memory management\n//\n// We use our own macros for allocating/freeing memory. If you want\n// to redefine them, please keep the following rules:\n//\n//  - The memory allocation must return NULL if not enough memory\n//    (i.e not to throw exception)\n//  - The allocating function does not need to fill the allocated buffer with zeros\n//  - The reallocating function must support NULL as the previous block\n//  - Memory freeing function must check for NULL pointer and do nothing if so\n//\n\n#define CASC_REALLOC(type, ptr, count) (type *)realloc(ptr, (count) * sizeof(type))\n\ntemplate <typename T>\nT * CASC_ALLOC(size_t nCount)\n{\n    return (T *)malloc(nCount * sizeof(T));\n}\n\ntemplate <typename T>\nT * CASC_ALLOC_ZERO(size_t nCount)\n{\n    T * ptr = CASC_ALLOC<T>(nCount);\n\n    if(ptr != NULL)\n        memset(ptr, 0, sizeof(T) * nCount);\n    return ptr;\n}\n\ntemplate <typename T>\nvoid CASC_FREE(T *& ptr)\n{\n    if (ptr != NULL)\n        free(ptr);\n    ptr = NULL;\n}\n\n//-----------------------------------------------------------------------------\n// 32-bit ROL\n\ninline DWORD Rol32(DWORD dwValue, DWORD dwRolCount)\n{\n    return (dwValue << dwRolCount) | (dwValue >> (32 - dwRolCount));\n}\n\n//-----------------------------------------------------------------------------\n// Big endian number manipulation\n\ninline DWORD ConvertBytesToInteger_2(LPBYTE ValueAsBytes)\n{\n    USHORT Value = 0;\n\n    Value = (Value << 0x08) | ValueAsBytes[0];\n    Value = (Value << 0x08) | ValueAsBytes[1];\n\n    return Value;\n}\n\ninline DWORD ConvertBytesToInteger_3(LPBYTE ValueAsBytes)\n{\n    DWORD Value = 0;\n\n    Value = (Value << 0x08) | ValueAsBytes[0];\n    Value = (Value << 0x08) | ValueAsBytes[1];\n    Value = (Value << 0x08) | ValueAsBytes[2];\n\n    return Value;\n}\n\ninline DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes)\n{\n    DWORD Value = 0;\n\n    Value = (Value << 0x08) | ValueAsBytes[0];\n    Value = (Value << 0x08) | ValueAsBytes[1];\n    Value = (Value << 0x08) | ValueAsBytes[2];\n    Value = (Value << 0x08) | ValueAsBytes[3];\n\n    return Value;\n}\n\n// Converts the variable-size big-endian into integer\ninline DWORD ConvertBytesToInteger_X(LPBYTE ValueAsBytes, DWORD dwByteSize)\n{\n    DWORD Value = 0;\n\n    if(dwByteSize > 0)\n        Value = (Value << 0x08) | ValueAsBytes[0];\n    if(dwByteSize > 1)\n        Value = (Value << 0x08) | ValueAsBytes[1];\n    if(dwByteSize > 2)\n        Value = (Value << 0x08) | ValueAsBytes[2];\n    if(dwByteSize > 3)\n        Value = (Value << 0x08) | ValueAsBytes[3];\n\n    return Value;\n}\n\ninline DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes)\n{\n    DWORD Value = 0;\n\n    Value = (Value << 0x08) | ValueAsBytes[3];\n    Value = (Value << 0x08) | ValueAsBytes[2];\n    Value = (Value << 0x08) | ValueAsBytes[1];\n    Value = (Value << 0x08) | ValueAsBytes[0];\n\n    return Value;\n}\n\n// Read the 40-bit big-endian offset into ULONGLONG\ninline ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes)\n{\n    ULONGLONG Value = 0;\n\n    Value = (Value << 0x08) | ValueAsBytes[0];\n    Value = (Value << 0x08) | ValueAsBytes[1];\n    Value = (Value << 0x08) | ValueAsBytes[2];\n    Value = (Value << 0x08) | ValueAsBytes[3];\n    Value = (Value << 0x08) | ValueAsBytes[4];\n\n    return Value;\n}\n\ninline void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes)\n{\n    ValueAsBytes[0] = (BYTE)((Value >> 0x18) & 0xFF);\n    ValueAsBytes[1] = (BYTE)((Value >> 0x10) & 0xFF);\n    ValueAsBytes[2] = (BYTE)((Value >> 0x08) & 0xFF);\n    ValueAsBytes[3] = (BYTE)((Value >> 0x00) & 0xFF);\n}\n\ninline void ConvertIntegerToBytes_4_LE(DWORD Value, LPBYTE ValueAsBytes)\n{\n    ValueAsBytes[0] = (BYTE)((Value >> 0x00) & 0xFF);\n    ValueAsBytes[1] = (BYTE)((Value >> 0x08) & 0xFF);\n    ValueAsBytes[2] = (BYTE)((Value >> 0x10) & 0xFF);\n    ValueAsBytes[3] = (BYTE)((Value >> 0x18) & 0xFF);\n}\n\n// Faster than memset(Buffer, 0, 0x10)\ninline void ZeroMemory16(void * Buffer)\n{\n    PDWORD PtrBuffer = (PDWORD)Buffer;\n\n    PtrBuffer[0] = 0;\n    PtrBuffer[1] = 0;\n    PtrBuffer[2] = 0;\n    PtrBuffer[3] = 0;\n}\n\n// Faster than memcpy(Target, Source, 0x10)\ninline void CopyMemory16(void * Target, void * Source)\n{\n    PDWORD PtrTarget = (PDWORD)Target;\n    PDWORD PtrSource = (PDWORD)Source;\n\n    PtrTarget[0] = PtrSource[0];\n    PtrTarget[1] = PtrSource[1];\n    PtrTarget[2] = PtrSource[2];\n    PtrTarget[3] = PtrSource[3];\n}\n\n//-----------------------------------------------------------------------------\n// Capturing various integral values\n\nLPBYTE CaptureInteger16_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue);\nLPBYTE CaptureInteger32(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue);\nLPBYTE CaptureInteger32_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue);\nLPBYTE CaptureByteArray(LPBYTE pbDataPtr, LPBYTE pbDataEnd, size_t nLength, LPBYTE pbOutput);\nLPBYTE CaptureContentKey(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PCONTENT_KEY * PtrCKey);\nLPBYTE CaptureEncodedKey(LPBYTE pbEKey, LPBYTE pbData, BYTE EKeyLength);\nLPBYTE CaptureArray_(LPBYTE pbDataPtr, LPBYTE pbDataEnd, LPBYTE * PtrArray, size_t ItemSize, size_t ItemCount);\n\n#define CaptureArray(pbDataPtr, pbDataEnd, PtrArray, type, count) CaptureArray_(pbDataPtr, pbDataEnd, PtrArray, sizeof(type), count) \n\n//-----------------------------------------------------------------------------\n// String copying and conversion\n\nvoid CascStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1);\nvoid CascStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource = -1);\nvoid CascStrCopy(wchar_t * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1);\nvoid CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource = -1);\n\n//-----------------------------------------------------------------------------\n// Safe version of s(w)printf\n\nsize_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...);\nsize_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...);\n\n//-----------------------------------------------------------------------------\n// String allocation\n\nchar    * CascNewStr(const char * szString, size_t nCharsToReserve = 0);\nwchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve = 0);\n\nLPSTR  CascNewStrT2A(LPCTSTR szString, size_t nCharsToReserve = 0);\nLPTSTR CascNewStrA2T(LPCSTR szString, size_t nCharsToReserve = 0);\n\nsize_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, va_list argList);\nsize_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, ...);\nLPTSTR GetLastPathPart(LPTSTR szWorkPath);\nbool CutLastPathPart(LPTSTR szWorkPath);\n\nsize_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars);\nsize_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars);\n\nULONGLONG CalcNormNameHash(const char * szNormName, size_t nLength);\nULONGLONG CalcFileNameHash(const char * szFileName);\n\n//-----------------------------------------------------------------------------\n// String conversion functions\n\ntemplate <typename xchar, typename INTXX>\nDWORD ConvertStringToInt(const xchar * szString, size_t nMaxDigits, INTXX & RefValue, const xchar ** PtrStringEnd = NULL)\n{\n    INTXX MaxValueMask = (INTXX)0x0F << ((sizeof(INTXX) * 8) - 4);\n    INTXX Accumulator = 0;\n    BYTE DigitOne;\n\n    // Set default value\n    if(nMaxDigits == 0)\n        nMaxDigits = sizeof(INTXX) * 2;\n\n    // Convert the string up to the number of digits\n    for(size_t i = 0; i < nMaxDigits; i++, szString++)\n    {\n        // Check for the end of the string\n        if(szString[0] > sizeof(AsciiToHexTable))\n            return ERROR_BAD_FORMAT;\n        if(szString[0] <= 0x20)\n            break;\n\n        // Extract the next digit\n        DigitOne = AsciiToHexTable[szString[0]];\n        if(DigitOne == 0xFF)\n            return ERROR_BAD_FORMAT;\n\n        // Check overflow. If OK, shift the value by 4 to the left\n        if(Accumulator & MaxValueMask)\n            return ERROR_ARITHMETIC_OVERFLOW;\n        Accumulator = (Accumulator << 4) | DigitOne;\n    }\n\n    // Give the results\n    if(PtrStringEnd != NULL)\n        PtrStringEnd[0] = szString;\n    RefValue = Accumulator;\n    return ERROR_SUCCESS;\n}\n\n// Converts string blob to binary blob\ntemplate <typename xchar>\nDWORD BinaryFromString(const xchar * szString, size_t nMaxDigits, LPBYTE pbBinary)\n{\n    const xchar * szStringEnd = szString + nMaxDigits;\n    DWORD dwCounter = 0;\n    BYTE DigitValue;\n    BYTE ByteValue = 0;\n\n    // Convert the string\n    while(szString < szStringEnd)\n    {\n        // Retrieve the digit converted to hexa\n        DigitValue = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - '0');\n        if(DigitValue > 9)\n            DigitValue -= 'A' - '9' - 1;\n        if(DigitValue > 0x0F)\n            return ERROR_BAD_FORMAT;\n\n        // Insert the digit to the binary buffer\n        ByteValue = (ByteValue << 0x04) | DigitValue;\n        dwCounter++;\n\n        // If we reached the second digit, it means that we need\n        // to flush the byte value and move on\n        if((dwCounter & 0x01) == 0)\n            *pbBinary++ = ByteValue;\n        szString++;\n    }\n\n    return ERROR_SUCCESS;\n}\n\n// Converts binary array to string.\n// The caller must ensure that the buffer has at least ((cbBinary * 2) + 1) characters\ntemplate <typename xchar>\nxchar * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, xchar * szBuffer)\n{\n    xchar * szSaveBuffer = szBuffer;\n\n    // Verify the binary pointer\n    if(pbBinary && cbBinary)\n    {\n        // Convert the bytes to string array\n        for(size_t i = 0; i < cbBinary; i++)\n        {\n            *szBuffer++ = IntToHexChar[pbBinary[i] >> 0x04];\n            *szBuffer++ = IntToHexChar[pbBinary[i] & 0x0F];\n        }\n    }\n\n    // Terminate the string\n    *szBuffer = 0;\n    return szSaveBuffer;\n}\n\n//-----------------------------------------------------------------------------\n// Structures for data blobs\n\nstruct QUERY_KEY\n{\n    QUERY_KEY()\n    {\n        pbData = NULL;\n        cbData = 0;\n    }\n\n    ~QUERY_KEY()\n    {\n        CASC_FREE(pbData);\n        cbData = 0;\n    }\n\n    DWORD SetData(const void * pv, size_t cb)\n    {\n        if((pbData = CASC_ALLOC<BYTE>(cb)) == NULL)\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        memcpy(pbData, pv, cb);\n        cbData = cb;\n        return ERROR_SUCCESS;\n    }\n\n    LPBYTE pbData;\n    size_t cbData;\n};\ntypedef QUERY_KEY *PQUERY_KEY;\n\n//-----------------------------------------------------------------------------\n// File name utilities\n\n// Retrieves the pointer to plain name\ntemplate <typename XCHAR>\nconst XCHAR * GetPlainFileName(const XCHAR * szFileName)\n{\n    const XCHAR * szPlainName = szFileName;\n\n    while(*szFileName != 0)\n    {\n        if(*szFileName == '\\\\' || *szFileName == '/')\n            szPlainName = szFileName + 1;\n        szFileName++;\n    }\n\n    return szPlainName;\n}\n\n// Retrieves the pointer to file extension\ntemplate <typename XCHAR>\nconst XCHAR * GetFileExtension(const XCHAR * szFileName)\n{\n    const XCHAR * szExtension = NULL;\n\n    // We need to start searching from the plain name\n    // Avoid: C:\\$RECYCLE.BIN\\File.ext\n    szFileName = GetPlainFileName(szFileName);\n    \n    // Find the last dot in the plain file name\n    while(szFileName[0] != 0)\n    {\n        if(szFileName[0] == '.')\n            szExtension = szFileName;\n        szFileName++;\n    }\n\n    // If not found, return the end of the file name\n    return (XCHAR *)((szExtension != NULL) ? szExtension : szFileName);\n}\n\nbool IsFileDataIdName(const char * szFileName, DWORD & FileDataId);\nbool IsFileCKeyEKeyName(const char * szFileName, LPBYTE PtrKeyBuffer);\n\nbool CascCheckWildCard(const char * szString, const char * szWildCard);\n\n//-----------------------------------------------------------------------------\n// Hashing functions\n\nULONGLONG HashStringJenkins(const char * szFileName);\n\nbool CascIsValidMD5(LPBYTE pbMd5);\nvoid CascCalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash);\nbool CascVerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5);\n\n//-----------------------------------------------------------------------------\n// Scanning a directory\n\ntypedef bool (*INDEX_FILE_FOUND)(LPCTSTR szFileName, void * pvContext);\n\nbool DirectoryExists(LPCTSTR szDirectory);\n\nint ScanIndexDirectory(LPCTSTR szIndexPath, INDEX_FILE_FOUND pfnOnFileFound, void * pvContext);\n\n//-----------------------------------------------------------------------------\n// Argument structure versioning\n// Safely retrieves field value from a structure\n// intended for cases where users upgrade CascLib by simply dropping in a new .dll without recompiling their app\n\ntemplate <typename ARG, typename ARG_HOLDER>\nbool ExtractVersionedArgument(const ARG_HOLDER * pHolder, size_t ArgOffset, ARG * pArg)\n{\n    if (pHolder == NULL)\n        return false;\n\n    // Check input structure size\n    if (ArgOffset + sizeof(ARG) > pHolder->Size)\n        return false;\n\n    *pArg = *((ARG *)(((char*)pHolder) + ArgOffset));\n    return true;\n}\n\n#endif // __COMMON_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/Csv.cpp",
    "content": "/*****************************************************************************/\n/* Csv.cpp                                Copyright (c) Ladislav Zezula 2019 */\n/*---------------------------------------------------------------------------*/\n/* Implementation for the CSV handler class                                  */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 24.05.19  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local variables\n\nstatic const CASC_CSV_LINE NullLine;\n#define NullColumn NullLine.Columns[0];\n\n//-----------------------------------------------------------------------------\n// Local functions\n\nstatic char * NextLine_Default(void * /* pvUserData */, char * szLine)\n{\n    // Find the end of the line\n    while(szLine[0] != 0 && szLine[0] != 0x0A && szLine[0] != 0x0D)\n        szLine++;\n\n    // Terminate the line\n    while(szLine[0] == 0x0A || szLine[0] == 0x0D)\n        *szLine++ = 0;\n\n    // If there's an end-of-string, it's over\n    return (szLine[0] != 0) ? szLine : NULL;\n}\n\nstatic char * NextColumn_Default(void * /* pvUserData */, char * szColumn)\n{\n    // Find the end of the column\n    while(szColumn[0] != 0 && szColumn[0] != '|')\n        szColumn++;\n\n    // Terminate the column\n    if (szColumn[0] == '|')\n    {\n        *szColumn++ = 0;\n        return szColumn;\n    }\n\n    // If there's an end-of-string, it's over\n    return NULL;\n}\n\nstatic size_t CalcHashValue(const char * szString)\n{\n    size_t dwHash = 0x7EEE7EEE;\n\n    // Hash the string itself\n    while(szString[0] != 0)\n    {\n        dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ szString[0];\n        szString++;\n    }\n\n    // Return the hash limited by the table size\n    return dwHash;\n}\n\nstatic BYTE HashToIndex(size_t dwHashValue)\n{\n    return (BYTE)(dwHashValue & (CSV_HASH_TABLE_SIZE - 1));\n}\n\n//-----------------------------------------------------------------------------\n// Class for CSV line\n\nCASC_CSV_LINE::CASC_CSV_LINE()\n{\n    m_pParent = NULL;\n    m_nColumns = 0;\n}\n\nCASC_CSV_LINE::~CASC_CSV_LINE()\n{}\n\nbool CASC_CSV_LINE::SetLine(CASC_CSV * pParent, char * szCsvLine)\n{\n    CASC_CSV_NEXTPROC PfnNextColumn = pParent->GetNextColumnProc();\n    char * szCsvColumn;\n    size_t nHdrColumns = 0;\n    size_t nColumns = 0;\n\n    // Reset the number of column to zero\n    m_pParent = pParent;\n    m_nColumns = 0;\n\n    // Parse each column\n    while(szCsvLine != NULL && nColumns < CSV_MAX_COLUMNS)\n    {\n        // Get current line and the next one\n        szCsvColumn = szCsvLine;\n        szCsvLine = PfnNextColumn(pParent->GetUserData(), szCsvLine);\n\n        // Save the current line\n        Columns[nColumns].szValue = szCsvColumn;\n        Columns[nColumns].nLength = strlen(szCsvColumn);\n        nColumns++;\n    }\n\n    // Columns overflow\n    if(nColumns >= CSV_MAX_COLUMNS)\n    {\n        assert(false);\n        return false;\n    }\n\n    // If the parent has header lines, then the number of columns must match\n    // In the case of mismatched column count, ignore the line\n    nHdrColumns = pParent->GetHeaderColumns();\n    if(nHdrColumns != 0 && nColumns != nHdrColumns)\n        return false;\n\n    // All OK\n    m_nColumns = nColumns;\n    return true;\n}\n\nconst CASC_CSV_COLUMN & CASC_CSV_LINE::operator[](const char * szColumnName) const\n{\n    size_t nIndex;\n\n    // The column must have a hash table\n    if(m_pParent != NULL)\n    {\n        nIndex = m_pParent->GetColumnIndex(szColumnName);\n        if(nIndex != CSV_INVALID_INDEX && nIndex < m_nColumns)\n        {\n            return Columns[nIndex];\n        }\n    }\n\n    return NullColumn;\n}\n\nconst CASC_CSV_COLUMN & CASC_CSV_LINE::operator[](size_t nIndex) const\n{\n    return (nIndex < m_nColumns) ? Columns[nIndex] : NullColumn;\n}\n\n//-----------------------------------------------------------------------------\n// Class for CSV object\n\nCASC_CSV::CASC_CSV(size_t nLinesMax, bool bHasHeader)\n{\n    // Initialize the class variables\n    memset(HashTable, 0xFF, sizeof(HashTable));\n    m_pvUserData = NULL;\n    m_szCsvFile = NULL;\n    m_szCsvPtr = NULL;\n    m_nCsvFile = 0;\n    m_nLines = 0;\n    m_bHasHeader = bHasHeader;\n\n    // Initialize the \"NextLine\" function that will serve for finding next line in the text\n    PfnNextLine = NextLine_Default;\n    PfnNextColumn = NextColumn_Default;\n\n    // Nonzero number of lines means a finite CSV handler. The CSV will be loaded at once.\n    // Zero means that the user needs to call LoadNextLine() and then the line data\n    if(nLinesMax != 0)\n    {\n        m_pLines = new CASC_CSV_LINE[nLinesMax];\n        m_nLinesMax = nLinesMax;\n        m_bHasAllLines = true;\n    }\n    else\n    {\n        m_pLines = new CASC_CSV_LINE[1];\n        m_nLinesMax = 1;\n        m_bHasAllLines = false;\n    }\n}\n\nCASC_CSV::~CASC_CSV()\n{\n    if(m_pLines != NULL)\n        delete[] m_pLines;\n    CASC_FREE(m_szCsvFile);\n}\n\nDWORD CASC_CSV::SetNextLineProc(CASC_CSV_NEXTPROC PfnNextLineProc, CASC_CSV_NEXTPROC PfnNextColProc, void * pvUserData)\n{\n    // Set the procedure for next line parsing\n    if(PfnNextLineProc != NULL)\n        PfnNextLine = PfnNextLineProc;\n\n    // Set procedure for next columne parsing\n    if(PfnNextColProc != NULL)\n        PfnNextColumn = PfnNextColProc;\n\n    // Save the user data\n    m_pvUserData = pvUserData;\n    return ERROR_SUCCESS;\n}\n\nDWORD CASC_CSV::Load(LPCTSTR szFileName)\n{\n    DWORD cbFileData = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    m_szCsvFile = (char *)LoadFileToMemory(szFileName, &cbFileData);\n    if (m_szCsvFile != NULL)\n    {\n        // Assign the data to the CSV object\n        m_szCsvPtr = m_szCsvFile;\n        m_nCsvFile = cbFileData;\n\n        // Parse the data\n        dwErrCode = ParseCsvData() ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\nDWORD CASC_CSV::Load(LPBYTE pbData, size_t cbData)\n{\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    m_szCsvFile = CASC_ALLOC<char>(cbData + 1);\n    if (m_szCsvFile != NULL)\n    {\n        // Copy the entire data and terminate them with zero\n        memcpy(m_szCsvFile, pbData, cbData);\n        m_szCsvFile[cbData] = 0;\n        m_szCsvPtr = m_szCsvFile;\n        m_nCsvFile = cbData;\n\n        // Parse the data\n        dwErrCode = ParseCsvData() ? ERROR_SUCCESS : ERROR_BAD_FORMAT;\n    }\n\n    return dwErrCode;\n}\n\nbool CASC_CSV::LoadNextLine()\n{\n    bool bResult = false;\n\n    // Only endless CSV handler can do this\n    if(m_bHasAllLines == false)\n    {\n        // A few checks\n        assert(m_pLines != NULL);\n        assert(m_nLinesMax == 1);\n\n        // Reset the current line and load it\n        bResult = LoadNextLine(m_pLines[0]);\n        m_nLines = (bResult) ? 1 : 0;\n    }\n\n    return bResult;\n}\n\nbool CASC_CSV::InitializeHashTable()\n{\n    // Create the hash table of HeaderText -> ColumnIndex\n    for(size_t i = 0; i < Header.GetColumnCount(); i++)\n    {\n        // Calculate the start slot and the current slot\n        size_t nStartIndex = HashToIndex(CalcHashValue(Header[i].szValue));\n        size_t nHashIndex = nStartIndex;\n\n        // Go as long as there is not a free space\n        while(HashTable[nHashIndex] != 0xFF)\n        {\n            nHashIndex = HashToIndex(nHashIndex + 1);\n        }\n\n        // Set the slot\n        HashTable[nHashIndex] = (BYTE)i;\n    }\n\n    return true;\n}\n\nbool CASC_CSV::LoadNextLine(CASC_CSV_LINE & Line)\n{\n    // Overwatch ROOT's header begins with \"#\"\n    if(m_szCsvPtr == m_szCsvFile && m_szCsvPtr[0] == '#')\n        m_szCsvPtr++;\n\n    // Parse the entire line\n    while(m_szCsvPtr != NULL && m_szCsvPtr[0] != 0)\n    {\n        char * szCsvLine = m_szCsvPtr;\n\n        // Get the next line\n        m_szCsvPtr = PfnNextLine(m_pvUserData, m_szCsvPtr);\n\n        // Initialize the line\n        if (Line.SetLine(this, szCsvLine))\n            return true;\n    }\n\n    // End-of-file found\n    return false;\n}\n\nbool CASC_CSV::ParseCsvData()\n{\n    // Sanity checks\n    assert(m_nLines == 0);\n\n    // If we have header, then parse it and set the pointer to the next line\n    if(m_bHasHeader)\n    {\n        // Load the current line to the header\n        if (!LoadNextLine(Header))\n            return false;\n\n        // Initialize the hash table\n        if(!InitializeHashTable())\n            return false;\n    }\n\n    // Are we supposed to load all lines?\n    if(m_bHasAllLines)\n    {\n        // Parse each line\n        for(size_t i = 0; i < m_nLinesMax; i++)\n        {\n            if(!LoadNextLine(m_pLines[i]))\n                break;\n            m_nLines++;\n        }\n    }\n\n    return true;\n}\n\nconst CASC_CSV_COLUMN & CASC_CSV::operator[](const char * szColumnName) const\n{\n    if (m_pLines == NULL || m_nLines == 0)\n        return NullColumn;\n    return m_pLines[0][GetColumnIndex(szColumnName)];\n}\n\nconst CASC_CSV_LINE & CASC_CSV::operator[](size_t nIndex) const\n{\n    if (m_pLines == NULL || nIndex >= m_nLines)\n        return NullLine;\n    return m_pLines[nIndex];\n}\n\nsize_t CASC_CSV::GetHeaderColumns() const\n{\n    return (m_bHasHeader) ? Header.GetColumnCount() : 0;\n}\n\nsize_t CASC_CSV::GetColumnIndex(const char * szColumnName) const\n{\n    if(m_bHasHeader)\n    {\n        // Calculate the start slot and the current slot\n        size_t nStartIndex = HashToIndex(CalcHashValue(szColumnName));\n        size_t nHashIndex = nStartIndex;\n        size_t nIndex;\n\n        // Go as long as there is not a free space\n        while((nIndex = HashTable[nHashIndex]) != 0xFF)\n        {\n            // Compare the string\n            if(!strcmp(Header[nIndex].szValue, szColumnName))\n                return nIndex;\n\n            // Move to the next column\n            nHashIndex = HashToIndex(nHashIndex + 1);\n        }\n    }\n\n    return CSV_INVALID_INDEX;\n}\n\n"
  },
  {
    "path": "deps/CascLib/src/common/Csv.h",
    "content": "/*****************************************************************************/\n/* Csv.h                                  Copyright (c) Ladislav Zezula 2019 */\n/*---------------------------------------------------------------------------*/\n/* Interface for the CSV handler class                                       */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 24.05.19  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __CSV_H__\n#define __CSV_H__\n\n//-----------------------------------------------------------------------------\n// Defines\n\n#define CSV_INVALID_INDEX       ((size_t)(-1))\n#define CSV_ZERO                ((size_t)(0))       // Use Csv[0][CSV_ZERO] instead of ambiguous Csv[0][0]\n#define CSV_MAX_COLUMNS         0x20\n#define CSV_HASH_TABLE_SIZE     0x80\n\n//-----------------------------------------------------------------------------\n// Interface for finding of next text element (line, column)\n\n// The function must find the next (line|column), put zero there and return begin\n// of the next (line|column). In case there is no next (line|column), the function returns NULL\ntypedef char * (*CASC_CSV_NEXTPROC)(void * pvUserData, char * szLine);\n\n//-----------------------------------------------------------------------------\n// Class for CSV line\n\nclass CASC_CSV;\n\nstruct CASC_CSV_COLUMN\n{\n    CASC_CSV_COLUMN()\n    {\n        szValue = NULL;\n        nLength = 0;\n    }\n\n    const char * szValue;\n    size_t nLength;\n};\n\nclass CASC_CSV_LINE\n{\n    public:\n\n    CASC_CSV_LINE();\n    ~CASC_CSV_LINE();\n\n    bool SetLine(CASC_CSV * pParent, char * szLine);\n\n    const CASC_CSV_COLUMN & operator[](const char * szColumnName) const;\n    const CASC_CSV_COLUMN & operator[](size_t nIndex) const;\n\n    size_t GetColumnCount() const\n    {\n        return m_nColumns;\n    }\n\n    protected:\n\n    friend class CASC_CSV;\n\n    CASC_CSV * m_pParent;\n    CASC_CSV_COLUMN Columns[CSV_MAX_COLUMNS];\n    size_t m_nColumns;\n};\n\nclass CASC_CSV\n{\n    public:\n\n    CASC_CSV(size_t nLinesMax, bool bHasHeader);\n    ~CASC_CSV();\n\n    DWORD SetNextLineProc(CASC_CSV_NEXTPROC PfnNextLineProc, CASC_CSV_NEXTPROC PfnNextColProc = NULL, void * pvUserData = NULL);\n    CASC_CSV_NEXTPROC GetNextColumnProc()\n    {\n        return PfnNextColumn;\n    }\n\n    DWORD Load(LPBYTE pbData, size_t cbData);\n    DWORD Load(LPCTSTR szFileName);\n    bool LoadNextLine();\n\n    const CASC_CSV_COLUMN & operator[](const char * szColumnName) const;\n    const CASC_CSV_LINE & operator[](size_t nIndex) const;\n\n    size_t GetHeaderColumns() const;\n    size_t GetColumnIndex(const char * szColumnName) const;\n\n    void * GetUserData() const \n    {\n        return m_pvUserData;\n    }\n\n    size_t GetLineCount() const\n    {\n        return m_nLines;\n    }\n\n    protected:\n\n    bool InitializeHashTable();\n    bool LoadNextLine(CASC_CSV_LINE & Line);\n    bool ParseCsvData();\n\n    CASC_CSV_NEXTPROC PfnNextLine;\n    CASC_CSV_NEXTPROC PfnNextColumn;\n\n    CASC_CSV_LINE * m_pLines;\n    CASC_CSV_LINE Header;\n    BYTE HashTable[CSV_HASH_TABLE_SIZE];\n    void * m_pvUserData;\n    char * m_szCsvFile;\n    char * m_szCsvPtr;\n    size_t m_nCsvFile;\n    size_t m_nLinesMax;\n    size_t m_nLines;\n    bool m_bHasHeader;\n    bool m_bHasAllLines;\n};\n\n#endif  // __CSV_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/Directory.cpp",
    "content": "/*****************************************************************************/\n/* Directory.cpp                          Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* System-dependent directory functions for CascLib                          */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.14  1.00  Lad  The first version of Directory.cpp                   */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nbool DirectoryExists(LPCTSTR szDirectory)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n\n    DWORD dwAttributes = GetFileAttributes(szDirectory);\n    if((dwAttributes != INVALID_FILE_ATTRIBUTES) && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))\n        return true;\n\n#else // CASCLIB_PLATFORM_WINDOWS\n\n    DIR * dir = opendir(szDirectory);\n\n    if(dir != NULL)\n    {\n        closedir(dir);\n        return true;\n    }\n\n#endif\n\n    return false;\n}\n\nbool MakeDirectory(LPCTSTR szDirectory)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n\n    BOOL bResult = CreateDirectory(szDirectory, NULL);\n    return (bResult) ? true : false;\n\n#else\n\n    return (mkdir(szDirectory, 0755) == 0);\n\n#endif\n}\n\nint ScanIndexDirectory(\n    LPCTSTR szIndexPath,\n    INDEX_FILE_FOUND pfnOnFileFound,\n    void * pvContext)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n\n    WIN32_FIND_DATA wf;\n    HANDLE hFind;\n    TCHAR szSearchMask[MAX_PATH];\n\n    // Prepare the search mask\n    CombinePath(szSearchMask, _countof(szSearchMask), szIndexPath, _T(\"*\"), NULL);\n\n    // Prepare directory search\n    hFind = FindFirstFile(szSearchMask, &wf);\n    if(hFind != INVALID_HANDLE_VALUE)\n    {\n        // Skip the first file as it's always just \".\" or \"..\"\n        while(FindNextFile(hFind, &wf))\n        {\n            // If the found object is a file, pass it to the handler\n            if(!(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n            {\n                // Let the callback scan the file name\n                pfnOnFileFound(wf.cFileName, pvContext);\n            }\n        }\n\n        // Close the search handle\n        FindClose(hFind);\n    }\n\n#else // CASCLIB_PLATFORM_WINDOWS\n\n    struct dirent * dir_entry;\n    DIR * dir;\n\n    dir = opendir(szIndexPath);\n    if(dir != NULL)\n    {\n        while((dir_entry = readdir(dir)) != NULL)\n        {\n            if(dir_entry->d_type != DT_DIR)\n            {\n                pfnOnFileFound(dir_entry->d_name, pvContext);\n            }\n        }\n\n        closedir(dir);\n    }\n\n#endif\n\n    return ERROR_SUCCESS;\n}\n"
  },
  {
    "path": "deps/CascLib/src/common/Directory.h",
    "content": "/*****************************************************************************/\n/* Directory.h                            Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Directory functions for CascLib                                           */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 30.10.15  1.00  Lad  The first version of Directory.h                     */\n/*****************************************************************************/\n\n#ifndef __DIRECTORY_H__\n#define __DIRECTORY_H__\n\n//-----------------------------------------------------------------------------\n// Scanning a directory\n\nbool DirectoryExists(LPCTSTR szDirectory);\n\nbool MakeDirectory(LPCTSTR szDirectory);\n\nint ScanIndexDirectory(\n    LPCTSTR szIndexPath,\n    INDEX_FILE_FOUND pfnOnFileFound,\n    void * pvContext\n    );\n\n#endif // __DIRECTORY_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/FileStream.cpp",
    "content": "/*****************************************************************************/\n/* FileStream.cpp                         Copyright (c) Ladislav Zezula 2010 */\n/*---------------------------------------------------------------------------*/\n/* File stream support                                                       */\n/*                                                                           */\n/* Windows support: Written by Ladislav Zezula                               */\n/* Mac support:     Written by Sam Wilkins                                   */\n/* Linux support:   Written by Sam Wilkins and Ivan Komissarov               */\n/* Big-endian:      Written & debugged by Sam Wilkins                        */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 28.04.14  1.00  Lad  Copied from StormLib                                 */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n#ifdef _MSC_VER\n#pragma warning(disable: 4800)                  // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)\n#endif\n\n//-----------------------------------------------------------------------------\n// Local functions - platform-specific functions\n\nstatic ULONGLONG GetByteOffset(ULONGLONG * ByteOffset1, ULONGLONG ByteOffset2)\n{\n    return (ByteOffset1 != NULL) ? ByteOffset1[0] : ByteOffset2;\n}\n\nstatic DWORD StringToInt(const char * szString)\n{\n    DWORD dwValue = 0;\n\n    while('0' <= szString[0] && szString[0] <= '9')\n    {\n        dwValue = (dwValue * 10) + (szString[0] - '9');\n        szString++;\n    }\n\n    return dwValue;\n}\n\n//-----------------------------------------------------------------------------\n// Dummy init function\n\nstatic void BaseNone_Init(TFileStream *)\n{\n    // Nothing here\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - base file support\n\nstatic bool BaseFile_Create(TFileStream * pStream)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    {\n        DWORD dwWriteShare = (pStream->dwFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0;\n\n        pStream->Base.File.hFile = CreateFile(pStream->szFileName,\n                                              GENERIC_READ | GENERIC_WRITE,\n                                              dwWriteShare | FILE_SHARE_READ,\n                                              NULL,\n                                              CREATE_ALWAYS,\n                                              0,\n                                              NULL);\n        if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE)\n            return false;\n    }\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n    {\n        intptr_t handle;\n\n        handle = open(pStream->szFileName, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);\n        if(handle == -1)\n        {\n            pStream->Base.File.hFile = INVALID_HANDLE_VALUE;\n            SetCascError(errno);\n            return false;\n        }\n\n        pStream->Base.File.hFile = (HANDLE)handle;\n    }\n#endif\n\n    // Reset the file size and position\n    pStream->Base.File.FileSize = 0;\n    pStream->Base.File.FilePos = 0;\n    return true;\n}\n\nstatic bool BaseFile_Open(TFileStream * pStream, LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    {\n        ULARGE_INTEGER FileSize;\n        DWORD dwWriteAccess = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES;\n        DWORD dwWriteShare = (dwStreamFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0;\n\n        // Open the file\n        pStream->Base.File.hFile = CreateFile(szFileName,\n                                              FILE_READ_DATA | FILE_READ_ATTRIBUTES | dwWriteAccess,\n                                              FILE_SHARE_READ | dwWriteShare,\n                                              NULL,\n                                              OPEN_EXISTING,\n                                              0,\n                                              NULL);\n        if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE)\n            return false;\n\n        // Query the file size\n        FileSize.LowPart = GetFileSize(pStream->Base.File.hFile, &FileSize.HighPart);\n        pStream->Base.File.FileSize = FileSize.QuadPart;\n\n        // Query last write time\n        GetFileTime(pStream->Base.File.hFile, NULL, NULL, (LPFILETIME)&pStream->Base.File.FileTime);\n    }\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n    {\n        struct stat64 fileinfo;\n        int oflag = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? O_RDONLY : O_RDWR;\n        intptr_t handle;\n\n        // Open the file\n        pStream->Base.File.hFile = INVALID_HANDLE_VALUE;\n        handle = open(szFileName, oflag | O_LARGEFILE);\n        if(handle == -1)\n        {\n            SetCascError(errno);\n            return false;\n        }\n\n        // Get the file size\n        if(fstat64(handle, &fileinfo) == -1)\n        {\n            SetCascError(errno);\n            close(handle);\n            return false;\n        }\n\n        // time_t is number of seconds since 1.1.1970, UTC.\n        // 1 second = 10000000 (decimal) in FILETIME\n        // Set the start to 1.1.1970 00:00:00\n        pStream->Base.File.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime);\n        pStream->Base.File.FileSize = (ULONGLONG)fileinfo.st_size;\n        pStream->Base.File.hFile = (HANDLE)handle;\n    }\n#endif\n\n    // Reset the file position\n    pStream->Base.File.FilePos = 0;\n    return true;\n}\n\nstatic bool BaseFile_Read(\n    TFileStream * pStream,                  // Pointer to an open stream\n    ULONGLONG * pByteOffset,                // Pointer to file byte offset. If NULL, it reads from the current position\n    void * pvBuffer,                        // Pointer to data to be read\n    DWORD dwBytesToRead)                    // Number of bytes to read from the file\n{\n    DWORD dwBytesRead = 0;                  // Must be set by platform-specific code\n\n    // Synchronize the access to the TFileStream structure\n    CascLock(pStream->Lock);\n    {\n        ULONGLONG ByteOffset = GetByteOffset(pByteOffset, pStream->Base.File.FilePos);\n\n#ifdef CASCLIB_PLATFORM_WINDOWS\n        {\n            // Note: We no longer support Windows 9x.\n            // Thus, we can use the OVERLAPPED structure to specify\n            // file offset to read from file. This allows us to skip\n            // one system call to SetFilePointer\n\n            // Update the byte offset\n            pStream->Base.File.FilePos = ByteOffset;\n\n            // Read the data\n            if (dwBytesToRead != 0)\n            {\n                OVERLAPPED Overlapped;\n\n                Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32);\n                Overlapped.Offset = (DWORD)ByteOffset;\n                Overlapped.hEvent = NULL;\n                if(!ReadFile(pStream->Base.File.hFile, pvBuffer, dwBytesToRead, &dwBytesRead, &Overlapped))\n                {\n                    CascUnlock(pStream->Lock);\n                    return false;\n                }\n            }\n        }\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n        {\n            ssize_t bytes_read;\n\n            // If the byte offset is different from the current file position,\n            // we have to update the file position\n            if (ByteOffset != pStream->Base.File.FilePos)\n            {\n                if (lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET) == (off64_t)-1)\n                {\n                    CascUnlock(pStream->Lock);\n                    SetCascError(errno);\n                    return false;\n                }\n                pStream->Base.File.FilePos = ByteOffset;\n            }\n\n            // Perform the read operation\n            if (dwBytesToRead != 0)\n            {\n                bytes_read = read((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToRead);\n                if (bytes_read == -1)\n                {\n                    CascUnlock(pStream->Lock);\n                    SetCascError(errno);\n                    return false;\n                }\n\n                dwBytesRead = (DWORD)(size_t)bytes_read;\n            }\n        }\n#endif\n\n        // Increment the current file position by number of bytes read\n        pStream->Base.File.FilePos = ByteOffset + dwBytesRead;\n    }\n    CascUnlock(pStream->Lock);\n\n    // If the number of bytes read doesn't match to required amount, return false\n    // However, Blizzard's CASC handlers read encoded data so that if less than expected\n    // was read, then they fill the rest with zeros\n    if(dwBytesRead < dwBytesToRead)\n    {\n        if(pStream->dwFlags & STREAM_FLAG_FILL_MISSING)\n        {\n            memset((LPBYTE)pvBuffer + dwBytesRead, 0, (dwBytesToRead - dwBytesRead));\n            dwBytesRead = dwBytesToRead;\n        }\n        else\n        {\n            SetCascError(ERROR_HANDLE_EOF);\n        }\n    }\n        \n    return (dwBytesRead == dwBytesToRead);\n}\n\n/**\n * \\a pStream Pointer to an open stream\n * \\a pByteOffset Pointer to file byte offset. If NULL, writes to current position\n * \\a pvBuffer Pointer to data to be written\n * \\a dwBytesToWrite Number of bytes to write to the file\n */\n\nstatic bool BaseFile_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite)\n{\n    DWORD dwBytesWritten = 0;               // Must be set by platform-specific code\n\n    // Synchronize the access to the TFileStream structure\n    CascLock(pStream->Lock);\n    {\n        ULONGLONG ByteOffset = GetByteOffset(pByteOffset, pStream->Base.File.FilePos);\n\n#ifdef CASCLIB_PLATFORM_WINDOWS\n        {\n            // Note: We no longer support Windows 9x.\n            // Thus, we can use the OVERLAPPED structure to specify\n            // file offset to read from file. This allows us to skip\n            // one system call to SetFilePointer\n\n            // Update the byte offset\n            pStream->Base.File.FilePos = ByteOffset;\n\n            // Read the data\n            if (dwBytesToWrite != 0)\n            {\n                OVERLAPPED Overlapped;\n\n                Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32);\n                Overlapped.Offset = (DWORD)ByteOffset;\n                Overlapped.hEvent = NULL;\n                if(!WriteFile(pStream->Base.File.hFile, pvBuffer, dwBytesToWrite, &dwBytesWritten, &Overlapped))\n                {\n                    CascUnlock(pStream->Lock);\n                    return false;\n                }\n            }\n        }\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n        {\n            ssize_t bytes_written;\n\n            // If the byte offset is different from the current file position,\n            // we have to update the file position\n            if (ByteOffset != pStream->Base.File.FilePos)\n            {\n                if (lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET) == (off64_t)-1)\n                {\n                    CascUnlock(pStream->Lock);\n                    SetCascError(errno);\n                    return false;\n                }\n                pStream->Base.File.FilePos = ByteOffset;\n            }\n\n            // Perform the read operation\n            bytes_written = write((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToWrite);\n            if (bytes_written == -1)\n            {\n                CascUnlock(pStream->Lock);\n                SetCascError(errno);\n                return false;\n            }\n\n            dwBytesWritten = (DWORD)(size_t)bytes_written;\n        }\n#endif\n\n        // Increment the current file position by number of bytes read\n        pStream->Base.File.FilePos = ByteOffset + dwBytesWritten;\n\n        // Also modify the file size, if needed\n        if(pStream->Base.File.FilePos > pStream->Base.File.FileSize)\n            pStream->Base.File.FileSize = pStream->Base.File.FilePos;\n    }\n    CascUnlock(pStream->Lock);\n\n    if(dwBytesWritten != dwBytesToWrite)\n        SetCascError(ERROR_DISK_FULL);\n    return (dwBytesWritten == dwBytesToWrite);\n}\n\n/**\n * \\a pStream Pointer to an open stream\n * \\a NewFileSize New size of the file\n */\nstatic bool BaseFile_Resize(TFileStream * pStream, ULONGLONG NewFileSize)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    {\n        LONG FileSizeHi = (LONG)(NewFileSize >> 32);\n        LONG FileSizeLo;\n        DWORD dwNewPos;\n        bool bResult;\n\n        // Set the position at the new file size\n        dwNewPos = SetFilePointer(pStream->Base.File.hFile, (LONG)NewFileSize, &FileSizeHi, FILE_BEGIN);\n        if(dwNewPos == INVALID_SET_FILE_POINTER && GetCascError() != ERROR_SUCCESS)\n            return false;\n\n        // Set the current file pointer as the end of the file\n        bResult = (bool)SetEndOfFile(pStream->Base.File.hFile);\n        if(bResult)\n            pStream->Base.File.FileSize = NewFileSize;\n\n        // Restore the file position\n        FileSizeHi = (LONG)(pStream->Base.File.FilePos >> 32);\n        FileSizeLo = (LONG)(pStream->Base.File.FilePos);\n        SetFilePointer(pStream->Base.File.hFile, FileSizeLo, &FileSizeHi, FILE_BEGIN);\n        return bResult;\n    }\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n    {\n        if(ftruncate64((intptr_t)pStream->Base.File.hFile, (off64_t)NewFileSize) == -1)\n        {\n            SetCascError(errno);\n            return false;\n        }\n\n        pStream->Base.File.FileSize = NewFileSize;\n        return true;\n    }\n#endif\n}\n\n// Gives the current file size\nstatic bool BaseFile_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)\n{\n    // Note: Used by all thre base providers.\n    // Requires the TBaseData union to have the same layout for all three base providers\n    *pFileSize = pStream->Base.File.FileSize;\n    return true;\n}\n\n// Gives the current file position\nstatic bool BaseFile_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)\n{\n    // Note: Used by all thre base providers.\n    // Requires the TBaseData union to have the same layout for all three base providers\n    *pByteOffset = pStream->Base.File.FilePos;\n    return true;\n}\n\n// Renames the file pointed by pStream so that it contains data from pNewStream\nstatic bool BaseFile_Replace(TFileStream * pStream, TFileStream * pNewStream)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    // Rename the new file to the old stream's file\n    return (bool)MoveFileEx(pNewStream->szFileName, pStream->szFileName, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n    // \"rename\" on Linux also works if the target file exists\n    if(rename(pNewStream->szFileName, pStream->szFileName) == -1)\n    {\n        SetCascError(errno);\n        return false;\n    }\n\n    return true;\n#endif\n}\n\nstatic void BaseFile_Close(TFileStream * pStream)\n{\n    // Synchronize the access to multiple threads\n    CascLock(pStream->Lock);\n    {\n        if(pStream->Base.File.hFile != INVALID_HANDLE_VALUE)\n        {\n#ifdef CASCLIB_PLATFORM_WINDOWS\n            CloseHandle(pStream->Base.File.hFile);\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n            close((intptr_t)pStream->Base.File.hFile);\n#endif\n        }\n\n        // Also invalidate the handle\n        pStream->Base.File.hFile = INVALID_HANDLE_VALUE;\n    }\n    CascUnlock(pStream->Lock);\n}\n\n// Initializes base functions for the disk file\nstatic void BaseFile_Init(TFileStream * pStream)\n{\n    pStream->BaseCreate  = BaseFile_Create;\n    pStream->BaseOpen    = BaseFile_Open;\n    pStream->BaseRead    = BaseFile_Read;\n    pStream->BaseWrite   = BaseFile_Write;\n    pStream->BaseResize  = BaseFile_Resize;\n    pStream->BaseGetSize = BaseFile_GetSize;\n    pStream->BaseGetPos  = BaseFile_GetPos;\n    pStream->BaseClose   = BaseFile_Close;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - base memory-mapped file support\n\nstatic bool BaseMap_Open(TFileStream * pStream, LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n\n    ULARGE_INTEGER FileSize;\n    HANDLE hFile;\n    HANDLE hMap;\n    bool bResult = false;\n\n    // Keep compiler happy\n    dwStreamFlags = dwStreamFlags;\n\n    // Open the file for read access\n    hFile = CreateFile(szFileName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\n    if(hFile != INVALID_HANDLE_VALUE)\n    {\n        // Retrieve file size. Don't allow mapping file of a zero size.\n        FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);\n        if(FileSize.QuadPart != 0)\n        {\n            // Now create mapping object\n            hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);\n            if(hMap != NULL)\n            {\n                // Map the entire view into memory\n                // Note that this operation will fail if the file can't fit\n                // into usermode address space\n                pStream->Base.Map.pbFile = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);\n                if(pStream->Base.Map.pbFile != NULL)\n                {\n                    // Retrieve file time\n                    GetFileTime(hFile, NULL, NULL, (LPFILETIME)&pStream->Base.Map.FileTime);\n\n                    // Retrieve file size and position\n                    pStream->Base.Map.FileSize = FileSize.QuadPart;\n                    pStream->Base.Map.FilePos = 0;\n                    bResult = true;\n                }\n\n                // Close the map handle\n                CloseHandle(hMap);\n            }\n        }\n\n        // Close the file handle\n        CloseHandle(hFile);\n    }\n\n    // If the file is not there and is not available for random access,\n    // report error\n    if(bResult == false)\n        return false;\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n    struct stat64 fileinfo;\n    intptr_t handle;\n    bool bResult = false;\n\n    // Open the file\n    handle = open(szFileName, O_RDONLY);\n    if(handle != -1)\n    {\n        // Get the file size\n        if(fstat64(handle, &fileinfo) != -1)\n        {\n            pStream->Base.Map.pbFile = (LPBYTE)mmap(NULL, (size_t)fileinfo.st_size, PROT_READ, MAP_PRIVATE, handle, 0);\n            if(pStream->Base.Map.pbFile != NULL)\n            {\n                // time_t is number of seconds since 1.1.1970, UTC.\n                // 1 second = 10000000 (decimal) in FILETIME\n                // Set the start to 1.1.1970 00:00:00\n                pStream->Base.Map.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime);\n                pStream->Base.Map.FileSize = (ULONGLONG)fileinfo.st_size;\n                pStream->Base.Map.FilePos = 0;\n                bResult = true;\n            }\n        }\n        close(handle);\n    }\n\n    // Did the mapping fail?\n    if(bResult == false)\n    {\n        SetCascError(errno);\n        return false;\n    }\n#endif\n\n    return true;\n}\n\nstatic bool BaseMap_Read(\n    TFileStream * pStream,                  // Pointer to an open stream\n    ULONGLONG * pByteOffset,                // Pointer to file byte offset. If NULL, it reads from the current position\n    void * pvBuffer,                        // Pointer to data to be read\n    DWORD dwBytesToRead)                    // Number of bytes to read from the file\n{\n    ULONGLONG ByteOffset = GetByteOffset(pByteOffset, pStream->Base.Map.FilePos);\n\n    // Do we have to read anything at all?\n    if(dwBytesToRead != 0)\n    {\n        // Don't allow reading past file size\n        if((ByteOffset + dwBytesToRead) > pStream->Base.Map.FileSize)\n            return false;\n\n        // Copy the required data\n        memcpy(pvBuffer, pStream->Base.Map.pbFile + (size_t)ByteOffset, dwBytesToRead);\n    }\n\n    // Move the current file position\n    pStream->Base.Map.FilePos += dwBytesToRead;\n    return true;\n}\n\nstatic void BaseMap_Close(TFileStream * pStream)\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    if(pStream->Base.Map.pbFile != NULL)\n        UnmapViewOfFile(pStream->Base.Map.pbFile);\n#endif\n\n#if defined(CASCLIB_PLATFORM_MAC) || defined(CASCLIB_PLATFORM_LINUX)\n    if(pStream->Base.Map.pbFile != NULL)\n        munmap(pStream->Base.Map.pbFile, (size_t )pStream->Base.Map.FileSize);\n#endif\n\n    pStream->Base.Map.pbFile = NULL;\n}\n\n// Initializes base functions for the mapped file\nstatic void BaseMap_Init(TFileStream * pStream)\n{\n    // Supply the file stream functions\n    pStream->BaseOpen    = BaseMap_Open;\n    pStream->BaseRead    = BaseMap_Read;\n    pStream->BaseGetSize = BaseFile_GetSize;    // Reuse BaseFile function\n    pStream->BaseGetPos  = BaseFile_GetPos;     // Reuse BaseFile function\n    pStream->BaseClose   = BaseMap_Close;\n\n    // Mapped files are read-only\n    pStream->dwFlags |= STREAM_FLAG_READ_ONLY;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - base HTTP file support\n\nstatic DWORD BaseHttp_ParseURL(TFileStream * pStream, LPCTSTR szFileName)\n{\n    LPCTSTR szFilePtr = szFileName;\n    char * hostName;\n    char * fileName;\n\n    // Find the end od the host name\n    if((szFilePtr = _tcschr(szFileName, '/')) == NULL)\n        return ERROR_INVALID_PARAMETER;\n\n    // Allocate and copy the host name\n    if((hostName = CASC_ALLOC<char>(szFilePtr - szFileName + 1)) != NULL)\n    {\n        CascStrCopy(hostName, 256, szFileName, (szFilePtr - szFileName));\n\n        // Allocate and copy the resource name\n        if((fileName = CascNewStrT2A(szFilePtr)) != NULL)\n        {\n            pStream->Base.Socket.hostName = hostName;\n            pStream->Base.Socket.fileName = fileName;\n            return ERROR_SUCCESS;\n        }\n\n        CASC_FREE(hostName);\n    }\n\n    return ERROR_NOT_ENOUGH_MEMORY;\n}\n\nstatic bool BaseHttp_Download(TFileStream * pStream)\n{\n    CASC_MIME Mime;\n    const char * request_mask = \"GET %s HTTP/1.1\\r\\nHost: %s\\r\\nConnection: Keep-Alive\\r\\n\\r\\n\";\n    char * server_response;\n    char * fileName = pStream->Base.Socket.fileName;\n    char request[0x100];\n    size_t response_length = 0;\n    size_t request_length = 0;\n    DWORD dwErrCode;\n\n    // If we already have the data, it's success\n    if(pStream->Base.Socket.fileData == NULL)\n    {\n        // Construct the request, either HTTP or Ribbit (https://wowdev.wiki/Ribbit).\n        // Note that Ribbit requests don't start with slash\n        if((pStream->dwFlags & BASE_PROVIDER_MASK) == BASE_PROVIDER_RIBBIT)\n        {\n            if(fileName[0] == '/')\n                fileName++;\n            request_mask = \"%s\\r\\n\";\n        }\n\n        // Send the request and receive decoded response\n        request_length = CascStrPrintf(request, _countof(request), request_mask, fileName, pStream->Base.Socket.hostName);\n        server_response = pStream->Base.Socket.pSocket->ReadResponse(request, request_length, &response_length);\n        if(server_response != NULL)\n        {\n            // Decode the MIME document\n            if((dwErrCode = Mime.Load(server_response, response_length)) == ERROR_SUCCESS)\n            {\n                // Move the data from MIME to HTTP stream\n                pStream->Base.Socket.fileData = Mime.GiveAway(&pStream->Base.Socket.fileDataLength);\n            }\n\n            CASC_FREE(server_response);\n        }\n    }\n\n    // If we have data loaded, return true\n    return (pStream->Base.Socket.fileData != NULL);\n}\n\nstatic bool BaseHttp_Open(TFileStream * pStream, LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n    DWORD dwErrCode;\n\n    // Extract the server part\n    if((dwErrCode = BaseHttp_ParseURL(pStream, szFileName)) == ERROR_SUCCESS)\n    {\n        // Determine the proper port\n        PCASC_SOCKET pSocket;\n        int portNum = ((dwStreamFlags & BASE_PROVIDER_MASK) == BASE_PROVIDER_RIBBIT) ? CASC_PORT_RIBBIT : CASC_PORT_HTTP;\n\n        // Initiate the remote connection\n        if((pSocket = sockets_connect(pStream->Base.Socket.hostName, portNum)) != NULL)\n        {\n            pStream->Base.Socket.pSocket = pSocket;\n            return true;\n        }\n    }\n\n    // Failure: set the last error and return false\n    SetCascError(dwErrCode);\n    return false;\n}\n\nstatic bool BaseHttp_Read(\n    TFileStream * pStream,                  // Pointer to an open stream\n    ULONGLONG * pByteOffset,                // Pointer to file byte offset. If NULL, it reads from the current position\n    void * pvBuffer,                        // Pointer to data to be read\n    DWORD dwBytesToRead)                    // Number of bytes to read from the file\n{\n    ULONGLONG ByteOffset = GetByteOffset(pByteOffset, pStream->Base.Socket.fileDataPos);\n    bool bCanReadTheWholeRange = true;\n\n    // Synchronize the access to the TFileStream structure\n    CascLock(pStream->Lock);\n    {\n        // Do we have to read anything at all?\n        if(dwBytesToRead != 0)\n        {\n            // Make sure that we have the file downloaded\n            if(!BaseHttp_Download(pStream))\n            {\n                CascUnlock(pStream->Lock);\n                return false;\n            }\n\n            // Are we trying to read more than available?\n            if(ByteOffset <= pStream->Base.Socket.fileDataLength)\n            {\n                if((ByteOffset + dwBytesToRead) > pStream->Base.Socket.fileDataLength)\n                {\n                    bCanReadTheWholeRange = false;\n                    dwBytesToRead = (DWORD)(pStream->Base.Socket.fileDataLength - ByteOffset);\n                }\n            }\n            else\n            {\n                bCanReadTheWholeRange = false;\n                dwBytesToRead = 0;\n            }\n\n            // Copy the data\n            if(dwBytesToRead != 0)\n            {\n                memcpy(pvBuffer, pStream->Base.Socket.fileData + ByteOffset, dwBytesToRead);\n            }\n        }\n\n        // Increment the current file position by number of bytes read\n        pStream->Base.Socket.fileDataPos = (size_t)(ByteOffset + dwBytesToRead);\n    }\n    CascUnlock(pStream->Lock);\n\n    // If the number of bytes read doesn't match the required amount, return false\n    if(bCanReadTheWholeRange == false)\n        SetCascError(ERROR_HANDLE_EOF);\n    return bCanReadTheWholeRange;\n}\n\n// Gives the current file size\nstatic bool BaseHttp_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)\n{\n    bool bResult;\n\n    // Synchronize the access to the TFileStream structure\n    CascLock(pStream->Lock);\n    {\n        // Make sure that we have the file data\n        bResult = BaseHttp_Download(pStream);\n        if(bResult)\n        {\n            *pFileSize = pStream->Base.Socket.fileDataLength;\n        }\n    }\n    CascUnlock(pStream->Lock);\n\n    // Give the result\n    return bResult;\n}\n\nstatic bool BaseHttp_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)\n{\n    // Give the current position\n    *pByteOffset = pStream->Base.Socket.fileDataPos;\n    return true;\n}\n\nstatic void BaseHttp_Close(TFileStream * pStream)\n{\n    if(pStream->Base.Socket.fileData != NULL)\n        CASC_FREE(pStream->Base.Socket.fileData);\n    if(pStream->Base.Socket.hostName != NULL)\n        CASC_FREE(pStream->Base.Socket.hostName);\n    if(pStream->Base.Socket.fileName != NULL)\n        CASC_FREE(pStream->Base.Socket.fileName);\n    if(pStream->Base.Socket.pSocket != NULL)\n        pStream->Base.Socket.pSocket->Release();\n    memset(&pStream->Base.Socket, 0, sizeof(pStream->Base.Socket));\n}\n\n// Initializes base functions for the mapped file\nstatic void BaseHttp_Init(TFileStream * pStream)\n{\n    // Supply the stream functions\n    pStream->BaseOpen    = BaseHttp_Open;\n    pStream->BaseRead    = BaseHttp_Read;\n    pStream->BaseGetSize = BaseHttp_GetSize;\n    pStream->BaseGetPos  = BaseHttp_GetPos;\n    pStream->BaseClose   = BaseHttp_Close;\n\n    // HTTP files are read-only\n    pStream->dwFlags |= STREAM_FLAG_READ_ONLY;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - base block-based support\n\n// Generic function that loads blocks from the file\n// The function groups the block with the same availability,\n// so the called BlockRead can finish the request in a single system call\nstatic bool BlockStream_Read(\n    TBlockStream * pStream,                 // Pointer to an open stream\n    ULONGLONG * pByteOffset,                // Pointer to file byte offset. If NULL, it reads from the current position\n    void * pvBuffer,                        // Pointer to data to be read\n    DWORD dwBytesToRead)                    // Number of bytes to read from the file\n{\n    ULONGLONG BlockOffset0;\n    ULONGLONG BlockOffset;\n    ULONGLONG ByteOffset;\n    ULONGLONG EndOffset;\n    LPBYTE TransferBuffer;\n    LPBYTE BlockBuffer;\n    DWORD BlockBufferOffset;                // Offset of the desired data in the block buffer\n    DWORD BytesNeeded;                      // Number of bytes that really need to be read\n    DWORD BlockSize = pStream->BlockSize;\n    DWORD BlockCount;\n    bool bPrevBlockAvailable;\n    bool bCallbackCalled = false;\n    bool bBlockAvailable;\n    bool bResult = true;\n\n    // The base block read function must be present\n    assert(pStream->BlockRead != NULL);\n\n    // NOP reading of zero bytes\n    if(dwBytesToRead == 0)\n        return true;\n\n    // Get the current position in the stream\n    ByteOffset = GetByteOffset(pByteOffset, pStream->StreamPos);\n    EndOffset = ByteOffset + dwBytesToRead;\n    if(EndOffset > pStream->StreamSize)\n    {\n        SetCascError(ERROR_HANDLE_EOF);\n        return false;\n    }\n\n    // Calculate the block parameters\n    BlockOffset0 = BlockOffset = ByteOffset & ~((ULONGLONG)BlockSize - 1);\n    BlockCount  = (DWORD)(((EndOffset - BlockOffset) + (BlockSize - 1)) / BlockSize);\n    BytesNeeded = (DWORD)(EndOffset - BlockOffset);\n\n    // Remember where we have our data\n    assert((BlockSize & (BlockSize - 1)) == 0);\n    BlockBufferOffset = (DWORD)(ByteOffset & (BlockSize - 1));\n\n    // Allocate buffer for reading blocks\n    TransferBuffer = BlockBuffer = CASC_ALLOC<BYTE>(BlockCount * BlockSize);\n    if(TransferBuffer == NULL)\n    {\n        SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n        return false;\n    }\n\n    // If all blocks are available, just read all blocks at once\n    if(pStream->IsComplete == 0)\n    {\n        // Now parse the blocks and send the block read request\n        // to all blocks with the same availability\n        assert(pStream->BlockCheck != NULL);\n        bPrevBlockAvailable = pStream->BlockCheck(pStream, BlockOffset);\n\n        // Loop as long as we have something to read\n        while(BlockOffset < EndOffset)\n        {\n            // Determine availability of the next block\n            bBlockAvailable = pStream->BlockCheck(pStream, BlockOffset);\n\n            // If the availability has changed, read all blocks up to this one\n            if(bBlockAvailable != bPrevBlockAvailable)\n            {\n                // Call the file stream callback, if the block is not available\n                if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false)\n                {\n                    pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0));\n                    bCallbackCalled = true;\n                }\n\n                // Load the continuous blocks with the same availability\n                assert(BlockOffset > BlockOffset0);\n                bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable);\n                if(!bResult)\n                    break;\n\n                // Move the block offset\n                BlockBuffer += (DWORD)(BlockOffset - BlockOffset0);\n                BytesNeeded -= (DWORD)(BlockOffset - BlockOffset0);\n                bPrevBlockAvailable = bBlockAvailable;\n                BlockOffset0 = BlockOffset;\n            }\n\n            // Move to the block offset in the stream\n            BlockOffset += BlockSize;\n        }\n\n        // If there is a block(s) remaining to be read, do it\n        if(BlockOffset > BlockOffset0)\n        {\n            // Call the file stream callback, if the block is not available\n            if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false)\n            {\n                pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0));\n                bCallbackCalled = true;\n            }\n\n            // Read the complete blocks from the file\n            if(BlockOffset > pStream->StreamSize)\n                BlockOffset = pStream->StreamSize;\n            bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable);\n        }\n    }\n    else\n    {\n        // Read the complete blocks from the file\n        if(EndOffset > pStream->StreamSize)\n            EndOffset = pStream->StreamSize;\n        bResult = pStream->BlockRead(pStream, BlockOffset, EndOffset, BlockBuffer, BytesNeeded, true);\n    }\n\n    // Now copy the data to the user buffer\n    if(bResult)\n    {\n        memcpy(pvBuffer, TransferBuffer + BlockBufferOffset, dwBytesToRead);\n        pStream->StreamPos = ByteOffset + dwBytesToRead;\n    }\n    else\n    {\n        // If the block read failed, set the last error\n        SetCascError(ERROR_FILE_INCOMPLETE);\n    }\n\n    // Call the callback to indicate we are done\n    if(bCallbackCalled)\n        pStream->pfnCallback(pStream->UserData, 0, 0);\n\n    // Free the block buffer and return\n    CASC_FREE(TransferBuffer);\n    return bResult;\n}\n\nstatic bool BlockStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)\n{\n    *pFileSize = pStream->StreamSize;\n    return true;\n}\n\nstatic bool BlockStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)\n{\n    *pByteOffset = pStream->StreamPos;\n    return true;\n}\n\nstatic void BlockStream_Close(TBlockStream * pStream)\n{\n    // Free the data map, if any\n    CASC_FREE(pStream->FileBitmap);\n\n    // Call the base class for closing the stream\n    pStream->BaseClose(pStream);\n}\n\n//-----------------------------------------------------------------------------\n// File stream allocation function\n\nstatic STREAM_INIT StreamBaseInit[5] =\n{\n    BaseFile_Init,\n    BaseMap_Init,\n    BaseHttp_Init,\n    BaseHttp_Init,      // Ribbit provider shares code with HTTP provider\n    BaseNone_Init\n};\n\n// This function allocates an empty structure for the file stream\n// The stream structure is created as flat block, variable length\n// The file name is placed after the end of the stream structure data\nstatic TFileStream * AllocateFileStream(\n    LPCTSTR szFileName,\n    size_t StreamSize,\n    DWORD dwStreamFlags)\n{\n    TFileStream * pMaster = NULL;\n    TFileStream * pStream;\n    LPCTSTR szNextFile = szFileName;\n    size_t FileNameSize;\n\n    // Sanity check\n    assert(StreamSize != 0);\n\n    // The caller can specify chain of files in the following form:\n    // C:\\archive.MPQ*http://www.server.com/MPQs/archive-server.MPQ\n    // In that case, we use the part after \"*\" as master file name\n    while(szNextFile[0] != 0 && szNextFile[0] != _T('*'))\n        szNextFile++;\n    FileNameSize = (size_t)((szNextFile - szFileName) * sizeof(TCHAR));\n\n    // If we have a next file, we need to open it as master stream\n    // Note that we don't care if the master stream exists or not,\n    // If it doesn't, later attempts to read missing file block will fail\n    if(szNextFile[0] == _T('*'))\n    {\n        // Don't allow another master file in the string\n        if(_tcschr(szNextFile + 1, _T('*')) != NULL)\n        {\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return NULL;\n        }\n\n        // Open the master file\n        pMaster = FileStream_OpenFile(szNextFile + 1, STREAM_FLAG_READ_ONLY);\n    }\n\n    // Allocate the stream structure for the given stream type\n    pStream = (TFileStream *)CASC_ALLOC<BYTE>(StreamSize + FileNameSize + sizeof(TCHAR));\n    if(pStream != NULL)\n    {\n        // Zero the entire structure\n        memset(pStream, 0, StreamSize + FileNameSize + sizeof(TCHAR));\n        pStream->pMaster = pMaster;\n        pStream->dwFlags = dwStreamFlags;\n\n        // Initialize the file name\n        pStream->szFileName = (LPTSTR)((BYTE *)pStream + StreamSize);\n        memcpy(pStream->szFileName, szFileName, FileNameSize);\n        pStream->szFileName[FileNameSize / sizeof(TCHAR)] = 0;\n\n        // Initialize the stream lock\n        CascInitLock(pStream->Lock);\n\n        // Initialize the stream functions\n        StreamBaseInit[dwStreamFlags & 0x03](pStream);\n    }\n\n    return pStream;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - flat stream support\n\nstatic DWORD FlatStream_CheckFile(TBlockStream * pStream)\n{\n    LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap;\n    DWORD WholeByteCount = (pStream->BlockCount / 8);\n    DWORD ExtraBitsCount = (pStream->BlockCount & 7);\n    BYTE ExpectedValue;\n\n    // Verify the whole bytes - their value must be 0xFF\n    for(DWORD i = 0; i < WholeByteCount; i++)\n    {\n        if(FileBitmap[i] != 0xFF)\n            return 0;\n    }\n\n    // If there are extra bits, calculate the mask\n    if(ExtraBitsCount != 0)\n    {\n        ExpectedValue = (BYTE)((1 << ExtraBitsCount) - 1);\n        if(FileBitmap[WholeByteCount] != ExpectedValue)\n            return 0;\n    }\n\n    // Yes, the file is complete\n    return 1;\n}\n\nstatic bool FlatStream_LoadBitmap(TBlockStream * pStream)\n{\n    FILE_BITMAP_FOOTER Footer;\n    ULONGLONG ByteOffset;\n    LPBYTE FileBitmap;\n    DWORD BlockCount;\n    DWORD BitmapSize;\n\n    // Do not load the bitmap if we should not have to\n    if(!(pStream->dwFlags & STREAM_FLAG_USE_BITMAP))\n        return false;\n\n    // Only if the size is greater than size of bitmap footer\n    if(pStream->Base.File.FileSize > sizeof(FILE_BITMAP_FOOTER))\n    {\n        // Load the bitmap footer\n        ByteOffset = pStream->Base.File.FileSize - sizeof(FILE_BITMAP_FOOTER);\n        if(pStream->BaseRead(pStream, &ByteOffset, &Footer, sizeof(FILE_BITMAP_FOOTER)))\n        {\n            // Make sure that the array is properly BSWAP-ed\n            BSWAP_ARRAY32_UNSIGNED((PDWORD)(&Footer), sizeof(FILE_BITMAP_FOOTER));\n\n            // Verify if there is actually a footer\n            if(Footer.Signature == ID_FILE_BITMAP_FOOTER && Footer.Version == 0x03)\n            {\n                // Get the offset of the bitmap, number of blocks and size of the bitmap\n                ByteOffset = MAKE_OFFSET64(Footer.MapOffsetHi, Footer.MapOffsetLo);\n                BlockCount = (DWORD)(((ByteOffset - 1) / Footer.BlockSize) + 1);\n                BitmapSize = ((BlockCount + 7) / 8);\n\n                // Check if the sizes match\n                if(ByteOffset + BitmapSize + sizeof(FILE_BITMAP_FOOTER) == pStream->Base.File.FileSize)\n                {\n                    // Allocate space for the bitmap\n                    FileBitmap = CASC_ALLOC<BYTE>(BitmapSize);\n                    if(FileBitmap != NULL)\n                    {\n                        // Load the bitmap bits\n                        if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize))\n                        {\n                            CASC_FREE(FileBitmap);\n                            return false;\n                        }\n\n                        // Update the stream size\n                        pStream->BuildNumber = Footer.BuildNumber;\n                        pStream->StreamSize = ByteOffset;\n\n                        // Fill the bitmap information\n                        pStream->FileBitmap = FileBitmap;\n                        pStream->BitmapSize = BitmapSize;\n                        pStream->BlockSize  = Footer.BlockSize;\n                        pStream->BlockCount = BlockCount;\n                        pStream->IsComplete = FlatStream_CheckFile(pStream);\n                        return true;\n                    }\n                }\n            }\n        }\n    }\n\n    return false;\n}\n\nstatic void FlatStream_UpdateBitmap(\n    TBlockStream * pStream,                // Pointer to an open stream\n    ULONGLONG StartOffset,\n    ULONGLONG EndOffset)\n{\n    LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap;\n    DWORD BlockIndex;\n    DWORD BlockSize = pStream->BlockSize;\n    DWORD ByteIndex;\n    BYTE BitMask;\n\n    // Sanity checks\n    assert((StartOffset & (BlockSize - 1)) == 0);\n    assert(FileBitmap != NULL);\n\n    // Calculate the index of the block\n    BlockIndex = (DWORD)(StartOffset / BlockSize);\n    ByteIndex = (BlockIndex / 0x08);\n    BitMask = (BYTE)(1 << (BlockIndex & 0x07));\n\n    // Set all bits for the specified range\n    while(StartOffset < EndOffset)\n    {\n        // Set the bit\n        FileBitmap[ByteIndex] |= BitMask;\n\n        // Move all\n        StartOffset += BlockSize;\n        ByteIndex += (BitMask >> 0x07);\n        BitMask = (BitMask >> 0x07) | (BitMask << 0x01);\n    }\n\n    // Increment the bitmap update count\n    pStream->IsModified = 1;\n}\n\nstatic bool FlatStream_BlockCheck(\n    TBlockStream * pStream,                // Pointer to an open stream\n    ULONGLONG BlockOffset)\n{\n    LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap;\n    DWORD BlockIndex;\n    BYTE BitMask;\n\n    // Sanity checks\n    assert((BlockOffset & (pStream->BlockSize - 1)) == 0);\n    assert(FileBitmap != NULL);\n\n    // Calculate the index of the block\n    BlockIndex = (DWORD)(BlockOffset / pStream->BlockSize);\n    BitMask = (BYTE)(1 << (BlockIndex & 0x07));\n\n    // Check if the bit is present\n    return (FileBitmap[BlockIndex / 0x08] & BitMask) ? true : false;\n}\n\nstatic bool FlatStream_BlockRead(\n    TBlockStream * pStream,                // Pointer to an open stream\n    ULONGLONG StartOffset,\n    ULONGLONG EndOffset,\n    LPBYTE BlockBuffer,\n    DWORD BytesNeeded,\n    bool bAvailable)\n{\n    DWORD BytesToRead = (DWORD)(EndOffset - StartOffset);\n\n    // The starting offset must be aligned to size of the block\n    assert(pStream->FileBitmap != NULL);\n    assert((StartOffset & (pStream->BlockSize - 1)) == 0);\n    assert(StartOffset < EndOffset);\n\n    // If the blocks are not available, we need to load them from the master\n    // and then save to the mirror\n    if(bAvailable == false)\n    {\n        // If we have no master, we cannot satisfy read request\n        if(pStream->pMaster == NULL)\n            return false;\n\n        // Load the blocks from the master stream\n        // Note that we always have to read complete blocks\n        // so they get properly stored to the mirror stream\n        if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead))\n            return false;\n\n        // Store the loaded blocks to the mirror file.\n        // Note that this operation is not required to succeed\n        if(pStream->BaseWrite(pStream, &StartOffset, BlockBuffer, BytesToRead))\n            FlatStream_UpdateBitmap(pStream, StartOffset, EndOffset);\n\n        return true;\n    }\n    else\n    {\n        if(BytesToRead > BytesNeeded)\n            BytesToRead = BytesNeeded;\n        return pStream->BaseRead(pStream, &StartOffset, BlockBuffer, BytesToRead);\n    }\n}\n\nstatic void FlatStream_Close(TBlockStream * pStream)\n{\n    FILE_BITMAP_FOOTER Footer;\n\n    if(pStream->FileBitmap && pStream->IsModified)\n    {\n        // Write the file bitmap\n        pStream->BaseWrite(pStream, &pStream->StreamSize, pStream->FileBitmap, pStream->BitmapSize);\n\n        // Prepare and write the file footer\n        Footer.Signature   = ID_FILE_BITMAP_FOOTER;\n        Footer.Version     = 3;\n        Footer.BuildNumber = pStream->BuildNumber;\n        Footer.MapOffsetLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF);\n        Footer.MapOffsetHi = (DWORD)(pStream->StreamSize >> 0x20);\n        Footer.BlockSize   = pStream->BlockSize;\n        BSWAP_ARRAY32_UNSIGNED(&Footer, sizeof(FILE_BITMAP_FOOTER));\n        pStream->BaseWrite(pStream, NULL, &Footer, sizeof(FILE_BITMAP_FOOTER));\n    }\n\n    // Close the base class\n    BlockStream_Close(pStream);\n}\n\nstatic bool FlatStream_CreateMirror(TBlockStream * pStream)\n{\n    ULONGLONG MasterSize = 0;\n    ULONGLONG MirrorSize = 0;\n    LPBYTE FileBitmap = NULL;\n    DWORD dwBitmapSize;\n    DWORD dwBlockCount;\n    bool bNeedCreateMirrorStream = true;\n    bool bNeedResizeMirrorStream = true;\n\n    // Do we have master function and base creation function?\n    if(pStream->pMaster == NULL || pStream->BaseCreate == NULL)\n        return false;\n\n    // Retrieve the master file size, block count and bitmap size\n    FileStream_GetSize(pStream->pMaster, &MasterSize);\n    dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE);\n    dwBitmapSize = (DWORD)((dwBlockCount + 7) / 8);\n\n    // Setup stream size and position\n    pStream->BuildNumber = DEFAULT_BUILD_NUMBER;        // BUGBUG: Really???\n    pStream->StreamSize = MasterSize;\n    pStream->StreamPos = 0;\n\n    // Open the base stream for write access\n    if(pStream->BaseOpen(pStream, pStream->szFileName, 0))\n    {\n        // If the file open succeeded, check if the file size matches required size\n        pStream->BaseGetSize(pStream, &MirrorSize);\n        if(MirrorSize == MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER))\n        {\n            // Attempt to load an existing file bitmap\n            if(FlatStream_LoadBitmap(pStream))\n                return true;\n\n            // We need to create new file bitmap\n            bNeedResizeMirrorStream = false;\n        }\n\n        // We need to create mirror stream\n        bNeedCreateMirrorStream = false;\n    }\n\n    // Create a new stream, if needed\n    if(bNeedCreateMirrorStream)\n    {\n        if(!pStream->BaseCreate(pStream))\n            return false;\n    }\n\n    // If we need to, then resize the mirror stream\n    if(bNeedResizeMirrorStream)\n    {\n        if(!pStream->BaseResize(pStream, MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER)))\n            return false;\n    }\n\n    // Allocate the bitmap array\n    FileBitmap = CASC_ALLOC_ZERO<BYTE>(dwBitmapSize);\n    if(FileBitmap == NULL)\n        return false;\n\n    // Initialize the bitmap\n    pStream->FileBitmap = FileBitmap;\n    pStream->BitmapSize = dwBitmapSize;\n    pStream->BlockSize  = DEFAULT_BLOCK_SIZE;\n    pStream->BlockCount = dwBlockCount;\n    pStream->IsComplete = 0;\n    pStream->IsModified = 1;\n\n    // Note: Don't write the stream bitmap right away.\n    // Doing so would cause sparse file resize on NTFS,\n    // which would take long time on larger files.\n    return true;\n}\n\nstatic TFileStream * FlatStream_Open(LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n    TBlockStream * pStream;\n    ULONGLONG ByteOffset = 0;\n\n    // Create new empty stream\n    pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);\n    if(pStream == NULL)\n    {\n        SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n        return NULL;\n    }\n\n    // Do we have a master stream?\n    if(pStream->pMaster != NULL)\n    {\n        if(!FlatStream_CreateMirror(pStream))\n        {\n            FileStream_Close(pStream);\n            SetCascError(ERROR_FILE_NOT_FOUND);\n            return NULL;\n        }\n    }\n    else\n    {\n        // Attempt to open the base stream\n        if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags))\n        {\n            FileStream_Close(pStream);\n            return NULL;\n        }\n\n        // Load the bitmap, if required to\n        if(dwStreamFlags & STREAM_FLAG_USE_BITMAP)\n            FlatStream_LoadBitmap(pStream);\n    }\n\n    // If we have a stream bitmap, set the reading functions\n    // which check presence of each file block\n    if(pStream->FileBitmap != NULL)\n    {\n        // Set the stream position to zero. Stream size is already set\n        assert(pStream->StreamSize != 0);\n        pStream->StreamPos = 0;\n        pStream->dwFlags |= STREAM_FLAG_READ_ONLY;\n\n        // Supply the stream functions\n        pStream->StreamRead    = (STREAM_READ)BlockStream_Read;\n        pStream->StreamGetSize = BlockStream_GetSize;\n        pStream->StreamGetPos  = BlockStream_GetPos;\n        pStream->StreamClose   = (STREAM_CLOSE)FlatStream_Close;\n\n        // Supply the block functions\n        pStream->BlockCheck    = (BLOCK_CHECK)FlatStream_BlockCheck;\n        pStream->BlockRead     = (BLOCK_READ)FlatStream_BlockRead;\n    }\n    else\n    {\n        // Reset the base position to zero\n        pStream->BaseRead(pStream, &ByteOffset, NULL, 0);\n\n        // Setup stream size and position\n        pStream->StreamSize = pStream->Base.File.FileSize;\n        pStream->StreamPos = 0;\n\n        // Set the base functions\n        pStream->StreamRead    = pStream->BaseRead;\n        pStream->StreamWrite   = pStream->BaseWrite;\n        pStream->StreamResize  = pStream->BaseResize;\n        pStream->StreamGetSize = pStream->BaseGetSize;\n        pStream->StreamGetPos  = pStream->BaseGetPos;\n        pStream->StreamClose   = pStream->BaseClose;\n    }\n\n    return pStream;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - partial stream support\n\nstatic bool IsPartHeader(PPART_FILE_HEADER pPartHdr)\n{\n    // Version number must be 2\n    if(pPartHdr->PartialVersion == 2)\n    {\n        // GameBuildNumber must be an ASCII number\n        if(isdigit(pPartHdr->GameBuildNumber[0]) && isdigit(pPartHdr->GameBuildNumber[1]) && isdigit(pPartHdr->GameBuildNumber[2]))\n        {\n            // Block size must be power of 2\n            if((pPartHdr->BlockSize & (pPartHdr->BlockSize - 1)) == 0)\n                return true;\n        }\n    }\n\n    return false;\n}\n\nstatic DWORD PartStream_CheckFile(TBlockStream * pStream)\n{\n    PPART_FILE_MAP_ENTRY FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap;\n    DWORD dwBlockCount;\n\n    // Get the number of blocks\n    dwBlockCount = (DWORD)((pStream->StreamSize + pStream->BlockSize - 1) / pStream->BlockSize);\n\n    // Check all blocks\n    for(DWORD i = 0; i < dwBlockCount; i++, FileBitmap++)\n    {\n        // Few sanity checks\n        assert(FileBitmap->LargeValueHi == 0);\n        assert(FileBitmap->LargeValueLo == 0);\n        assert(FileBitmap->Flags == 0 || FileBitmap->Flags == 3);\n\n        // Check if this block is present\n        if(FileBitmap->Flags != 3)\n            return 0;\n    }\n\n    // Yes, the file is complete\n    return 1;\n}\n\nstatic bool PartStream_LoadBitmap(TBlockStream * pStream)\n{\n    PPART_FILE_MAP_ENTRY FileBitmap;\n    PART_FILE_HEADER PartHdr;\n    ULONGLONG ByteOffset = 0;\n    ULONGLONG StreamSize = 0;\n    DWORD BlockCount;\n    DWORD BitmapSize;\n\n    // Only if the size is greater than size of the bitmap header\n    if(pStream->Base.File.FileSize > sizeof(PART_FILE_HEADER))\n    {\n        // Attempt to read PART file header\n        if(pStream->BaseRead(pStream, &ByteOffset, &PartHdr, sizeof(PART_FILE_HEADER)))\n        {\n            // We need to swap PART file header on big-endian platforms\n            BSWAP_ARRAY32_UNSIGNED(&PartHdr, sizeof(PART_FILE_HEADER));\n\n            // Verify the PART file header\n            if(IsPartHeader(&PartHdr))\n            {\n                // Get the number of blocks and size of one block\n                StreamSize = MAKE_OFFSET64(PartHdr.FileSizeHi, PartHdr.FileSizeLo);\n                ByteOffset = sizeof(PART_FILE_HEADER);\n                BlockCount = (DWORD)((StreamSize + PartHdr.BlockSize - 1) / PartHdr.BlockSize);\n                BitmapSize = BlockCount * sizeof(PART_FILE_MAP_ENTRY);\n\n                // Check if sizes match\n                if((ByteOffset + BitmapSize) < pStream->Base.File.FileSize)\n                {\n                    // Allocate space for the array of PART_FILE_MAP_ENTRY\n                    FileBitmap = CASC_ALLOC<PART_FILE_MAP_ENTRY>(BlockCount);\n                    if(FileBitmap != NULL)\n                    {\n                        // Load the block map\n                        if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize))\n                        {\n                            CASC_FREE(FileBitmap);\n                            return false;\n                        }\n\n                        // Make sure that the byte order is correct\n                        BSWAP_ARRAY32_UNSIGNED(FileBitmap, BitmapSize);\n\n                        // Update the stream size\n                        pStream->BuildNumber = StringToInt(PartHdr.GameBuildNumber);\n                        pStream->StreamSize = StreamSize;\n\n                        // Fill the bitmap information\n                        pStream->FileBitmap = FileBitmap;\n                        pStream->BitmapSize = BitmapSize;\n                        pStream->BlockSize  = PartHdr.BlockSize;\n                        pStream->BlockCount = BlockCount;\n                        pStream->IsComplete = PartStream_CheckFile(pStream);\n                        return true;\n                    }\n                }\n            }\n        }\n    }\n\n    return false;\n}\n\nstatic void PartStream_UpdateBitmap(\n    TBlockStream * pStream,                // Pointer to an open stream\n    ULONGLONG StartOffset,\n    ULONGLONG EndOffset,\n    ULONGLONG RealOffset)\n{\n    PPART_FILE_MAP_ENTRY FileBitmap;\n    DWORD BlockSize = pStream->BlockSize;\n\n    // Sanity checks\n    assert((StartOffset & (BlockSize - 1)) == 0);\n    assert(pStream->FileBitmap != NULL);\n\n    // Calculate the first entry in the block map\n    FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (StartOffset / BlockSize);\n\n    // Set all bits for the specified range\n    while(StartOffset < EndOffset)\n    {\n        // Set the bit\n        FileBitmap->BlockOffsHi = (DWORD)(RealOffset >> 0x20);\n        FileBitmap->BlockOffsLo = (DWORD)(RealOffset & 0xFFFFFFFF);\n        FileBitmap->Flags = 3;\n\n        // Move all\n        StartOffset += BlockSize;\n        RealOffset += BlockSize;\n        FileBitmap++;\n    }\n\n    // Increment the bitmap update count\n    pStream->IsModified = 1;\n}\n\nstatic bool PartStream_BlockCheck(\n    TBlockStream * pStream,                // Pointer to an open stream\n    ULONGLONG BlockOffset)\n{\n    PPART_FILE_MAP_ENTRY FileBitmap;\n\n    // Sanity checks\n    assert((BlockOffset & (pStream->BlockSize - 1)) == 0);\n    assert(pStream->FileBitmap != NULL);\n\n    // Calculate the block map entry\n    FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (BlockOffset / pStream->BlockSize);\n\n    // Check if the flags are present\n    return (FileBitmap->Flags & 0x03) ? true : false;\n}\n\nstatic bool PartStream_BlockRead(\n    TBlockStream * pStream,\n    ULONGLONG StartOffset,\n    ULONGLONG EndOffset,\n    LPBYTE BlockBuffer,\n    DWORD BytesNeeded,\n    bool bAvailable)\n{\n    PPART_FILE_MAP_ENTRY FileBitmap;\n    ULONGLONG ByteOffset;\n    DWORD BytesToRead;\n    DWORD BlockIndex = (DWORD)(StartOffset / pStream->BlockSize);\n\n    // The starting offset must be aligned to size of the block\n    assert(pStream->FileBitmap != NULL);\n    assert((StartOffset & (pStream->BlockSize - 1)) == 0);\n    assert(StartOffset < EndOffset);\n\n    // If the blocks are not available, we need to load them from the master\n    // and then save to the mirror\n    if(bAvailable == false)\n    {\n        // If we have no master, we cannot satisfy read request\n        if(pStream->pMaster == NULL)\n            return false;\n\n        // Load the blocks from the master stream\n        // Note that we always have to read complete blocks\n        // so they get properly stored to the mirror stream\n        BytesToRead = (DWORD)(EndOffset - StartOffset);\n        if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead))\n            return false;\n\n        // The loaded blocks are going to be stored to the end of the file\n        // Note that this operation is not required to succeed\n        if(pStream->BaseGetSize(pStream, &ByteOffset))\n        {\n            // Store the loaded blocks to the mirror file.\n            if(pStream->BaseWrite(pStream, &ByteOffset, BlockBuffer, BytesToRead))\n            {\n                PartStream_UpdateBitmap(pStream, StartOffset, EndOffset, ByteOffset);\n            }\n        }\n    }\n    else\n    {\n        // Get the file map entry\n        FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + BlockIndex;\n\n        // Read all blocks\n        while(StartOffset < EndOffset)\n        {\n            // Get the number of bytes to be read\n            BytesToRead = (DWORD)(EndOffset - StartOffset);\n            if(BytesToRead > pStream->BlockSize)\n                BytesToRead = pStream->BlockSize;\n            if(BytesToRead > BytesNeeded)\n                BytesToRead = BytesNeeded;\n\n            // Read the block\n            ByteOffset = MAKE_OFFSET64(FileBitmap->BlockOffsHi, FileBitmap->BlockOffsLo);\n            if(!pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead))\n                return false;\n\n            // Move the pointers\n            StartOffset += pStream->BlockSize;\n            BlockBuffer += pStream->BlockSize;\n            BytesNeeded -= pStream->BlockSize;\n            FileBitmap++;\n        }\n    }\n\n    return true;\n}\n\nstatic void PartStream_Close(TBlockStream * pStream)\n{\n    PART_FILE_HEADER PartHeader;\n    ULONGLONG ByteOffset = 0;\n\n    if(pStream->FileBitmap && pStream->IsModified)\n    {\n        // Prepare the part file header\n        memset(&PartHeader, 0, sizeof(PART_FILE_HEADER));\n        PartHeader.PartialVersion = 2;\n        PartHeader.FileSizeHi     = (DWORD)(pStream->StreamSize >> 0x20);\n        PartHeader.FileSizeLo     = (DWORD)(pStream->StreamSize & 0xFFFFFFFF);\n        PartHeader.BlockSize      = pStream->BlockSize;\n\n        // Make sure that the header is properly BSWAPed\n        BSWAP_ARRAY32_UNSIGNED(&PartHeader, sizeof(PART_FILE_HEADER));\n        CascStrPrintf(PartHeader.GameBuildNumber, _countof(PartHeader.GameBuildNumber), \"%u\", (unsigned int)pStream->BuildNumber);\n\n        // Write the part header\n        pStream->BaseWrite(pStream, &ByteOffset, &PartHeader, sizeof(PART_FILE_HEADER));\n\n        // Write the block bitmap\n        BSWAP_ARRAY32_UNSIGNED(pStream->FileBitmap, pStream->BitmapSize);\n        pStream->BaseWrite(pStream, NULL, pStream->FileBitmap, pStream->BitmapSize);\n    }\n\n    // Close the base class\n    BlockStream_Close(pStream);\n}\n\nstatic bool PartStream_CreateMirror(TBlockStream * pStream)\n{\n    ULONGLONG RemainingSize;\n    ULONGLONG MasterSize = 0;\n    ULONGLONG MirrorSize = 0;\n    LPBYTE FileBitmap = NULL;\n    DWORD dwBitmapSize;\n    DWORD dwBlockCount;\n    bool bNeedCreateMirrorStream = true;\n    bool bNeedResizeMirrorStream = true;\n\n    // Do we have master function and base creation function?\n    if(pStream->pMaster == NULL || pStream->BaseCreate == NULL)\n        return false;\n\n    // Retrieve the master file size, block count and bitmap size\n    FileStream_GetSize(pStream->pMaster, &MasterSize);\n    dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE);\n    dwBitmapSize = (DWORD)(dwBlockCount * sizeof(PART_FILE_MAP_ENTRY));\n\n    // Setup stream size and position\n    pStream->BuildNumber = DEFAULT_BUILD_NUMBER;        // BUGBUG: Really???\n    pStream->StreamSize = MasterSize;\n    pStream->StreamPos = 0;\n\n    // Open the base stream for write access\n    if(pStream->BaseOpen(pStream, pStream->szFileName, 0))\n    {\n        // If the file open succeeded, check if the file size matches required size\n        pStream->BaseGetSize(pStream, &MirrorSize);\n        if(MirrorSize >= sizeof(PART_FILE_HEADER) + dwBitmapSize)\n        {\n            // Check if the remaining size is aligned to block\n            RemainingSize = MirrorSize - sizeof(PART_FILE_HEADER) - dwBitmapSize;\n            if((RemainingSize & (DEFAULT_BLOCK_SIZE - 1)) == 0 || RemainingSize == MasterSize)\n            {\n                // Attempt to load an existing file bitmap\n                if(PartStream_LoadBitmap(pStream))\n                    return true;\n            }\n        }\n\n        // We need to create mirror stream\n        bNeedCreateMirrorStream = false;\n    }\n\n    // Create a new stream, if needed\n    if(bNeedCreateMirrorStream)\n    {\n        if(!pStream->BaseCreate(pStream))\n            return false;\n    }\n\n    // If we need to, then resize the mirror stream\n    if(bNeedResizeMirrorStream)\n    {\n        if(!pStream->BaseResize(pStream, sizeof(PART_FILE_HEADER) + dwBitmapSize))\n            return false;\n    }\n\n    // Allocate the bitmap array\n    FileBitmap = CASC_ALLOC_ZERO<BYTE>(dwBitmapSize);\n    if(FileBitmap == NULL)\n        return false;\n\n    // Initialize the bitmap\n    pStream->FileBitmap = FileBitmap;\n    pStream->BitmapSize = dwBitmapSize;\n    pStream->BlockSize  = DEFAULT_BLOCK_SIZE;\n    pStream->BlockCount = dwBlockCount;\n    pStream->IsComplete = 0;\n    pStream->IsModified = 1;\n\n    // Note: Don't write the stream bitmap right away.\n    // Doing so would cause sparse file resize on NTFS,\n    // which would take long time on larger files.\n    return true;\n}\n\nstatic TFileStream * PartStream_Open(LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n    TBlockStream * pStream;\n\n    // Create new empty stream\n    pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);\n    if(pStream == NULL)\n        return NULL;\n\n    // Do we have a master stream?\n    if(pStream->pMaster != NULL)\n    {\n        if(!PartStream_CreateMirror(pStream))\n        {\n            FileStream_Close(pStream);\n            SetCascError(ERROR_FILE_NOT_FOUND);\n            return NULL;\n        }\n    }\n    else\n    {\n        // Attempt to open the base stream\n        if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags))\n        {\n            FileStream_Close(pStream);\n            return NULL;\n        }\n\n        // Load the part stream block map\n        if(!PartStream_LoadBitmap(pStream))\n        {\n            FileStream_Close(pStream);\n            SetCascError(ERROR_BAD_FORMAT);\n            return NULL;\n        }\n    }\n\n    // Set the stream position to zero. Stream size is already set\n    assert(pStream->StreamSize != 0);\n    pStream->StreamPos = 0;\n    pStream->dwFlags |= STREAM_FLAG_READ_ONLY;\n\n    // Set new function pointers\n    pStream->StreamRead    = (STREAM_READ)BlockStream_Read;\n    pStream->StreamGetPos  = BlockStream_GetPos;\n    pStream->StreamGetSize = BlockStream_GetSize;\n    pStream->StreamClose   = (STREAM_CLOSE)PartStream_Close;\n\n    // Supply the block functions\n    pStream->BlockCheck    = (BLOCK_CHECK)PartStream_BlockCheck;\n    pStream->BlockRead     = (BLOCK_READ)PartStream_BlockRead;\n    return pStream;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - encrypted stream support\n\nstatic const char * szKeyTemplate = \"expand 32-byte k000000000000000000000000000000000000000000000000\";\n\nstatic const char * AuthCodeArray[] =\n{\n    // Starcraft II (Heart of the Swarm)\n    // Authentication code URL: http://dist.blizzard.com/mediakey/hots-authenticationcode-bgdl.txt\n    //                                                                                          -0C-    -1C--08-    -18--04-    -14--00-    -10-\n    \"S48B6CDTN5XEQAKQDJNDLJBJ73FDFM3U\",         // SC2 Heart of the Swarm-all : \"expand 32-byte kQAKQ0000FM3UN5XE000073FD6CDT0000LJBJS48B0000DJND\"\n\n    // Diablo III: Agent.exe (1.0.0.954)\n    // Address of decryption routine: 00502b00\n    // Pointer to decryptor object: ECX\n    // Pointer to key: ECX+0x5C\n    // Authentication code URL: http://dist.blizzard.com/mediakey/d3-authenticationcode-enGB.txt\n    //                                                                                           -0C-    -1C--08-    -18--04-    -14--00-    -10-\n    \"UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK\",         // Diablo III Installer (deDE): \"expand 32-byte kEFH40000QRZKY3520000XC9MF6EJ0000CFH2UCMX0000XFRX\"\n    \"MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP\",         // Diablo III Installer (enGB): \"expand 32-byte kXP4G0000PHBPRP7W0000J9UNHY4800007SL9MMKV0000HYBQ\"\n    \"8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP\",         // Diablo III Installer (enSG): \"expand 32-byte kTZ9M00003CPPVGGL0000JYETWHQ70000FDCL8MXL0000QZQS\"\n    \"EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ\",         // Diablo III Installer (enUS): \"expand 32-byte kGUNG0000WZSZXFE20000UAKP5TM60000HKQ9EJ2R00005QDG\"\n    \"PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT\",         // Diablo III Installer (esES): \"expand 32-byte kK65U0000HQQTZ6LN0000CLP4BE420000WZVMPBGF0000GJQ3\"\n    \"X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2\",         // Diablo III Installer (esMX): \"expand 32-byte kW5P200008VU2TSGC0000JPEYJJS90000C47AX7SE00008EBS\"\n    \"5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2\",         // Diablo III Installer (frFR): \"expand 32-byte kRY3D00007YA2YE6X0000XS4PQA8V0000ZDE45KVB0000LGC5\"\n    \"478JD2K56EVNVVY4XX8TDWYT5B8KB254\",         // Diablo III Installer (itIT): \"expand 32-byte kVVY40000B2546EVN00005B8KD2K50000DWYT478J0000XX8T\"\n    \"8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A\",         // Diablo III Installer (koKR): \"expand 32-byte k6YWH0000474ARZTN0000NVWDVNFQ0000VDH98TS40000E9CH\"\n    \"LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB\",         // Diablo III Installer (plPL): \"expand 32-byte k4ZJJ0000BLJBF4LZ0000A6GAZ32D00003AZQLJ520000XVKK\"\n    \"K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG\",         // Diablo III Installer (ptBR): \"expand 32-byte k545Y0000XYAGCUE20000WHE7HY2E0000JPVYK6BD0000KNLB\"\n    \"NDVW8GWLAYCRPGRNY8RT7ZZUQU63VLPR\",         // Diablo III Installer (ruRU): \"expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n    \"6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H\",         // Diablo III Installer (zhTW): \"expand 32-byte kMRUC0000AA8HV3ZZ0000UX2TQTN80000A8CG6VWC0000ZXV8\"\n//  \"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",         // Diablo III Installer (zhCN): \"expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n\n    // Starcraft II (Wings of Liberty): Installer.exe (4.1.1.4219)\n    // Address of decryption routine: 0053A3D0\n    // Pointer to decryptor object: ECX\n    // Pointer to key: ECX+0x5C\n    // Authentication code URL: http://dist.blizzard.com/mediakey/sc2-authenticationcode-enUS.txt\n    //                                                                                          -0C-    -1C--08-    -18--04-    -14--00-    -10-\n    \"Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX\",         // SC2 Wings of Liberty (deDE): \"expand 32-byte kSSXH00004XFXK4KX00008EKJD3CA0000Y64ZY45M0000YD9V\"\n    \"G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH\",         // SC2 Wings of Liberty (enGB): \"expand 32-byte kANGY000029ZH6NA20000HRGF8UDG0000NY82G8MN00006A3D\"\n    \"W9RRHLB2FDU9WW5B3ECEBLRSFWZSF7HW\",         // SC2 Wings of Liberty (enSG): \"expand 32-byte kWW5B0000F7HWFDU90000FWZSHLB20000BLRSW9RR00003ECE\"\n    \"3DH5RE5NVM5GTFD85LXGWT6FK859ETR5\",         // SC2 Wings of Liberty (enUS): \"expand 32-byte kTFD80000ETR5VM5G0000K859RE5N0000WT6F3DH500005LXG\"\n    \"8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ\",         // SC2 Wings of Liberty (esES): \"expand 32-byte kQU4Y0000XKTQ94PF0000N4R4UAXE0000AZ248WLK0000249P\"\n    \"A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54\",         // SC2 Wings of Liberty (esMX): \"expand 32-byte kSQBR00004G54HGGX0000MF9GXX3V0000FFDXA34D0000FE5U\"\n    \"ZG7J9K938HJEFWPQUA768MA2PFER6EAJ\",         // SC2 Wings of Liberty (frFR): \"expand 32-byte kFWPQ00006EAJ8HJE0000PFER9K9300008MA2ZG7J0000UA76\"\n    \"NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2\",         // SC2 Wings of Liberty (itIT): \"expand 32-byte kXV7E00008BL2TVAP0000GVMWUNNN0000SVBWNE7C00003G2B\"\n    \"3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F\",         // SC2 Wings of Liberty (koKR): \"expand 32-byte kQWK70000838FBM9Q0000WQDB2FTM0000MWAZ3V9E0000U6MA\"\n    \"2NSFB8MELULJ83U6YHA3UP6K4MQD48L6\",         // SC2 Wings of Liberty (plPL): \"expand 32-byte k83U6000048L6LULJ00004MQDB8ME0000UP6K2NSF0000YHA3\"\n    \"QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E\",         // SC2 Wings of Liberty (ptBR): \"expand 32-byte kU8BM0000SW4EZ4CU00005F9CZ9EW0000CTY6QA2T0000B5WX\"\n    \"VHB378W64BAT9SH7D68VV9NLQDK9YEGT\",         // SC2 Wings of Liberty (ruRU): \"expand 32-byte k9SH70000YEGT4BAT0000QDK978W60000V9NLVHB30000D68V\"\n    \"U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE\",         // SC2 Wings of Liberty (zhTW): \"expand 32-byte k7KBN0000D9NEM6GC0000N3PLQJV400003BRDU3NF00009XQJ\"\n\n    NULL\n};\n\nstatic void CreateKeyFromAuthCode(\n    LPBYTE pbKeyBuffer,\n    const char * szAuthCode)\n{\n    PDWORD KeyPosition = (PDWORD)(pbKeyBuffer + 0x10);\n    PDWORD AuthCode32 = (PDWORD)szAuthCode;\n\n    memcpy(pbKeyBuffer, szKeyTemplate, ENCRYPTED_CHUNK_SIZE);\n    KeyPosition[0x00] = AuthCode32[0x03];\n    KeyPosition[0x02] = AuthCode32[0x07];\n    KeyPosition[0x03] = AuthCode32[0x02];\n    KeyPosition[0x05] = AuthCode32[0x06];\n    KeyPosition[0x06] = AuthCode32[0x01];\n    KeyPosition[0x08] = AuthCode32[0x05];\n    KeyPosition[0x09] = AuthCode32[0x00];\n    KeyPosition[0x0B] = AuthCode32[0x04];\n    BSWAP_ARRAY32_UNSIGNED(pbKeyBuffer, ENCRYPTED_CHUNK_SIZE);\n}\n\nstatic void DecryptFileChunk(\n    DWORD * ChunkData,\n    LPBYTE pbKey,\n    ULONGLONG ByteOffset,\n    DWORD dwLength)\n{\n    ULONGLONG ChunkOffset;\n    DWORD KeyShuffled[0x10];\n    DWORD KeyMirror[0x10];\n    DWORD RoundCount = 0x14;\n\n    // Prepare the key\n    ChunkOffset = ByteOffset / ENCRYPTED_CHUNK_SIZE;\n    memcpy(KeyMirror, pbKey, ENCRYPTED_CHUNK_SIZE);\n    BSWAP_ARRAY32_UNSIGNED(KeyMirror, ENCRYPTED_CHUNK_SIZE);\n    KeyMirror[0x05] = (DWORD)(ChunkOffset >> 32);\n    KeyMirror[0x08] = (DWORD)(ChunkOffset);\n\n    while(dwLength >= ENCRYPTED_CHUNK_SIZE)\n    {\n        // Shuffle the key - part 1\n        KeyShuffled[0x0E] = KeyMirror[0x00];\n        KeyShuffled[0x0C] = KeyMirror[0x01];\n        KeyShuffled[0x05] = KeyMirror[0x02];\n        KeyShuffled[0x0F] = KeyMirror[0x03];\n        KeyShuffled[0x0A] = KeyMirror[0x04];\n        KeyShuffled[0x07] = KeyMirror[0x05];\n        KeyShuffled[0x0B] = KeyMirror[0x06];\n        KeyShuffled[0x09] = KeyMirror[0x07];\n        KeyShuffled[0x03] = KeyMirror[0x08];\n        KeyShuffled[0x06] = KeyMirror[0x09];\n        KeyShuffled[0x08] = KeyMirror[0x0A];\n        KeyShuffled[0x0D] = KeyMirror[0x0B];\n        KeyShuffled[0x02] = KeyMirror[0x0C];\n        KeyShuffled[0x04] = KeyMirror[0x0D];\n        KeyShuffled[0x01] = KeyMirror[0x0E];\n        KeyShuffled[0x00] = KeyMirror[0x0F];\n\n        // Shuffle the key - part 2\n        for(DWORD i = 0; i < RoundCount; i += 2)\n        {\n            KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x02]), 0x07);\n            KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0E]), 0x09);\n            KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x0A]), 0x0D);\n            KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x03]), 0x12);\n\n            KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x04]), 0x07);\n            KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x0C]), 0x09);\n            KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x07]), 0x0D);\n            KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x06]), 0x12);\n\n            KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x01]), 0x07);\n            KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x05]), 0x09);\n            KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x0B]), 0x0D);\n            KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x08]), 0x12);\n\n            KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x00]), 0x07);\n            KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x0F]), 0x09);\n            KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x09]), 0x0D);\n            KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x0D]), 0x12);\n\n            KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x09]), 0x07);\n            KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x0E]), 0x09);\n            KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x04]), 0x0D);\n            KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x08]), 0x12);\n\n            KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x0A]), 0x07);\n            KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x0C]), 0x09);\n            KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x01]), 0x0D);\n            KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0D]), 0x12);\n\n            KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x07]), 0x07);\n            KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x05]), 0x09);\n            KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x00]), 0x0D);\n            KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x03]), 0x12);\n\n            KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x0B]), 0x07);\n            KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x0F]), 0x09);\n            KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x02]), 0x0D);\n            KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x06]), 0x12);\n        }\n\n        // Decrypt one data chunk\n        BSWAP_ARRAY32_UNSIGNED(ChunkData, ENCRYPTED_CHUNK_SIZE);\n        ChunkData[0x00] = ChunkData[0x00] ^ (KeyShuffled[0x0E] + KeyMirror[0x00]);\n        ChunkData[0x01] = ChunkData[0x01] ^ (KeyShuffled[0x04] + KeyMirror[0x0D]);\n        ChunkData[0x02] = ChunkData[0x02] ^ (KeyShuffled[0x08] + KeyMirror[0x0A]);\n        ChunkData[0x03] = ChunkData[0x03] ^ (KeyShuffled[0x09] + KeyMirror[0x07]);\n        ChunkData[0x04] = ChunkData[0x04] ^ (KeyShuffled[0x0A] + KeyMirror[0x04]);\n        ChunkData[0x05] = ChunkData[0x05] ^ (KeyShuffled[0x0C] + KeyMirror[0x01]);\n        ChunkData[0x06] = ChunkData[0x06] ^ (KeyShuffled[0x01] + KeyMirror[0x0E]);\n        ChunkData[0x07] = ChunkData[0x07] ^ (KeyShuffled[0x0D] + KeyMirror[0x0B]);\n        ChunkData[0x08] = ChunkData[0x08] ^ (KeyShuffled[0x03] + KeyMirror[0x08]);\n        ChunkData[0x09] = ChunkData[0x09] ^ (KeyShuffled[0x07] + KeyMirror[0x05]);\n        ChunkData[0x0A] = ChunkData[0x0A] ^ (KeyShuffled[0x05] + KeyMirror[0x02]);\n        ChunkData[0x0B] = ChunkData[0x0B] ^ (KeyShuffled[0x00] + KeyMirror[0x0F]);\n        ChunkData[0x0C] = ChunkData[0x0C] ^ (KeyShuffled[0x02] + KeyMirror[0x0C]);\n        ChunkData[0x0D] = ChunkData[0x0D] ^ (KeyShuffled[0x06] + KeyMirror[0x09]);\n        ChunkData[0x0E] = ChunkData[0x0E] ^ (KeyShuffled[0x0B] + KeyMirror[0x06]);\n        ChunkData[0x0F] = ChunkData[0x0F] ^ (KeyShuffled[0x0F] + KeyMirror[0x03]);\n        BSWAP_ARRAY32_UNSIGNED(ChunkData, ENCRYPTED_CHUNK_SIZE);\n\n        // Update byte offset in the key\n        KeyMirror[0x08]++;\n        if(KeyMirror[0x08] == 0)\n            KeyMirror[0x05]++;\n\n        // Move pointers and decrease number of bytes to decrypt\n        ChunkData += (ENCRYPTED_CHUNK_SIZE / sizeof(DWORD));\n        dwLength -= ENCRYPTED_CHUNK_SIZE;\n    }\n}\n\nstatic bool EncrStream_DetectFileKey(TEncryptedStream * pStream)\n{\n    ULONGLONG ByteOffset = 0;\n    BYTE EncryptedHeader[ENCRYPTED_CHUNK_SIZE];\n    BYTE FileHeader[ENCRYPTED_CHUNK_SIZE];\n\n    // Read the first file chunk\n    if(pStream->BaseRead(pStream, &ByteOffset, EncryptedHeader, sizeof(EncryptedHeader)))\n    {\n        // We just try all known keys one by one\n        for(int i = 0; AuthCodeArray[i] != NULL; i++)\n        {\n            // Prepare they decryption key from game serial number\n            CreateKeyFromAuthCode(pStream->Key, AuthCodeArray[i]);\n\n            // Try to decrypt with the given key\n            memcpy(FileHeader, EncryptedHeader, ENCRYPTED_CHUNK_SIZE);\n            DecryptFileChunk((PDWORD)FileHeader, pStream->Key, ByteOffset, ENCRYPTED_CHUNK_SIZE);\n\n            // We check the decrypted data\n            // All known encrypted archives have header at the begin of the file,\n            // so we check for archive signature there.\n            if(FileHeader[0] == 'M' && FileHeader[1] == 'P' && FileHeader[2] == 'Q')\n            {\n                // Update the stream size\n                pStream->StreamSize = pStream->Base.File.FileSize;\n\n                // Fill the block information\n                pStream->BlockSize  = ENCRYPTED_CHUNK_SIZE;\n                pStream->BlockCount = (DWORD)(pStream->Base.File.FileSize + ENCRYPTED_CHUNK_SIZE - 1) / ENCRYPTED_CHUNK_SIZE;\n                pStream->IsComplete = 1;\n                return true;\n            }\n        }\n    }\n\n    // Key not found, sorry\n    return false;\n}\n\nstatic bool EncrStream_BlockRead(\n    TEncryptedStream * pStream,\n    ULONGLONG StartOffset,\n    ULONGLONG EndOffset,\n    LPBYTE BlockBuffer,\n    DWORD BytesNeeded,\n    bool bAvailable)\n{\n    DWORD dwBytesToRead;\n\n    assert((StartOffset & (pStream->BlockSize - 1)) == 0);\n    assert(StartOffset < EndOffset);\n    assert(bAvailable != false);\n    BytesNeeded = BytesNeeded;\n    bAvailable = bAvailable;\n\n    // Read the file from the stream as-is\n    // Limit the reading to number of blocks really needed\n    dwBytesToRead = (DWORD)(EndOffset - StartOffset);\n    if(!pStream->BaseRead(pStream, &StartOffset, BlockBuffer, dwBytesToRead))\n        return false;\n\n    // Decrypt the data\n    dwBytesToRead = (dwBytesToRead + ENCRYPTED_CHUNK_SIZE - 1) & ~(ENCRYPTED_CHUNK_SIZE - 1);\n    DecryptFileChunk((PDWORD)BlockBuffer, pStream->Key, StartOffset, dwBytesToRead);\n    return true;\n}\n\nstatic TFileStream * EncrStream_Open(LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n    TEncryptedStream * pStream;\n\n    // Create new empty stream\n    pStream = (TEncryptedStream *)AllocateFileStream(szFileName, sizeof(TEncryptedStream), dwStreamFlags);\n    if(pStream == NULL)\n        return NULL;\n\n    // Attempt to open the base stream\n    assert(pStream->BaseOpen != NULL);\n    if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags))\n        return NULL;\n\n    // Determine the encryption key for the archive\n    if(EncrStream_DetectFileKey(pStream))\n    {\n        // Set the stream position and size\n        assert(pStream->StreamSize != 0);\n        pStream->StreamPos = 0;\n        pStream->dwFlags |= STREAM_FLAG_READ_ONLY;\n\n        // Set new function pointers\n        pStream->StreamRead    = (STREAM_READ)BlockStream_Read;\n        pStream->StreamGetPos  = BlockStream_GetPos;\n        pStream->StreamGetSize = BlockStream_GetSize;\n        pStream->StreamClose   = pStream->BaseClose;\n\n        // Supply the block functions\n        pStream->BlockRead     = (BLOCK_READ)EncrStream_BlockRead;\n        return pStream;\n    }\n\n    // Cleanup the stream and return\n    FileStream_Close(pStream);\n    SetCascError(ERROR_FILE_ENCRYPTED);\n    return NULL;\n}\n\n//-----------------------------------------------------------------------------\n// Local functions - Block4 stream support\n\n#define BLOCK4_BLOCK_SIZE   0x4000          // Size of one block\n#define BLOCK4_HASH_SIZE    0x20            // Size of MD5 hash that is after each block\n#define BLOCK4_MAX_BLOCKS   0x00002000      // Maximum amount of blocks per file\n#define BLOCK4_MAX_FSIZE    0x08040000      // Max size of one file\n\nstatic bool Block4Stream_BlockRead(\n    TBlockStream * pStream,                // Pointer to an open stream\n    ULONGLONG StartOffset,\n    ULONGLONG EndOffset,\n    LPBYTE BlockBuffer,\n    DWORD BytesNeeded,\n    bool bAvailable)\n{\n    TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap;\n    ULONGLONG ByteOffset;\n    DWORD BytesToRead;\n    DWORD StreamIndex;\n    DWORD BlockIndex;\n    bool bResult;\n\n    // The starting offset must be aligned to size of the block\n    assert(pStream->FileBitmap != NULL);\n    assert((StartOffset & (pStream->BlockSize - 1)) == 0);\n    assert(StartOffset < EndOffset);\n    assert(bAvailable == true);\n\n    // Keep compiler happy\n    bAvailable = bAvailable;\n    EndOffset = EndOffset;\n\n    while(BytesNeeded != 0)\n    {\n        // Calculate the block index and the file index\n        StreamIndex = (DWORD)((StartOffset / pStream->BlockSize) / BLOCK4_MAX_BLOCKS);\n        BlockIndex  = (DWORD)((StartOffset / pStream->BlockSize) % BLOCK4_MAX_BLOCKS);\n        if(StreamIndex > pStream->BitmapSize)\n            return false;\n\n        // Calculate the block offset\n        ByteOffset = ((ULONGLONG)BlockIndex * (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE));\n        BytesToRead = CASCLIB_MIN(BytesNeeded, BLOCK4_BLOCK_SIZE);\n\n        // Read from the base stream\n        pStream->Base = BaseArray[StreamIndex];\n        bResult = pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead);\n        BaseArray[StreamIndex] = pStream->Base;\n\n        // Did the result succeed?\n        if(bResult == false)\n            return false;\n\n        // Move pointers\n        StartOffset += BytesToRead;\n        BlockBuffer += BytesToRead;\n        BytesNeeded -= BytesToRead;\n    }\n\n    return true;\n}\n\n\nstatic void Block4Stream_Close(TBlockStream * pStream)\n{\n    TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap;\n\n    // If we have a non-zero count of base streams,\n    // we have to close them all\n    if(BaseArray != NULL)\n    {\n        // Close all base streams\n        for(DWORD i = 0; i < pStream->BitmapSize; i++)\n        {\n            memcpy(&pStream->Base, BaseArray + i, sizeof(TBaseProviderData));\n            pStream->BaseClose(pStream);\n        }\n    }\n\n    // Free the data map, if any\n    CASC_FREE(pStream->FileBitmap);\n\n    // Do not call the BaseClose function,\n    // we closed all handles already\n    return;\n}\n\nstatic TFileStream * Block4Stream_Open(LPCTSTR szFileName, DWORD dwStreamFlags)\n{\n    TBaseProviderData * NewBaseArray = NULL;\n    ULONGLONG RemainderBlock;\n    ULONGLONG BlockCount;\n    ULONGLONG FileSize;\n    TBlockStream * pStream;\n    LPTSTR szNameBuff;\n    size_t nNameLength;\n    DWORD dwBaseFiles = 0;\n    DWORD dwBaseFlags;\n\n    // Create new empty stream\n    pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);\n    if(pStream == NULL)\n        return NULL;\n\n    // Sanity check\n    assert(pStream->BaseOpen != NULL);\n\n    // Get the length of the file name without numeric suffix\n    nNameLength = _tcslen(pStream->szFileName);\n    if(pStream->szFileName[nNameLength - 2] == '.' && pStream->szFileName[nNameLength - 1] == '0')\n        nNameLength -= 2;\n    pStream->szFileName[nNameLength] = 0;\n\n    // Supply the stream functions\n    pStream->StreamRead    = (STREAM_READ)BlockStream_Read;\n    pStream->StreamGetSize = BlockStream_GetSize;\n    pStream->StreamGetPos  = BlockStream_GetPos;\n    pStream->StreamClose   = (STREAM_CLOSE)Block4Stream_Close;\n    pStream->BlockRead     = (BLOCK_READ)Block4Stream_BlockRead;\n\n    // Allocate work space for numeric names\n    szNameBuff = CASC_ALLOC<TCHAR>(nNameLength + 4);\n    if(szNameBuff != NULL)\n    {\n        // Set the base flags\n        dwBaseFlags = (dwStreamFlags & STREAM_PROVIDERS_MASK) | STREAM_FLAG_READ_ONLY;\n\n        // Go all suffixes from 0 to 30\n        for(int nSuffix = 0; nSuffix < 30; nSuffix++)\n        {\n            // Open the n-th file\n            CascStrPrintf(szNameBuff, (nNameLength + 4), _T(\"%s.%u\"), pStream->szFileName, nSuffix);\n            if(!pStream->BaseOpen(pStream, szNameBuff, dwBaseFlags))\n                break;\n\n            // If the open succeeded, we re-allocate the base provider array\n            NewBaseArray = CASC_ALLOC<TBaseProviderData>(dwBaseFiles + 1);\n            if(NewBaseArray == NULL)\n            {\n                SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n                return NULL;\n            }\n\n            // Copy the old base data array to the new base data array\n            if(pStream->FileBitmap != NULL)\n            {\n                memcpy(NewBaseArray, pStream->FileBitmap, sizeof(TBaseProviderData) * dwBaseFiles);\n                CASC_FREE(pStream->FileBitmap);\n            }\n\n            // Also copy the opened base array\n            memcpy(NewBaseArray + dwBaseFiles, &pStream->Base, sizeof(TBaseProviderData));\n            pStream->FileBitmap = NewBaseArray;\n            dwBaseFiles++;\n\n            // Get the size of the base stream\n            pStream->BaseGetSize(pStream, &FileSize);\n            assert(FileSize <= BLOCK4_MAX_FSIZE);\n            RemainderBlock = FileSize % (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE);\n            BlockCount = FileSize / (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE);\n\n            // Increment the stream size and number of blocks\n            pStream->StreamSize += (BlockCount * BLOCK4_BLOCK_SIZE);\n            pStream->BlockCount += (DWORD)BlockCount;\n\n            // Is this the last file?\n            if(FileSize < BLOCK4_MAX_FSIZE)\n            {\n                if(RemainderBlock)\n                {\n                    pStream->StreamSize += (RemainderBlock - BLOCK4_HASH_SIZE);\n                    pStream->BlockCount++;\n                }\n                break;\n            }\n        }\n\n        // Fill the remainining block stream variables\n        pStream->BitmapSize = dwBaseFiles;\n        pStream->BlockSize  = BLOCK4_BLOCK_SIZE;\n        pStream->IsComplete = 1;\n        pStream->IsModified = 0;\n\n        // Fill the remaining stream variables\n        pStream->StreamPos = 0;\n        pStream->dwFlags |= STREAM_FLAG_READ_ONLY;\n\n        CASC_FREE(szNameBuff);\n    }\n\n    // If we opened something, return success\n    if(dwBaseFiles == 0)\n    {\n        FileStream_Close(pStream);\n        SetCascError(ERROR_FILE_NOT_FOUND);\n        pStream = NULL;\n    }\n\n    return pStream;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\n/**\n * This function creates a new file for read-write access\n *\n * - If the current platform supports file sharing,\n *   the file must be created for read sharing (i.e. another application\n *   can open the file for read, but not for write)\n * - If the file does not exist, the function must create new one\n * - If the file exists, the function must rewrite it and set to zero size\n * - The parameters of the function must be validate by the caller\n * - The function must initialize all stream function pointers in TFileStream\n * - If the function fails from any reason, it must close all handles\n *   and free all memory that has been allocated in the process of stream creation,\n *   including the TFileStream structure itself\n *\n * \\a szFileName Name of the file to create\n */\n\nTFileStream * FileStream_CreateFile(\n    LPCTSTR szFileName,\n    DWORD dwStreamFlags)\n{\n    TFileStream * pStream;\n\n    // We only support creation of flat, local file\n    if((dwStreamFlags & (STREAM_PROVIDERS_MASK)) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE))\n    {\n        SetCascError(ERROR_NOT_SUPPORTED);\n        return NULL;\n    }\n\n    // Allocate file stream structure for flat stream\n    pStream = AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);\n    if(pStream != NULL)\n    {\n        // Attempt to create the disk file\n        if(BaseFile_Create(pStream))\n        {\n            // Fill the stream provider functions\n            pStream->StreamRead    = pStream->BaseRead;\n            pStream->StreamWrite   = pStream->BaseWrite;\n            pStream->StreamResize  = pStream->BaseResize;\n            pStream->StreamGetSize = pStream->BaseGetSize;\n            pStream->StreamGetPos  = pStream->BaseGetPos;\n            pStream->StreamClose   = pStream->BaseClose;\n            return pStream;\n        }\n\n        // File create failed, delete the stream\n        CASC_FREE(pStream);\n    }\n\n    // Return the stream\n    return pStream;\n}\n\n/**\n * This function opens an existing file for read or read-write access\n * - If the current platform supports file sharing,\n *   the file must be open for read sharing (i.e. another application\n *   can open the file for read, but not for write)\n * - If the file does not exist, the function must return NULL\n * - If the file exists but cannot be open, then function must return NULL\n * - The parameters of the function must be validate by the caller\n * - The function must initialize all stream function pointers in TFileStream\n * - If the function fails from any reason, it must close all handles\n *   and free all memory that has been allocated in the process of stream creation,\n *   including the TFileStream structure itself\n *\n * \\a szFileName Name of the file to open\n * \\a dwStreamFlags specifies the provider and base storage type\n */\n\nTFileStream * FileStream_OpenFile(\n    LPCTSTR szFileName,\n    DWORD dwStreamFlags)\n{\n    DWORD dwProvider = dwStreamFlags & STREAM_PROVIDERS_MASK;\n    size_t nPrefixLength = FileStream_Prefix(szFileName, &dwProvider);\n\n    // Re-assemble the stream flags\n    dwStreamFlags = (dwStreamFlags & STREAM_OPTIONS_MASK) | dwProvider;\n    szFileName += nPrefixLength;\n\n    // Perform provider-specific open\n    switch(dwStreamFlags & STREAM_PROVIDER_MASK)\n    {\n        case STREAM_PROVIDER_FLAT:\n            return FlatStream_Open(szFileName, dwStreamFlags);\n\n        case STREAM_PROVIDER_PARTIAL:\n            return PartStream_Open(szFileName, dwStreamFlags);\n\n        case STREAM_PROVIDER_ENCRYPTED:\n            return EncrStream_Open(szFileName, dwStreamFlags);\n\n        case STREAM_PROVIDER_BLOCK4:\n            return Block4Stream_Open(szFileName, dwStreamFlags);\n\n        default:\n            SetCascError(ERROR_INVALID_PARAMETER);\n            return NULL;\n    }\n}\n\n/**\n * Returns the file name of the stream\n *\n * \\a pStream Pointer to an open stream\n */\nLPCTSTR FileStream_GetFileName(TFileStream * pStream)\n{\n    assert(pStream != NULL);\n    return pStream->szFileName;\n}\n\n/**\n * Returns the length of the provider prefix. Returns zero if no prefix\n *\n * \\a szFileName Pointer to a stream name (file, mapped file, URL)\n * \\a pdwStreamProvider Pointer to a DWORD variable that receives stream provider (STREAM_PROVIDER_XXX)\n */\n\nsize_t FileStream_Prefix(LPCTSTR szFileName, DWORD * pdwProvider)\n{\n    size_t nPrefixLength1 = 0;\n    size_t nPrefixLength2 = 0;\n    DWORD dwProvider = 0;\n\n    if(szFileName != NULL)\n    {\n        //\n        // Determine the stream provider\n        //\n\n        if(!_tcsnicmp(szFileName, _T(\"flat-\"), 5))\n        {\n            dwProvider |= STREAM_PROVIDER_FLAT;\n            nPrefixLength1 = 5;\n        }\n\n        else if(!_tcsnicmp(szFileName, _T(\"part-\"), 5))\n        {\n            dwProvider |= STREAM_PROVIDER_PARTIAL;\n            nPrefixLength1 = 5;\n        }\n\n        else if(!_tcsnicmp(szFileName, _T(\"mpqe-\"), 5))\n        {\n            dwProvider |= STREAM_PROVIDER_ENCRYPTED;\n            nPrefixLength1 = 5;\n        }\n\n        else if(!_tcsnicmp(szFileName, _T(\"blk4-\"), 5))\n        {\n            dwProvider |= STREAM_PROVIDER_BLOCK4;\n            nPrefixLength1 = 5;\n        }\n\n        // Cut out the stream provider\n        szFileName += nPrefixLength1;\n\n        //\n        // Determine the base provider\n        //\n\n        if(!_tcsnicmp(szFileName, _T(\"file:\"), 5))\n        {\n            dwProvider |= BASE_PROVIDER_FILE;\n            nPrefixLength2 = 5;\n        }\n\n        else if(!_tcsnicmp(szFileName, _T(\"map:\"), 4))\n        {\n            dwProvider |= BASE_PROVIDER_MAP;\n            nPrefixLength2 = 4;\n        }\n\n        else if(!_tcsnicmp(szFileName, _T(\"http:\"), 5))\n        {\n            dwProvider |= BASE_PROVIDER_HTTP;\n            nPrefixLength2 = 5;\n        }\n\n        else if(!_tcsnicmp(szFileName, _T(\"ribbit:\"), 7))\n        {\n            dwProvider |= BASE_PROVIDER_RIBBIT;\n            nPrefixLength2 = 7;\n        }\n\n        // Only accept stream provider if we recognized the base provider\n        if(nPrefixLength2 != 0)\n        {\n            // It is also allowed to put \"//\" after the base provider, e.g. \"file://\", \"http://\"\n            if(szFileName[nPrefixLength2] == '/' && szFileName[nPrefixLength2+1] == '/')\n                nPrefixLength2 += 2;\n\n            if(pdwProvider != NULL)\n                *pdwProvider = dwProvider;\n        }\n    }\n\n    return nPrefixLength1 + nPrefixLength2;\n}\n\n/**\n * Sets a download callback. Whenever the stream needs to download one or more blocks\n * from the server, the callback is called\n *\n * \\a pStream Pointer to an open stream\n * \\a pfnCallback Pointer to callback function\n * \\a pvUserData Arbitrary user pointer passed to the download callback\n */\n\nbool FileStream_SetCallback(TFileStream * pStream, STREAM_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData)\n{\n    TBlockStream * pBlockStream = (TBlockStream *)pStream;\n\n    if(pStream->BlockRead == NULL)\n    {\n        SetCascError(ERROR_NOT_SUPPORTED);\n        return false;\n    }\n\n    pBlockStream->pfnCallback = pfnCallback;\n    pBlockStream->UserData = pvUserData;\n    return true;\n}\n\n/**\n * Reads data from the stream\n *\n * - Returns true if the read operation succeeded and all bytes have been read\n * - Returns false if either read failed or not all bytes have been read\n * - If the pByteOffset is NULL, the function must read the data from the current file position\n * - The function can be called with dwBytesToRead = 0. In that case, pvBuffer is ignored\n *   and the function just adjusts file pointer.\n *\n * \\a pStream Pointer to an open stream\n * \\a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position\n * \\a pvBuffer Pointer to data to be read\n * \\a dwBytesToRead Number of bytes to read from the file\n *\n * \\returns\n * - If the function reads the required amount of bytes, it returns true.\n * - If the function reads less than required bytes, it returns false and GetCascError() returns ERROR_HANDLE_EOF\n * - If the function fails, it reads false and GetCascError() returns an error code different from ERROR_HANDLE_EOF\n */\nbool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead)\n{\n    assert(pStream->StreamRead != NULL);\n    return pStream->StreamRead(pStream, pByteOffset, pvBuffer, dwBytesToRead);\n}\n\n/**\n * This function writes data to the stream\n *\n * - Returns true if the write operation succeeded and all bytes have been written\n * - Returns false if either write failed or not all bytes have been written\n * - If the pByteOffset is NULL, the function must write the data to the current file position\n *\n * \\a pStream Pointer to an open stream\n * \\a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position\n * \\a pvBuffer Pointer to data to be written\n * \\a dwBytesToWrite Number of bytes to write to the file\n */\nbool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite)\n{\n    if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)\n    {\n        SetCascError(ERROR_ACCESS_DENIED);\n        return false;\n    }\n\n    assert(pStream->StreamWrite != NULL);\n    return pStream->StreamWrite(pStream, pByteOffset, pvBuffer, dwBytesToWrite);\n}\n\n/**\n * Returns the size of a file\n *\n * \\a pStream Pointer to an open stream\n * \\a FileSize Pointer where to store the file size\n */\nbool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)\n{\n    assert(pStream->StreamGetSize != NULL);\n    return pStream->StreamGetSize(pStream, pFileSize);\n}\n\n/**\n * Sets the size of a file\n *\n * \\a pStream Pointer to an open stream\n * \\a NewFileSize File size to set\n */\nbool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize)\n{\n    if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)\n    {\n        SetCascError(ERROR_ACCESS_DENIED);\n        return false;\n    }\n\n    assert(pStream->StreamResize != NULL);\n    return pStream->StreamResize(pStream, NewFileSize);\n}\n\n/**\n * This function returns the current file position\n * \\a pStream\n * \\a pByteOffset\n */\nbool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)\n{\n    assert(pStream->StreamGetPos != NULL);\n    return pStream->StreamGetPos(pStream, pByteOffset);\n}\n\n/**\n * Returns the last write time of a file\n *\n * \\a pStream Pointer to an open stream\n * \\a pFileType Pointer where to store the file last write time\n */\nbool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFileTime)\n{\n    // Just use the saved filetime value\n    *pFileTime = pStream->Base.File.FileTime;\n    return true;\n}\n\n/**\n * Returns the stream flags\n *\n * \\a pStream Pointer to an open stream\n * \\a pdwStreamFlags Pointer where to store the stream flags\n */\nbool FileStream_GetFlags(TFileStream * pStream, PDWORD pdwStreamFlags)\n{\n    *pdwStreamFlags = pStream->dwFlags;\n    return true;\n}\n\n/**\n * Switches a stream with another. Used for final phase of archive compacting.\n * Performs these steps:\n *\n * 1) Closes the handle to the existing file\n * 2) Renames the temporary file to the original file, overwrites existing one\n * 3) Opens the file stores the handle and stream position to the new stream structure\n *\n * \\a pStream Pointer to an open stream\n * \\a pNewStream Temporary (\"working\") stream (created during archive compacting)\n */\nbool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream)\n{\n    // Only supported on flat files\n    if((pStream->dwFlags & STREAM_PROVIDERS_MASK) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE))\n    {\n        SetCascError(ERROR_NOT_SUPPORTED);\n        return false;\n    }\n\n    // Not supported on read-only streams\n    if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)\n    {\n        SetCascError(ERROR_ACCESS_DENIED);\n        return false;\n    }\n\n    // Close both stream's base providers\n    pNewStream->BaseClose(pNewStream);\n    pStream->BaseClose(pStream);\n\n    // Now we have to delete the (now closed) old file and rename the new file\n    if(!BaseFile_Replace(pStream, pNewStream))\n        return false;\n\n    // Now open the base file again\n    if(!BaseFile_Open(pStream, pStream->szFileName, pStream->dwFlags))\n        return false;\n\n    // Cleanup the new stream\n    FileStream_Close(pNewStream);\n    return true;\n}\n\n/**\n * This function closes an archive file and frees any data buffers\n * that have been allocated for stream management. The function must also\n * support partially allocated structure, i.e. one or more buffers\n * can be NULL, if there was an allocation failure during the process\n *\n * \\a pStream Pointer to an open stream\n */\nvoid FileStream_Close(TFileStream * pStream)\n{\n    // Check if the stream structure is allocated at all\n    if(pStream != NULL)\n    {\n        // Free the master stream, if any\n        if(pStream->pMaster != NULL)\n            FileStream_Close(pStream->pMaster);\n        pStream->pMaster = NULL;\n\n        // Close the stream provider.\n        if(pStream->StreamClose != NULL)\n            pStream->StreamClose(pStream);\n\n        // Also close base stream, if any\n        else if(pStream->BaseClose != NULL)\n            pStream->BaseClose(pStream);\n\n        // Free the stream lock\n        CascFreeLock(pStream->Lock);\n\n        // Free the stream itself\n        CASC_FREE(pStream);\n    }\n}\n"
  },
  {
    "path": "deps/CascLib/src/common/FileStream.h",
    "content": "/*****************************************************************************/\n/* FileStream.h                           Copyright (c) Ladislav Zezula 2012 */\n/*---------------------------------------------------------------------------*/\n/* Description: Definitions for FileStream object                            */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 14.04.12  1.00  Lad  The first version of FileStream.h                    */\n/*****************************************************************************/\n\n#ifndef __FILESTREAM_H__\n#define __FILESTREAM_H__\n\n//-----------------------------------------------------------------------------\n// Flags for file stream\n\n#define BASE_PROVIDER_FILE          0x00000000  // Base data source is a file\n#define BASE_PROVIDER_MAP           0x00000001  // Base data source is memory-mapped file\n#define BASE_PROVIDER_HTTP          0x00000002  // Base data source is a file on web server via the HTTP protocol\n#define BASE_PROVIDER_RIBBIT        0x00000003  // Base data source is a file on web server via the Ribbit protocol\n#define BASE_PROVIDER_MASK          0x0000000F  // Mask for base provider value\n\n#define STREAM_PROVIDER_FLAT        0x00000000  // Stream is linear with no offset mapping\n#define STREAM_PROVIDER_PARTIAL     0x00000010  // Stream is partial file (.part)\n#define STREAM_PROVIDER_ENCRYPTED   0x00000020  // Stream is an encrypted archive\n#define STREAM_PROVIDER_BLOCK4      0x00000030  // 0x4000 per block, text MD5 after each block, max 0x2000 blocks per file\n#define STREAM_PROVIDER_MASK        0x000000F0  // Mask for stream provider value\n\n#define STREAM_FLAG_READ_ONLY       0x00000100  // Stream is read only\n#define STREAM_FLAG_WRITE_SHARE     0x00000200  // Allow write sharing when open for write\n#define STREAM_FLAG_USE_BITMAP      0x00000400  // If the file has a file bitmap, load it and use it\n#define STREAM_FLAG_FILL_MISSING    0x00000800  // If less than expected was read from the file, fill the missing part with zeros\n#define STREAM_OPTIONS_MASK         0x0000FF00  // Mask for stream options\n\n#define STREAM_PROVIDERS_MASK       0x000000FF  // Mask to get stream providers\n#define STREAM_FLAGS_MASK           0x0000FFFF  // Mask for all stream flags (providers+options)\n\n//-----------------------------------------------------------------------------\n// Function prototypes\n\ntypedef void (*STREAM_INIT)(\n    struct TFileStream * pStream        // Pointer to an unopened stream\n);\n\ntypedef bool (*STREAM_CREATE)(\n    struct TFileStream * pStream        // Pointer to an unopened stream\n    );\n\ntypedef bool (*STREAM_OPEN)(\n    struct TFileStream * pStream,       // Pointer to an unopened stream\n    LPCTSTR szFileName,           // Pointer to file name to be open\n    DWORD dwStreamFlags                 // Stream flags\n    );\n\ntypedef bool (*STREAM_READ)(\n    struct TFileStream * pStream,       // Pointer to an open stream\n    ULONGLONG * pByteOffset,            // Pointer to file byte offset. If NULL, it reads from the current position\n    void * pvBuffer,                    // Pointer to data to be read\n    DWORD dwBytesToRead                 // Number of bytes to read from the file\n    );\n\ntypedef bool (*STREAM_WRITE)(\n    struct TFileStream * pStream,       // Pointer to an open stream\n    ULONGLONG * pByteOffset,            // Pointer to file byte offset. If NULL, it writes to the current position\n    const void * pvBuffer,              // Pointer to data to be written\n    DWORD dwBytesToWrite                // Number of bytes to read from the file\n    );\n\ntypedef bool (*STREAM_RESIZE)(\n    struct TFileStream * pStream,       // Pointer to an open stream\n    ULONGLONG FileSize                  // New size for the file, in bytes\n    );\n\ntypedef bool (*STREAM_GETSIZE)(\n    struct TFileStream * pStream,       // Pointer to an open stream\n    ULONGLONG * pFileSize               // Receives the file size, in bytes\n    );\n\ntypedef bool (*STREAM_GETPOS)(\n    struct TFileStream * pStream,       // Pointer to an open stream\n    ULONGLONG * pByteOffset             // Pointer to store current file position\n    );\n\ntypedef void (*STREAM_CLOSE)(\n    struct TFileStream * pStream        // Pointer to an open stream\n    );\n\ntypedef bool (*BLOCK_READ)(\n    struct TFileStream * pStream,       // Pointer to a block-oriented stream\n    ULONGLONG StartOffset,              // Byte offset of start of the block array\n    ULONGLONG EndOffset,                // End offset (either end of the block or end of the file)\n    LPBYTE BlockBuffer,                 // Pointer to block-aligned buffer\n    DWORD BytesNeeded,                  // Number of bytes that are really needed\n    bool bAvailable                     // true if the block is available\n    );\n\ntypedef bool (*BLOCK_CHECK)(\n    struct TFileStream * pStream,       // Pointer to a block-oriented stream\n    ULONGLONG BlockOffset               // Offset of the file to check\n    );\n\ntypedef void (*BLOCK_SAVEMAP)(\n    struct TFileStream * pStream        // Pointer to a block-oriented stream\n    );\n\ntypedef void (WINAPI * STREAM_DOWNLOAD_CALLBACK)(\n    void * pvUserData,\n    ULONGLONG ByteOffset,\n    DWORD dwTotalBytes\n    );\n\n//-----------------------------------------------------------------------------\n// Local structures - partial file structure and bitmap footer\n\n#define ID_FILE_BITMAP_FOOTER   0x33767470  // Signature of the file bitmap footer ('ptv3')\n#define DEFAULT_BLOCK_SIZE      0x00004000  // Default size of the stream block\n#define DEFAULT_BUILD_NUMBER         10958  // Build number for newly created partial MPQs\n\ntypedef struct _PART_FILE_HEADER\n{\n    DWORD PartialVersion;                   // Always set to 2\n    char  GameBuildNumber[0x20];            // Minimum build number of the game that can use this MPQ\n    DWORD Flags;                            // Flags (details unknown)\n    DWORD FileSizeLo;                       // Low 32 bits of the contained file size\n    DWORD FileSizeHi;                       // High 32 bits of the contained file size\n    DWORD BlockSize;                        // Size of one file block, in bytes\n\n} PART_FILE_HEADER, *PPART_FILE_HEADER;\n\n// Structure describing the block-to-file map entry\ntypedef struct _PART_FILE_MAP_ENTRY\n{\n    DWORD Flags;                            // 3 = the block is present in the file\n    DWORD BlockOffsLo;                      // Low 32 bits of the block position in the file\n    DWORD BlockOffsHi;                      // High 32 bits of the block position in the file\n    DWORD LargeValueLo;                     // 64-bit value, meaning is unknown\n    DWORD LargeValueHi;\n\n} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY;\n\ntypedef struct _FILE_BITMAP_FOOTER\n{\n    DWORD Signature;                      // 'ptv3' (ID_FILE_BITMAP_FOOTER)\n    DWORD Version;                        // Unknown, seems to always have value of 3 (version?)\n    DWORD BuildNumber;                    // Game build number for that MPQ\n    DWORD MapOffsetLo;                    // Low 32-bits of the offset of the bit map\n    DWORD MapOffsetHi;                    // High 32-bits of the offset of the bit map\n    DWORD BlockSize;                      // Size of one block (usually 0x4000 bytes)\n\n} FILE_BITMAP_FOOTER, *PFILE_BITMAP_FOOTER;\n\n//-----------------------------------------------------------------------------\n// Structure for file stream\n\nunion TBaseProviderData\n{\n    struct\n    {\n        ULONGLONG FileSize;                 // Size of the file\n        ULONGLONG FilePos;                  // Current file position\n        ULONGLONG FileTime;                 // Last write time\n        HANDLE hFile;                       // File handle\n    } File;\n\n    struct\n    {\n        ULONGLONG FileSize;                 // Size of the file\n        ULONGLONG FilePos;                  // Current file position\n        ULONGLONG FileTime;                 // Last write time\n        LPBYTE pbFile;                      // Pointer to mapped view\n    } Map;\n\n    struct\n    {\n        class CASC_SOCKET * pSocket;        // An open socket\n        unsigned char * fileData;           // Raw response converted to file data\n        char * hostName;                    // Name of the remote host\n        char * fileName;                    // Name of the remote resource\n        size_t fileDataLength;              // Length of the file data, in bytes\n        size_t fileDataPos;                 // Current position in the data\n    } Socket;\n};\n\nstruct TFileStream\n{\n    // Stream provider functions\n    STREAM_READ    StreamRead;              // Pointer to stream read function for this archive. Do not use directly.\n    STREAM_WRITE   StreamWrite;             // Pointer to stream write function for this archive. Do not use directly.\n    STREAM_RESIZE  StreamResize;            // Pointer to function changing file size\n    STREAM_GETSIZE StreamGetSize;           // Pointer to function returning file size\n    STREAM_GETPOS  StreamGetPos;            // Pointer to function that returns current file position\n    STREAM_CLOSE   StreamClose;             // Pointer to function closing the stream\n\n    // Block-oriented functions\n    BLOCK_READ     BlockRead;               // Pointer to function reading one or more blocks\n    BLOCK_CHECK    BlockCheck;              // Pointer to function checking whether the block is present\n\n    // Base provider functions\n    STREAM_CREATE  BaseCreate;              // Pointer to base create function\n    STREAM_OPEN    BaseOpen;                // Pointer to base open function\n    STREAM_READ    BaseRead;                // Read from the stream\n    STREAM_WRITE   BaseWrite;               // Write to the stream\n    STREAM_RESIZE  BaseResize;              // Pointer to function changing file size\n    STREAM_GETSIZE BaseGetSize;             // Pointer to function returning file size\n    STREAM_GETPOS  BaseGetPos;              // Pointer to function that returns current file position\n    STREAM_CLOSE   BaseClose;               // Pointer to function closing the stream\n\n    // Base provider data (file size, file position)\n    TBaseProviderData Base;                 // Stream information, like size or current position\n    CASC_LOCK Lock;                         // For multi-threaded synchronization\n\n    // Stream provider data\n    TFileStream * pMaster;                  // Master stream (e.g. MPQ on a web server)\n    LPTSTR szFileName;                      // File name (self-relative pointer)\n\n    ULONGLONG StreamSize;                   // Stream size (can be less than file size)\n    ULONGLONG StreamPos;                    // Stream position\n    DWORD BuildNumber;                      // Game build number\n    DWORD dwFlags;                          // Stream flags\n\n    // Followed by stream provider data, with variable length\n};\n\n//-----------------------------------------------------------------------------\n// Structures for block-oriented stream\n\nstruct TBlockStream : public TFileStream\n{\n    STREAM_DOWNLOAD_CALLBACK pfnCallback;   // Callback for downloading\n    void * FileBitmap;                      // Array of bits for file blocks\n    void * UserData;                        // User data to be passed to the download callback\n    DWORD BitmapSize;                       // Size of the file bitmap (in bytes)\n    DWORD BlockSize;                        // Size of one block, in bytes\n    DWORD BlockCount;                       // Number of data blocks in the file\n    DWORD IsComplete;                       // If nonzero, no blocks are missing\n    DWORD IsModified;                       // nonzero if the bitmap has been modified\n};        \n\n//-----------------------------------------------------------------------------\n// Structure for encrypted stream\n\n#define ENCRYPTED_CHUNK_SIZE 0x40           // Size of one chunk to be decrypted\n\nstruct TEncryptedStream : public TBlockStream\n{\n    BYTE Key[ENCRYPTED_CHUNK_SIZE];         // File key\n};\n\n//-----------------------------------------------------------------------------\n// Public functions for file stream\n\nTFileStream * FileStream_CreateFile(LPCTSTR szFileName, DWORD dwStreamFlags);\nTFileStream * FileStream_OpenFile(LPCTSTR szFileName, DWORD dwStreamFlags = 0);\nLPCTSTR FileStream_GetFileName(TFileStream * pStream);\nsize_t FileStream_Prefix(LPCTSTR szFileName, DWORD * pdwProvider);\n\nbool FileStream_SetCallback(TFileStream * pStream, STREAM_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData);\n\nbool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead);\nbool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite);\nbool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize);\nbool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize);\nbool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset);\nbool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT);\nbool FileStream_GetFlags(TFileStream * pStream, PDWORD pdwStreamFlags);\nbool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream);\nvoid FileStream_Close(TFileStream * pStream);\n\n\n#endif // __FILESTREAM_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/FileTree.cpp",
    "content": "/*****************************************************************************/\n/* FileTree.cpp                           Copyright (c) Ladislav Zezula 2018 */\n/*---------------------------------------------------------------------------*/\n/* Common implementation of a file tree object for various ROOt file formats */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.05.18  1.00  Lad  The first version of FileTree.cpp                    */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local defines\n\n#define START_ITEM_COUNT          0x4000\n\ninline DWORD GET_NODE_INT32(void * node, size_t offset)\n{\n    PDWORD PtrValue = (PDWORD)((LPBYTE)node + offset);\n    \n    return PtrValue[0];\n}\n\ninline void SET_NODE_INT32(void * node, size_t offset, DWORD value)\n{\n    PDWORD PtrValue = (PDWORD)((LPBYTE)node + offset);\n    \n    PtrValue[0] = value;\n}\n\n//-----------------------------------------------------------------------------\n// Protected functions\n\n// Inserts a new file node to the file tree.\n// If the pointer to file node array changes, the function also rebuilds all maps\nPCASC_FILE_NODE CASC_FILE_TREE::InsertNew(PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    // Create a brand new node\n    pFileNode = InsertNew();\n    if(pFileNode != NULL)\n    {\n        // Initialize the file node's CKeyEntry\n        pFileNode->pCKeyEntry = pCKeyEntry;\n\n        // Don't insert the node into any of the arrays here.\n        // That is the caller's responsibility\n    }\n\n    return pFileNode;\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::InsertNew()\n{\n    PCASC_FILE_NODE pFileNode;\n    void * SaveItemArray = NodeTable.ItemArray();   // We need to save the array pointers. If it changes, we must rebuild both maps\n\n    // Create a brand new node\n    pFileNode = (PCASC_FILE_NODE)NodeTable.Insert(1);\n    if(pFileNode != NULL)\n    {\n        // Initialize the file node\n        pFileNode->FileNameHash = 0;\n        pFileNode->pCKeyEntry = NULL;\n        pFileNode->Parent = 0;\n        pFileNode->NameIndex = 0;\n        pFileNode->NameLength = 0;\n        pFileNode->Flags = 0;\n\n        // We need to supply a file data id for the new entry, otherwise the rebuilding function\n        // will use the uninitialized one\n        SetExtras(pFileNode, CASC_INVALID_ID, CASC_INVALID_ID, CASC_INVALID_ID);\n\n        // If the array pointer changed or we are close to the size of the array, we need to rebuild the maps\n        if(NodeTable.ItemArray() != SaveItemArray || (NodeTable.ItemCount() * 3 / 2) > NameMap.HashTableSize())\n        {\n            // Rebuild both maps. Note that rebuilding also inserts all items to the maps, so no need to insert them here\n            if(!RebuildNameMaps())\n            {\n                pFileNode = NULL;\n                assert(false);\n            }\n        }\n    }\n\n    return pFileNode;\n}\n\n// Insert the node to the map of FileNameHash -> CASC_FILE_NODE\nbool CASC_FILE_TREE::InsertToHashTable(PCASC_FILE_NODE pFileNode)\n{\n    bool bResult = false;\n\n    // Insert the file node to the table\n    if(pFileNode->FileNameHash != 0)\n        bResult = NameMap.InsertObject(pFileNode, &pFileNode->FileNameHash);\n    return bResult;\n}\n\n// Inserts the file node to the array of file data ids\nbool CASC_FILE_TREE::InsertToIdTable(PCASC_FILE_NODE pFileNode)\n{\n    PCASC_FILE_NODE * RefElement;\n    DWORD FileDataId = CASC_INVALID_ID;\n\n    if(FileDataIds.IsInitialized())\n    {\n        // Retrieve the file data id\n        GetExtras(pFileNode, &FileDataId, NULL, NULL);\n        if(FileDataId != CASC_INVALID_ID)\n        {\n            // Sanity check\n            assert(FileDataId < 0x10000000);\n\n            // Insert the element to the array\n            RefElement = (PCASC_FILE_NODE *)FileDataIds.InsertAt(FileDataId);\n            if(RefElement != NULL)\n            {\n                RefElement[0] = pFileNode;\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nbool CASC_FILE_TREE::SetNodePlainName(PCASC_FILE_NODE pFileNode, const char * szPlainName, const char * szPlainNameEnd)\n{\n    char * szNodeName;\n    size_t nLength = (szPlainNameEnd - szPlainName);\n\n    // Insert all chars to the name array\n    szNodeName = (char *)NameTable.Insert(nLength);\n    if(szNodeName != NULL)\n    {\n        // Copy the plain name to the node. Do not include the string terminator\n        memcpy(szNodeName, szPlainName, nLength);\n\n        // Supply the file name to the file node\n        pFileNode->NameIndex = (DWORD)NameTable.IndexOf(szNodeName);\n        pFileNode->NameLength = (USHORT)nLength;\n        return true;\n    }\n\n    return false;\n}\n\nbool CASC_FILE_TREE::SetKeyLength(DWORD aKeyLength)\n{\n    if(aKeyLength > MD5_HASH_SIZE)\n        return false;\n    KeyLength = aKeyLength;\n    return true;\n}\n\nDWORD CASC_FILE_TREE::GetNextFileDataId()\n{\n    if(FileDataIds.IsInitialized())\n        return (DWORD)(FileDataIds.ItemCount() + 1);\n    return CASC_INVALID_ID;\n}\n\nbool CASC_FILE_TREE::RebuildNameMaps()\n{\n    PCASC_FILE_NODE pFileNode;\n    size_t nMaxItems = NodeTable.ItemCountMax();\n\n    // Free the map of \"FullName -> CASC_FILE_NODE\"\n    NameMap.Free();\n\n    // Create new map map \"FullName -> CASC_FILE_NODE\"\n    if(NameMap.Create(nMaxItems, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_NODE, FileNameHash)) != ERROR_SUCCESS)\n        return false;\n\n    // Reset the entire array, but keep the buffer allocated\n    FileDataIds.Reset();\n\n    // Parse all items and insert them to the map\n    for(size_t i = 0; i < NodeTable.ItemCount(); i++)\n    {\n        // Retrieve the n-th object\n        pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(i);\n        if(pFileNode != NULL)\n        {\n            // Insert it to the map \"FileNameHash -> CASC_FILE_NODE\"\n            if(pFileNode->FileNameHash != 0)\n                InsertToHashTable(pFileNode);\n\n            // Insert it to the array \"FileDataId -> CASC_FILE_NODE\"\n            if(FileDataIds.IsInitialized())\n                InsertToIdTable(pFileNode);\n        }\n    }\n\n    return true;\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nDWORD CASC_FILE_TREE::Create(DWORD Flags)\n{\n    PCASC_FILE_NODE pRootNode;\n    size_t FileNodeSize = FIELD_OFFSET(CASC_FILE_NODE, ExtraValues);\n    DWORD dwErrCode;\n\n    // Initialize the file tree\n    memset(this, 0, sizeof(CASC_FILE_TREE));\n    KeyLength = MD5_HASH_SIZE;\n\n    // Shall we use the data ID in the tree node?\n    if(Flags & FTREE_FLAG_USE_DATA_ID)\n    {\n        // Set the offset of the file data id in the entry\n        FileDataIdOffset = FileNodeSize;\n        FileNodeSize += sizeof(DWORD);\n\n        // Create the array for FileDataId -> CASC_FILE_NODE\n        dwErrCode = FileDataIds.Create<PCASC_FILE_NODE>(START_ITEM_COUNT);\n        if(dwErrCode != ERROR_SUCCESS)\n            return dwErrCode;\n    }\n\n    // Shall we use the locale ID in the tree node?\n    if(Flags & FTREE_FLAG_USE_LOCALE_FLAGS)\n    {\n        LocaleFlagsOffset = FileNodeSize;\n        FileNodeSize += sizeof(DWORD);\n    }\n\n    if(Flags & FTREE_FLAG_USE_CONTENT_FLAGS)\n    {\n        ContentFlagsOffset = FileNodeSize;\n        FileNodeSize += sizeof(DWORD);\n    }\n\n    // Align the file node size to 8 bytes\n    FileNodeSize = ALIGN_TO_SIZE(FileNodeSize, 8);\n\n    // Initialize the dynamic array\n    dwErrCode = NodeTable.Create(FileNodeSize, START_ITEM_COUNT);\n    if(dwErrCode == ERROR_SUCCESS)\n    {\n        // Create the dynamic array that will hold the node names\n        dwErrCode = NameTable.Create<char>(START_ITEM_COUNT);\n        if(dwErrCode == ERROR_SUCCESS)\n        {\n            // Insert the first \"root\" node, without name\n            pRootNode = (PCASC_FILE_NODE)NodeTable.Insert(1);\n            if(pRootNode != NULL)\n            {\n                // Initialize the node\n                memset(pRootNode, 0, NodeTable.ItemSize());\n                pRootNode->Parent = CASC_INVALID_INDEX;\n                pRootNode->NameIndex = CASC_INVALID_INDEX;\n                pRootNode->Flags = CFN_FLAG_FOLDER;\n                SetExtras(pRootNode, CASC_INVALID_ID, CASC_INVALID_ID, CASC_INVALID_ID);\n            }\n        }\n    }\n\n    // Create both maps\n    if(!RebuildNameMaps())\n        dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n    return dwErrCode;\n}\n\nvoid CASC_FILE_TREE::Free()\n{\n    // Free both arrays\n    NodeTable.Free();\n    NameTable.Free();\n    FileDataIds.Free();\n\n    // Free the name map\n    NameMap.Free();\n\n    // Zero the object\n    memset(this, 0, sizeof(CASC_FILE_TREE));\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const char * szFileName, DWORD FileDataId, DWORD LocaleFlags, DWORD ContentFlags)\n{\n    PCASC_FILE_NODE pFileNode;\n    ULONGLONG FileNameHash;\n\n    // Sanity checks\n    assert(szFileName != NULL && szFileName[0] != 0);\n    assert(pCKeyEntry != NULL);\n\n    //BREAK_ON_XKEY3(pCKeyEntry->EKey, 0x00, 0x00, 0x0F);\n\n    // Calculate the file name hash\n    FileNameHash = CalcFileNameHash(szFileName);\n\n    // Do nothing if the file name is there already.\n    pFileNode = (PCASC_FILE_NODE)NameMap.FindObject(&FileNameHash);\n    if(pFileNode == NULL)\n    {\n        // Insert new item\n        pFileNode = InsertNew(pCKeyEntry);\n        if(pFileNode != NULL)\n        {\n            // Supply the name hash\n            pFileNode->FileNameHash = FileNameHash;\n\n            // Set the file data id and the extra values\n            SetExtras(pFileNode, FileDataId, LocaleFlags, ContentFlags);\n\n            // Insert the file node to the hash map\n            InsertToHashTable(pFileNode);\n\n            // Also make sure that it's in the file data id table, if the table is initialized\n            InsertToIdTable(pFileNode);\n\n            // Set the file name of the new file node\n            SetNodeFileName(pFileNode, szFileName);\n\n            // If we created a new node, we need to increment the reference count\n            assert(pCKeyEntry->RefCount != 0xFFFF);\n            pCKeyEntry->RefCount++;\n            FileNodes++;\n        }\n    }\n\n    return pFileNode;\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::InsertByHash(PCASC_CKEY_ENTRY pCKeyEntry, ULONGLONG FileNameHash, DWORD FileDataId, DWORD LocaleFlags, DWORD ContentFlags)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    // Sanity checks\n    assert(FileDataIds.IsInitialized());\n    assert(FileDataId != CASC_INVALID_ID);\n    assert(FileNameHash != 0);\n    assert(pCKeyEntry != NULL);\n\n    // Insert the node to the tree by file data id\n    pFileNode = InsertById(pCKeyEntry, FileDataId, LocaleFlags, ContentFlags);\n    if(pFileNode != NULL)\n    {\n        // Supply the name hash\n        pFileNode->FileNameHash = FileNameHash;\n\n        // Insert the file node to the hash map\n        InsertToHashTable(pFileNode);\n    }\n\n    return pFileNode;\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::InsertById(PCASC_CKEY_ENTRY pCKeyEntry, DWORD FileDataId, DWORD LocaleFlags, DWORD ContentFlags)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    // Sanity checks\n    assert(FileDataIds.IsInitialized());\n    assert(FileDataId != CASC_INVALID_ID);\n    assert(pCKeyEntry != NULL);\n\n    // Check whether the file data id exists in the array of file data ids\n    if((pFileNode = FindById(FileDataId)) == NULL)\n    {\n        // Insert the new file node\n        pFileNode = InsertNew(pCKeyEntry);\n        if(pFileNode != NULL)\n        {\n            // Set the file data id and the extra values\n            SetExtras(pFileNode, FileDataId, LocaleFlags, ContentFlags);\n\n            // Insert the file node to the FileDataId array\n            InsertToIdTable(pFileNode);\n\n            // Increment the number of references\n            pCKeyEntry->RefCount++;\n        }\n    }\n\n    // Return the new or old node\n    return pFileNode;\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::ItemAt(size_t nItemIndex)\n{\n    return (PCASC_FILE_NODE)NodeTable.ItemAt(nItemIndex);\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::PathAt(char * szBuffer, size_t cchBuffer, size_t nItemIndex)\n{\n    PCASC_FILE_NODE pFileNode = NULL;\n\n    // If we have FileDataId, then we need to enumerate the files by FileDataId\n    if(FileDataIds.IsInitialized())\n        pFileNode = *(PCASC_FILE_NODE *)FileDataIds.ItemAt(nItemIndex);\n    else\n        pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(nItemIndex);\n\n    // Construct the entire path\n    PathAt(szBuffer, cchBuffer, pFileNode);\n    return pFileNode;\n}\n\nsize_t CASC_FILE_TREE::PathAt(char * szBuffer, size_t cchBuffer, PCASC_FILE_NODE pFileNode)\n{\n    PCASC_FILE_NODE pParentNode;\n    const char * szNamePtr;\n    char * szSaveBuffer = szBuffer;\n    char * szBufferEnd = szBuffer + cchBuffer - 1;\n\n    if(pFileNode != NULL && pFileNode->Parent != CASC_INVALID_INDEX)\n    {\n        // Copy all parents\n        pParentNode = (PCASC_FILE_NODE)NodeTable.ItemAt(pFileNode->Parent);\n        if(pParentNode != NULL)\n        {\n            // Query the parent and move the buffer\n            szBuffer = szBuffer + PathAt(szBuffer, cchBuffer, pParentNode);\n        }\n\n        // Retrieve the node name\n        szNamePtr = (const char *)NameTable.ItemAt(pFileNode->NameIndex);\n\n        // Check whether we have enough space\n        if((szBuffer + pFileNode->NameLength) < szBufferEnd)\n        {\n            // Copy the path part\n            memcpy(szBuffer, szNamePtr, pFileNode->NameLength);\n            szBuffer += pFileNode->NameLength;\n\n            // Append backslash\n            if((pFileNode->Flags & CFN_FLAG_FOLDER) && ((szBuffer + 1) < szBufferEnd))\n            {\n                *szBuffer++ = (pFileNode->Flags & CFN_FLAG_MOUNT_POINT) ? ':' : '\\\\';\n            }\n        }\n    }\n\n    // Terminate buffer with zero\n    szBuffer[0] = 0;\n\n    // Return length of the copied string\n    return (szBuffer - szSaveBuffer);\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::Find(const char * szFullPath, DWORD FileDataId, PCASC_FIND_DATA pFindData)\n{\n    PCASC_FILE_NODE pFileNode = NULL;\n    ULONGLONG FileNameHash;\n\n    // Can we search by FileDataId?\n    if(FileDataIds.IsInitialized() && (FileDataId != CASC_INVALID_ID || IsFileDataIdName(szFullPath, FileDataId)))\n    {\n        pFileNode = FindById(FileDataId);\n    }\n    else\n    {\n        if(szFullPath != NULL && szFullPath[0] != 0)\n        {\n            FileNameHash = CalcFileNameHash(szFullPath);\n            pFileNode = (PCASC_FILE_NODE)NameMap.FindObject(&FileNameHash);\n        }\n    }\n\n    // Did we find anything?\n    if(pFileNode != NULL && pFindData != NULL)\n    {\n        GetExtras(pFileNode, &pFindData->dwFileDataId, &pFindData->dwLocaleFlags, &pFindData->dwContentFlags);\n    }\n\n    return pFileNode;\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::Find(PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    for(size_t i = 0; i < NodeTable.ItemCount(); i++)\n    {\n        pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(i);\n        if((pFileNode->Flags & (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT)) == 0)\n        {\n            if(pFileNode->pCKeyEntry == pCKeyEntry)\n                return pFileNode;\n        }\n    }\n\n    return NULL;\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::Find(ULONGLONG FileNameHash)\n{\n    return (PCASC_FILE_NODE)NameMap.FindObject(&FileNameHash);\n}\n\nPCASC_FILE_NODE CASC_FILE_TREE::FindById(DWORD FileDataId)\n{\n    PCASC_FILE_NODE * RefElement;\n    PCASC_FILE_NODE pFileNode = NULL;\n\n    if(FileDataId != CASC_INVALID_ID && FileDataIds.IsInitialized())\n    {\n        // Insert the element to the array\n        RefElement = (PCASC_FILE_NODE *)FileDataIds.ItemAt(FileDataId);\n        if(RefElement != NULL)\n        {\n            pFileNode = RefElement[0];\n        }\n    }\n\n    return pFileNode;\n}\n\nbool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szFileName)\n{\n    ULONGLONG FileNameHash = 0;\n    PCASC_FILE_NODE pFolderNode = NULL;\n    CASC_PATH<char> PathBuffer;\n    LPCSTR szNodeBegin = szFileName;\n    size_t nFileNode = NodeTable.IndexOf(pFileNode);\n    size_t i;\n    DWORD Parent = 0;\n\n    // Sanity checks\n    assert(szFileName != NULL && szFileName[0] != 0);\n\n    // Traverse the entire path. For each subfolder, we insert an appropriate fake entry\n    for(i = 0; szFileName[i] != 0; i++)\n    {\n        char chOneChar = szFileName[i];\n\n        // Is there a path separator?\n        // Note: Warcraft III paths may contain \"mount points\".\n        // Example: \"frFR-War3Local.mpq:Maps/FrozenThrone/Campaign/NightElfX06Interlude.w3x:war3map.j\"\n        if(chOneChar == '\\\\' || chOneChar == '/' || chOneChar == ':')\n        {\n            // Calculate hash of the file name up to the end of the node name\n            FileNameHash = CalcNormNameHash(PathBuffer, i);\n\n            // If the entry is not there yet, create new one\n            if((pFolderNode = Find(FileNameHash)) == NULL)\n            {\n                // Insert new entry to the tree\n                pFolderNode = InsertNew();\n                if(pFolderNode == NULL)\n                    return false;\n\n                // Populate the file entry\n                pFolderNode->FileNameHash = FileNameHash;\n                pFolderNode->Parent = Parent;\n                pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;\n                FolderNodes++;\n\n                // Set the node sub name to the node\n                SetNodePlainName(pFolderNode, szNodeBegin, szFileName + i);\n\n                // Insert the entry to the name map\n                InsertToHashTable(pFolderNode);\n            }\n\n            // Move the parent to the current node\n            Parent = (DWORD)NodeTable.IndexOf(pFolderNode);\n\n            // Move the begin of the node after the separator\n            szNodeBegin = szFileName + i + 1;\n        }\n\n        // Copy the next character, even if it was slash/backslash before\n        PathBuffer.AppendChar(AsciiToUpperTable_BkSlash[chOneChar]);\n    }\n\n    // If anything left, this is gonna be our node name\n    if(szNodeBegin < szFileName + i)\n    {\n        // We need to reset the file node pointer, as the file node table might have changed\n        pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(nFileNode);\n        \n        // Write the plain file name to the node\n        SetNodePlainName(pFileNode, szNodeBegin, szFileName + i);\n        pFileNode->Parent = Parent;\n\n        // Also insert the node to the hash table so CascOpenFile can find it\n        if(pFileNode->FileNameHash == 0)\n        {\n            pFileNode->FileNameHash = CalcNormNameHash(PathBuffer, i);\n            InsertToHashTable(pFileNode);\n        }\n    }\n    return true;\n}\n/*\nbool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szFileName)\n{\n    ULONGLONG FileNameHash = 0;\n    PCASC_FILE_NODE pFolderNode = NULL;\n    LPCSTR szNodeBegin = szFileName;\n    char szPathBuffer[MAX_PATH+1];\n    size_t nFileNode = NodeTable.IndexOf(pFileNode);\n    size_t i;\n    DWORD Parent = 0;\n\n    // Sanity checks\n    assert(szFileName != NULL && szFileName[0] != 0);\n\n    // Traverse the entire path. For each subfolder, we insert an appropriate fake entry\n    for(i = 0; szFileName[i] != 0; i++)\n    {\n        char chOneChar = szFileName[i];\n\n        // Is there a path separator?\n        // Note: Warcraft III paths may contain \"mount points\".\n        // Example: \"frFR-War3Local.mpq:Maps/FrozenThrone/Campaign/NightElfX06Interlude.w3x:war3map.j\"\n        if(chOneChar == '\\\\' || chOneChar == '/' || chOneChar == ':')\n        {\n            // Calculate hash of the file name up to the end of the node name\n            FileNameHash = CalcNormNameHash(szPathBuffer, i);\n\n            // If the entry is not there yet, create new one\n            if((pFolderNode = Find(FileNameHash)) == NULL)\n            {\n                // Insert new entry to the tree\n                pFolderNode = InsertNew();\n                if(pFolderNode == NULL)\n                    return false;\n\n                // Populate the file entry\n                pFolderNode->FileNameHash = FileNameHash;\n                pFolderNode->Parent = Parent;\n                pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;\n                FolderNodes++;\n\n                // Set the node sub name to the node\n                SetNodePlainName(pFolderNode, szNodeBegin, szFileName + i);\n\n                // Insert the entry to the name map\n                InsertToHashTable(pFolderNode);\n            }\n\n            // Move the parent to the current node\n            Parent = (DWORD)NodeTable.IndexOf(pFolderNode);\n\n            // Move the begin of the node after the separator\n            szNodeBegin = szFileName + i + 1;\n        }\n\n        // Copy the next character, even if it was slash/backslash before\n        szPathBuffer[i] = AsciiToUpperTable_BkSlash[chOneChar];\n    }\n\n    // If anything left, this is gonna be our node name\n    if(szNodeBegin < szFileName + i)\n    {\n        // We need to reset the file node pointer, as the file node table might have changed\n        pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(nFileNode);\n        \n        // Write the plain file name to the node\n        SetNodePlainName(pFileNode, szNodeBegin, szFileName + i);\n        pFileNode->Parent = Parent;\n\n        // Also insert the node to the hash table so CascOpenFile can find it\n        if(pFileNode->FileNameHash == 0)\n        {\n            pFileNode->FileNameHash = CalcNormNameHash(szPathBuffer, i);\n            InsertToHashTable(pFileNode);\n        }\n    }\n    return true;\n}\n*/\nsize_t CASC_FILE_TREE::GetMaxFileIndex()\n{\n    if(FileDataIds.IsInitialized())\n    {\n        return FileDataIds.ItemCount();\n    }\n    else\n    {\n        return NodeTable.ItemCount();\n    }\n}\n\nsize_t CASC_FILE_TREE::GetCount()\n{\n    return NodeTable.ItemCount();\n}\n\nsize_t CASC_FILE_TREE::IndexOf(PCASC_FILE_NODE pFileNode)\n{\n    return NodeTable.IndexOf(pFileNode);\n}\n\nvoid CASC_FILE_TREE::GetExtras(PCASC_FILE_NODE pFileNode, PDWORD PtrFileDataId, PDWORD PtrLocaleFlags, PDWORD PtrContentFlags)\n{\n    DWORD FileDataId = CASC_INVALID_ID;\n    DWORD LocaleFlags = CASC_INVALID_ID;\n    DWORD ContentFlags = CASC_INVALID_ID;\n\n    // Retrieve the data ID, if supported\n    if(PtrFileDataId != NULL)\n    {\n        if(FileDataIdOffset != 0)\n            FileDataId = GET_NODE_INT32(pFileNode, FileDataIdOffset);\n        PtrFileDataId[0] = FileDataId;\n    }\n\n    // Retrieve the locale ID, if supported\n    if(PtrLocaleFlags != NULL)\n    {\n        if(LocaleFlagsOffset != 0)\n            LocaleFlags = GET_NODE_INT32(pFileNode, LocaleFlagsOffset);\n        PtrLocaleFlags[0] = LocaleFlags;\n    }\n\n    if(PtrContentFlags != NULL)\n    {\n        if(ContentFlagsOffset != 0)\n            ContentFlags = GET_NODE_INT32(pFileNode, ContentFlagsOffset);\n        PtrContentFlags[0] = ContentFlags;\n    }\n}\n\nvoid CASC_FILE_TREE::SetExtras(PCASC_FILE_NODE pFileNode, DWORD FileDataId, DWORD LocaleFlags, DWORD ContentFlags)\n{\n    // Set the file data ID, if supported\n    if(FileDataIdOffset != 0)\n    {\n        SET_NODE_INT32(pFileNode, FileDataIdOffset, FileDataId);\n    }\n\n    // Set the locale ID, if supported\n    if(LocaleFlagsOffset != 0)\n    {\n        SET_NODE_INT32(pFileNode, LocaleFlagsOffset, LocaleFlags);\n    }\n\n    // Set the locale ID, if supported\n    if(ContentFlagsOffset != 0)\n    {\n        SET_NODE_INT32(pFileNode, ContentFlagsOffset, ContentFlags);\n    }\n}\n"
  },
  {
    "path": "deps/CascLib/src/common/FileTree.h",
    "content": "/*****************************************************************************/\n/* FileTree.h                             Copyright (c) Ladislav Zezula 2018 */\n/*---------------------------------------------------------------------------*/\n/* Common implementation of a file tree object for various ROOt file formats */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.05.18  1.00  Lad  The first version of FileTree.h                      */\n/*****************************************************************************/\n\n#ifndef __FILETREE_H__\n#define __FILETREE_H__\n\n//-----------------------------------------------------------------------------\n// Structures\n\n#define FTREE_FLAG_USE_DATA_ID        0x0001        // The FILE_NODE also contains file data ID\n#define FTREE_FLAG_USE_LOCALE_FLAGS   0x0002        // The FILE_NODE also contains file locale flags\n#define FTREE_FLAG_USE_CONTENT_FLAGS  0x0004        // The FILE_NODE also contains content flags\n\n#define CFN_FLAG_FOLDER               0x0001        // This item is a folder\n#define CFN_FLAG_MOUNT_POINT          0x0002        // This item is a mount point.\n\n// Common structure for holding a single folder/file node\ntypedef struct _CASC_FILE_NODE\n{\n    ULONGLONG FileNameHash;                         // Jenkins hash of the normalized file name (uppercase, backslashes)\n    PCASC_CKEY_ENTRY pCKeyEntry;                    // Pointer to the CKey entry\n\n    DWORD Parent;                                   // The index of a parent directory. If CASC_INVALID_INDEX, then this is the root item\n    DWORD NameIndex;                                // Index of the node name. If CASC_INVALID_INDEX, then this node has no name\n    USHORT NameLength;                              // Length of the node name (without the zero terminator)\n    USHORT Flags;                                   // See CFN_FLAG_XXX\n\n    DWORD ExtraValues[4];                           // FileDataId: Only if FTREE_FLAG_USE_DATA_ID specified at create\n                                                    // LocaleFlags: Only if FTREE_FLAG_USE_LOCALE_FLAGS specified at create\n                                                    // ContentFlags: Only if FTREE_FLAG_USE_CONTENT_FLAGS specified at create\n} CASC_FILE_NODE, *PCASC_FILE_NODE;\n\n// Main structure for the file tree\nclass CASC_FILE_TREE\n{\n    public:\n\n    // Initializes/destroys the entire tree\n    DWORD Create(DWORD Flags = 0);\n    void Free();\n\n    // Inserts a new node to the tree; either with name or nameless\n    PCASC_FILE_NODE InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const char * szFileName, DWORD FileDataId = CASC_INVALID_ID, DWORD LocaleFlags = CASC_INVALID_ID, DWORD ContentFlags = CASC_INVALID_ID);\n    PCASC_FILE_NODE InsertByHash(PCASC_CKEY_ENTRY pCKeyEntry, ULONGLONG FileNameHash, DWORD FileDataId, DWORD LocaleFlags = CASC_INVALID_ID, DWORD ContentFlags = CASC_INVALID_ID);\n    PCASC_FILE_NODE InsertById(PCASC_CKEY_ENTRY pCKeyEntry, DWORD FileDataId, DWORD LocaleFlags = CASC_INVALID_ID, DWORD ContentFlags = CASC_INVALID_ID);\n\n    // Returns an item at the given index. The PathAt also builds the full path of the node\n    PCASC_FILE_NODE ItemAt(size_t nItemIndex);\n    PCASC_FILE_NODE PathAt(char * szBuffer, size_t cchBuffer, size_t nItemIndex);\n    size_t PathAt(char * szBuffer, size_t cchBuffer, PCASC_FILE_NODE pFileNode);\n\n    // Finds a file using its full path, FileDataId or CKey/EKey\n    PCASC_FILE_NODE Find(const char * szFullPath, DWORD FileDataId, struct _CASC_FIND_DATA * pFindData);\n    PCASC_FILE_NODE Find(PCASC_CKEY_ENTRY pCKeyEntry);\n    PCASC_FILE_NODE Find(ULONGLONG FileNameHash);\n    PCASC_FILE_NODE FindById(DWORD FileDataId);\n\n    // Assigns a file name to the node\n    bool SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szFileName);\n\n    // Returns the number of items in the tree\n    size_t GetMaxFileIndex();\n    size_t GetCount();\n\n    // Returns the index of an item in the tree\n    size_t IndexOf(PCASC_FILE_NODE pFileNode);\n\n    // Retrieves the extra values from the node (if supported)\n    void GetExtras(PCASC_FILE_NODE pFileNode, PDWORD PtrFileDataId, PDWORD PtrLocaleFlags, PDWORD PtrContentFlags);\n    void SetExtras(PCASC_FILE_NODE pFileNode, DWORD FileDataId, DWORD LocaleFlags, DWORD ContentFlags);\n\n    // Change the length of the key\n    bool SetKeyLength(DWORD KeyLength);\n\n    // Retrieve the maximum FileDataId ever inserted\n    DWORD GetNextFileDataId();\n\n    protected:\n\n    PCASC_FILE_NODE InsertNew(PCASC_CKEY_ENTRY pCKeyEntry);\n    PCASC_FILE_NODE InsertNew();\n    bool InsertToHashTable(PCASC_FILE_NODE pFileNode);\n    bool InsertToIdTable(PCASC_FILE_NODE pFileNode);\n\n    bool SetNodePlainName(PCASC_FILE_NODE pFileNode, const char * szPlainName, const char * szPlainNameEnd);\n    bool RebuildNameMaps();\n\n    CASC_ARRAY NodeTable;                           // Dynamic array that holds all CASC_FILE_NODEs\n    CASC_ARRAY NameTable;                           // Dynamic array that holds all node names\n\n    CASC_ARRAY FileDataIds;                         // Dynamic array that maps FileDataId -> CASC_FILE_NODE\n    CASC_MAP NameMap;                               // Map of FileNameHash -> CASC_FILE_NODE\n\n    size_t FileDataIdOffset;                        // If nonzero, this is the offset of the \"FileDataId\" field in the CASC_FILE_NODE\n    size_t LocaleFlagsOffset;                       // If nonzero, this is the offset of the \"LocaleFlags\" field in the CASC_FILE_NODE\n    size_t ContentFlagsOffset;                      // If nonzero, this is the offset of the \"ContentFlags\" field in the CASC_FILE_NODE\n    size_t FolderNodes;                             // Number of folder nodes\n    size_t FileNodes;                               // Number of file nodes\n    DWORD KeyLength;                                // Actual length of the key supported by the root handler\n};\n\ntypedef CASC_FILE_TREE * PCASC_FILE_TREE;\n\n#endif // __FILETREE_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/IndexMap.h",
    "content": "/*****************************************************************************/\n/* IndexMap.h                             Copyright (c) Ladislav Zezula 2019 */\n/*---------------------------------------------------------------------------*/\n/* Interface of index-based map for CascLib. This is a map type created      */\n/* on top of an array of contant-size objects, that is already sorted.       */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 29.04.19  1.00  Lad  The first version of Index.h                         */\n/*****************************************************************************/\n\n#ifndef __CASC_INDEX_MAP_H__\n#define __CASC_INDEX_MAP_H__\n\n//-----------------------------------------------------------------------------\n// Structures\n\nclass CASC_INDEX_MAP\n{\n    public:\n\n    int Create(size_t MaxItems, size_t ObjectLength_, size_t KeyLength_, size_t KeyOffset_)\n    {\n        DWORD IndexBitSize = 8;\n\n        // Determine the index size\n        if(MaxItems >= 0x10000)\n            IndexBitSize = 16;\n        if(MaxItems >= 0x100000)\n            IndexBitSize = 20;\n\n        // Save the values\n        IndexTableSize = (1 << IndexBitSize);\n        IndexTableMask = IndexTableSize - 1;\n        ObjectLength = ObjectLength_;\n        KeyOffset = KeyOffset_;\n        KeyLength = KeyLength_;\n\n        // Allocate the new index object\n        IndexTable = CASC_ALLOC(void *, IndexTableSize);\n        if(IndexTable != NULL)\n        {\n            memset(IndexTable, 0, IndexTableSize * sizeof(void *));\n            return ERROR_SUCCESS;\n        }\n\n        return ERROR_NOT_ENOUGH_MEMORY;\n    }\n\n    void * FindObject(void * pvKey)\n    {\n        LPBYTE StartObject;\n        DWORD StartIndex;\n\n        // Verify pointer to the map\n        if(IndexTable != NULL)\n        {\n            // Retrieve the index from the key\n            StartIndex = KeyToIndex(pvKey);\n            StartObject = (LPBYTE)IndexTable[StartIndex];\n            if(StartObject == NULL)\n                return NULL;\n\n            // Enumerate the array as long as the index matches\n            do\n            {\n                // Compare the key\n                if(!memcmp(StartObject + KeyOffset, pvKey, KeyLength))\n                    return StartObject;\n\n                // Key mismatch -> go next object\n                StartObject = StartObject + ObjectLength;\n            }\n            while(KeyToIndex(StartObject + KeyOffset) == StartIndex);\n        }\n\n        // Not found\n        return NULL;\n    }\n\n    protected:\n\n    inline DWORD KeyToIndex(void * pvKey)\n    {\n        return *((PDWORD)pvKey) & IndexTableMask;\n    }\n\n    void ** IndexTable;                         // Pointer table. Each entry, if non-NULL, contains a pointer to the first object\n                                                // into a sorted array. Search function must then match the entire key.\n                                                // In case of no match, the search process must go to the next-in-array object.\n    size_t ObjectLength;                        // Length of the single object\n    size_t KeyOffset;                           // How far is the key from the begin of the structure (in bytes)\n    size_t KeyLength;                           // Length of the key\n    DWORD  IndexTableSize;                      // Size of the IndexTableSize, in bytes\n    DWORD  IndexTableMask;                      // Bit mask for conversion from hash to index\n};\n\ntypedef CASC_INDEX_MAP *PCASC_INDEX_MAP;\n\n//-----------------------------------------------------------------------------\n// Functions\n\nbool IndexMap_InsertObject(PCASC_INDEX_MAP pIndexMap, void * pvNewObject, void * pvKey);\nvoid IndexMap_Free(PCASC_INDEX_MAP pIndexMap);\n\n#endif // __CASC_INDEX_MAP_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/ListFile.cpp",
    "content": "/*****************************************************************************/\n/* ListFile.cpp                           Copyright (c) Ladislav Zezula 2004 */\n/*---------------------------------------------------------------------------*/\n/* Description:                                                              */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 12.06.04  1.00  Lad  The first version of ListFile.cpp                    */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Listfile cache structure\n\n#define LISTFILE_FLAG_USES_FILEDATAID   0x0001   // A new CSV format, containing FileDataId; FullFileName\n\ntypedef struct _LISTFILE_CACHE\n{\n    char * pBegin;                              // The begin of the listfile cache\n    char * pPos;                                // Current position in the cache\n    char * pEnd;                                // The last character in the file cache\n    DWORD Flags;\n\n    // Followed by the cache (variable length)\n\n} LISTFILE_CACHE, *PLISTFILE_CACHE;\n\n//-----------------------------------------------------------------------------\n// Creating the listfile cache for the given amount of data\n\nstatic PLISTFILE_CACHE ListFile_CreateCache(DWORD dwFileSize)\n{\n    PLISTFILE_CACHE pCache;\n\n    // Allocate cache for one file block\n    pCache = (PLISTFILE_CACHE)CASC_ALLOC<BYTE>(sizeof(LISTFILE_CACHE) + dwFileSize);\n    if(pCache != NULL)\n    {\n        // Set the initial pointers\n        pCache->pBegin =\n        pCache->pPos   = (char *)(pCache + 1);\n        pCache->pEnd   = pCache->pBegin + dwFileSize;\n        pCache->Flags  = 0;\n    }\n\n    // Return the cache\n    return pCache;\n}\n\nstatic char * ListFile_SkipSpaces(PLISTFILE_CACHE pCache)\n{\n    // Skip newlines, spaces, tabs and another non-printable stuff\n    while(pCache->pPos < pCache->pEnd && pCache->pPos[0] <= 0x20)\n        pCache->pPos++;\n\n    // Remember the begin of the line\n    return pCache->pPos;\n}\n\nstatic void ListFile_CheckFormat(PLISTFILE_CACHE pCache)\n{\n    // Only if the listfile is greatger than 2 MB\n    if((pCache->pEnd - pCache->pBegin) > 0x100000)\n    {\n        char * szPtr = pCache->pBegin;\n        size_t nDigitCount = 0;\n\n        // Calculate the amount of digits\n        while(nDigitCount <= 20 && '0' <= szPtr[nDigitCount] && szPtr[nDigitCount] <= '9')\n            nDigitCount++;\n\n        // There must be a semicolon after\n        if(nDigitCount <= 10 && szPtr[nDigitCount] == ';')\n        {\n            pCache->Flags |= LISTFILE_FLAG_USES_FILEDATAID;\n        }\n    }\n}\n\nstatic int ListFile_GetFileDataId(PLISTFILE_CACHE pCache, PDWORD PtrFileDataId)\n{\n    char * szLineBegin = ListFile_SkipSpaces(pCache);\n    char * szLineEnd;\n    DWORD dwNewInt32 = 0;\n    DWORD dwInt32 = 0;\n\n    // Set the limit for loading the number\n    szLineEnd = CASCLIB_MIN((szLineBegin + 20), pCache->pEnd);\n\n    // Extract decimal digits from the string\n    while(szLineBegin < szLineEnd && '0' <= szLineBegin[0] && szLineBegin[0] <= '9')\n    {\n        // Check integer overflow\n        dwNewInt32 = (dwInt32 * 10) + (szLineBegin[0] - '0');\n        if(dwNewInt32 < dwInt32)\n            return ERROR_BAD_FORMAT;\n\n        dwInt32 = dwNewInt32;\n        szLineBegin++;\n    }\n\n    // There must still be some space\n    if(szLineBegin < szLineEnd)\n    {\n        // There must be a semicolon after the decimal integer\n        // The decimal integer must be smaller than 10 MB (files)\n        if(szLineBegin[0] != ';' || dwInt32 >= 0xA00000)\n            return ERROR_BAD_FORMAT;\n\n        pCache->pPos = szLineBegin + 1;\n        PtrFileDataId[0] = dwInt32;\n        return ERROR_SUCCESS;\n    }\n\n    return ERROR_NO_MORE_FILES;\n}\n\n//-----------------------------------------------------------------------------\n// Functions for parsing an external listfile\n\nvoid * ListFile_OpenExternal(LPCTSTR szListFile)\n{\n    PLISTFILE_CACHE pCache = NULL;\n    TFileStream * pStream;\n    ULONGLONG FileSize = 0;\n\n    // Open the external listfile\n    pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY);\n    if(pStream != NULL)\n    {\n        // Retrieve the size of the external listfile\n        FileStream_GetSize(pStream, &FileSize);\n        if(0 < FileSize && FileSize <= 0x30000000)\n        {\n            // Create the in-memory cache for the entire listfile\n            // The listfile does not have any data loaded yet\n            pCache = ListFile_CreateCache((DWORD)FileSize);\n            if(pCache != NULL)\n            {\n                if(FileStream_Read(pStream, NULL, pCache->pBegin, (DWORD)FileSize))\n                {\n                    ListFile_CheckFormat(pCache);\n                }\n                else\n                {\n                    CASC_FREE(pCache);\n                }\n            }\n        }\n\n        // Close the file stream\n        FileStream_Close(pStream);\n    }\n\n    return pCache;\n}\n\nvoid * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer)\n{\n    PLISTFILE_CACHE pCache = NULL;\n\n    // Create the in-memory cache for the entire listfile\n    // The listfile does not have any data loaded yet\n    pCache = ListFile_CreateCache(cbBuffer);\n    if(pCache != NULL)\n        memcpy(pCache->pBegin, pbBuffer, cbBuffer);\n\n    return pCache;\n}\n\n// Performs the MD5-based check on the listfile\nbool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5)\n{\n    PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;\n\n    // Must be at the beginning\n    assert(pCache->pPos == pCache->pBegin);\n\n    // Verify the MD5 hash for the entire block\n    return CascVerifyDataBlockHash(pCache->pBegin, (DWORD)(pCache->pEnd - pCache->pBegin), pbHashMD5);\n}\n\nsize_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd)\n{\n    PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;\n    char * szExtraString = NULL;\n    char * szLineBegin;\n    char * szLineEnd;\n\n    // Skip newlines, spaces, tabs and another non-printable stuff\n    // Remember the begin of the line\n    szLineBegin = ListFile_SkipSpaces(pCache);\n\n    // Copy the remaining characters\n    while(pCache->pPos < pCache->pEnd)\n    {\n        // If we have found a newline, stop loading\n        // Note: the 0x85 char came from Overwatch build 24919\n        if(pCache->pPos[0] == '\\x0A' || pCache->pPos[0] == '\\x0D' || pCache->pPos[0] == '\\x85')\n            break;\n\n        // Blizzard listfiles can also contain information about patch:\n        // Pass1\\Files\\MacOS\\unconditional\\user\\Background Downloader.app\\Contents\\Info.plist~Patch(Data#frFR#base-frFR,1326)\n        if(pCache->pPos[0] == '~')\n            szExtraString = pCache->pPos;\n\n        // Move the position by one character forward\n        pCache->pPos++;\n    }\n\n    // Remember the end of the line\n    szLineEnd = (szExtraString != NULL && szExtraString[0] == '~' && szExtraString[1] == 'P') ? szExtraString : pCache->pPos;\n\n    // Give the caller the positions of the begin and end of the line\n    pszLineBegin[0] = szLineBegin;\n    pszLineEnd[0] = szLineEnd;\n    return (size_t)(szLineEnd - szLineBegin);\n}\n\nsize_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars)\n{\n    const char * szLineBegin = NULL;\n    const char * szLineEnd = NULL;\n    size_t nLength;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Retrieve the next line\n    nLength = ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd);\n\n    // Check the length\n    if(nLength < nMaxChars)\n    {\n        // Copy the line to the user buffer\n        memcpy(szBuffer, szLineBegin, nLength);\n        szBuffer[nLength] = 0;\n    }\n    else\n    {\n        dwErrCode = ERROR_INSUFFICIENT_BUFFER;\n        nLength = 0;\n    }\n\n    // If we didn't read anything, set the error code\n    if(nLength == 0)\n        SetCascError(dwErrCode);\n    return nLength;\n}\n\nsize_t ListFile_GetNext(void * pvListFile, char * szBuffer, size_t nMaxChars, PDWORD PtrFileDataId)\n{\n    PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;\n    const char * szTemp;\n    size_t nLength = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Check for parameters\n    for(;;)\n    {\n        DWORD FileDataId = CASC_INVALID_ID;\n\n        // If this is a CSV-format listfile, we need to extract the FileDataId\n        // Lines that contain bogus data, invalid numbers or too big values will be skipped\n        if(pCache->Flags & LISTFILE_FLAG_USES_FILEDATAID)\n        {\n            // Retrieve the data ID from the current position\n            dwErrCode = ListFile_GetFileDataId(pCache, &FileDataId);\n            if(dwErrCode == ERROR_NO_MORE_FILES)\n                break;\n            \n            // If there was an error, skip the current line\n            if(dwErrCode != ERROR_SUCCESS || FileDataId == CASC_INVALID_ID)\n            {\n                ListFile_GetNextLine(pvListFile, &szTemp, &szTemp);\n                continue;\n            }\n        }\n\n        // Read the (next) line\n        nLength = ListFile_GetNextLine(pvListFile, szBuffer, nMaxChars);\n        if(nLength == 0)\n        {\n            dwErrCode = GetCascError();\n            break;\n        }\n\n        // Give the file data id and return true\n        PtrFileDataId[0] = FileDataId;\n        return nLength;\n    }\n\n    if(dwErrCode != ERROR_SUCCESS)\n        SetCascError(dwErrCode);\n    return nLength;\n}\n\nLPBYTE ListFile_GetData(void * pvListFile, PDWORD PtrDataSize)\n{\n    PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;\n    LPBYTE pbData = NULL;\n    DWORD cbData = 0;\n\n    // Get data from the list file cache\n    if (pvListFile != NULL)\n    {\n        pbData = (LPBYTE)pCache->pBegin;\n        cbData = (DWORD)(pCache->pEnd - pCache->pBegin);\n    }\n\n    // Give the data to the caller\n    if (PtrDataSize != NULL)\n        PtrDataSize[0] = cbData;\n    return pbData;\n}\n\n"
  },
  {
    "path": "deps/CascLib/src/common/ListFile.h",
    "content": "/*****************************************************************************/\n/* ListFile.h                             Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Common functions for CascLib                                              */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 10.05.14  1.00  Lad  The first version of ListFile.h                      */\n/*****************************************************************************/\n\n#ifndef __LISTFILE_H__\n#define __LISTFILE_H__\n\n//-----------------------------------------------------------------------------\n// Functions for parsing an external listfile\n\nvoid * ListFile_OpenExternal(LPCTSTR szListFile);\nvoid * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer);\nbool   ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5);\nsize_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd);\nsize_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars);\nsize_t ListFile_GetNext(void * pvListFile, char * szBuffer, size_t nMaxChars, PDWORD PtrFileDataId);\nLPBYTE ListFile_GetData(void * pvListFile, PDWORD PtrDataSize);\n\n#endif // __LISTFILE_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/Map.h",
    "content": "/*****************************************************************************/\n/* Map.h                                  Copyright (c) Ladislav Zezula 2014 */\n/*---------------------------------------------------------------------------*/\n/* Interface of hash-to-ptr map for CascLib                                  */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 10.06.14  1.00  Lad  The first version of Map.h                           */\n/*****************************************************************************/\n\n#ifndef __CASC_MAP_H__\n#define __CASC_MAP_H__\n\n//-----------------------------------------------------------------------------\n// Structures\n\n#define MIN_HASH_TABLE_SIZE     0x00000100      // The smallest size of the hash table.\n#define MAX_HASH_TABLE_SIZE     0x00800000      // The largest size of the hash table. Should be enough for any game.\n\ntypedef int   (*PFNCOMPAREFUNC)(const void * pvObjectKey, const void * pvKey, size_t nKeyLength);\ntypedef DWORD (*PFNHASHFUNC)(void * pvKey, size_t nKeyLength);\n\ntypedef enum _KEY_TYPE\n{\n    KeyIsHash,                                  // Use when the key is already a hash. If specified, the map will not hash the key\n    KeyIsArbitrary,                             // The key is an arbitrary array of bytes. The map will hash it to get a map index\n    KeyIsString                                 // Use when the key is a string\n} KEY_TYPE, *PKEY_TYPE;\n\n#define KEY_LENGTH_STRING 0xFFFFFFFF\n\n//-----------------------------------------------------------------------------\n// Hashing functions\n\n// Used when the key is a hash already - no need to hash it again\ninline DWORD CalcHashValue_Hash(void * pvKey, size_t /* nKeyLength */)\n{\n    // Get the hash directly as value\n    return ConvertBytesToInteger_4((LPBYTE)pvKey);\n}\n\n// Calculates hash value from a key\ninline DWORD CalcHashValue_Key(void * pvKey, size_t nKeyLength)\n{\n    LPBYTE pbKey = (LPBYTE)pvKey;\n    DWORD dwHash = 0x7EEE7EEE;\n\n    // Construct the hash from the key\n    for(DWORD i = 0; i < nKeyLength; i++)\n        dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[i];\n\n    // Return the hash limited by the table size\n    return dwHash;\n}\n\n// Calculates hash value from a string\ninline DWORD CalcHashValue_String(const char * szString, const char * szStringEnd)\n{\n    LPBYTE pbKeyEnd = (LPBYTE)szStringEnd;\n    LPBYTE pbKey = (LPBYTE)szString;\n    DWORD dwHash = 0x7EEE7EEE;\n\n    // Hash the string itself\n    while(pbKey < pbKeyEnd)\n    {\n        dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ AsciiToUpperTable_BkSlash[pbKey[0]];\n        pbKey++;\n    }\n\n    // Return the hash limited by the table size\n    return dwHash;\n}\n\n//-----------------------------------------------------------------------------\n// Map implementation\n\nclass CASC_MAP\n{\n    public:\n\n    CASC_MAP()\n    {\n        PfnCalcHashValue = NULL;\n        m_HashTable = NULL;\n        m_HashTableSize = 0;\n        m_ItemCount = 0;\n        m_KeyOffset = 0;\n        m_KeyLength = 0;\n        m_bKeyIsHash = false;\n    }\n\n    ~CASC_MAP()\n    {\n        Free();\n    }\n\n    DWORD Create(size_t MaxItems, size_t KeyLength, size_t KeyOffset, KEY_TYPE KeyType = KeyIsHash)\n    {\n        // Set the class variables\n        m_KeyLength = CASCLIB_MAX(KeyLength, 8);\n        m_KeyOffset = KeyOffset;\n        m_ItemCount = 0;\n\n        // Setup the hashing function\n        switch(KeyType)\n        {\n            case KeyIsHash:\n                PfnCalcHashValue = CalcHashValue_Hash;\n                break;\n\n            case KeyIsArbitrary:\n                PfnCalcHashValue = CalcHashValue_Key;\n                break;\n\n            case KeyIsString:\n                PfnCalcHashValue = NULL;\n                break;\n\n            default:\n                assert(false);\n                return ERROR_NOT_SUPPORTED;\n        }\n\n        // Calculate the hash table size. Take 133% of the item count and round it up to the next power of two\n        // This will make the hash table indexes somewhat more resilient against count changes and will make\n        // e.g. file order in the file tree more stable.\n        m_HashTableSize = GetNearestPowerOfTwo(MaxItems * 4 / 3);\n        if(m_HashTableSize == 0)\n            return ERROR_NOT_ENOUGH_MEMORY;\n\n        // Allocate new map for the objects\n        m_HashTable = (void **)CASC_ALLOC_ZERO<void *>(m_HashTableSize);\n        return (m_HashTable != NULL) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;\n    }\n\n    void * FindObject(void * pvKey, PDWORD PtrIndex = NULL)\n    {\n        void * pvObject;\n        DWORD dwHashIndex;\n\n        // Verify pointer to the map\n        if(m_HashTable != NULL)\n        {\n            // Construct the hash index\n            dwHashIndex = HashToIndex(PfnCalcHashValue(pvKey, m_KeyLength));\n\n            // Search the hash table\n            while((pvObject = m_HashTable[dwHashIndex]) != NULL)\n            {\n                // Compare the hash\n                if(CompareObject_Key(pvObject, pvKey))\n                {\n                    if(PtrIndex != NULL)\n                        PtrIndex[0] = dwHashIndex;\n                    return pvObject;\n                }\n\n                // Move to the next entry\n                dwHashIndex = HashToIndex(dwHashIndex + 1);\n            }\n        }\n\n        // Not found, sorry\n        return NULL;\n    }\n\n    bool InsertObject(void * pvNewObject, void * pvKey)\n    {\n        void * pvExistingObject;\n        DWORD dwHashIndex;\n\n        // Verify pointer to the map\n        if(m_HashTable != NULL)\n        {\n            // Limit check\n            if((m_ItemCount + 1) >= m_HashTableSize)\n                return false;\n\n            // Construct the hash index\n            dwHashIndex = HashToIndex(PfnCalcHashValue(pvKey, m_KeyLength));\n\n            // Search the hash table\n            while((pvExistingObject = m_HashTable[dwHashIndex]) != NULL)\n            {\n                // Check if hash being inserted conflicts with an existing hash\n                if(CompareObject_Key(pvExistingObject, pvKey))\n                    return false;\n\n                // Move to the next entry\n                dwHashIndex = HashToIndex(dwHashIndex + 1);\n            }\n\n            // Insert at that position\n            m_HashTable[dwHashIndex] = pvNewObject;\n            m_ItemCount++;\n            return true;\n        }\n\n        // Failed\n        return false;\n    }\n\n    const char * FindString(const char * szString, const char * szStringEnd)\n    {\n        const char * szExistingString;\n        DWORD dwHashIndex;\n\n        // Verify pointer to the map\n        if(m_HashTable != NULL)\n        {\n            // Construct the main index\n            dwHashIndex = HashToIndex(CalcHashValue_String(szString, szStringEnd));\n\n            // Search the hash table\n            while((szExistingString = (const char *)m_HashTable[dwHashIndex]) != NULL)\n            {\n                // Compare the hash\n                if(CompareObject_String(szExistingString, szString, szStringEnd))\n                    return szExistingString;\n\n                // Move to the next entry\n                dwHashIndex = HashToIndex(dwHashIndex + 1);\n            }\n        }\n\n        // Not found, sorry\n        return NULL;\n    }\n\n    bool InsertString(const char * szString, bool bCutExtension)\n    {\n        const char * szExistingString;\n        const char * szStringEnd = NULL;\n        DWORD dwHashIndex;\n\n        // Verify pointer to the map\n        if(m_HashTable != NULL)\n        {\n            // Limit check\n            if((m_ItemCount + 1) >= m_HashTableSize)\n                return false;\n\n            // Retrieve the length of the string without extension\n            if(bCutExtension)\n                szStringEnd = GetFileExtension(szString);\n            else\n                szStringEnd = szString + strlen(szString);\n\n            // Construct the hash index\n            dwHashIndex = HashToIndex(CalcHashValue_String(szString, szStringEnd));\n\n            // Search the hash table\n            while((szExistingString = (const char *)m_HashTable[dwHashIndex]) != NULL)\n            {\n                // Check if hash being inserted conflicts with an existing hash\n                if(CompareObject_String(szExistingString, szString, szStringEnd))\n                    return false;\n\n                // Move to the next entry\n                dwHashIndex = HashToIndex(dwHashIndex + 1);\n            }\n\n            // Insert at that position\n            m_HashTable[dwHashIndex] = (void *)szString;\n            m_ItemCount++;\n            return true;\n        }\n\n        // Failed\n        return false;\n    }\n\n    void * ItemAt(size_t nIndex)\n    {\n        assert(nIndex < m_HashTableSize);\n        return m_HashTable[nIndex];\n    }\n\n    size_t HashTableSize()\n    {\n        return m_HashTableSize;\n    }\n\n    size_t ItemCount()\n    {\n        return m_ItemCount;\n    }\n\n    bool IsInitialized()\n    {\n        return (m_HashTable && m_HashTableSize);\n    }\n\n    void Free()\n    {\n        PfnCalcHashValue = NULL;\n        CASC_FREE(m_HashTable);\n        m_HashTableSize = 0;\n    }\n\n    protected:\n\n    DWORD HashToIndex(DWORD HashValue)\n    {\n        return HashValue & (m_HashTableSize - 1);\n    }\n\n    bool CompareObject_Key(void * pvObject, void * pvKey)\n    {\n        LPBYTE pbObjectKey = (LPBYTE)pvObject + m_KeyOffset;\n        return (memcmp(pbObjectKey, pvKey, m_KeyLength) == 0);\n    }\n\n    bool CompareObject_String(const char * szExistingString, const char * szString, const char * szStringEnd)\n    {\n        // Compare the whole part, case insensitive\n        while(szString < szStringEnd)\n        {\n            if(AsciiToUpperTable_BkSlash[*szExistingString] != AsciiToUpperTable_BkSlash[*szString])\n                return false;\n\n            szExistingString++;\n            szString++;\n        }\n\n        return true;\n    }\n\n    size_t GetNearestPowerOfTwo(size_t MaxItems)\n    {\n        size_t PowerOfTwo;\n        \n        // Round the hash table size up to the nearest power of two\n        for(PowerOfTwo = MIN_HASH_TABLE_SIZE; PowerOfTwo <= MAX_HASH_TABLE_SIZE; PowerOfTwo <<= 1)\n        {\n            if(PowerOfTwo > MaxItems)\n            {\n                return PowerOfTwo;\n            }\n        }\n\n        // If the hash table is too big, we cannot create the map\n        assert(false);\n        return 0;\n    }\n\n    PFNHASHFUNC PfnCalcHashValue;\n    void ** m_HashTable;                        // Hash table\n    size_t m_HashTableSize;                     // Size of the hash table, in entries. Always a power of two.\n    size_t m_ItemCount;                         // Number of objects in the map\n    size_t m_KeyOffset;                         // How far is the hash from the begin of the objects (in bytes)\n    size_t m_KeyLength;                         // Length of the hash key, in bytes\n    bool m_bKeyIsHash;                          // If set, then it means that the key is a hash of some sort.\n                                                // Will improve performance, as we will not hash a hash :-)\n};\n\n//-----------------------------------------------------------------------------\n// Key map interface\n\n// Maximum length of encryption key\n#define CASC_KEY_LENGTH         0x10\n#define CASC_KEY_TABLE_SIZE     0x100\n#define CASC_KEY_TABLE_MASK     (CASC_KEY_TABLE_SIZE - 1)\n\nclass CASC_KEY_MAP\n{\n    public:\n\n    CASC_KEY_MAP();\n    ~CASC_KEY_MAP();\n\n    LPBYTE FindKey(ULONGLONG KeyName);\n    bool AddKey(ULONGLONG KeyName, LPBYTE Key);\n\n    protected:\n\n    void * HashTable[CASC_KEY_TABLE_SIZE];\n};\n\n#endif // __CASC_MAP_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/Mime.cpp",
    "content": "/*****************************************************************************/\n/* Mime.cpp                               Copyright (c) Ladislav Zezula 2021 */\n/*---------------------------------------------------------------------------*/\n/* Mime functions for CascLib                                                */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 21.01.21  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local variables\n\n#define BASE64_INVALID_CHAR 0xFF\n#define BASE64_WHITESPACE_CHAR 0xFE\n\nstatic const char * CascBase64Table = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nstatic unsigned char CascBase64ToBits[0x80] = {0};\n\n//-----------------------------------------------------------------------------\n// CASC_MIME_HTTP implementation\n\nstatic size_t DecodeValueInt32(const char * string, const char * string_end)\n{\n    size_t result = 0;\n\n    while(string < string_end && isdigit(string[0]))\n    {\n        result = (result * 10) + (string[0] - '0');\n        string++;\n    }\n\n    return result;\n}\n\nbool CASC_MIME_HTTP::IsDataComplete(const char * response, size_t response_length)\n{\n    const char * content_length_ptr;\n    const char * content_begin_ptr;\n\n    // Do not parse the HTTP response multiple times\n    if(response_valid == 0 && response_length > 8)\n    {\n        // Check the begin of the response\n        if(!strncmp(response, \"HTTP/1.1\", 8))\n        {\n            // Check if there's begin of the content\n            if((content_begin_ptr = strstr(response, \"\\r\\n\\r\\n\")) != NULL)\n            {\n                // HTTP responses contain \"Content-Length: %u\\n\\r\"\n                if((content_length_ptr = strstr(response, \"Content-Length: \")) != NULL)\n                {\n                    // The content length info muse be before the actual content\n                    if(content_length_ptr < content_begin_ptr)\n                    {\n                        // Fill the HTTP info cache\n                        response_valid = 0x48545450;    // 'HTTP'\n                        content_offset = (content_begin_ptr + 4) - response;\n                        content_length = DecodeValueInt32(content_length_ptr + 16, content_begin_ptr);\n                        total_length = content_offset + content_length;\n                    }\n                }\n            }\n        }\n    }\n\n    // If we know the expected total length, we can tell whether it's complete or not\n    return ((response_valid != 0) && (total_length == response_length));\n}\n\n//-----------------------------------------------------------------------------\n// The MIME blob class\n\nCASC_MIME_BLOB::CASC_MIME_BLOB(char * mime_ptr, char * mime_end)\n{\n    ptr = mime_ptr;\n    end = mime_end;\n}\n\nCASC_MIME_BLOB::~CASC_MIME_BLOB()\n{\n    ptr = end = NULL;\n}\n\nchar * CASC_MIME_BLOB::GetNextLine()\n{\n    char * mime_line = ptr;\n\n    while(ptr < end)\n    {\n        // Every line, even the last one, must be terminated with 0D 0A\n        if(ptr[0] == 0x0D && ptr[1] == 0x0A)\n        {\n            // If space or tabulator follows, then this is continuation of the line\n            if(ptr[2] == 0x09 || ptr[2] == 0x20)\n            {\n                ptr = ptr + 2;\n                continue;\n            }\n\n            // Terminate the line and return its begin\n            ptr[0] = 0;\n            ptr[1] = 0;\n            ptr = ptr + 2;\n            return mime_line;\n        }\n\n        // Move to tne next character\n        ptr++;\n    }\n\n    // No EOL terminated line found, break the search\n    return NULL;\n}\n\n//-----------------------------------------------------------------------------\n// The MIME element class\n\nCASC_MIME_ELEMENT::CASC_MIME_ELEMENT()\n{\n    memset(this, 0, sizeof(CASC_MIME_ELEMENT));\n}\n\nCASC_MIME_ELEMENT::~CASC_MIME_ELEMENT()\n{\n    // Free the children and next elements\n    if(folder.pChild != NULL)\n        delete folder.pChild;\n    folder.pChild = NULL;\n\n    if(folder.pNext != NULL)\n        delete folder.pNext;\n    folder.pNext = NULL;\n\n    // Free the data\n    if(data.begin != NULL)\n        CASC_FREE(data.begin);\n    data.begin = NULL;\n}\n\nunsigned char * CASC_MIME_ELEMENT::GiveAway(size_t * ptr_data_length)\n{\n    unsigned char * give_away_data = data.begin;\n    size_t give_away_length = data.length;\n\n    // Clear the data (DO NOT FREE)\n    data.begin = NULL;\n    data.length = 0;\n\n    // Copy the data to local buffer\n    if(ptr_data_length != NULL)\n        ptr_data_length[0] = give_away_length;\n    return give_away_data;\n}\n\nDWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, const char * boundary_ptr)\n{\n    CASC_MIME_ENCODING Encoding = MimeEncodingTextPlain;\n    CASC_MIME_BLOB mime_data(mime_data_begin, mime_data_end);\n    CASC_MIME_HTTP HttpInfo;\n    size_t length_begin;\n    size_t length_end;\n    char * mime_line;\n    char boundary_begin[MAX_LENGTH_BOUNDARY + 2];\n    char boundary_end[MAX_LENGTH_BOUNDARY + 4];\n    DWORD dwErrCode = ERROR_SUCCESS;\n    bool mime_version = false;\n\n    // Diversion for HTTP: No need to parse the entire headers and stuff.\n    // Just give the data right away\n    if(HttpInfo.IsDataComplete(mime_data_begin, (mime_data_end - mime_data_begin)))\n    {\n        if((data.begin = CASC_ALLOC<BYTE>(HttpInfo.content_length)) == NULL)\n            return ERROR_NOT_ENOUGH_MEMORY;\n        \n        memcpy(data.begin, mime_data_begin + HttpInfo.content_offset, HttpInfo.content_length);\n        data.length = HttpInfo.content_length;\n        return ERROR_SUCCESS;\n    }\n\n    // Reset the boundary\n    boundary[0] = 0;\n\n    // Parse line-by-line untile we find the end of data\n    while((mime_line = mime_data.GetNextLine()) != NULL)\n    {\n        // If the line is empty, this means that it's the end of the MIME header and begin of the MIME data\n        if(mime_line[0] == 0)\n        {\n            mime_data.ptr = mime_line + 2;\n            break;\n        }\n\n        // Root nodes are required to have MIME version\n        if(boundary_ptr == NULL && mime_version == false)\n        {\n            if(!strcmp(mime_line, \"MIME-Version: 1.0\"))\n            {\n                mime_version = true;\n                continue;\n            }\n            if(!strcmp(mime_line, \"HTTP/1.1 200 OK\"))\n            {\n                mime_version = true;\n                continue;\n            }\n        }\n\n        // Get the encoding\n        if(!strncmp(mime_line, \"Content-Transfer-Encoding: \", 27))\n        {\n            ExtractEncoding(mime_line + 27, Encoding);\n            continue;\n        }\n\n        // Is there content type?\n        if(!strncmp(mime_line, \"Content-Type: \", 14))\n        {\n            ExtractBoundary(mime_line + 14);\n            continue;\n        }\n    }\n\n    // Keep going only if we have MIME version\n    if(boundary_ptr != NULL || mime_version == true)\n    {\n        // If we have boundary, it means that the element begin\n        // and end is marked by the boundary\n        if(boundary[0])\n        {\n            CASC_MIME_ELEMENT * pLast = NULL;\n            CASC_MIME_ELEMENT * pChild;\n            CASC_MIME_BLOB sub_mime(mime_data.ptr, NULL);\n\n            // Construct the begin of the boundary. Don't include newline there,\n            // as it must also match end of the boundary\n            length_begin = CascStrPrintf(boundary_begin, _countof(boundary_begin), \"--%s\", boundary);\n            dwErrCode = ERROR_SUCCESS;\n\n            // The current line must point to the begin of the boundary\n            // Find the end of the boundary\n            if(memcmp(sub_mime.ptr, boundary_begin, length_begin))\n                return ERROR_BAD_FORMAT;\n            sub_mime.ptr += length_begin;\n\n            // Find the end of the boundary\n            length_end = CascStrPrintf(boundary_end, _countof(boundary_end), \"--%s--\\r\\n\", boundary);\n            sub_mime.end = strstr(sub_mime.ptr, boundary_end);\n            if(sub_mime.end == NULL)\n                return ERROR_BAD_FORMAT;\n\n            // This is the end of the MIME section. Cut it to blocks\n            // and put each into the separate CASC_MIME_ELEMENT\n            while(sub_mime.ptr < sub_mime.end)\n            {\n                char * sub_mime_next;\n\n                // At this point, there must be newline in the current data pointer\n                if(sub_mime.ptr[0] != 0x0D || sub_mime.ptr[1] != 0x0A)\n                    return ERROR_BAD_FORMAT;\n                sub_mime.ptr += 2;\n\n                // Find the next MIME element. This must succeed, as the last element also matches the first element\n                sub_mime_next = strstr(sub_mime.ptr, boundary_begin);\n                if(sub_mime_next == NULL)\n                    return ERROR_BAD_FORMAT;\n\n                // Allocate the element\n                pChild = AllocateAndLoadElement(sub_mime.ptr, sub_mime_next - 2, boundary_begin);\n                if(pChild == NULL)\n                {\n                    dwErrCode = GetCascError();\n                    break;\n                }\n\n                // Link the element\n                if(folder.pChild == NULL)\n                    folder.pChild = pChild;\n                if(pLast != NULL)\n                    pLast->folder.pNext = pChild;\n                pLast = pChild;\n\n                // Move to the next MIME element. Note that if we are at the ending boundary,\n                // this moves past the end, but it's OK, because the while loop will catch that\n                sub_mime.ptr = sub_mime_next + length_begin;\n            }\n        }\n        else\n        {\n            CASC_MIME_BLOB content(mime_data.ptr, NULL);\n            unsigned char * data_buffer;\n            size_t data_length = 0;\n            size_t raw_length;\n\n            // If we have boundary pointer, we need to cut the data up to the boundary end.\n            // Otherwise, we decode the data to the end of the document\n            if(boundary_ptr != NULL)\n            {\n                // Find the end of the current data by the boundary. It is 2 characters before the next boundary \n                content.end = strstr(content.ptr, boundary_ptr);\n                if(content.end == NULL)\n                    return ERROR_BAD_FORMAT;\n                if((content.ptr + 2) >= content.end)\n                    return ERROR_BAD_FORMAT;\n                content.end -= 2;\n            }\n            else\n            {\n                content.end = mime_data_end - 2;\n                if(content.end[0] != 0x0D || content.end[1] != 0x0A)\n                    return ERROR_BAD_FORMAT;\n                if((content.ptr + 2) >= content.end)\n                    return ERROR_BAD_FORMAT;\n            }\n\n            // Allocate buffer for decoded data.\n            // Make it the same size like source data plus zero at the end\n            raw_length = (content.end - content.ptr);\n            data_buffer = CASC_ALLOC<unsigned char>(raw_length);\n            if(data_buffer != NULL)\n            {\n                // Decode the data\n                switch(Encoding)\n                {\n                    case MimeEncodingTextPlain:\n                        dwErrCode = DecodeTextPlain(content.ptr, content.end, data_buffer, &data_length);\n                        break;\n\n                    case MimeEncodingQuotedPrintable:\n                        dwErrCode = DecodeQuotedPrintable(content.ptr, content.end, data_buffer, &data_length);\n                        break;\n\n                    case MimeEncodingBase64:\n                        dwErrCode = DecodeBase64(content.ptr, content.end, data_buffer, &data_length);\n                        break;\n                    \n                    default:;\n                        // to remove warning\n                }\n\n                // If failed, free the buffer back\n                if(dwErrCode != ERROR_SUCCESS)\n                {\n                    CASC_FREE(data_buffer);\n                    data_buffer = NULL;\n                    data_length = 0;\n                }\n            }\n            else\n            {\n                dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n            }\n\n            // Put the data there, even if they are invalid\n            data.begin = data_buffer;\n            data.length = data_length;\n        }\n    }\n    else\n    {\n        dwErrCode = ERROR_NOT_SUPPORTED;\n    }\n\n    // Return the result of the decoding\n    return dwErrCode;\n}\n\n#ifdef _DEBUG\n#define MAX_LEVEL 0x10\nvoid CASC_MIME_ELEMENT::Print(size_t nLevel, size_t nIndex)\n{\n    char Prefix[(MAX_LEVEL * 4) + 0x20 + 1] = {0};\n    size_t nSpaces;\n\n    // Fill-in the spaces\n    nSpaces = (nLevel < MAX_LEVEL) ? (nLevel * 4) : (MAX_LEVEL * 4);\n    memset(Prefix, ' ', nSpaces);\n\n    // Print the spaces and index\n    nSpaces = printf(\"%s* [%u]: \", Prefix, (int)nIndex);\n    memset(Prefix, ' ', nSpaces);\n\n    // Is this a folder item?\n    if(folder.pChild != NULL)\n    {\n        printf(\"Folder item (boundary: %s)\\n\", boundary);\n        folder.pChild->Print(nLevel + 1, 0);\n    }\n    else\n    {\n        char data_printable[0x20] = {0};\n\n        for(size_t i = 0; (i < data.length && i < _countof(data_printable) - 1); i++)\n        {\n            if(0x20 <= data.begin[i] && data.begin[i] <= 0x7F)\n                data_printable[i] = data.begin[i];\n            else\n                data_printable[i] = '.';\n        }\n\n        printf(\"Data item (%u bytes): \\\"%s\\\"\\n\", (int)data.length, data_printable);\n    }\n\n    // Do we have a next element?\n    if(folder.pNext != NULL)\n    {\n        folder.pNext->Print(nLevel, nIndex + 1);\n    }\n}\n#endif\n\nCASC_MIME_ELEMENT * CASC_MIME_ELEMENT::AllocateAndLoadElement(char * a_mime_data, char * a_mime_data_end, const char * boundary_begin)\n{\n    CASC_MIME_ELEMENT * pElement;\n    DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;\n\n    // Allocate the element\n    if((pElement = new CASC_MIME_ELEMENT()) != NULL)\n    {\n        // Load the element\n        dwErrCode = pElement->Load(a_mime_data, a_mime_data_end, boundary_begin);\n        if(dwErrCode == ERROR_SUCCESS)\n            return pElement;\n\n        // Free the element on failure\n        delete pElement;\n    }\n\n    SetCascError(dwErrCode);\n    return NULL;\n}\n\nbool CASC_MIME_ELEMENT::ExtractEncoding(const char * line, CASC_MIME_ENCODING & Encoding)\n{\n    if(!_stricmp(line, \"base64\"))\n    {\n        Encoding = MimeEncodingBase64;\n        return true;\n    }\n\n    if(!_stricmp(line, \"quoted-printable\"))\n    {\n        Encoding = MimeEncodingQuotedPrintable;\n        return true;\n    }\n\n    // Unknown encoding\n    return false;\n}\n\n\nbool CASC_MIME_ELEMENT::ExtractBoundary(const char * line)\n{\n    const char * begin;\n    const char * end;\n\n    // Find the begin of the boundary\n    if((begin = strstr(line, \"boundary=\\\"\")) != NULL)\n    {\n        // Set begin of the boundary\n        begin = begin + 10;\n        \n        // Is there also end?\n        if((end = strchr(begin, '\\\"')) != NULL)\n        {\n            CascStrCopy(boundary, _countof(boundary), begin, end - begin);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nDWORD CASC_MIME_ELEMENT::DecodeTextPlain(char * content_begin, char * content_end, unsigned char * data_buffer, size_t * ptr_length)\n{\n    size_t data_length = (size_t)(content_end - content_begin);\n\n    // Sanity checks\n    assert(content_begin && content_end);\n    assert(content_end > content_begin);\n\n    // Plain copy\n    memcpy(data_buffer, content_begin, data_length);\n\n    // Give the result\n    if(ptr_length != NULL)\n        ptr_length[0] = data_length;\n    return ERROR_SUCCESS;\n}\n\n\nDWORD CASC_MIME_ELEMENT::DecodeQuotedPrintable(char * content_begin, char * content_end, unsigned char * data_buffer, size_t * ptr_length)\n{\n    unsigned char * save_data_buffer = data_buffer;\n    char * content_ptr;\n    DWORD dwErrCode;\n\n    // Sanity checks\n    assert(content_begin && content_end);\n    assert(content_end > content_begin);\n\n    // Decode the data\n    for(content_ptr = content_begin; content_ptr < content_end; )\n    {\n        // If the data begins with '=', there is either newline or 2-char hexa number\n        if(content_ptr[0] == '=')\n        {\n            // Is there a newline after the equal sign?\n            if(content_ptr[1] == 0x0D && content_ptr[2] == 0x0A)\n            {\n                content_ptr += 3;\n                continue;\n            }\n\n            // Is there hexa number after the equal sign?\n            dwErrCode = BinaryFromString(content_ptr + 1, 2, data_buffer);\n            if(dwErrCode != ERROR_SUCCESS)\n                return dwErrCode;\n\n            content_ptr += 3;\n            data_buffer++;\n            continue;\n        }\n        else\n        {\n            *data_buffer++ = (unsigned char)(*content_ptr++);\n        }\n    }\n\n    if(ptr_length != NULL)\n        ptr_length[0] = (size_t)(data_buffer - save_data_buffer);\n    return ERROR_SUCCESS;\n}\n\nDWORD CASC_MIME_ELEMENT::DecodeBase64(char * content_begin, char * content_end, unsigned char * data_buffer, size_t * ptr_length)\n{\n    unsigned char * save_data_buffer = data_buffer;\n    DWORD BitBuffer = 0;\n    DWORD BitCount = 0;\n    BYTE OneByte;\n\n    // One time preparation of the conversion table\n    if(CascBase64ToBits[0] == 0)\n    {\n        // Fill the entire table with 0xFF to mark invalid characters\n        memset(CascBase64ToBits, BASE64_INVALID_CHAR, sizeof(CascBase64ToBits));\n\n        // Set all whitespace characters\n        for(BYTE i = 1; i <= 0x20; i++)\n            CascBase64ToBits[i] = BASE64_WHITESPACE_CHAR;\n\n        // Set all valid characters\n        for(BYTE i = 0; CascBase64Table[i] != 0; i++)\n        {\n            OneByte = CascBase64Table[i];\n            CascBase64ToBits[OneByte] = i;\n        }\n    }\n\n    // Do the decoding\n    while(content_begin < content_end && content_begin[0] != '=')\n    {\n        // Check for end of string\n        if(content_begin[0] > sizeof(CascBase64ToBits))\n            return ERROR_BAD_FORMAT;\n        if((OneByte = CascBase64ToBits[*content_begin++]) == BASE64_INVALID_CHAR)\n            return ERROR_BAD_FORMAT;\n        if(OneByte == BASE64_WHITESPACE_CHAR)\n            continue;\n\n        // Put the 6 bits into the bit buffer\n        BitBuffer = (BitBuffer << 6) | OneByte;\n        BitCount += 6;\n\n        // Flush all values\n        while(BitCount >= 8)\n        {\n            // Decrement the bit count in the bit buffer\n            BitCount -= 8;\n\n            // The byte is the upper 8 bits of the bit buffer\n            OneByte = (BYTE)(BitBuffer >> BitCount);\n            BitBuffer = BitBuffer % (1 << BitCount);\n\n            // Put the byte value. The buffer can not overflow,\n            // because it is guaranteed to be equal to the length of the base64 string\n            *data_buffer++ = OneByte;\n        }\n    }\n\n    // Return the decoded length\n    if(ptr_length != NULL)\n        ptr_length[0] = (data_buffer - save_data_buffer);\n    return ERROR_SUCCESS;\n}\n\n//-----------------------------------------------------------------------------\n// The MIME class\n\nCASC_MIME::CASC_MIME()\n{}\n\nCASC_MIME::~CASC_MIME()\n{}\n\nunsigned char * CASC_MIME::GiveAway(size_t * ptr_data_length)\n{\n    CASC_MIME_ELEMENT * pElement = &root;\n    unsigned char * data;\n\n    // 1) Give the data from the root\n    if((data = root.GiveAway(ptr_data_length)) != NULL)\n        return data;\n\n    // 2) If we have children, then give away from the first child\n    pElement = root.GetChild();\n    if(pElement && (data = pElement->GiveAway(ptr_data_length)) != NULL)\n        return data;\n\n    // Return NULL\n    if(ptr_data_length != NULL)\n        ptr_data_length[0] = 0;\n    return NULL;\n}\n\nDWORD CASC_MIME::Load(char * data, size_t length)\n{\n    // Clear the root element\n    memset(&root, 0, sizeof(CASC_MIME_ELEMENT));\n\n    //FILE * fp = fopen(\"E:\\\\html_response.txt\", \"wb\");\n    //if(fp != NULL)\n    //{\n    //    fwrite(data, 1, length, fp);\n    //    fclose(fp);\n    //}\n\n    // Load the root element\n    return root.Load(data, data + length);\n}\n\nDWORD CASC_MIME::Load(LPCTSTR szFileName)\n{\n    char * szFileData;\n    DWORD cbFileData = 0;\n    DWORD dwErrCode = ERROR_SUCCESS;\n\n    // Note that LoadFileToMemory allocated one byte more and puts zero at the end\n    // Thus, we can treat it as zero-terminated string\n    szFileData = (char *)LoadFileToMemory(szFileName, &cbFileData);\n    if(szFileData != NULL)\n    {\n        dwErrCode = Load(szFileData, cbFileData);\n        CASC_FREE(szFileData);\n    }\n    else\n    {\n        dwErrCode = GetCascError();\n    }\n\n    return dwErrCode;\n}\n\n#ifdef _DEBUG\nvoid CASC_MIME::Print()\n{\n    root.Print(0, 0);\n}\n#endif\n\n"
  },
  {
    "path": "deps/CascLib/src/common/Mime.h",
    "content": "/*****************************************************************************/\n/* Mime.h                                 Copyright (c) Ladislav Zezula 2021 */\n/*---------------------------------------------------------------------------*/\n/* MIME parsing functions for CascLib                                        */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 21.01.21  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __MIME_H__\n#define __MIME_H__\n\n//-----------------------------------------------------------------------------\n// MIME constants\n\n#define MAX_LENGTH_BOUNDARY 128\n\nenum CASC_MIME_ENCODING\n{\n    MimeEncodingTextPlain,\n    MimeEncodingBase64,\n    MimeEncodingQuotedPrintable,\n    MimeEncodingMax\n};\n\n//-----------------------------------------------------------------------------\n// Structure for caching parsed HTTP response information\n\nstruct CASC_MIME_HTTP\n{\n    CASC_MIME_HTTP()\n    {\n        response_valid = content_length = content_offset = total_length = 0;\n    }\n\n    bool IsDataComplete(const char * response, size_t response_length);\n\n    size_t response_valid;              // Nonzero if this is an already parsed HTTP response\n    size_t content_length;              // Parsed value of \"Content-Length\"\n    size_t content_offset;              // Offset of the HTTP data, relative to the begin of the response\n    size_t total_length;                // Expected total length of the HTTP response (content_offset + content_size)\n};\n\n//-----------------------------------------------------------------------------\n// MIME blob class\n\nstruct CASC_MIME_BLOB\n{\n    CASC_MIME_BLOB(char * mime_ptr, char * mime_end);\n    ~CASC_MIME_BLOB();\n\n    char * GetNextLine();\n\n    char * ptr;\n    char * end;\n};\n\n//-----------------------------------------------------------------------------\n// MIME class\n\nclass CASC_MIME_ELEMENT\n{\n    public:\n\n    CASC_MIME_ELEMENT();\n    ~CASC_MIME_ELEMENT();\n\n    unsigned char * GiveAway(size_t * ptr_data_length);\n\n    DWORD Load(char * mime_data_begin, char * mime_data_end, const char * boundary_ptr = NULL);\n\n    CASC_MIME_ELEMENT * GetChild()  { return folder.pChild; }\n\n#ifdef _DEBUG\n    void Print(size_t nLevel, size_t nIndex);\n#endif\n\n    protected:\n\n    CASC_MIME_ELEMENT * AllocateAndLoadElement(char * a_mime_data, char * a_mime_data_end, const char * boundary_begin);\n    bool   ExtractEncoding(const char * line, CASC_MIME_ENCODING & Encoding);\n    bool   ExtractBoundary(const char * line);\n\n    DWORD DecodeTextPlain(char * content_begin, char * content_end, unsigned char * data_ptr, size_t * ptr_length);\n    DWORD DecodeQuotedPrintable(char * content_begin, char * content_end, unsigned char * data_ptr, size_t * ptr_length);\n    DWORD DecodeBase64(char * content_begin, char * content_end, unsigned char * data_ptr, size_t * ptr_length);\n\n    struct\n    {\n        CASC_MIME_ELEMENT * pChild;     // Pointer to the first child\n        CASC_MIME_ELEMENT * pNext;      // Pointer to the next-in-folder element\n    } folder;\n\n    struct\n    {\n        unsigned char * begin;\n        size_t length;\n    } data;\n\n    char boundary[MAX_LENGTH_BOUNDARY];\n};\n\nclass CASC_MIME\n{\n    public:\n\n    CASC_MIME();\n    ~CASC_MIME();\n\n    unsigned char * GiveAway(size_t * ptr_data_length);\n\n    DWORD Load(char * data, size_t length);\n    DWORD Load(LPCTSTR fileName);\n\n#ifdef _DEBUG\n    void Print();\n#endif\n\n    protected:\n\n    CASC_MIME_ELEMENT root;\n};\n\n//-----------------------------------------------------------------------------\n// HTTP helpers\n\nbool IsHttpResponseComplete(CASC_MIME_HTTP & HttpInfo, const char * response, size_t response_length);\n\n#endif // __MIME_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/Path.h",
    "content": "/*****************************************************************************/\n/* Path.h                                 Copyright (c) Ladislav Zezula 2019 */\n/*---------------------------------------------------------------------------*/\n/* Global path merger class                                                  */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 24.07.17  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __CASC_PATH_H__\n#define __CASC_PATH_H__\n\n//-----------------------------------------------------------------------------\n// Structures\n\ntemplate <typename xchar>\nstruct CASC_PATH\n{\n    CASC_PATH(int chSeparator = PATH_SEP_CHAR)\n    {\n        m_szBufferBegin = m_szBufferPtr = m_Buffer;\n        m_szBufferEnd = m_szBufferBegin + _countof(m_Buffer);\n        m_chSeparator = (xchar)chSeparator;\n        m_Buffer[0] = 0;\n    }\n\n    ~CASC_PATH()\n    {\n        if(m_szBufferBegin != m_Buffer)\n        {\n            CASC_FREE(m_szBufferBegin);\n        }\n    }\n\n    // LPCTSTR szPath = Path;\n    operator const xchar *()\n    {\n        return m_szBufferBegin;\n    }\n\n    // LPTSTR szPath = Path.New();\n    xchar * New()\n    {\n        xchar * szNewStr;\n\n        if((szNewStr = CASC_ALLOC<xchar>(Length() + 1)) != NULL)\n        {\n            memcpy(szNewStr, m_szBufferBegin, Length() * sizeof(xchar));\n            szNewStr[Length()] = 0;\n        }\n\n        return szNewStr;\n    }\n\n    size_t Save()\n    {\n        return (m_szBufferPtr - m_szBufferBegin);\n    }\n\n    bool Restore(size_t nSavePos)\n    {\n        if((m_szBufferBegin + nSavePos) < m_szBufferEnd)\n        {\n            m_szBufferPtr = m_szBufferBegin + nSavePos;\n            m_szBufferPtr[0] = 0;\n            return true;\n        }\n\n        return false;\n    }\n\n    // Path.Copy(szBuffer, _countof(szBuffer));\n    bool Copy(xchar * szBuffer, size_t cchBuffer)\n    {\n        if((Length() + 1) > cchBuffer)\n            return false;\n\n        memcpy(szBuffer, m_szBufferBegin, Length() * sizeof(xchar));\n        szBuffer[Length()] = 0;\n        return true;\n    }\n\n    size_t Length()\n    {\n        return m_szBufferPtr - m_szBufferBegin;\n    }\n\n    bool SetPathRoot(const xchar * szRoot)\n    {\n        // Make sure that there is no characters\n        m_szBufferPtr = m_szBufferBegin;\n        m_szBufferPtr[0] = 0;\n\n        // Append the root path\n        return AppendString(szRoot, false);\n    }\n\n    bool AppendStringN(const xchar * szString, size_t nMaxchars, bool bWithSeparator)\n    {\n        const xchar * szStringEnd = szString + nMaxchars;\n        xchar chOneChar;\n\n        if(szString && szString[0] && nMaxchars)\n        {\n            // Append separator, if required and not in begin of the string\n            if(m_szBufferPtr > m_szBufferBegin && bWithSeparator)\n                AppendChar(m_chSeparator);\n\n            // Append the characters from the string\n            while(szString[0] && szString < szStringEnd)\n            {\n                // Retrieve the single character\n                chOneChar = *szString++;\n\n                // Normalize the character\n                if(chOneChar == '/' || chOneChar == '\\\\')\n                    chOneChar = m_chSeparator;\n\n                if(!AppendChar(chOneChar))\n                    break;\n            }\n        }\n\n        return true;\n    }\n\n    bool AppendString(const xchar * szString, bool bWithSeparator)\n    {\n        return AppendStringN(szString, (0x10000 / sizeof(xchar)), bWithSeparator);\n    }\n\n    bool AppendEKey(LPBYTE pbEKey)\n    {\n        xchar szEKey[MD5_STRING_SIZE + 1];\n\n        StringFromBinary(pbEKey, MD5_HASH_SIZE, szEKey);\n        AppendStringN(szEKey, 2, true);\n        AppendStringN(szEKey+2, 2, true);\n        return AppendString(szEKey, true);\n    }\n\n    bool AppendChar(xchar chOneChar)\n    {\n        // Buffer our of space?\n        if((m_szBufferPtr + 2) >= m_szBufferEnd)\n        {\n            xchar * szOldBuffer = m_szBufferBegin;\n            xchar * szNewBuffer;\n            size_t nToAllocate = (m_szBufferEnd - m_szBufferBegin) * 2;\n            size_t nLength = (m_szBufferPtr - m_szBufferBegin);\n\n            if((szNewBuffer = CASC_ALLOC<xchar>(nToAllocate)) == NULL)\n                return false;\n\n            // Copy the chars\n            memcpy(szNewBuffer, m_szBufferBegin, (m_szBufferPtr - m_szBufferBegin) * sizeof(xchar));\n            m_szBufferBegin = szNewBuffer;\n            m_szBufferPtr = m_szBufferBegin + nLength;\n            m_szBufferEnd = m_szBufferBegin + nToAllocate;\n            \n            // Free the old buffer\n            if(szOldBuffer != m_Buffer)\n                CASC_FREE(szOldBuffer);\n        }\n\n        // Append the character\n        *m_szBufferPtr++ = chOneChar;\n        m_szBufferPtr[0] = 0;\n        return true;\n    }\n\n    protected:\n\n    xchar * m_szBufferBegin;\n    xchar * m_szBufferPtr;\n    xchar * m_szBufferEnd;\n    xchar m_Buffer[MAX_PATH];\n    xchar m_chSeparator;\n};\n\n#endif // __CASC_PATH_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/RootHandler.cpp",
    "content": "/*****************************************************************************/\n/* RootHandler.cpp                        Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Implementation of root handler                                            */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 09.03.15  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Constructor and destructor - TFileTreeRoot\n\nTFileTreeRoot::TFileTreeRoot(DWORD FileTreeFlags) : TRootHandler()\n{\n    // Initialize the file tree\n    FileTree.Create(FileTreeFlags);\n}\n\nTFileTreeRoot::~TFileTreeRoot()\n{\n    // Free the file tree\n    FileTree.Free();\n    dwFeatures = 0;\n}\n\n//-----------------------------------------------------------------------------\n// Virtual functions - TFileTreeRoot\n\nint TFileTreeRoot::Insert(\n    const char * szFileName,\n    PCASC_CKEY_ENTRY pCKeyEntry)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    pFileNode = FileTree.InsertByName(pCKeyEntry, szFileName, FileTree.GetNextFileDataId());\n    return (pFileNode != NULL) ? ERROR_SUCCESS : ERROR_CAN_NOT_COMPLETE;\n}\n\nPCASC_CKEY_ENTRY TFileTreeRoot::GetFile(TCascStorage * /* hs */, const char * szFileName)\n{\n    PCASC_FILE_NODE pFileNode;\n    ULONGLONG FileNameHash = CalcFileNameHash(szFileName);\n    \n    pFileNode = FileTree.Find(FileNameHash);\n    return (pFileNode != NULL) ? pFileNode->pCKeyEntry : NULL;\n}\n\nPCASC_CKEY_ENTRY TFileTreeRoot::GetFile(TCascStorage * /* hs */, DWORD FileDataId)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    pFileNode = FileTree.FindById(FileDataId);\n    return (pFileNode != NULL) ? pFileNode->pCKeyEntry : NULL;\n}\n\nPCASC_CKEY_ENTRY TFileTreeRoot::Search(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)\n{\n    PCASC_FILE_NODE pFileNode;\n    size_t nMaxFileIndex = FileTree.GetMaxFileIndex();\n\n    // Are we still inside the root directory range?\n    while(pSearch->nFileIndex < nMaxFileIndex)\n    {\n        //BREAKIF(pSearch->nFileIndex >= 2823765);\n\n        // Retrieve the file item\n        pFileNode = FileTree.PathAt(pFindData->szFileName, MAX_PATH, pSearch->nFileIndex++);\n        if(pFileNode != NULL)\n        {\n            // Ignore folders and mount points\n            if(!(pFileNode->Flags & CFN_FLAG_FOLDER))\n            {\n                // Check the wildcard\n                if (CascCheckWildCard(pFindData->szFileName, pSearch->szMask))\n                {\n                    // Retrieve the extra values (FileDataId, file size and locale flags)\n                    FileTree.GetExtras(pFileNode, &pFindData->dwFileDataId, &pFindData->dwLocaleFlags, &pFindData->dwContentFlags);\n\n                    // Return the found CKey entry\n                    return pFileNode->pCKeyEntry;\n                }\n            }\n        }\n    }\n\n    // No more entries\n    return NULL;\n}\n\nbool TFileTreeRoot::GetInfo(PCASC_CKEY_ENTRY pCKeyEntry, PCASC_FILE_FULL_INFO pFileInfo)\n{\n    PCASC_FILE_NODE pFileNode;\n\n    // Can't do much if the root key is NULL\n    if(pCKeyEntry != NULL)\n    {\n        pFileNode = FileTree.Find(pCKeyEntry);\n        if(pFileNode != NULL)\n        {\n            FileTree.GetExtras(pFileNode, &pFileInfo->FileDataId, &pFileInfo->LocaleFlags, &pFileInfo->ContentFlags);\n            pFileInfo->FileNameHash = pFileNode->FileNameHash;\n            return true;\n        }\n    }\n\n    return false;\n}\n\n"
  },
  {
    "path": "deps/CascLib/src/common/RootHandler.h",
    "content": "/*****************************************************************************/\n/* RootHandler.h                          Copyright (c) Ladislav Zezula 2015 */\n/*---------------------------------------------------------------------------*/\n/* Interface for root handlers                                               */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 09.03.15  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __ROOT_HANDLER_H__\n#define __ROOT_HANDLER_H__\n\n//-----------------------------------------------------------------------------\n// Defines\n\n#define CASC_MNDX_ROOT_SIGNATURE        0x58444E4D  // 'MNDX'\n#define CASC_TVFS_ROOT_SIGNATURE        0x53465654  // 'TVFS'\n#define CASC_DIABLO3_ROOT_SIGNATURE     0x8007D0C4\n#define CASC_WOW82_ROOT_SIGNATURE       0x4D465354  // 'TSFM', WoW since 8.2\n\n#define DUMP_LEVEL_ROOT_FILE                     1  // Dump root file\n#define DUMP_LEVEL_ENCODING_FILE                 2  // Dump root file + encoding file\n#define DUMP_LEVEL_INDEX_ENTRIES                 3  // Dump root file + encoding file + index entries\n\n//-----------------------------------------------------------------------------\n// Class for generic root handler\n\nstruct TRootHandler\n{\n    public:\n\n    TRootHandler()\n    {\n        dwFeatures = 0;\n    }\n\n    virtual ~TRootHandler()\n    {}\n\n    // Inserts new file name to the root handler\n    // szFileName - Pointer to the file name\n    // pCKeyEntry - Pointer to the CASC_CKEY_ENTRY for the file\n    virtual int Insert(const char * /* szFileName */, PCASC_CKEY_ENTRY /* pCKeyEntry */)\n    {\n        return ERROR_NOT_SUPPORTED;\n    }\n\n    // Searches the file by file name\n    // hs         - Pointer to the storage structure\n    // szFileName - Pointer to the file name\n    virtual PCASC_CKEY_ENTRY GetFile(struct TCascStorage * /* hs */, const char * /* szFileName */)\n    {\n        return NULL;\n    }\n\n    // Searches the file by file data id\n    // hs         - Pointer to the storage structure\n    // FileDataId - File data id\n    virtual PCASC_CKEY_ENTRY GetFile(struct TCascStorage * /* hs */, DWORD /* FileDataId */)\n    {\n        return NULL;\n    }\n\n    // Performs find-next-file operation\n    // pSearch   - Pointer to the initialized search structure\n    // pFindData - Pointer to output structure that will contain the information\n    virtual PCASC_CKEY_ENTRY Search(struct TCascSearch * /* pSearch */, struct _CASC_FIND_DATA * /* pFindData */)\n    {\n        return NULL;\n    }\n\n    // Returns advanced info from the root file entry.\n    // pCKeyEntry - CKey/EKey, depending on which type the root handler provides\n    // pFileInfo - Pointer to CASC_FILE_FULL_INFO structure\n    virtual bool GetInfo(PCASC_CKEY_ENTRY /* pCKeyEntry */, struct _CASC_FILE_FULL_INFO * /* pFileInfo */)\n    {\n        return false;\n    }\n\n    DWORD GetFeatures()\n    {\n        return dwFeatures;\n    }\n\n    protected:\n\n    DWORD dwFeatures;                               // CASC features. See CASC_FEATURE_XXX\n};\n\n//-----------------------------------------------------------------------------\n// Class for root handler that has basic mapping of FileName -> CASC_FILE_NODE\n\nstruct TFileTreeRoot : public TRootHandler\n{\n    TFileTreeRoot(DWORD FileTreeFlags);\n    virtual ~TFileTreeRoot();\n\n    int Insert(const char * szFileName, PCASC_CKEY_ENTRY pCKeyEntry);\n\n    PCASC_CKEY_ENTRY GetFile(struct TCascStorage * hs, const char * szFileName);\n    PCASC_CKEY_ENTRY GetFile(struct TCascStorage * hs, DWORD FileDataId);\n    PCASC_CKEY_ENTRY Search(struct TCascSearch * pSearch, struct _CASC_FIND_DATA * pFindData);\n    bool GetInfo(PCASC_CKEY_ENTRY pCKeyEntry, struct _CASC_FILE_FULL_INFO * pFileInfo);\n\n    protected:\n\n    CASC_FILE_TREE FileTree;\n};\n\n#endif  // __ROOT_HANDLER_H__\n"
  },
  {
    "path": "deps/CascLib/src/common/Sockets.cpp",
    "content": "/*****************************************************************************/\n/* Sockets.cpp                            Copyright (c) Ladislav Zezula 2021 */\n/*---------------------------------------------------------------------------*/\n/* Don't call this module \"Socket.cpp\", otherwise VS 2019 will not link it   */\n/* Socket functions for CascLib.                                             */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 13.02.21  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#define __CASCLIB_SELF__\n#include \"../CascLib.h\"\n#include \"../CascCommon.h\"\n\n//-----------------------------------------------------------------------------\n// Local variables\n\nCASC_SOCKET_CACHE SocketCache;\n\n//-----------------------------------------------------------------------------\n// CASC_SOCKET functions\n\n// Guarantees that there is zero terminator after the response\nchar * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, size_t * PtrLength)\n{\n    CASC_MIME_HTTP HttpInfo;\n    char * server_response = NULL;\n    size_t total_received = 0;\n    size_t block_increment = 0x8000;\n    size_t buffer_size = block_increment;\n    int bytes_received = 0;\n\n    // Pre-set the result length\n    if(PtrLength != NULL)\n        PtrLength[0] = 0;\n    if(request_length == 0)\n        request_length = strlen(request);\n\n    // Lock the socket\n    CascLock(Lock);\n\n    // Send the request to the remote host. On Linux, this call may send signal(SIGPIPE),\n    // we need to prevend that by using the MSG_NOSIGNAL flag. On Windows, it fails normally.\n    while(send(sock, request, (int)request_length, MSG_NOSIGNAL) == SOCKET_ERROR)\n    {\n        // If the connection was closed by the remote host, we try to reconnect\n        if(ReconnectAfterShutdown(sock, remoteItem) == INVALID_SOCKET)\n        {\n            SetCascError(ERROR_NETWORK_NOT_AVAILABLE);\n            CascUnlock(Lock);\n            return NULL;\n        }\n    }\n\n    // Allocate buffer for server response. Allocate one extra byte for zero terminator\n    if((server_response = CASC_ALLOC<char>(buffer_size + 1)) != NULL)\n    {\n        for(;;)\n        {\n            // Reallocate the buffer size, if needed\n            if(total_received == buffer_size)\n            {\n                if((server_response = CASC_REALLOC(char, server_response, buffer_size + block_increment + 1)) == NULL)\n                {\n                    SetCascError(ERROR_NOT_ENOUGH_MEMORY);\n                    CascUnlock(Lock);\n                    return NULL;\n                }\n                buffer_size += block_increment;\n            }\n\n            // Receive the next part of the response, up to buffer size\n            // Return value 0 means \"connection closed\", -1 means an error\n            bytes_received = recv(sock, server_response + total_received, (int)(buffer_size - total_received), 0);\n            if(bytes_received <= 0)\n                break;\n\n            // Append the number of bytes received. Also terminate response with zero\n            total_received += bytes_received;\n            server_response[total_received] = 0;\n\n            // On a HTTP protocol, we need to check whether we received all data\n            if(HttpInfo.IsDataComplete(server_response, total_received))\n                break;\n        }\n    }\n\n    // Unlock the socket\n    CascUnlock(Lock);\n\n    // Give the result to the caller\n    if(PtrLength != NULL)\n        PtrLength[0] = total_received;\n    return server_response;\n}\n\nDWORD CASC_SOCKET::AddRef()\n{\n    return CascInterlockedIncrement(&dwRefCount);\n}\n\nvoid CASC_SOCKET::Release()\n{\n    // Note: If this is a cached socket, there will be extra reference from the cache\n    if(CascInterlockedDecrement(&dwRefCount) == 0)\n    {\n        Delete();\n    }\n}\n\nint CASC_SOCKET::GetSockError()\n{\n#ifdef CASCLIB_PLATFORM_WINDOWS\n    return WSAGetLastError();\n#else\n    return errno;\n#endif\n}\n\nDWORD CASC_SOCKET::GetAddrInfoWrapper(const char * hostName, unsigned portNum, PADDRINFO hints, PADDRINFO * ppResult)\n{\n    char portNumString[16];\n\n    // Prepare the port number\n    CascStrPrintf(portNumString, _countof(portNumString), \"%d\", portNum);\n\n    // Attempt to connect\n    for(;;)\n    {\n        // Attempt to call the addrinfo\n        DWORD dwErrCode = getaddrinfo(hostName, portNumString, hints, ppResult);\n\n        // Error-specific handling\n        switch(dwErrCode)\n        {\n#ifdef CASCLIB_PLATFORM_WINDOWS\n            case WSANOTINITIALISED:     // Windows-specific: WSAStartup not called\n            {\n                WSADATA wsd;\n\n                WSAStartup(MAKEWORD(2, 2), &wsd);\n                continue;\n            }\n#endif\n            case (DWORD)EAI_AGAIN:             // Temporary error, try again\n                continue;\n\n            default:                    // Any other result, incl. ERROR_SUCCESS\n                return dwErrCode;\n        }\n    }\n}\n\nSOCKET CASC_SOCKET::CreateAndConnect(addrinfo * remoteItem)\n{\n    SOCKET sock;\n\n    // Create new socket\n    // On error, returns returns INVALID_SOCKET (-1) on Windows, -1 on Linux\n    if((sock = socket(remoteItem->ai_family, remoteItem->ai_socktype, remoteItem->ai_protocol)) > 0)\n    {\n        // Connect to the remote host\n        // On error, returns SOCKET_ERROR (-1) on Windows, -1 on Linux\n        if(connect(sock, remoteItem->ai_addr, (int)remoteItem->ai_addrlen) == 0)\n            return sock;\n\n        // Failed. Close the socket and return 0\n        closesocket(sock);\n        sock = INVALID_SOCKET;\n    }\n\n    return sock;\n}\n\nSOCKET CASC_SOCKET::ReconnectAfterShutdown(SOCKET & sock, addrinfo * remoteItem)\n{\n    // Retrieve the error code related to previous socket operation\n    switch(GetSockError())\n    {\n        case EPIPE:         // Non-Windows\n        case WSAECONNRESET: // Windows\n        {\n            // Close the old socket\n            if(sock != INVALID_SOCKET)\n                closesocket(sock);\n\n            // Attempt to reconnect\n            sock = CreateAndConnect(remoteItem);\n            return sock;\n        }\n    }\n\n    // Another problem\n    return INVALID_SOCKET;\n}\n\nPCASC_SOCKET CASC_SOCKET::New(addrinfo * remoteList, addrinfo * remoteItem, const char * hostName, unsigned portNum, SOCKET sock)\n{\n    PCASC_SOCKET pSocket;\n    size_t length = strlen(hostName);\n\n    // Allocate enough bytes\n    pSocket = (PCASC_SOCKET)CASC_ALLOC<BYTE>(sizeof(CASC_SOCKET) + length);\n    if(pSocket != NULL)\n    {\n        // Fill the entire object with zero\n        memset(pSocket, 0, sizeof(CASC_SOCKET) + length);\n        pSocket->remoteList = remoteList;\n        pSocket->remoteItem = remoteItem;\n        pSocket->dwRefCount = 1;\n        pSocket->portNum = portNum;\n        pSocket->sock = sock;\n\n        // Init the remote host name\n        CascStrCopy((char *)pSocket->hostName, length + 1, hostName);\n\n        // Init the socket lock\n        CascInitLock(pSocket->Lock);\n    }\n\n    return pSocket;\n}\n\nPCASC_SOCKET CASC_SOCKET::Connect(const char * hostName, unsigned portNum)\n{\n    PCASC_SOCKET pSocket;\n    addrinfo * remoteList;\n    addrinfo * remoteItem;\n    addrinfo hints = {0};\n    SOCKET sock;\n    int nErrCode;\n\n    // Retrieve the information about the remote host\n    // This will fail immediately if there is no connection to the internet\n    hints.ai_family = AF_INET;\n    hints.ai_socktype = SOCK_STREAM;\n    nErrCode = GetAddrInfoWrapper(hostName, portNum, &hints, &remoteList);\n\n    // Handle error code\n    if(nErrCode == 0)\n    {\n        // Try to connect to any address provided by the getaddrinfo()\n        for(remoteItem = remoteList; remoteItem != NULL; remoteItem = remoteItem->ai_next)\n        {\n            // Create new socket and connect to the remote host\n            if((sock = CreateAndConnect(remoteItem)) != 0)\n            {\n                // Create new instance of the CASC_SOCKET structure\n                if((pSocket = CASC_SOCKET::New(remoteList, remoteItem, hostName, portNum, sock)) != NULL)\n                {\n                    return pSocket;\n                }\n\n                // Close the socket\n                closesocket(sock);\n            }\n        }\n\n        // Couldn't find a network\n        nErrCode = ERROR_NETWORK_NOT_AVAILABLE;\n    }\n\n    SetCascError(nErrCode);\n    return NULL;\n}\n\nvoid CASC_SOCKET::Delete()\n{\n    PCASC_SOCKET pThis = this;\n\n    // Remove the socket from the cache\n    if(pCache != NULL)\n        pCache->UnlinkSocket(this);\n    pCache = NULL;\n\n    // Close the socket, if any\n    if(sock != 0)\n        closesocket(sock);\n    sock = 0;\n\n    // Free the lock\n    CascFreeLock(Lock);\n\n    // Free the socket itself\n    CASC_FREE(pThis);\n}\n\n//-----------------------------------------------------------------------------\n// The CASC_SOCKET_CACHE class\n\nCASC_SOCKET_CACHE::CASC_SOCKET_CACHE()\n{\n    pFirst = pLast = NULL;\n    dwRefCount = 0;\n}\n\nCASC_SOCKET_CACHE::~CASC_SOCKET_CACHE()\n{\n    PurgeAll();\n}\n\nPCASC_SOCKET CASC_SOCKET_CACHE::Find(const char * hostName, unsigned portNum)\n{\n    PCASC_SOCKET pSocket;\n\n    for(pSocket = pFirst; pSocket != NULL; pSocket = pSocket->pNext)\n    {\n        if(!_stricmp(pSocket->hostName, hostName) && (pSocket->portNum == portNum))\n            break;\n    }\n\n    return pSocket;\n}\n\nPCASC_SOCKET CASC_SOCKET_CACHE::InsertSocket(PCASC_SOCKET pSocket)\n{\n    if(pSocket != NULL && pSocket->pCache == NULL)\n    {\n        // Do we have caching turned on?\n        if(dwRefCount > 0)\n        {\n            // Insert one reference to the socket to mark it as cached\n            pSocket->AddRef();\n\n            // Insert the socket to the chain\n            if(pFirst == NULL && pLast == NULL)\n            {\n                pFirst = pLast = pSocket;\n            }\n            else\n            {\n                pSocket->pPrev = pLast;\n                pLast->pNext = pSocket;\n                pLast = pSocket;\n            }\n\n            // Mark the socket as cached\n            pSocket->pCache = this;\n        }\n    }\n\n    return pSocket;\n}\n\nvoid CASC_SOCKET_CACHE::UnlinkSocket(PCASC_SOCKET pSocket)\n{\n    // Only if it's a valid socket\n    if(pSocket != NULL)\n    {\n        // Check the first and the last items\n        if(pSocket == pFirst)\n            pFirst = pSocket->pNext;\n        if(pSocket == pLast)\n            pLast = pSocket->pPrev;\n\n        // Disconnect the socket from the chain\n        if(pSocket->pPrev != NULL)\n            pSocket->pPrev->pNext = pSocket->pNext;\n        if(pSocket->pNext != NULL)\n            pSocket->pNext->pPrev = pSocket->pPrev;\n    }\n}\n\nvoid CASC_SOCKET_CACHE::SetCaching(bool bAddRef)\n{\n    PCASC_SOCKET pSocket;\n    PCASC_SOCKET pNext;\n\n    // We need to increment reference count for each enabled caching\n    if(bAddRef)\n    {\n        // Add one reference to all currently held sockets\n        if(dwRefCount == 0)\n        {\n            for(pSocket = pFirst; pSocket != NULL; pSocket = pSocket->pNext)\n                pSocket->AddRef();\n        }\n\n        // Increment of references for the future sockets\n        CascInterlockedIncrement(&dwRefCount);\n    }\n    else\n    {\n        // Sanity check for multiple calls to dereference\n        assert(dwRefCount > 0);\n\n        // Dereference the reference count. If drops to zero, dereference all sockets as well\n        if(CascInterlockedDecrement(&dwRefCount) == 0)\n        {\n            for(pSocket = pFirst; pSocket != NULL; pSocket = pNext)\n            {\n                pNext = pSocket->pNext;\n                pSocket->Release();\n            }\n        }\n    }\n}\n\nvoid CASC_SOCKET_CACHE::PurgeAll()\n{\n    PCASC_SOCKET pSocket;\n    PCASC_SOCKET pNext;\n\n    // Dereference all current sockets\n    for(pSocket = pFirst; pSocket != NULL; pSocket = pNext)\n    {\n        pNext = pSocket->pNext;\n        pSocket->Delete();\n    }\n}\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nPCASC_SOCKET sockets_connect(const char * hostName, unsigned portNum)\n{\n    PCASC_SOCKET pSocket;\n\n    // Try to find the item in the cache\n    if((pSocket = SocketCache.Find(hostName, portNum)) != NULL)\n    {\n        pSocket->AddRef();\n    }\n    else\n    {\n        // Create new socket and connect it to the remote host\n        pSocket = CASC_SOCKET::Connect(hostName, portNum);\n\n        // Insert it to the cache, if it's a HTTP connection\n        if(pSocket->portNum == CASC_PORT_HTTP)\n            pSocket = SocketCache.InsertSocket(pSocket);\n    }\n\n    return pSocket;\n}\n\nvoid sockets_set_caching(bool caching)\n{\n    SocketCache.SetCaching(caching);\n}\n"
  },
  {
    "path": "deps/CascLib/src/common/Sockets.h",
    "content": "/*****************************************************************************/\n/* Sockets.h                              Copyright (c) Ladislav Zezula 2021 */\n/*---------------------------------------------------------------------------*/\n/* MIME parsing functions for CascLib                                        */\n/*---------------------------------------------------------------------------*/\n/*   Date    Ver   Who  Comment                                              */\n/* --------  ----  ---  -------                                              */\n/* 13.02.21  1.00  Lad  Created                                              */\n/*****************************************************************************/\n\n#ifndef __SOCKET_H__\n#define __SOCKET_H__\n\n//-----------------------------------------------------------------------------\n// Defines\n\n#ifndef INVALID_SOCKET\n#define INVALID_SOCKET (SOCKET)(-1)\n#endif\n\n#ifndef SOCKET_ERROR\n#define SOCKET_ERROR   (-1)\n#endif\n\n#ifndef MSG_NOSIGNAL\n#define MSG_NOSIGNAL 0\n#endif\n\n#ifndef WSAECONNRESET\n#define WSAECONNRESET       10054L\n#endif\n\n#ifndef EPIPE\n#define EPIPE               32\n#endif\n\n#define CASC_PORT_HTTP      80\n#define CASC_PORT_RIBBIT    1119\n\n//-----------------------------------------------------------------------------\n// The CASC_SOCKET class\n\ntypedef class CASC_SOCKET_CACHE * PCASC_SOCKET_CACHE;\ntypedef class CASC_SOCKET * PCASC_SOCKET;\ntypedef struct addrinfo * PADDRINFO;\n\nclass CASC_SOCKET\n{\n    public:\n\n    char * ReadResponse(const char * request, size_t request_length = 0, size_t * PtrLength = NULL);\n    DWORD AddRef();\n    void Release();\n\n    private:\n\n    // Constructor and destructor\n    static int GetSockError();\n    static DWORD GetAddrInfoWrapper(const char * hostName, unsigned portNum, PADDRINFO hints, PADDRINFO * ppResult);\n    static SOCKET CreateAndConnect(addrinfo * remoteItem);\n    static SOCKET ReconnectAfterShutdown(SOCKET & sock, addrinfo * remoteItem);\n    static PCASC_SOCKET New(addrinfo * remoteList, addrinfo * remoteItem, const char * hostName, unsigned portNum, SOCKET sock);\n    static PCASC_SOCKET Connect(const char * hostName, unsigned portNum);\n\n    // Frees all resources and deletes the socket\n    void Delete();\n\n    // Entities allowed to manipulate with the class\n    friend CASC_SOCKET * sockets_connect(const char * hostName, unsigned portNum);\n    friend char * sockets_read_response(PCASC_SOCKET pSocket, const char * request, size_t request_length, size_t * PtrLength);\n    friend class CASC_SOCKET_CACHE;\n\n    PCASC_SOCKET_CACHE pCache;          // Pointer to the cache. If NULL, the socket is not cached\n    PCASC_SOCKET pPrev;                 // Pointer to the prev socket in the list\n    PCASC_SOCKET pNext;                 // Pointer to the next socket in the list\n    PADDRINFO remoteList;               // List of the remote host informations\n    PADDRINFO remoteItem;               // The particular host picked during the last connection attempt\n    CASC_LOCK Lock;                     // Lock for single threaded access\n    SOCKET sock;                        // Opened and connected socket\n    DWORD dwRefCount;                   // Number of references\n    DWORD portNum;                      // Port number\n    char hostName[1];                   // Buffer for storing remote host (variable length)\n};\n\n//-----------------------------------------------------------------------------\n// Socket cache class\n\nclass CASC_SOCKET_CACHE\n{\n    public:\n\n    CASC_SOCKET_CACHE();\n    ~CASC_SOCKET_CACHE();\n\n    PCASC_SOCKET Find(const char * hostName, unsigned portNum);\n    PCASC_SOCKET InsertSocket(PCASC_SOCKET pSocket);\n    void UnlinkSocket(PCASC_SOCKET pSocket);\n\n    void SetCaching(bool bAddRef);\n    void PurgeAll();\n\n    private:\n\n    PCASC_SOCKET pFirst;\n    PCASC_SOCKET pLast;\n    DWORD dwRefCount;\n};\n\n//-----------------------------------------------------------------------------\n// Public functions\n\nPCASC_SOCKET sockets_connect(const char * hostName, unsigned portNum);\nvoid sockets_set_caching(bool caching);\n\n#endif  // __SOCKET_H__\n"
  },
  {
    "path": "deps/CascLib/src/jenkins/lookup.h",
    "content": "#ifndef __LOOKUP3_H__\n#define __LOOKUP3_H__\n\n#ifdef WIN32\ntypedef unsigned char  uint8_t;\ntypedef unsigned short uint16_t;\ntypedef unsigned int   uint32_t;\n#else\n#include <stdint.h>     /* defines uint32_t etc */\n#endif\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\nuint32_t hashlittle(const void *key, size_t length, uint32_t initval);\nvoid hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // __LOOKUP3_H__\n"
  },
  {
    "path": "deps/CascLib/src/jenkins/lookup3.c",
    "content": "/*\n-------------------------------------------------------------------------------\nlookup3.c, by Bob Jenkins, May 2006, Public Domain.\n\nThese are functions for producing 32-bit hashes for hash table lookup.\nhashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()\nare externally useful functions.  Routines to test the hash are included\nif SELF_TEST is defined.  You can use this free for any purpose.  It's in\nthe public domain.  It has no warranty.\n\nYou probably want to use hashlittle().  hashlittle() and hashbig()\nhash byte arrays.  hashlittle() is is faster than hashbig() on\nlittle-endian machines.  Intel and AMD are little-endian machines.\nOn second thought, you probably want hashlittle2(), which is identical to\nhashlittle() except it returns two 32-bit hashes for the price of one.\nYou could implement hashbig2() if you wanted but I haven't bothered here.\n\nIf you want to find a hash of, say, exactly 7 integers, do\n  a = i1;  b = i2;  c = i3;\n  mix(a,b,c);\n  a += i4; b += i5; c += i6;\n  mix(a,b,c);\n  a += i7;\n  final(a,b,c);\nthen use c as the hash value.  If you have a variable length array of\n4-byte integers to hash, use hashword().  If you have a byte array (like\na character string), use hashlittle().  If you have several byte arrays, or\na mix of things, see the comments above hashlittle().\n\nWhy is this so big?  I read 12 bytes at a time into 3 4-byte integers,\nthen mix those integers.  This is fast (you can do a lot more thorough\nmixing with 12*3 instructions on 3 integers than you can with 3 instructions\non 1 byte), but shoehorning those bytes into integers efficiently is messy.\n-------------------------------------------------------------------------------\n*/\n//#define SELF_TEST 1\n\n#include <stdio.h>      /* defines printf for tests */\n#include <time.h>       /* defines time_t for timings in the test */\n\n#ifdef linux\n#include <sys/param.h>  /* attempt to define endianness */\n#include <endian.h>    /* attempt to define endianness */\n#endif\n\n#include \"lookup.h\"\n\n/*\n * My best guess at if you are big-endian or little-endian.  This may\n * need adjustment.\n */\n#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \\\n     __BYTE_ORDER == __LITTLE_ENDIAN) || \\\n    (defined(i386) || defined(__i386__) || defined(__i486__) || \\\n     defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))\n# define HASH_LITTLE_ENDIAN 1\n# define HASH_BIG_ENDIAN 0\n#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \\\n       __BYTE_ORDER == __BIG_ENDIAN) || \\\n      (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))\n# define HASH_LITTLE_ENDIAN 0\n# define HASH_BIG_ENDIAN 1\n#else\n# define HASH_LITTLE_ENDIAN 0\n# define HASH_BIG_ENDIAN 0\n#endif\n\n#define hashsize(n) ((uint32_t)1<<(n))\n#define hashmask(n) (hashsize(n)-1)\n#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))\n\n/*\n-------------------------------------------------------------------------------\nmix -- mix 3 32-bit values reversibly.\n\nThis is reversible, so any information in (a,b,c) before mix() is\nstill in (a,b,c) after mix().\n\nIf four pairs of (a,b,c) inputs are run through mix(), or through\nmix() in reverse, there are at least 32 bits of the output that\nare sometimes the same for one pair and different for another pair.\nThis was tested for:\n* pairs that differed by one bit, by two bits, in any combination\n  of top bits of (a,b,c), or in any combination of bottom bits of\n  (a,b,c).\n* \"differ\" is defined as +, -, ^, or ~^.  For + and -, I transformed\n  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as\n  is commonly produced by subtraction) look like a single 1-bit\n  difference.\n* the base values were pseudorandom, all zero but one bit set, or\n  all zero plus a counter that starts at zero.\n\nSome k values for my \"a-=c; a^=rot(c,k); c+=b;\" arrangement that\nsatisfy this are\n    4  6  8 16 19  4\n    9 15  3 18 27 15\n   14  9  3  7 17  3\nWell, \"9 15 3 18 27 15\" didn't quite get 32 bits diffing\nfor \"differ\" defined as + with a one-bit base and a two-bit delta.  I\nused http://burtleburtle.net/bob/hash/avalanche.html to choose\nthe operations, constants, and arrangements of the variables.\n\nThis does not achieve avalanche.  There are input bits of (a,b,c)\nthat fail to affect some output bits of (a,b,c), especially of a.  The\nmost thoroughly mixed value is c, but it doesn't really even achieve\navalanche in c.\n\nThis allows some parallelism.  Read-after-writes are good at doubling\nthe number of bits affected, so the goal of mixing pulls in the opposite\ndirection as the goal of parallelism.  I did what I could.  Rotates\nseem to cost as much as shifts on every machine I could lay my hands\non, and rotates are much kinder to the top and bottom bits, so I used\nrotates.\n-------------------------------------------------------------------------------\n*/\n#define mix(a,b,c) \\\n{ \\\n  a -= c;  a ^= rot(c, 4);  c += b; \\\n  b -= a;  b ^= rot(a, 6);  a += c; \\\n  c -= b;  c ^= rot(b, 8);  b += a; \\\n  a -= c;  a ^= rot(c,16);  c += b; \\\n  b -= a;  b ^= rot(a,19);  a += c; \\\n  c -= b;  c ^= rot(b, 4);  b += a; \\\n}\n\n/*\n-------------------------------------------------------------------------------\nfinal -- final mixing of 3 32-bit values (a,b,c) into c\n\nPairs of (a,b,c) values differing in only a few bits will usually\nproduce values of c that look totally different.  This was tested for\n* pairs that differed by one bit, by two bits, in any combination\n  of top bits of (a,b,c), or in any combination of bottom bits of\n  (a,b,c).\n* \"differ\" is defined as +, -, ^, or ~^.  For + and -, I transformed\n  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as\n  is commonly produced by subtraction) look like a single 1-bit\n  difference.\n* the base values were pseudorandom, all zero but one bit set, or\n  all zero plus a counter that starts at zero.\n\nThese constants passed:\n 14 11 25 16 4 14 24\n 12 14 25 16 4 14 24\nand these came close:\n  4  8 15 26 3 22 24\n 10  8 15 26 3 22 24\n 11  8 15 26 3 22 24\n-------------------------------------------------------------------------------\n*/\n#define final(a,b,c) \\\n{ \\\n  c ^= b; c -= rot(b,14); \\\n  a ^= c; a -= rot(c,11); \\\n  b ^= a; b -= rot(a,25); \\\n  c ^= b; c -= rot(b,16); \\\n  a ^= c; a -= rot(c,4);  \\\n  b ^= a; b -= rot(a,14); \\\n  c ^= b; c -= rot(b,24); \\\n}\n\n/*\n--------------------------------------------------------------------\n This works on all machines.  To be useful, it requires\n -- that the key be an array of uint32_t's, and\n -- that the length be the number of uint32_t's in the key\n\n The function hashword() is identical to hashlittle() on little-endian\n machines, and identical to hashbig() on big-endian machines,\n except that the length has to be measured in uint32_ts rather than in\n bytes.  hashlittle() is more complicated than hashword() only because\n hashlittle() has to dance around fitting the key bytes into registers.\n--------------------------------------------------------------------\n*/\nuint32_t hashword(\nconst uint32_t *k,                   /* the key, an array of uint32_t values */\nsize_t          length,               /* the length of the key, in uint32_ts */\nuint32_t        initval)         /* the previous hash, or an arbitrary value */\n{\n  uint32_t a,b,c;\n\n  /* Set up the internal state */\n  a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;\n\n  /*------------------------------------------------- handle most of the key */\n  while (length > 3)\n  {\n    a += k[0];\n    b += k[1];\n    c += k[2];\n    mix(a,b,c);\n    length -= 3;\n    k += 3;\n  }\n\n  /*------------------------------------------- handle the last 3 uint32_t's */\n  switch(length)                     /* all the case statements fall through */\n  {\n  case 3 : c+=k[2];\n  case 2 : b+=k[1];\n  case 1 : a+=k[0];\n    final(a,b,c);\n  case 0:     /* case 0: nothing left to add */\n    break;\n  }\n  /*------------------------------------------------------ report the result */\n  return c;\n}\n\n\n/*\n--------------------------------------------------------------------\nhashword2() -- same as hashword(), but take two seeds and return two\n32-bit values.  pc and pb must both be nonnull, and *pc and *pb must\nboth be initialized with seeds.  If you pass in (*pb)==0, the output\n(*pc) will be the same as the return value from hashword().\n--------------------------------------------------------------------\n*/\nvoid hashword2 (\nconst uint32_t *k,                   /* the key, an array of uint32_t values */\nsize_t          length,               /* the length of the key, in uint32_ts */\nuint32_t       *pc,                      /* IN: seed OUT: primary hash value */\nuint32_t       *pb)               /* IN: more seed OUT: secondary hash value */\n{\n  uint32_t a,b,c;\n\n  /* Set up the internal state */\n  a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc;\n  c += *pb;\n\n  /*------------------------------------------------- handle most of the key */\n  while (length > 3)\n  {\n    a += k[0];\n    b += k[1];\n    c += k[2];\n    mix(a,b,c);\n    length -= 3;\n    k += 3;\n  }\n\n  /*------------------------------------------- handle the last 3 uint32_t's */\n  switch(length)                     /* all the case statements fall through */\n  {\n  case 3 : c+=k[2];\n  case 2 : b+=k[1];\n  case 1 : a+=k[0];\n    final(a,b,c);\n  case 0:     /* case 0: nothing left to add */\n    break;\n  }\n  /*------------------------------------------------------ report the result */\n  *pc=c; *pb=b;\n}\n\n\n/*\n-------------------------------------------------------------------------------\nhashlittle() -- hash a variable-length key into a 32-bit value\n  k       : the key (the unaligned variable-length array of bytes)\n  length  : the length of the key, counting by bytes\n  initval : can be any 4-byte value\nReturns a 32-bit value.  Every bit of the key affects every bit of\nthe return value.  Two keys differing by one or two bits will have\ntotally different hash values.\n\nThe best hash table sizes are powers of 2.  There is no need to do\nmod a prime (mod is sooo slow!).  If you need less than 32 bits,\nuse a bitmask.  For example, if you need only 10 bits, do\n  h = (h & hashmask(10));\nIn which case, the hash table should have hashsize(10) elements.\n\nIf you are hashing n strings (uint8_t **)k, do it like this:\n  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);\n\nBy Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this\ncode any way you wish, private, educational, or commercial.  It's free.\n\nUse for hash table lookup, or anything where one collision in 2^^32 is\nacceptable.  Do NOT use for cryptographic purposes.\n-------------------------------------------------------------------------------\n*/\n\nuint32_t hashlittle( const void *key, size_t length, uint32_t initval)\n{\n  uint32_t a,b,c;                                          /* internal state */\n  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */\n\n  /* Set up the internal state */\n  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;\n\n  u.ptr = key;\n  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {\n    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */\n    const uint8_t  *k8;\n\n    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      b += k[1];\n      c += k[2];\n      mix(a,b,c);\n      length -= 12;\n      k += 3;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    /*\n     * \"k[2]&0xffffff\" actually reads beyond the end of the string, but\n     * then masks off the part it's not allowed to read.  Because the\n     * string is aligned, the masked-off tail is in the same word as the\n     * rest of the string.  Every machine with memory protection I've seen\n     * does it on word boundaries, so is OK with this.  But VALGRIND will\n     * still catch it and complain.  The masking trick does make the hash\n     * noticably faster for short strings (like English words).\n     */\n#ifndef VALGRIND\n\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;\n    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;\n    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;\n    case 6 : b+=k[1]&0xffff; a+=k[0]; break;\n    case 5 : b+=k[1]&0xff; a+=k[0]; break;\n    case 4 : a+=k[0]; break;\n    case 3 : a+=k[0]&0xffffff; break;\n    case 2 : a+=k[0]&0xffff; break;\n    case 1 : a+=k[0]&0xff; break;\n    case 0 : return c;              /* zero length strings require no mixing */\n    }\n\n#else /* make valgrind happy */\n\n    k8 = (const uint8_t *)k;\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */\n    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */\n    case 9 : c+=k8[8];                   /* fall through */\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */\n    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */\n    case 5 : b+=k8[4];                   /* fall through */\n    case 4 : a+=k[0]; break;\n    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */\n    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */\n    case 1 : a+=k8[0]; break;\n    case 0 : return c;\n    }\n\n#endif /* !valgrind */\n\n  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {\n    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */\n    const uint8_t  *k8;\n\n    /*--------------- all but last block: aligned reads and different mixing */\n    while (length > 12)\n    {\n      a += k[0] + (((uint32_t)k[1])<<16);\n      b += k[2] + (((uint32_t)k[3])<<16);\n      c += k[4] + (((uint32_t)k[5])<<16);\n      mix(a,b,c);\n      length -= 12;\n      k += 6;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    k8 = (const uint8_t *)k;\n    switch(length)\n    {\n    case 12: c+=k[4]+(((uint32_t)k[5])<<16);\n             b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */\n    case 10: c+=k[4];\n             b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 9 : c+=k8[8];                      /* fall through */\n    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */\n    case 6 : b+=k[2];\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 5 : b+=k8[4];                      /* fall through */\n    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */\n    case 2 : a+=k[0];\n             break;\n    case 1 : a+=k8[0];\n             break;\n    case 0 : return c;                     /* zero length requires no mixing */\n    }\n\n  } else {                        /* need to read the key one byte at a time */\n    const uint8_t *k = (const uint8_t *)key;\n\n    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      a += ((uint32_t)k[1])<<8;\n      a += ((uint32_t)k[2])<<16;\n      a += ((uint32_t)k[3])<<24;\n      b += k[4];\n      b += ((uint32_t)k[5])<<8;\n      b += ((uint32_t)k[6])<<16;\n      b += ((uint32_t)k[7])<<24;\n      c += k[8];\n      c += ((uint32_t)k[9])<<8;\n      c += ((uint32_t)k[10])<<16;\n      c += ((uint32_t)k[11])<<24;\n      mix(a,b,c);\n      length -= 12;\n      k += 12;\n    }\n\n    /*-------------------------------- last block: affect all 32 bits of (c) */\n    switch(length)                   /* all the case statements fall through */\n    {\n    case 12: c+=((uint32_t)k[11])<<24;\n    case 11: c+=((uint32_t)k[10])<<16;\n    case 10: c+=((uint32_t)k[9])<<8;\n    case 9 : c+=k[8];\n    case 8 : b+=((uint32_t)k[7])<<24;\n    case 7 : b+=((uint32_t)k[6])<<16;\n    case 6 : b+=((uint32_t)k[5])<<8;\n    case 5 : b+=k[4];\n    case 4 : a+=((uint32_t)k[3])<<24;\n    case 3 : a+=((uint32_t)k[2])<<16;\n    case 2 : a+=((uint32_t)k[1])<<8;\n    case 1 : a+=k[0];\n             break;\n    case 0 : return c;\n    }\n  }\n\n  final(a,b,c);\n  return c;\n}\n\n\n/*\n * hashlittle2: return 2 32-bit hash values\n *\n * This is identical to hashlittle(), except it returns two 32-bit hash\n * values instead of just one.  This is good enough for hash table\n * lookup with 2^^64 buckets, or if you want a second hash if you're not\n * happy with the first, or if you want a probably-unique 64-bit ID for\n * the key.  *pc is better mixed than *pb, so use *pc first.  If you want\n * a 64-bit value do something like \"*pc + (((uint64_t)*pb)<<32)\".\n */\nvoid hashlittle2(\n  const void *key,       /* the key to hash */\n  size_t      length,    /* length of the key */\n  uint32_t   *pc,        /* IN: primary initval, OUT: primary hash */\n  uint32_t   *pb)        /* IN: secondary initval, OUT: secondary hash */\n{\n  uint32_t a,b,c;                                          /* internal state */\n  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */\n\n  /* Set up the internal state */\n  a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc;\n  c += *pb;\n\n  u.ptr = key;\n  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {\n    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */\n    const uint8_t  *k8;\n\n    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      b += k[1];\n      c += k[2];\n      mix(a,b,c);\n      length -= 12;\n      k += 3;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    /*\n     * \"k[2]&0xffffff\" actually reads beyond the end of the string, but\n     * then masks off the part it's not allowed to read.  Because the\n     * string is aligned, the masked-off tail is in the same word as the\n     * rest of the string.  Every machine with memory protection I've seen\n     * does it on word boundaries, so is OK with this.  But VALGRIND will\n     * still catch it and complain.  The masking trick does make the hash\n     * noticably faster for short strings (like English words).\n     */\n#ifndef VALGRIND\n\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;\n    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;\n    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;\n    case 6 : b+=k[1]&0xffff; a+=k[0]; break;\n    case 5 : b+=k[1]&0xff; a+=k[0]; break;\n    case 4 : a+=k[0]; break;\n    case 3 : a+=k[0]&0xffffff; break;\n    case 2 : a+=k[0]&0xffff; break;\n    case 1 : a+=k[0]&0xff; break;\n    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */\n    }\n\n#else /* make valgrind happy */\n\n    k8 = (const uint8_t *)k;\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */\n    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */\n    case 9 : c+=k8[8];                   /* fall through */\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */\n    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */\n    case 5 : b+=k8[4];                   /* fall through */\n    case 4 : a+=k[0]; break;\n    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */\n    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */\n    case 1 : a+=k8[0]; break;\n    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */\n    }\n\n#endif /* !valgrind */\n\n  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {\n    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */\n    const uint8_t  *k8;\n\n    /*--------------- all but last block: aligned reads and different mixing */\n    while (length > 12)\n    {\n      a += k[0] + (((uint32_t)k[1])<<16);\n      b += k[2] + (((uint32_t)k[3])<<16);\n      c += k[4] + (((uint32_t)k[5])<<16);\n      mix(a,b,c);\n      length -= 12;\n      k += 6;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    k8 = (const uint8_t *)k;\n    switch(length)\n    {\n    case 12: c+=k[4]+(((uint32_t)k[5])<<16);\n             b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */\n    case 10: c+=k[4];\n             b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 9 : c+=k8[8];                      /* fall through */\n    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */\n    case 6 : b+=k[2];\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 5 : b+=k8[4];                      /* fall through */\n    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */\n    case 2 : a+=k[0];\n             break;\n    case 1 : a+=k8[0];\n             break;\n    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */\n    }\n\n  } else {                        /* need to read the key one byte at a time */\n    const uint8_t *k = (const uint8_t *)key;\n\n    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      a += ((uint32_t)k[1])<<8;\n      a += ((uint32_t)k[2])<<16;\n      a += ((uint32_t)k[3])<<24;\n      b += k[4];\n      b += ((uint32_t)k[5])<<8;\n      b += ((uint32_t)k[6])<<16;\n      b += ((uint32_t)k[7])<<24;\n      c += k[8];\n      c += ((uint32_t)k[9])<<8;\n      c += ((uint32_t)k[10])<<16;\n      c += ((uint32_t)k[11])<<24;\n      mix(a,b,c);\n      length -= 12;\n      k += 12;\n    }\n\n    /*-------------------------------- last block: affect all 32 bits of (c) */\n    switch(length)                   /* all the case statements fall through */\n    {\n    case 12: c+=((uint32_t)k[11])<<24;\n    case 11: c+=((uint32_t)k[10])<<16;\n    case 10: c+=((uint32_t)k[9])<<8;\n    case 9 : c+=k[8];\n    case 8 : b+=((uint32_t)k[7])<<24;\n    case 7 : b+=((uint32_t)k[6])<<16;\n    case 6 : b+=((uint32_t)k[5])<<8;\n    case 5 : b+=k[4];\n    case 4 : a+=((uint32_t)k[3])<<24;\n    case 3 : a+=((uint32_t)k[2])<<16;\n    case 2 : a+=((uint32_t)k[1])<<8;\n    case 1 : a+=k[0];\n             break;\n    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */\n    }\n  }\n\n  final(a,b,c);\n  *pc=c; *pb=b;\n}\n\n\n\n/*\n * hashbig():\n * This is the same as hashword() on big-endian machines.  It is different\n * from hashlittle() on all machines.  hashbig() takes advantage of\n * big-endian byte ordering.\n */\nuint32_t hashbig( const void *key, size_t length, uint32_t initval)\n{\n  uint32_t a,b,c;\n  union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */\n\n  /* Set up the internal state */\n  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;\n\n  u.ptr = key;\n  if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {\n    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */\n    const uint8_t  *k8;\n\n    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      b += k[1];\n      c += k[2];\n      mix(a,b,c);\n      length -= 12;\n      k += 3;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    /*\n     * \"k[2]<<8\" actually reads beyond the end of the string, but\n     * then shifts out the part it's not allowed to read.  Because the\n     * string is aligned, the illegal read is in the same word as the\n     * rest of the string.  Every machine with memory protection I've seen\n     * does it on word boundaries, so is OK with this.  But VALGRIND will\n     * still catch it and complain.  The masking trick does make the hash\n     * noticably faster for short strings (like English words).\n     */\n#ifndef VALGRIND\n\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;\n    case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;\n    case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;\n    case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;\n    case 5 : b+=k[1]&0xff000000; a+=k[0]; break;\n    case 4 : a+=k[0]; break;\n    case 3 : a+=k[0]&0xffffff00; break;\n    case 2 : a+=k[0]&0xffff0000; break;\n    case 1 : a+=k[0]&0xff000000; break;\n    case 0 : return c;              /* zero length strings require no mixing */\n    }\n\n#else  /* make valgrind happy */\n\n    k8 = (const uint8_t *)k;\n    switch(length)                   /* all the case statements fall through */\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=((uint32_t)k8[10])<<8;  /* fall through */\n    case 10: c+=((uint32_t)k8[9])<<16;  /* fall through */\n    case 9 : c+=((uint32_t)k8[8])<<24;  /* fall through */\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=((uint32_t)k8[6])<<8;   /* fall through */\n    case 6 : b+=((uint32_t)k8[5])<<16;  /* fall through */\n    case 5 : b+=((uint32_t)k8[4])<<24;  /* fall through */\n    case 4 : a+=k[0]; break;\n    case 3 : a+=((uint32_t)k8[2])<<8;   /* fall through */\n    case 2 : a+=((uint32_t)k8[1])<<16;  /* fall through */\n    case 1 : a+=((uint32_t)k8[0])<<24; break;\n    case 0 : return c;\n    }\n\n#endif /* !VALGRIND */\n\n  } else {                        /* need to read the key one byte at a time */\n    const uint8_t *k = (const uint8_t *)key;\n\n    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += ((uint32_t)k[0])<<24;\n      a += ((uint32_t)k[1])<<16;\n      a += ((uint32_t)k[2])<<8;\n      a += ((uint32_t)k[3]);\n      b += ((uint32_t)k[4])<<24;\n      b += ((uint32_t)k[5])<<16;\n      b += ((uint32_t)k[6])<<8;\n      b += ((uint32_t)k[7]);\n      c += ((uint32_t)k[8])<<24;\n      c += ((uint32_t)k[9])<<16;\n      c += ((uint32_t)k[10])<<8;\n      c += ((uint32_t)k[11]);\n      mix(a,b,c);\n      length -= 12;\n      k += 12;\n    }\n\n    /*-------------------------------- last block: affect all 32 bits of (c) */\n    switch(length)                   /* all the case statements fall through */\n    {\n    case 12: c+=k[11];\n    case 11: c+=((uint32_t)k[10])<<8;\n    case 10: c+=((uint32_t)k[9])<<16;\n    case 9 : c+=((uint32_t)k[8])<<24;\n    case 8 : b+=k[7];\n    case 7 : b+=((uint32_t)k[6])<<8;\n    case 6 : b+=((uint32_t)k[5])<<16;\n    case 5 : b+=((uint32_t)k[4])<<24;\n    case 4 : a+=k[3];\n    case 3 : a+=((uint32_t)k[2])<<8;\n    case 2 : a+=((uint32_t)k[1])<<16;\n    case 1 : a+=((uint32_t)k[0])<<24;\n             break;\n    case 0 : return c;\n    }\n  }\n\n  final(a,b,c);\n  return c;\n}\n\n\n#ifdef SELF_TEST\n\n/* used for timings */\nvoid driver1()\n{\n  uint8_t buf[256];\n  uint32_t i;\n  uint32_t h=0;\n  time_t a,z;\n\n  time(&a);\n  for (i=0; i<256; ++i) buf[i] = 'x';\n  for (i=0; i<1; ++i)\n  {\n    h = hashlittle(&buf[0],1,h);\n  }\n  time(&z);\n  if (z-a > 0) printf(\"time %d %.8x\\n\", z-a, h);\n}\n\n/* check that every input bit changes every output bit half the time */\n#define HASHSTATE 1\n#define HASHLEN   1\n#define MAXPAIR 60\n#define MAXLEN  70\nvoid driver2()\n{\n  uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];\n  uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;\n  uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];\n  uint32_t x[HASHSTATE],y[HASHSTATE];\n  uint32_t hlen;\n\n  printf(\"No more than %d trials should ever be needed \\n\",MAXPAIR/2);\n  for (hlen=0; hlen < MAXLEN; ++hlen)\n  {\n    z=0;\n    for (i=0; i<hlen; ++i)  /*----------------------- for each input byte, */\n    {\n      for (j=0; j<8; ++j)   /*------------------------ for each input bit, */\n      {\n\tfor (m=1; m<8; ++m) /*------------ for serveral possible initvals, */\n\t{\n\t  for (l=0; l<HASHSTATE; ++l)\n\t    e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);\n\n      \t  /*---- check that every output bit is affected by that input bit */\n\t  for (k=0; k<MAXPAIR; k+=2)\n\t  {\n\t    uint32_t finished=1;\n\t    /* keys have one bit different */\n\t    for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}\n\t    /* have a and b be two keys differing in only one bit */\n\t    a[i] ^= (k<<j);\n\t    a[i] ^= (k>>(8-j));\n\t     c[0] = hashlittle(a, hlen, m);\n\t    b[i] ^= ((k+1)<<j);\n\t    b[i] ^= ((k+1)>>(8-j));\n\t     d[0] = hashlittle(b, hlen, m);\n\t    /* check every bit is 1, 0, set, and not set at least once */\n\t    for (l=0; l<HASHSTATE; ++l)\n\t    {\n\t      e[l] &= (c[l]^d[l]);\n\t      f[l] &= ~(c[l]^d[l]);\n\t      g[l] &= c[l];\n\t      h[l] &= ~c[l];\n\t      x[l] &= d[l];\n\t      y[l] &= ~d[l];\n\t      if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;\n\t    }\n\t    if (finished) break;\n\t  }\n\t  if (k>z) z=k;\n\t  if (k==MAXPAIR)\n\t  {\n\t     printf(\"Some bit didn't change: \");\n\t     printf(\"%.8x %.8x %.8x %.8x %.8x %.8x  \",\n\t            e[0],f[0],g[0],h[0],x[0],y[0]);\n\t     printf(\"i %d j %d m %d len %d\\n\", i, j, m, hlen);\n\t  }\n\t  if (z==MAXPAIR) goto done;\n\t}\n      }\n    }\n   done:\n    if (z < MAXPAIR)\n    {\n      printf(\"Mix success  %2d bytes  %2d initvals  \",i,m);\n      printf(\"required  %d  trials\\n\", z/2);\n    }\n  }\n  printf(\"\\n\");\n}\n\n/* Check for reading beyond the end of the buffer and alignment problems */\nvoid driver3()\n{\n  uint8_t buf[MAXLEN+20], *b;\n  uint32_t len;\n  uint8_t q[] = \"This is the time for all good men to come to the aid of their country...\";\n  uint32_t h;\n  uint8_t qq[] = \"xThis is the time for all good men to come to the aid of their country...\";\n  uint32_t i;\n  uint8_t qqq[] = \"xxThis is the time for all good men to come to the aid of their country...\";\n  uint32_t j;\n  uint8_t qqqq[] = \"xxxThis is the time for all good men to come to the aid of their country...\";\n  uint32_t ref,x,y;\n  uint8_t *p;\n\n  printf(\"Endianness.  These lines should all be the same (for values filled in):\\n\");\n  printf(\"%.8x                            %.8x                            %.8x\\n\",\n         hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13),\n         hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13),\n         hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13));\n  p = q;\n  printf(\"%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\\n\",\n         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),\n         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),\n         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),\n         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),\n         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),\n         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));\n  p = &qq[1];\n  printf(\"%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\\n\",\n         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),\n         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),\n         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),\n         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),\n         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),\n         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));\n  p = &qqq[2];\n  printf(\"%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\\n\",\n         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),\n         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),\n         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),\n         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),\n         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),\n         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));\n  p = &qqqq[3];\n  printf(\"%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\\n\",\n         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),\n         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),\n         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),\n         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),\n         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),\n         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));\n  printf(\"\\n\");\n\n  /* check that hashlittle2 and hashlittle produce the same results */\n  i=47; j=0;\n  hashlittle2(q, sizeof(q), &i, &j);\n  if (hashlittle(q, sizeof(q), 47) != i)\n    printf(\"hashlittle2 and hashlittle mismatch\\n\");\n\n  /* check that hashword2 and hashword produce the same results */\n  len = 0xdeadbeef;\n  i=47, j=0;\n  hashword2(&len, 1, &i, &j);\n  if (hashword(&len, 1, 47) != i)\n    printf(\"hashword2 and hashword mismatch %x %x\\n\",\n\t   i, hashword(&len, 1, 47));\n\n  /* check hashlittle doesn't read before or after the ends of the string */\n  for (h=0, b=buf+1; h<8; ++h, ++b)\n  {\n    for (i=0; i<MAXLEN; ++i)\n    {\n      len = i;\n      for (j=0; j<i; ++j) *(b+j)=0;\n\n      /* these should all be equal */\n      ref = hashlittle(b, len, (uint32_t)1);\n      *(b+i)=(uint8_t)~0;\n      *(b-1)=(uint8_t)~0;\n      x = hashlittle(b, len, (uint32_t)1);\n      y = hashlittle(b, len, (uint32_t)1);\n      if ((ref != x) || (ref != y))\n      {\n\tprintf(\"alignment error: %.8x %.8x %.8x %d %d\\n\",ref,x,y,\n               h, i);\n      }\n    }\n  }\n}\n\n/* check for problems with nulls */\n void driver4()\n{\n  uint8_t buf[1];\n  uint32_t h,i,state[HASHSTATE];\n\n\n  buf[0] = ~0;\n  for (i=0; i<HASHSTATE; ++i) state[i] = 1;\n  printf(\"These should all be different\\n\");\n  for (i=0, h=0; i<8; ++i)\n  {\n    h = hashlittle(buf, 0, h);\n    printf(\"%2ld  0-byte strings, hash is  %.8x\\n\", i, h);\n  }\n}\n\nvoid driver5()\n{\n  uint32_t b,c;\n  b=0, c=0, hashlittle2(\"\", 0, &c, &b);\n  printf(\"hash is %.8lx %.8lx\\n\", c, b);   /* deadbeef deadbeef */\n  b=0xdeadbeef, c=0, hashlittle2(\"\", 0, &c, &b);\n  printf(\"hash is %.8lx %.8lx\\n\", c, b);   /* bd5b7dde deadbeef */\n  b=0xdeadbeef, c=0xdeadbeef, hashlittle2(\"\", 0, &c, &b);\n  printf(\"hash is %.8lx %.8lx\\n\", c, b);   /* 9c093ccd bd5b7dde */\n  b=0, c=0, hashlittle2(\"Four score and seven years ago\", 30, &c, &b);\n  printf(\"hash is %.8lx %.8lx\\n\", c, b);   /* 17770551 ce7226e6 */\n  b=1, c=0, hashlittle2(\"Four score and seven years ago\", 30, &c, &b);\n  printf(\"hash is %.8lx %.8lx\\n\", c, b);   /* e3607cae bd371de4 */\n  b=0, c=1, hashlittle2(\"Four score and seven years ago\", 30, &c, &b);\n  printf(\"hash is %.8lx %.8lx\\n\", c, b);   /* cd628161 6cbea4b3 */\n  c = hashlittle(\"Four score and seven years ago\", 30, 0);\n  printf(\"hash is %.8lx\\n\", c);   /* 17770551 */\n  c = hashlittle(\"Four score and seven years ago\", 30, 1);\n  printf(\"hash is %.8lx\\n\", c);   /* cd628161 */\n}\n\n\nint main()\n{\n  driver1();   /* test that the key is hashed: used for timings */\n  driver2();   /* test that whole key is hashed thoroughly */\n  driver3();   /* test that nothing but the key is hashed */\n  driver4();   /* test hashing multiple buffers (all buffers are null) */\n  driver5();   /* test the hash against known vectors */\n  return 1;\n}\n\n#endif  /* SELF_TEST */\n"
  },
  {
    "path": "deps/CascLib/src/md5/md5.cpp",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * (This is a heavily cut-down \"BSD license\".)\n *\n * This differs from Colin Plumb's older public domain implementation in that\n * no exactly 32-bit integer data type is required (any 32-bit or wider\n * unsigned integer data type will do), there's no compile-time endianness\n * configuration, and the function prototypes match OpenSSL's.  No code from\n * Colin Plumb's implementation has been reused; this comment merely compares\n * the properties of the two independent implementations.\n *\n * The primary goals of this implementation are portability and ease of use.\n * It is meant to be fast, but not as fast as possible.  Some known\n * optimizations are not included to reduce source code size and avoid\n * compile-time configuration.\n */\n\n#ifndef HAVE_OPENSSL\n\n#include <string.h>\n\n#include \"md5.h\"\n\n/*\n * The basic MD5 functions.\n *\n * F and G are optimized compared to their RFC 1321 definitions for\n * architectures that lack an AND-NOT instruction, just like in Colin Plumb's\n * implementation.\n */\n#define F(x, y, z)\t\t\t((z) ^ ((x) & ((y) ^ (z))))\n#define G(x, y, z)\t\t\t((y) ^ ((z) & ((x) ^ (y))))\n#define H(x, y, z)\t\t\t(((x) ^ (y)) ^ (z))\n#define H2(x, y, z)\t\t\t((x) ^ ((y) ^ (z)))\n#define I(x, y, z)\t\t\t((y) ^ ((x) | ~(z)))\n\n/*\n * The MD5 transformation for all four rounds.\n */\n#define STEP(f, a, b, c, d, x, t, s) \\\n\t(a) += f((b), (c), (d)) + (x) + (t); \\\n\t(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \\\n\t(a) += (b);\n\n/*\n * SET reads 4 input bytes in little-endian byte order and stores them in a\n * properly aligned word in host byte order.\n *\n * The check for little-endian architectures that tolerate unaligned memory\n * accesses is just an optimization.  Nothing will break if it fails to detect\n * a suitable architecture.\n *\n * Unfortunately, this optimization may be a C strict aliasing rules violation\n * if the caller's data buffer has effective type that cannot be aliased by\n * MD5_u32plus.  In practice, this problem may occur if these MD5 routines are\n * inlined into a calling function, or with future and dangerously advanced\n * link-time optimizations.  For the time being, keeping these MD5 routines in\n * their own translation unit avoids the problem.\n */\n#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)\n#define SET(n) \\\n\t(*(MD5_u32plus *)&ptr[(n) * 4])\n#define GET(n) \\\n\tSET(n)\n#else\n#define SET(n) \\\n\t(ctx->block[(n)] = \\\n\t(MD5_u32plus)ptr[(n) * 4] | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 3] << 24))\n#define GET(n) \\\n\t(ctx->block[(n)])\n#endif\n\n/*\n * This processes one or more 64-byte data blocks, but does NOT update the bit\n * counters.  There are no alignment requirements.\n */\nstatic const void *body(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tconst unsigned char *ptr;\n\tMD5_u32plus a, b, c, d;\n\tMD5_u32plus saved_a, saved_b, saved_c, saved_d;\n\n\tptr = (const unsigned char *)data;\n\n\ta = ctx->a;\n\tb = ctx->b;\n\tc = ctx->c;\n\td = ctx->d;\n\n\tdo {\n\t\tsaved_a = a;\n\t\tsaved_b = b;\n\t\tsaved_c = c;\n\t\tsaved_d = d;\n\n/* Round 1 */\n\t\tSTEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)\n\t\tSTEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)\n\t\tSTEP(F, c, d, a, b, SET(2), 0x242070db, 17)\n\t\tSTEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)\n\t\tSTEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)\n\t\tSTEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)\n\t\tSTEP(F, c, d, a, b, SET(6), 0xa8304613, 17)\n\t\tSTEP(F, b, c, d, a, SET(7), 0xfd469501, 22)\n\t\tSTEP(F, a, b, c, d, SET(8), 0x698098d8, 7)\n\t\tSTEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)\n\t\tSTEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)\n\t\tSTEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)\n\t\tSTEP(F, a, b, c, d, SET(12), 0x6b901122, 7)\n\t\tSTEP(F, d, a, b, c, SET(13), 0xfd987193, 12)\n\t\tSTEP(F, c, d, a, b, SET(14), 0xa679438e, 17)\n\t\tSTEP(F, b, c, d, a, SET(15), 0x49b40821, 22)\n\n/* Round 2 */\n\t\tSTEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)\n\t\tSTEP(G, d, a, b, c, GET(6), 0xc040b340, 9)\n\t\tSTEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)\n\t\tSTEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)\n\t\tSTEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)\n\t\tSTEP(G, d, a, b, c, GET(10), 0x02441453, 9)\n\t\tSTEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)\n\t\tSTEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)\n\t\tSTEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)\n\t\tSTEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)\n\t\tSTEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)\n\t\tSTEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)\n\t\tSTEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)\n\t\tSTEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)\n\t\tSTEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)\n\t\tSTEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)\n\n/* Round 3 */\n\t\tSTEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)\n\t\tSTEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)\n\t\tSTEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)\n\t\tSTEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)\n\t\tSTEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)\n\t\tSTEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)\n\t\tSTEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)\n\t\tSTEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)\n\t\tSTEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)\n\t\tSTEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)\n\t\tSTEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)\n\t\tSTEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)\n\t\tSTEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)\n\t\tSTEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)\n\t\tSTEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)\n\t\tSTEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)\n\n/* Round 4 */\n\t\tSTEP(I, a, b, c, d, GET(0), 0xf4292244, 6)\n\t\tSTEP(I, d, a, b, c, GET(7), 0x432aff97, 10)\n\t\tSTEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)\n\t\tSTEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)\n\t\tSTEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)\n\t\tSTEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)\n\t\tSTEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)\n\t\tSTEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)\n\t\tSTEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)\n\t\tSTEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)\n\t\tSTEP(I, c, d, a, b, GET(6), 0xa3014314, 15)\n\t\tSTEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)\n\t\tSTEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)\n\t\tSTEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)\n\t\tSTEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)\n\t\tSTEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)\n\n\t\ta += saved_a;\n\t\tb += saved_b;\n\t\tc += saved_c;\n\t\td += saved_d;\n\n\t\tptr += 64;\n\t} while (size -= 64);\n\n\tctx->a = a;\n\tctx->b = b;\n\tctx->c = c;\n\tctx->d = d;\n\n\treturn ptr;\n}\n\nvoid MD5_Init(MD5_CTX *ctx)\n{\n\tctx->a = 0x67452301;\n\tctx->b = 0xefcdab89;\n\tctx->c = 0x98badcfe;\n\tctx->d = 0x10325476;\n\n\tctx->lo = 0;\n\tctx->hi = 0;\n}\n\nvoid MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tMD5_u32plus saved_lo;\n\tunsigned long used, available;\n\n\tsaved_lo = ctx->lo;\n\tif ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)\n\t\tctx->hi++;\n\tctx->hi += size >> 29;\n\n\tused = saved_lo & 0x3f;\n\n\tif (used) {\n\t\tavailable = 64 - used;\n\n\t\tif (size < available) {\n\t\t\tmemcpy(&ctx->buffer[used], data, size);\n\t\t\treturn;\n\t\t}\n\n\t\tmemcpy(&ctx->buffer[used], data, available);\n\t\tdata = (const unsigned char *)data + available;\n\t\tsize -= available;\n\t\tbody(ctx, ctx->buffer, 64);\n\t}\n\n\tif (size >= 64) {\n\t\tdata = body(ctx, data, size & ~(unsigned long)0x3f);\n\t\tsize &= 0x3f;\n\t}\n\n\tmemcpy(ctx->buffer, data, size);\n}\n\n#define PUT_VALUE32(dst, src) \\\n\t(dst)[0] = (unsigned char)(src); \\\n\t(dst)[1] = (unsigned char)((src) >> 8); \\\n\t(dst)[2] = (unsigned char)((src) >> 16); \\\n\t(dst)[3] = (unsigned char)((src) >> 24);\n\nvoid MD5_Final(unsigned char *result, MD5_CTX *ctx)\n{\n\tunsigned long used, available;\n\n\tused = ctx->lo & 0x3f;\n\n\tctx->buffer[used++] = 0x80;\n\n\tavailable = 64 - used;\n\n\tif (available < 8) {\n\t\tmemset(&ctx->buffer[used], 0, available);\n\t\tbody(ctx, ctx->buffer, 64);\n\t\tused = 0;\n\t\tavailable = 64;\n\t}\n\n\tmemset(&ctx->buffer[used], 0, available - 8);\n\n\tctx->lo <<= 3;\n\tPUT_VALUE32(&ctx->buffer[56], ctx->lo)\n\tPUT_VALUE32(&ctx->buffer[60], ctx->hi)\n\n\tbody(ctx, ctx->buffer, 64);\n\n\tPUT_VALUE32(&result[0], ctx->a)\n\tPUT_VALUE32(&result[4], ctx->b)\n\tPUT_VALUE32(&result[8], ctx->c)\n\tPUT_VALUE32(&result[12], ctx->d)\n\n\tmemset(ctx, 0, sizeof(*ctx));\n}\n\n#endif\n"
  },
  {
    "path": "deps/CascLib/src/md5/md5.h",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * See md5.c for more information.\n */\n \n#ifdef HAVE_OPENSSL\n#include <openssl/md5.h>\n#elif !defined(_MD5_H)\n#define _MD5_H\n \n/* Any 32-bit or wider unsigned integer data type will do */\ntypedef unsigned int MD5_u32plus;\n \ntypedef struct {\n\tMD5_u32plus lo, hi;\n\tMD5_u32plus a, b, c, d;\n\tunsigned char buffer[64];\n\tMD5_u32plus block[16];\n} MD5_CTX;\n \nvoid MD5_Init(MD5_CTX *ctx);\nvoid MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);\nvoid MD5_Final(unsigned char *result, MD5_CTX *ctx);\n \n#endif\n"
  },
  {
    "path": "deps/CascLib/src/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by DllMain.rc\n//\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        101\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1000\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "deps/CascLib/src/zlib/adler32.c",
    "content": "/* adler32.c -- compute the Adler-32 checksum of a data stream\n * Copyright (C) 1995-2011, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#include \"zutil.h\"\n\nlocal uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));\n\n#define BASE 65521U     /* largest prime smaller than 65536 */\n#define NMAX 5552\n/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */\n\n#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}\n#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);\n#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);\n#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);\n#define DO16(buf)   DO8(buf,0); DO8(buf,8);\n\n/* use NO_DIVIDE if your processor does not do division in hardware --\n   try it both ways to see which is faster */\n#ifdef NO_DIVIDE\n/* note that this assumes BASE is 65521, where 65536 % 65521 == 15\n   (thank you to John Reiser for pointing this out) */\n#  define CHOP(a) \\\n    do { \\\n        unsigned long tmp = a >> 16; \\\n        a &= 0xffffUL; \\\n        a += (tmp << 4) - tmp; \\\n    } while (0)\n#  define MOD28(a) \\\n    do { \\\n        CHOP(a); \\\n        if (a >= BASE) a -= BASE; \\\n    } while (0)\n#  define MOD(a) \\\n    do { \\\n        CHOP(a); \\\n        MOD28(a); \\\n    } while (0)\n#  define MOD63(a) \\\n    do { /* this assumes a is not negative */ \\\n        z_off64_t tmp = a >> 32; \\\n        a &= 0xffffffffL; \\\n        a += (tmp << 8) - (tmp << 5) + tmp; \\\n        tmp = a >> 16; \\\n        a &= 0xffffL; \\\n        a += (tmp << 4) - tmp; \\\n        tmp = a >> 16; \\\n        a &= 0xffffL; \\\n        a += (tmp << 4) - tmp; \\\n        if (a >= BASE) a -= BASE; \\\n    } while (0)\n#else\n#  define MOD(a) a %= BASE\n#  define MOD28(a) a %= BASE\n#  define MOD63(a) a %= BASE\n#endif\n\n/* ========================================================================= */\nuLong ZEXPORT adler32_z(adler, buf, len)\n    uLong adler;\n    const Bytef *buf;\n    z_size_t len;\n{\n    unsigned long sum2;\n    unsigned n;\n\n    /* split Adler-32 into component sums */\n    sum2 = (adler >> 16) & 0xffff;\n    adler &= 0xffff;\n\n    /* in case user likes doing a byte at a time, keep it fast */\n    if (len == 1) {\n        adler += buf[0];\n        if (adler >= BASE)\n            adler -= BASE;\n        sum2 += adler;\n        if (sum2 >= BASE)\n            sum2 -= BASE;\n        return adler | (sum2 << 16);\n    }\n\n    /* initial Adler-32 value (deferred check for len == 1 speed) */\n    if (buf == Z_NULL)\n        return 1L;\n\n    /* in case short lengths are provided, keep it somewhat fast */\n    if (len < 16) {\n        while (len--) {\n            adler += *buf++;\n            sum2 += adler;\n        }\n        if (adler >= BASE)\n            adler -= BASE;\n        MOD28(sum2);            /* only added so many BASE's */\n        return adler | (sum2 << 16);\n    }\n\n    /* do length NMAX blocks -- requires just one modulo operation */\n    while (len >= NMAX) {\n        len -= NMAX;\n        n = NMAX / 16;          /* NMAX is divisible by 16 */\n        do {\n            DO16(buf);          /* 16 sums unrolled */\n            buf += 16;\n        } while (--n);\n        MOD(adler);\n        MOD(sum2);\n    }\n\n    /* do remaining bytes (less than NMAX, still just one modulo) */\n    if (len) {                  /* avoid modulos if none remaining */\n        while (len >= 16) {\n            len -= 16;\n            DO16(buf);\n            buf += 16;\n        }\n        while (len--) {\n            adler += *buf++;\n            sum2 += adler;\n        }\n        MOD(adler);\n        MOD(sum2);\n    }\n\n    /* return recombined sums */\n    return adler | (sum2 << 16);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT adler32(adler, buf, len)\n    uLong adler;\n    const Bytef *buf;\n    uInt len;\n{\n    return adler32_z(adler, buf, len);\n}\n\n/* ========================================================================= */\nlocal uLong adler32_combine_(adler1, adler2, len2)\n    uLong adler1;\n    uLong adler2;\n    z_off64_t len2;\n{\n    unsigned long sum1;\n    unsigned long sum2;\n    unsigned rem;\n\n    /* for negative len, return invalid adler32 as a clue for debugging */\n    if (len2 < 0)\n        return 0xffffffffUL;\n\n    /* the derivation of this formula is left as an exercise for the reader */\n    MOD63(len2);                /* assumes len2 >= 0 */\n    rem = (unsigned)len2;\n    sum1 = adler1 & 0xffff;\n    sum2 = rem * sum1;\n    MOD(sum2);\n    sum1 += (adler2 & 0xffff) + BASE - 1;\n    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;\n    if (sum1 >= BASE) sum1 -= BASE;\n    if (sum1 >= BASE) sum1 -= BASE;\n    if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);\n    if (sum2 >= BASE) sum2 -= BASE;\n    return sum1 | (sum2 << 16);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT adler32_combine(adler1, adler2, len2)\n    uLong adler1;\n    uLong adler2;\n    z_off_t len2;\n{\n    return adler32_combine_(adler1, adler2, len2);\n}\n\nuLong ZEXPORT adler32_combine64(adler1, adler2, len2)\n    uLong adler1;\n    uLong adler2;\n    z_off64_t len2;\n{\n    return adler32_combine_(adler1, adler2, len2);\n}\n"
  },
  {
    "path": "deps/CascLib/src/zlib/crc32.c",
    "content": "/* crc32.c -- compute the CRC-32 of a data stream\n * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n *\n * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster\n * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing\n * tables for updating the shift register in one step with three exclusive-ors\n * instead of four steps with four exclusive-ors.  This results in about a\n * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.\n */\n\n/* @(#) $Id$ */\n\n/*\n  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore\n  protection on the static variables used to control the first-use generation\n  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should\n  first call get_crc_table() to initialize the tables before allowing more than\n  one thread to use crc32().\n\n  DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.\n */\n\n#ifdef MAKECRCH\n#  include <stdio.h>\n#  ifndef DYNAMIC_CRC_TABLE\n#    define DYNAMIC_CRC_TABLE\n#  endif /* !DYNAMIC_CRC_TABLE */\n#endif /* MAKECRCH */\n\n#include \"zutil.h\"      /* for STDC and FAR definitions */\n\n/* Definitions for doing the crc four data bytes at a time. */\n#if !defined(NOBYFOUR) && defined(Z_U4)\n#  define BYFOUR\n#endif\n#ifdef BYFOUR\n   local unsigned long crc32_little OF((unsigned long,\n                        const unsigned char FAR *, z_size_t));\n   local unsigned long crc32_big OF((unsigned long,\n                        const unsigned char FAR *, z_size_t));\n#  define TBLS 8\n#else\n#  define TBLS 1\n#endif /* BYFOUR */\n\n/* Local functions for crc concatenation */\nlocal unsigned long gf2_matrix_times OF((unsigned long *mat,\n                                         unsigned long vec));\nlocal void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));\nlocal uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));\n\n\n#ifdef DYNAMIC_CRC_TABLE\n\nlocal volatile int crc_table_empty = 1;\nlocal z_crc_t FAR crc_table[TBLS][256];\nlocal void make_crc_table OF((void));\n#ifdef MAKECRCH\n   local void write_table OF((FILE *, const z_crc_t FAR *));\n#endif /* MAKECRCH */\n/*\n  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:\n  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.\n\n  Polynomials over GF(2) are represented in binary, one bit per coefficient,\n  with the lowest powers in the most significant bit.  Then adding polynomials\n  is just exclusive-or, and multiplying a polynomial by x is a right shift by\n  one.  If we call the above polynomial p, and represent a byte as the\n  polynomial q, also with the lowest power in the most significant bit (so the\n  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,\n  where a mod b means the remainder after dividing a by b.\n\n  This calculation is done using the shift-register method of multiplying and\n  taking the remainder.  The register is initialized to zero, and for each\n  incoming bit, x^32 is added mod p to the register if the bit is a one (where\n  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by\n  x (which is shifting right by one and adding x^32 mod p if the bit shifted\n  out is a one).  We start with the highest power (least significant bit) of\n  q and repeat for all eight bits of q.\n\n  The first table is simply the CRC of all possible eight bit values.  This is\n  all the information needed to generate CRCs on data a byte at a time for all\n  combinations of CRC register values and incoming bytes.  The remaining tables\n  allow for word-at-a-time CRC calculation for both big-endian and little-\n  endian machines, where a word is four bytes.\n*/\nlocal void make_crc_table()\n{\n    z_crc_t c;\n    int n, k;\n    z_crc_t poly;                       /* polynomial exclusive-or pattern */\n    /* terms of polynomial defining this crc (except x^32): */\n    static volatile int first = 1;      /* flag to limit concurrent making */\n    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};\n\n    /* See if another task is already doing this (not thread-safe, but better\n       than nothing -- significantly reduces duration of vulnerability in\n       case the advice about DYNAMIC_CRC_TABLE is ignored) */\n    if (first) {\n        first = 0;\n\n        /* make exclusive-or pattern from polynomial (0xedb88320UL) */\n        poly = 0;\n        for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)\n            poly |= (z_crc_t)1 << (31 - p[n]);\n\n        /* generate a crc for every 8-bit value */\n        for (n = 0; n < 256; n++) {\n            c = (z_crc_t)n;\n            for (k = 0; k < 8; k++)\n                c = c & 1 ? poly ^ (c >> 1) : c >> 1;\n            crc_table[0][n] = c;\n        }\n\n#ifdef BYFOUR\n        /* generate crc for each value followed by one, two, and three zeros,\n           and then the byte reversal of those as well as the first table */\n        for (n = 0; n < 256; n++) {\n            c = crc_table[0][n];\n            crc_table[4][n] = ZSWAP32(c);\n            for (k = 1; k < 4; k++) {\n                c = crc_table[0][c & 0xff] ^ (c >> 8);\n                crc_table[k][n] = c;\n                crc_table[k + 4][n] = ZSWAP32(c);\n            }\n        }\n#endif /* BYFOUR */\n\n        crc_table_empty = 0;\n    }\n    else {      /* not first */\n        /* wait for the other guy to finish (not efficient, but rare) */\n        while (crc_table_empty)\n            ;\n    }\n\n#ifdef MAKECRCH\n    /* write out CRC tables to crc32.h */\n    {\n        FILE *out;\n\n        out = fopen(\"crc32.h\", \"w\");\n        if (out == NULL) return;\n        fprintf(out, \"/* crc32.h -- tables for rapid CRC calculation\\n\");\n        fprintf(out, \" * Generated automatically by crc32.c\\n */\\n\\n\");\n        fprintf(out, \"local const z_crc_t FAR \");\n        fprintf(out, \"crc_table[TBLS][256] =\\n{\\n  {\\n\");\n        write_table(out, crc_table[0]);\n#  ifdef BYFOUR\n        fprintf(out, \"#ifdef BYFOUR\\n\");\n        for (k = 1; k < 8; k++) {\n            fprintf(out, \"  },\\n  {\\n\");\n            write_table(out, crc_table[k]);\n        }\n        fprintf(out, \"#endif\\n\");\n#  endif /* BYFOUR */\n        fprintf(out, \"  }\\n};\\n\");\n        fclose(out);\n    }\n#endif /* MAKECRCH */\n}\n\n#ifdef MAKECRCH\nlocal void write_table(out, table)\n    FILE *out;\n    const z_crc_t FAR *table;\n{\n    int n;\n\n    for (n = 0; n < 256; n++)\n        fprintf(out, \"%s0x%08lxUL%s\", n % 5 ? \"\" : \"    \",\n                (unsigned long)(table[n]),\n                n == 255 ? \"\\n\" : (n % 5 == 4 ? \",\\n\" : \", \"));\n}\n#endif /* MAKECRCH */\n\n#else /* !DYNAMIC_CRC_TABLE */\n/* ========================================================================\n * Tables of CRC-32s of all single-byte values, made by make_crc_table().\n */\n#include \"crc32.h\"\n#endif /* DYNAMIC_CRC_TABLE */\n\n/* =========================================================================\n * This function can be used by asm versions of crc32()\n */\nconst z_crc_t FAR * ZEXPORT get_crc_table()\n{\n#ifdef DYNAMIC_CRC_TABLE\n    if (crc_table_empty)\n        make_crc_table();\n#endif /* DYNAMIC_CRC_TABLE */\n    return (const z_crc_t FAR *)crc_table;\n}\n\n/* ========================================================================= */\n#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)\n#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1\n\n/* ========================================================================= */\nunsigned long ZEXPORT crc32_z(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    z_size_t len;\n{\n    if (buf == Z_NULL) return 0UL;\n\n#ifdef DYNAMIC_CRC_TABLE\n    if (crc_table_empty)\n        make_crc_table();\n#endif /* DYNAMIC_CRC_TABLE */\n\n#ifdef BYFOUR\n    if (sizeof(void *) == sizeof(ptrdiff_t)) {\n        z_crc_t endian;\n\n        endian = 1;\n        if (*((unsigned char *)(&endian)))\n            return crc32_little(crc, buf, len);\n        else\n            return crc32_big(crc, buf, len);\n    }\n#endif /* BYFOUR */\n    crc = crc ^ 0xffffffffUL;\n    while (len >= 8) {\n        DO8;\n        len -= 8;\n    }\n    if (len) do {\n        DO1;\n    } while (--len);\n    return crc ^ 0xffffffffUL;\n}\n\n/* ========================================================================= */\nunsigned long ZEXPORT crc32(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    uInt len;\n{\n    return crc32_z(crc, buf, len);\n}\n\n#ifdef BYFOUR\n\n/*\n   This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit\n   integer pointer type. This violates the strict aliasing rule, where a\n   compiler can assume, for optimization purposes, that two pointers to\n   fundamentally different types won't ever point to the same memory. This can\n   manifest as a problem only if one of the pointers is written to. This code\n   only reads from those pointers. So long as this code remains isolated in\n   this compilation unit, there won't be a problem. For this reason, this code\n   should not be copied and pasted into a compilation unit in which other code\n   writes to the buffer that is passed to these routines.\n */\n\n/* ========================================================================= */\n#define DOLIT4 c ^= *buf4++; \\\n        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \\\n            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]\n#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4\n\n/* ========================================================================= */\nlocal unsigned long crc32_little(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    z_size_t len;\n{\n    register z_crc_t c;\n    register const z_crc_t FAR *buf4;\n\n    c = (z_crc_t)crc;\n    c = ~c;\n    while (len && ((ptrdiff_t)buf & 3)) {\n        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);\n        len--;\n    }\n\n    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;\n    while (len >= 32) {\n        DOLIT32;\n        len -= 32;\n    }\n    while (len >= 4) {\n        DOLIT4;\n        len -= 4;\n    }\n    buf = (const unsigned char FAR *)buf4;\n\n    if (len) do {\n        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);\n    } while (--len);\n    c = ~c;\n    return (unsigned long)c;\n}\n\n/* ========================================================================= */\n#define DOBIG4 c ^= *buf4++; \\\n        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \\\n            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]\n#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4\n\n/* ========================================================================= */\nlocal unsigned long crc32_big(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    z_size_t len;\n{\n    register z_crc_t c;\n    register const z_crc_t FAR *buf4;\n\n    c = ZSWAP32((z_crc_t)crc);\n    c = ~c;\n    while (len && ((ptrdiff_t)buf & 3)) {\n        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);\n        len--;\n    }\n\n    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;\n    while (len >= 32) {\n        DOBIG32;\n        len -= 32;\n    }\n    while (len >= 4) {\n        DOBIG4;\n        len -= 4;\n    }\n    buf = (const unsigned char FAR *)buf4;\n\n    if (len) do {\n        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);\n    } while (--len);\n    c = ~c;\n    return (unsigned long)(ZSWAP32(c));\n}\n\n#endif /* BYFOUR */\n\n#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */\n\n/* ========================================================================= */\nlocal unsigned long gf2_matrix_times(mat, vec)\n    unsigned long *mat;\n    unsigned long vec;\n{\n    unsigned long sum;\n\n    sum = 0;\n    while (vec) {\n        if (vec & 1)\n            sum ^= *mat;\n        vec >>= 1;\n        mat++;\n    }\n    return sum;\n}\n\n/* ========================================================================= */\nlocal void gf2_matrix_square(square, mat)\n    unsigned long *square;\n    unsigned long *mat;\n{\n    int n;\n\n    for (n = 0; n < GF2_DIM; n++)\n        square[n] = gf2_matrix_times(mat, mat[n]);\n}\n\n/* ========================================================================= */\nlocal uLong crc32_combine_(crc1, crc2, len2)\n    uLong crc1;\n    uLong crc2;\n    z_off64_t len2;\n{\n    int n;\n    unsigned long row;\n    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */\n    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */\n\n    /* degenerate case (also disallow negative lengths) */\n    if (len2 <= 0)\n        return crc1;\n\n    /* put operator for one zero bit in odd */\n    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */\n    row = 1;\n    for (n = 1; n < GF2_DIM; n++) {\n        odd[n] = row;\n        row <<= 1;\n    }\n\n    /* put operator for two zero bits in even */\n    gf2_matrix_square(even, odd);\n\n    /* put operator for four zero bits in odd */\n    gf2_matrix_square(odd, even);\n\n    /* apply len2 zeros to crc1 (first square will put the operator for one\n       zero byte, eight zero bits, in even) */\n    do {\n        /* apply zeros operator for this bit of len2 */\n        gf2_matrix_square(even, odd);\n        if (len2 & 1)\n            crc1 = gf2_matrix_times(even, crc1);\n        len2 >>= 1;\n\n        /* if no more bits set, then done */\n        if (len2 == 0)\n            break;\n\n        /* another iteration of the loop with odd and even swapped */\n        gf2_matrix_square(odd, even);\n        if (len2 & 1)\n            crc1 = gf2_matrix_times(odd, crc1);\n        len2 >>= 1;\n\n        /* if no more bits set, then done */\n    } while (len2 != 0);\n\n    /* return combined crc */\n    crc1 ^= crc2;\n    return crc1;\n}\n\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine(crc1, crc2, len2)\n    uLong crc1;\n    uLong crc2;\n    z_off_t len2;\n{\n    return crc32_combine_(crc1, crc2, len2);\n}\n\nuLong ZEXPORT crc32_combine64(crc1, crc2, len2)\n    uLong crc1;\n    uLong crc2;\n    z_off64_t len2;\n{\n    return crc32_combine_(crc1, crc2, len2);\n}\n"
  },
  {
    "path": "deps/CascLib/src/zlib/crc32.h",
    "content": "/* crc32.h -- tables for rapid CRC calculation\n * Generated automatically by crc32.c\n */\n\nlocal const z_crc_t FAR crc_table[TBLS][256] =\n{\n  {\n    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,\n    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,\n    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,\n    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,\n    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,\n    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,\n    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,\n    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,\n    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,\n    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,\n    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,\n    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,\n    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,\n    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,\n    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,\n    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,\n    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,\n    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,\n    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,\n    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,\n    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,\n    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,\n    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,\n    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,\n    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,\n    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,\n    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,\n    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,\n    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,\n    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,\n    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,\n    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,\n    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,\n    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,\n    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,\n    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,\n    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,\n    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,\n    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,\n    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,\n    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,\n    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,\n    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,\n    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,\n    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,\n    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,\n    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,\n    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,\n    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,\n    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,\n    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,\n    0x2d02ef8dUL\n#ifdef BYFOUR\n  },\n  {\n    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,\n    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,\n    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,\n    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,\n    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,\n    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,\n    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,\n    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,\n    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,\n    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,\n    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,\n    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,\n    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,\n    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,\n    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,\n    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,\n    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,\n    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,\n    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,\n    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,\n    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,\n    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,\n    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,\n    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,\n    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,\n    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,\n    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,\n    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,\n    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,\n    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,\n    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,\n    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,\n    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,\n    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,\n    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,\n    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,\n    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,\n    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,\n    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,\n    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,\n    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,\n    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,\n    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,\n    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,\n    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,\n    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,\n    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,\n    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,\n    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,\n    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,\n    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,\n    0x9324fd72UL\n  },\n  {\n    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,\n    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,\n    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,\n    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,\n    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,\n    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,\n    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,\n    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,\n    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,\n    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,\n    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,\n    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,\n    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,\n    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,\n    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,\n    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,\n    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,\n    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,\n    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,\n    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,\n    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,\n    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,\n    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,\n    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,\n    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,\n    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,\n    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,\n    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,\n    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,\n    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,\n    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,\n    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,\n    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,\n    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,\n    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,\n    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,\n    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,\n    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,\n    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,\n    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,\n    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,\n    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,\n    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,\n    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,\n    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,\n    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,\n    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,\n    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,\n    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,\n    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,\n    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,\n    0xbe9834edUL\n  },\n  {\n    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,\n    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,\n    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,\n    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,\n    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,\n    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,\n    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,\n    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,\n    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,\n    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,\n    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,\n    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,\n    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,\n    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,\n    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,\n    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,\n    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,\n    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,\n    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,\n    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,\n    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,\n    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,\n    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,\n    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,\n    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,\n    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,\n    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,\n    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,\n    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,\n    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,\n    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,\n    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,\n    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,\n    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,\n    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,\n    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,\n    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,\n    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,\n    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,\n    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,\n    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,\n    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,\n    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,\n    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,\n    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,\n    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,\n    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,\n    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,\n    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,\n    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,\n    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,\n    0xde0506f1UL\n  },\n  {\n    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,\n    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,\n    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,\n    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,\n    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,\n    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,\n    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,\n    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,\n    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,\n    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,\n    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,\n    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,\n    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,\n    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,\n    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,\n    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,\n    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,\n    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,\n    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,\n    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,\n    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,\n    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,\n    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,\n    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,\n    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,\n    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,\n    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,\n    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,\n    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,\n    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,\n    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,\n    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,\n    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,\n    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,\n    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,\n    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,\n    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,\n    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,\n    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,\n    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,\n    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,\n    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,\n    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,\n    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,\n    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,\n    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,\n    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,\n    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,\n    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,\n    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,\n    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,\n    0x8def022dUL\n  },\n  {\n    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,\n    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,\n    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,\n    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,\n    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,\n    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,\n    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,\n    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,\n    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,\n    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,\n    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,\n    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,\n    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,\n    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,\n    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,\n    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,\n    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,\n    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,\n    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,\n    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,\n    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,\n    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,\n    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,\n    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,\n    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,\n    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,\n    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,\n    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,\n    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,\n    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,\n    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,\n    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,\n    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,\n    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,\n    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,\n    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,\n    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,\n    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,\n    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,\n    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,\n    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,\n    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,\n    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,\n    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,\n    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,\n    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,\n    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,\n    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,\n    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,\n    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,\n    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,\n    0x72fd2493UL\n  },\n  {\n    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,\n    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,\n    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,\n    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,\n    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,\n    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,\n    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,\n    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,\n    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,\n    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,\n    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,\n    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,\n    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,\n    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,\n    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,\n    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,\n    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,\n    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,\n    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,\n    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,\n    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,\n    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,\n    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,\n    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,\n    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,\n    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,\n    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,\n    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,\n    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,\n    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,\n    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,\n    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,\n    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,\n    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,\n    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,\n    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,\n    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,\n    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,\n    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,\n    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,\n    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,\n    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,\n    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,\n    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,\n    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,\n    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,\n    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,\n    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,\n    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,\n    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,\n    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,\n    0xed3498beUL\n  },\n  {\n    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,\n    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,\n    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,\n    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,\n    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,\n    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,\n    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,\n    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,\n    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,\n    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,\n    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,\n    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,\n    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,\n    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,\n    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,\n    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,\n    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,\n    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,\n    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,\n    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,\n    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,\n    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,\n    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,\n    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,\n    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,\n    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,\n    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,\n    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,\n    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,\n    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,\n    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,\n    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,\n    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,\n    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,\n    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,\n    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,\n    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,\n    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,\n    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,\n    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,\n    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,\n    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,\n    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,\n    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,\n    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,\n    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,\n    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,\n    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,\n    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,\n    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,\n    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,\n    0xf10605deUL\n#endif\n  }\n};\n"
  },
  {
    "path": "deps/CascLib/src/zlib/deflate.c",
    "content": "/* deflate.c -- compress data using the deflation algorithm\n * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n *  ALGORITHM\n *\n *      The \"deflation\" process depends on being able to identify portions\n *      of the input text which are identical to earlier input (within a\n *      sliding window trailing behind the input currently being processed).\n *\n *      The most straightforward technique turns out to be the fastest for\n *      most input files: try all possible matches and select the longest.\n *      The key feature of this algorithm is that insertions into the string\n *      dictionary are very simple and thus fast, and deletions are avoided\n *      completely. Insertions are performed at each input character, whereas\n *      string matches are performed only when the previous match ends. So it\n *      is preferable to spend more time in matches to allow very fast string\n *      insertions and avoid deletions. The matching algorithm for small\n *      strings is inspired from that of Rabin & Karp. A brute force approach\n *      is used to find longer strings when a small match has been found.\n *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze\n *      (by Leonid Broukhis).\n *         A previous version of this file used a more sophisticated algorithm\n *      (by Fiala and Greene) which is guaranteed to run in linear amortized\n *      time, but has a larger average cost, uses more memory and is patented.\n *      However the F&G algorithm may be faster for some highly redundant\n *      files if the parameter max_chain_length (described below) is too large.\n *\n *  ACKNOWLEDGEMENTS\n *\n *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and\n *      I found it in 'freeze' written by Leonid Broukhis.\n *      Thanks to many people for bug reports and testing.\n *\n *  REFERENCES\n *\n *      Deutsch, L.P.,\"DEFLATE Compressed Data Format Specification\".\n *      Available in http://tools.ietf.org/html/rfc1951\n *\n *      A description of the Rabin and Karp algorithm is given in the book\n *         \"Algorithms\" by R. Sedgewick, Addison-Wesley, p252.\n *\n *      Fiala,E.R., and Greene,D.H.\n *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595\n *\n */\n\n/* @(#) $Id$ */\n\n#include \"deflate.h\"\n\nconst char deflate_copyright[] =\n   \" deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler \";\n/*\n  If you use the zlib library in a product, an acknowledgment is welcome\n  in the documentation of your product. If for some reason you cannot\n  include such an acknowledgment, I would appreciate that you keep this\n  copyright string in the executable of your product.\n */\n\n/* ===========================================================================\n *  Function prototypes.\n */\ntypedef enum {\n    need_more,      /* block not completed, need more input or more output */\n    block_done,     /* block flush performed */\n    finish_started, /* finish started, need only more output at next deflate */\n    finish_done     /* finish done, accept no more input or output */\n} block_state;\n\ntypedef block_state (*compress_func) OF((deflate_state *s, int flush));\n/* Compression function. Returns the block state after the call. */\n\nlocal int deflateStateCheck      OF((z_streamp strm));\nlocal void slide_hash     OF((deflate_state *s));\nlocal void fill_window    OF((deflate_state *s));\nlocal block_state deflate_stored OF((deflate_state *s, int flush));\nlocal block_state deflate_fast   OF((deflate_state *s, int flush));\n#ifndef FASTEST\nlocal block_state deflate_slow   OF((deflate_state *s, int flush));\n#endif\nlocal block_state deflate_rle    OF((deflate_state *s, int flush));\nlocal block_state deflate_huff   OF((deflate_state *s, int flush));\nlocal void lm_init        OF((deflate_state *s));\nlocal void putShortMSB    OF((deflate_state *s, uInt b));\nlocal void flush_pending  OF((z_streamp strm));\nlocal unsigned read_buf   OF((z_streamp strm, Bytef *buf, unsigned size));\n#ifdef ASMV\n#  pragma message(\"Assembler code may have bugs -- use at your own risk\")\n      void match_init OF((void)); /* asm code initialization */\n      uInt longest_match  OF((deflate_state *s, IPos cur_match));\n#else\nlocal uInt longest_match  OF((deflate_state *s, IPos cur_match));\n#endif\n\n#ifdef ZLIB_DEBUG\nlocal  void check_match OF((deflate_state *s, IPos start, IPos match,\n                            int length));\n#endif\n\n/* ===========================================================================\n * Local data\n */\n\n#define NIL 0\n/* Tail of hash chains */\n\n#ifndef TOO_FAR\n#  define TOO_FAR 4096\n#endif\n/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\ntypedef struct config_s {\n   ush good_length; /* reduce lazy search above this match length */\n   ush max_lazy;    /* do not perform lazy search above this match length */\n   ush nice_length; /* quit search above this match length */\n   ush max_chain;\n   compress_func func;\n} config;\n\n#ifdef FASTEST\nlocal const config configuration_table[2] = {\n/*      good lazy nice chain */\n/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */\n/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */\n#else\nlocal const config configuration_table[10] = {\n/*      good lazy nice chain */\n/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */\n/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */\n/* 2 */ {4,    5, 16,    8, deflate_fast},\n/* 3 */ {4,    6, 32,   32, deflate_fast},\n\n/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */\n/* 5 */ {8,   16, 32,   32, deflate_slow},\n/* 6 */ {8,   16, 128, 128, deflate_slow},\n/* 7 */ {8,   32, 128, 256, deflate_slow},\n/* 8 */ {32, 128, 258, 1024, deflate_slow},\n/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */\n#endif\n\n/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4\n * For deflate_fast() (levels <= 3) good is ignored and lazy has a different\n * meaning.\n */\n\n/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */\n#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))\n\n/* ===========================================================================\n * Update a hash value with the given input byte\n * IN  assertion: all calls to UPDATE_HASH are made with consecutive input\n *    characters, so that a running hash key can be computed from the previous\n *    key instead of complete recalculation each time.\n */\n#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)\n\n\n/* ===========================================================================\n * Insert string str in the dictionary and set match_head to the previous head\n * of the hash chain (the most recent string with same hash key). Return\n * the previous length of the hash chain.\n * If this file is compiled with -DFASTEST, the compression level is forced\n * to 1, and no hash chains are maintained.\n * IN  assertion: all calls to INSERT_STRING are made with consecutive input\n *    characters and the first MIN_MATCH bytes of str are valid (except for\n *    the last MIN_MATCH-1 bytes of the input file).\n */\n#ifdef FASTEST\n#define INSERT_STRING(s, str, match_head) \\\n   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \\\n    match_head = s->head[s->ins_h], \\\n    s->head[s->ins_h] = (Pos)(str))\n#else\n#define INSERT_STRING(s, str, match_head) \\\n   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \\\n    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \\\n    s->head[s->ins_h] = (Pos)(str))\n#endif\n\n/* ===========================================================================\n * Initialize the hash table (avoiding 64K overflow for 16 bit systems).\n * prev[] will be initialized on the fly.\n */\n#define CLEAR_HASH(s) \\\n    s->head[s->hash_size-1] = NIL; \\\n    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));\n\n/* ===========================================================================\n * Slide the hash table when sliding the window down (could be avoided with 32\n * bit values at the expense of memory usage). We slide even when level == 0 to\n * keep the hash table consistent if we switch back to level > 0 later.\n */\nlocal void slide_hash(s)\n    deflate_state *s;\n{\n    unsigned n, m;\n    Posf *p;\n    uInt wsize = s->w_size;\n\n    n = s->hash_size;\n    p = &s->head[n];\n    do {\n        m = *--p;\n        *p = (Pos)(m >= wsize ? m - wsize : NIL);\n    } while (--n);\n    n = wsize;\n#ifndef FASTEST\n    p = &s->prev[n];\n    do {\n        m = *--p;\n        *p = (Pos)(m >= wsize ? m - wsize : NIL);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n    } while (--n);\n#endif\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateInit_(strm, level, version, stream_size)\n    z_streamp strm;\n    int level;\n    const char *version;\n    int stream_size;\n{\n    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,\n                         Z_DEFAULT_STRATEGY, version, stream_size);\n    /* To do: ignore strm->next_in if we use it as window */\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,\n                  version, stream_size)\n    z_streamp strm;\n    int  level;\n    int  method;\n    int  windowBits;\n    int  memLevel;\n    int  strategy;\n    const char *version;\n    int stream_size;\n{\n    deflate_state *s;\n    int wrap = 1;\n    static const char my_version[] = ZLIB_VERSION;\n\n    ushf *overlay;\n    /* We overlay pending_buf and d_buf+l_buf. This works since the average\n     * output size for (length,distance) codes is <= 24 bits.\n     */\n\n    if (version == Z_NULL || version[0] != my_version[0] ||\n        stream_size != sizeof(z_stream)) {\n        return Z_VERSION_ERROR;\n    }\n    if (strm == Z_NULL) return Z_STREAM_ERROR;\n\n    strm->msg = Z_NULL;\n    if (strm->zalloc == (alloc_func)0) {\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zalloc = zcalloc;\n        strm->opaque = (voidpf)0;\n#endif\n    }\n    if (strm->zfree == (free_func)0)\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zfree = zcfree;\n#endif\n\n#ifdef FASTEST\n    if (level != 0) level = 1;\n#else\n    if (level == Z_DEFAULT_COMPRESSION) level = 6;\n#endif\n\n    if (windowBits < 0) { /* suppress zlib wrapper */\n        wrap = 0;\n        windowBits = -windowBits;\n    }\n#ifdef GZIP\n    else if (windowBits > 15) {\n        wrap = 2;       /* write gzip wrapper instead */\n        windowBits -= 16;\n    }\n#endif\n    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||\n        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n        strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) {\n        return Z_STREAM_ERROR;\n    }\n    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */\n    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));\n    if (s == Z_NULL) return Z_MEM_ERROR;\n    strm->state = (struct internal_state FAR *)s;\n    s->strm = strm;\n    s->status = INIT_STATE;     /* to pass state test in deflateReset() */\n\n    s->wrap = wrap;\n    s->gzhead = Z_NULL;\n    s->w_bits = (uInt)windowBits;\n    s->w_size = 1 << s->w_bits;\n    s->w_mask = s->w_size - 1;\n\n    s->hash_bits = (uInt)memLevel + 7;\n    s->hash_size = 1 << s->hash_bits;\n    s->hash_mask = s->hash_size - 1;\n    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);\n\n    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));\n    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));\n    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));\n\n    s->high_water = 0;      /* nothing written to s->window yet */\n\n    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);\n    s->pending_buf = (uchf *) overlay;\n    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);\n\n    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||\n        s->pending_buf == Z_NULL) {\n        s->status = FINISH_STATE;\n        strm->msg = ERR_MSG(Z_MEM_ERROR);\n        deflateEnd (strm);\n        return Z_MEM_ERROR;\n    }\n    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);\n    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;\n\n    s->level = level;\n    s->strategy = strategy;\n    s->method = (Byte)method;\n\n    return deflateReset(strm);\n}\n\n/* =========================================================================\n * Check for a valid deflate stream state. Return 0 if ok, 1 if not.\n */\nlocal int deflateStateCheck (strm)\n    z_streamp strm;\n{\n    deflate_state *s;\n    if (strm == Z_NULL ||\n        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)\n        return 1;\n    s = strm->state;\n    if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&\n#ifdef GZIP\n                                           s->status != GZIP_STATE &&\n#endif\n                                           s->status != EXTRA_STATE &&\n                                           s->status != NAME_STATE &&\n                                           s->status != COMMENT_STATE &&\n                                           s->status != HCRC_STATE &&\n                                           s->status != BUSY_STATE &&\n                                           s->status != FINISH_STATE))\n        return 1;\n    return 0;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)\n    z_streamp strm;\n    const Bytef *dictionary;\n    uInt  dictLength;\n{\n    deflate_state *s;\n    uInt str, n;\n    int wrap;\n    unsigned avail;\n    z_const unsigned char *next;\n\n    if (deflateStateCheck(strm) || dictionary == Z_NULL)\n        return Z_STREAM_ERROR;\n    s = strm->state;\n    wrap = s->wrap;\n    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)\n        return Z_STREAM_ERROR;\n\n    /* when using zlib wrappers, compute Adler-32 for provided dictionary */\n    if (wrap == 1)\n        strm->adler = adler32(strm->adler, dictionary, dictLength);\n    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */\n\n    /* if dictionary would fill window, just replace the history */\n    if (dictLength >= s->w_size) {\n        if (wrap == 0) {            /* already empty otherwise */\n            CLEAR_HASH(s);\n            s->strstart = 0;\n            s->block_start = 0L;\n            s->insert = 0;\n        }\n        dictionary += dictLength - s->w_size;  /* use the tail */\n        dictLength = s->w_size;\n    }\n\n    /* insert dictionary into window and hash */\n    avail = strm->avail_in;\n    next = strm->next_in;\n    strm->avail_in = dictLength;\n    strm->next_in = (z_const Bytef *)dictionary;\n    fill_window(s);\n    while (s->lookahead >= MIN_MATCH) {\n        str = s->strstart;\n        n = s->lookahead - (MIN_MATCH-1);\n        do {\n            UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);\n#ifndef FASTEST\n            s->prev[str & s->w_mask] = s->head[s->ins_h];\n#endif\n            s->head[s->ins_h] = (Pos)str;\n            str++;\n        } while (--n);\n        s->strstart = str;\n        s->lookahead = MIN_MATCH-1;\n        fill_window(s);\n    }\n    s->strstart += s->lookahead;\n    s->block_start = (long)s->strstart;\n    s->insert = s->lookahead;\n    s->lookahead = 0;\n    s->match_length = s->prev_length = MIN_MATCH-1;\n    s->match_available = 0;\n    strm->next_in = next;\n    strm->avail_in = avail;\n    s->wrap = wrap;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)\n    z_streamp strm;\n    Bytef *dictionary;\n    uInt  *dictLength;\n{\n    deflate_state *s;\n    uInt len;\n\n    if (deflateStateCheck(strm))\n        return Z_STREAM_ERROR;\n    s = strm->state;\n    len = s->strstart + s->lookahead;\n    if (len > s->w_size)\n        len = s->w_size;\n    if (dictionary != Z_NULL && len)\n        zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);\n    if (dictLength != Z_NULL)\n        *dictLength = len;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateResetKeep (strm)\n    z_streamp strm;\n{\n    deflate_state *s;\n\n    if (deflateStateCheck(strm)) {\n        return Z_STREAM_ERROR;\n    }\n\n    strm->total_in = strm->total_out = 0;\n    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */\n    strm->data_type = Z_UNKNOWN;\n\n    s = (deflate_state *)strm->state;\n    s->pending = 0;\n    s->pending_out = s->pending_buf;\n\n    if (s->wrap < 0) {\n        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */\n    }\n    s->status =\n#ifdef GZIP\n        s->wrap == 2 ? GZIP_STATE :\n#endif\n        s->wrap ? INIT_STATE : BUSY_STATE;\n    strm->adler =\n#ifdef GZIP\n        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :\n#endif\n        adler32(0L, Z_NULL, 0);\n    s->last_flush = Z_NO_FLUSH;\n\n    _tr_init(s);\n\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateReset (strm)\n    z_streamp strm;\n{\n    int ret;\n\n    ret = deflateResetKeep(strm);\n    if (ret == Z_OK)\n        lm_init(strm->state);\n    return ret;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateSetHeader (strm, head)\n    z_streamp strm;\n    gz_headerp head;\n{\n    if (deflateStateCheck(strm) || strm->state->wrap != 2)\n        return Z_STREAM_ERROR;\n    strm->state->gzhead = head;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflatePending (strm, pending, bits)\n    unsigned *pending;\n    int *bits;\n    z_streamp strm;\n{\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    if (pending != Z_NULL)\n        *pending = strm->state->pending;\n    if (bits != Z_NULL)\n        *bits = strm->state->bi_valid;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflatePrime (strm, bits, value)\n    z_streamp strm;\n    int bits;\n    int value;\n{\n    deflate_state *s;\n    int put;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n    if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))\n        return Z_BUF_ERROR;\n    do {\n        put = Buf_size - s->bi_valid;\n        if (put > bits)\n            put = bits;\n        s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);\n        s->bi_valid += put;\n        _tr_flush_bits(s);\n        value >>= put;\n        bits -= put;\n    } while (bits);\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateParams(strm, level, strategy)\n    z_streamp strm;\n    int level;\n    int strategy;\n{\n    deflate_state *s;\n    compress_func func;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n\n#ifdef FASTEST\n    if (level != 0) level = 1;\n#else\n    if (level == Z_DEFAULT_COMPRESSION) level = 6;\n#endif\n    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {\n        return Z_STREAM_ERROR;\n    }\n    func = configuration_table[s->level].func;\n\n    if ((strategy != s->strategy || func != configuration_table[level].func) &&\n        s->high_water) {\n        /* Flush the last buffer: */\n        int err = deflate(strm, Z_BLOCK);\n        if (err == Z_STREAM_ERROR)\n            return err;\n        if (strm->avail_out == 0)\n            return Z_BUF_ERROR;\n    }\n    if (s->level != level) {\n        if (s->level == 0 && s->matches != 0) {\n            if (s->matches == 1)\n                slide_hash(s);\n            else\n                CLEAR_HASH(s);\n            s->matches = 0;\n        }\n        s->level = level;\n        s->max_lazy_match   = configuration_table[level].max_lazy;\n        s->good_match       = configuration_table[level].good_length;\n        s->nice_match       = configuration_table[level].nice_length;\n        s->max_chain_length = configuration_table[level].max_chain;\n    }\n    s->strategy = strategy;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)\n    z_streamp strm;\n    int good_length;\n    int max_lazy;\n    int nice_length;\n    int max_chain;\n{\n    deflate_state *s;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n    s->good_match = (uInt)good_length;\n    s->max_lazy_match = (uInt)max_lazy;\n    s->nice_match = nice_length;\n    s->max_chain_length = (uInt)max_chain;\n    return Z_OK;\n}\n\n/* =========================================================================\n * For the default windowBits of 15 and memLevel of 8, this function returns\n * a close to exact, as well as small, upper bound on the compressed size.\n * They are coded as constants here for a reason--if the #define's are\n * changed, then this function needs to be changed as well.  The return\n * value for 15 and 8 only works for those exact settings.\n *\n * For any setting other than those defaults for windowBits and memLevel,\n * the value returned is a conservative worst case for the maximum expansion\n * resulting from using fixed blocks instead of stored blocks, which deflate\n * can emit on compressed data for some combinations of the parameters.\n *\n * This function could be more sophisticated to provide closer upper bounds for\n * every combination of windowBits and memLevel.  But even the conservative\n * upper bound of about 14% expansion does not seem onerous for output buffer\n * allocation.\n */\nuLong ZEXPORT deflateBound(strm, sourceLen)\n    z_streamp strm;\n    uLong sourceLen;\n{\n    deflate_state *s;\n    uLong complen, wraplen;\n\n    /* conservative upper bound for compressed data */\n    complen = sourceLen +\n              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;\n\n    /* if can't get parameters, return conservative bound plus zlib wrapper */\n    if (deflateStateCheck(strm))\n        return complen + 6;\n\n    /* compute wrapper length */\n    s = strm->state;\n    switch (s->wrap) {\n    case 0:                                 /* raw deflate */\n        wraplen = 0;\n        break;\n    case 1:                                 /* zlib wrapper */\n        wraplen = 6 + (s->strstart ? 4 : 0);\n        break;\n#ifdef GZIP\n    case 2:                                 /* gzip wrapper */\n        wraplen = 18;\n        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */\n            Bytef *str;\n            if (s->gzhead->extra != Z_NULL)\n                wraplen += 2 + s->gzhead->extra_len;\n            str = s->gzhead->name;\n            if (str != Z_NULL)\n                do {\n                    wraplen++;\n                } while (*str++);\n            str = s->gzhead->comment;\n            if (str != Z_NULL)\n                do {\n                    wraplen++;\n                } while (*str++);\n            if (s->gzhead->hcrc)\n                wraplen += 2;\n        }\n        break;\n#endif\n    default:                                /* for compiler happiness */\n        wraplen = 6;\n    }\n\n    /* if not default parameters, return conservative bound */\n    if (s->w_bits != 15 || s->hash_bits != 8 + 7)\n        return complen + wraplen;\n\n    /* default settings: return tight bound for that case */\n    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +\n           (sourceLen >> 25) + 13 - 6 + wraplen;\n}\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nlocal void putShortMSB (s, b)\n    deflate_state *s;\n    uInt b;\n{\n    put_byte(s, (Byte)(b >> 8));\n    put_byte(s, (Byte)(b & 0xff));\n}\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output, except for\n * some deflate_stored() output, goes through this function so some\n * applications may wish to modify it to avoid allocating a large\n * strm->next_out buffer and copying into it. (See also read_buf()).\n */\nlocal void flush_pending(strm)\n    z_streamp strm;\n{\n    unsigned len;\n    deflate_state *s = strm->state;\n\n    _tr_flush_bits(s);\n    len = s->pending;\n    if (len > strm->avail_out) len = strm->avail_out;\n    if (len == 0) return;\n\n    zmemcpy(strm->next_out, s->pending_out, len);\n    strm->next_out  += len;\n    s->pending_out  += len;\n    strm->total_out += len;\n    strm->avail_out -= len;\n    s->pending      -= len;\n    if (s->pending == 0) {\n        s->pending_out = s->pending_buf;\n    }\n}\n\n/* ===========================================================================\n * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1].\n */\n#define HCRC_UPDATE(beg) \\\n    do { \\\n        if (s->gzhead->hcrc && s->pending > (beg)) \\\n            strm->adler = crc32(strm->adler, s->pending_buf + (beg), \\\n                                s->pending - (beg)); \\\n    } while (0)\n\n/* ========================================================================= */\nint ZEXPORT deflate (strm, flush)\n    z_streamp strm;\n    int flush;\n{\n    int old_flush; /* value of flush param for previous deflate call */\n    deflate_state *s;\n\n    if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {\n        return Z_STREAM_ERROR;\n    }\n    s = strm->state;\n\n    if (strm->next_out == Z_NULL ||\n        (strm->avail_in != 0 && strm->next_in == Z_NULL) ||\n        (s->status == FINISH_STATE && flush != Z_FINISH)) {\n        ERR_RETURN(strm, Z_STREAM_ERROR);\n    }\n    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);\n\n    old_flush = s->last_flush;\n    s->last_flush = flush;\n\n    /* Flush as much pending output as possible */\n    if (s->pending != 0) {\n        flush_pending(strm);\n        if (strm->avail_out == 0) {\n            /* Since avail_out is 0, deflate will be called again with\n             * more output space, but possibly with both pending and\n             * avail_in equal to zero. There won't be anything to do,\n             * but this is not an error situation so make sure we\n             * return OK instead of BUF_ERROR at next call of deflate:\n             */\n            s->last_flush = -1;\n            return Z_OK;\n        }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n    } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&\n               flush != Z_FINISH) {\n        ERR_RETURN(strm, Z_BUF_ERROR);\n    }\n\n    /* User must not provide more input after the first FINISH: */\n    if (s->status == FINISH_STATE && strm->avail_in != 0) {\n        ERR_RETURN(strm, Z_BUF_ERROR);\n    }\n\n    /* Write the header */\n    if (s->status == INIT_STATE) {\n        /* zlib header */\n        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;\n        uInt level_flags;\n\n        if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)\n            level_flags = 0;\n        else if (s->level < 6)\n            level_flags = 1;\n        else if (s->level == 6)\n            level_flags = 2;\n        else\n            level_flags = 3;\n        header |= (level_flags << 6);\n        if (s->strstart != 0) header |= PRESET_DICT;\n        header += 31 - (header % 31);\n\n        putShortMSB(s, header);\n\n        /* Save the adler32 of the preset dictionary: */\n        if (s->strstart != 0) {\n            putShortMSB(s, (uInt)(strm->adler >> 16));\n            putShortMSB(s, (uInt)(strm->adler & 0xffff));\n        }\n        strm->adler = adler32(0L, Z_NULL, 0);\n        s->status = BUSY_STATE;\n\n        /* Compression must start with an empty pending buffer */\n        flush_pending(strm);\n        if (s->pending != 0) {\n            s->last_flush = -1;\n            return Z_OK;\n        }\n    }\n#ifdef GZIP\n    if (s->status == GZIP_STATE) {\n        /* gzip header */\n        strm->adler = crc32(0L, Z_NULL, 0);\n        put_byte(s, 31);\n        put_byte(s, 139);\n        put_byte(s, 8);\n        if (s->gzhead == Z_NULL) {\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, s->level == 9 ? 2 :\n                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?\n                      4 : 0));\n            put_byte(s, OS_CODE);\n            s->status = BUSY_STATE;\n\n            /* Compression must start with an empty pending buffer */\n            flush_pending(strm);\n            if (s->pending != 0) {\n                s->last_flush = -1;\n                return Z_OK;\n            }\n        }\n        else {\n            put_byte(s, (s->gzhead->text ? 1 : 0) +\n                     (s->gzhead->hcrc ? 2 : 0) +\n                     (s->gzhead->extra == Z_NULL ? 0 : 4) +\n                     (s->gzhead->name == Z_NULL ? 0 : 8) +\n                     (s->gzhead->comment == Z_NULL ? 0 : 16)\n                     );\n            put_byte(s, (Byte)(s->gzhead->time & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));\n            put_byte(s, s->level == 9 ? 2 :\n                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?\n                      4 : 0));\n            put_byte(s, s->gzhead->os & 0xff);\n            if (s->gzhead->extra != Z_NULL) {\n                put_byte(s, s->gzhead->extra_len & 0xff);\n                put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);\n            }\n            if (s->gzhead->hcrc)\n                strm->adler = crc32(strm->adler, s->pending_buf,\n                                    s->pending);\n            s->gzindex = 0;\n            s->status = EXTRA_STATE;\n        }\n    }\n    if (s->status == EXTRA_STATE) {\n        if (s->gzhead->extra != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;\n            while (s->pending + left > s->pending_buf_size) {\n                uInt copy = s->pending_buf_size - s->pending;\n                zmemcpy(s->pending_buf + s->pending,\n                        s->gzhead->extra + s->gzindex, copy);\n                s->pending = s->pending_buf_size;\n                HCRC_UPDATE(beg);\n                s->gzindex += copy;\n                flush_pending(strm);\n                if (s->pending != 0) {\n                    s->last_flush = -1;\n                    return Z_OK;\n                }\n                beg = 0;\n                left -= copy;\n            }\n            zmemcpy(s->pending_buf + s->pending,\n                    s->gzhead->extra + s->gzindex, left);\n            s->pending += left;\n            HCRC_UPDATE(beg);\n            s->gzindex = 0;\n        }\n        s->status = NAME_STATE;\n    }\n    if (s->status == NAME_STATE) {\n        if (s->gzhead->name != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            int val;\n            do {\n                if (s->pending == s->pending_buf_size) {\n                    HCRC_UPDATE(beg);\n                    flush_pending(strm);\n                    if (s->pending != 0) {\n                        s->last_flush = -1;\n                        return Z_OK;\n                    }\n                    beg = 0;\n                }\n                val = s->gzhead->name[s->gzindex++];\n                put_byte(s, val);\n            } while (val != 0);\n            HCRC_UPDATE(beg);\n            s->gzindex = 0;\n        }\n        s->status = COMMENT_STATE;\n    }\n    if (s->status == COMMENT_STATE) {\n        if (s->gzhead->comment != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            int val;\n            do {\n                if (s->pending == s->pending_buf_size) {\n                    HCRC_UPDATE(beg);\n                    flush_pending(strm);\n                    if (s->pending != 0) {\n                        s->last_flush = -1;\n                        return Z_OK;\n                    }\n                    beg = 0;\n                }\n                val = s->gzhead->comment[s->gzindex++];\n                put_byte(s, val);\n            } while (val != 0);\n            HCRC_UPDATE(beg);\n        }\n        s->status = HCRC_STATE;\n    }\n    if (s->status == HCRC_STATE) {\n        if (s->gzhead->hcrc) {\n            if (s->pending + 2 > s->pending_buf_size) {\n                flush_pending(strm);\n                if (s->pending != 0) {\n                    s->last_flush = -1;\n                    return Z_OK;\n                }\n            }\n            put_byte(s, (Byte)(strm->adler & 0xff));\n            put_byte(s, (Byte)((strm->adler >> 8) & 0xff));\n            strm->adler = crc32(0L, Z_NULL, 0);\n        }\n        s->status = BUSY_STATE;\n\n        /* Compression must start with an empty pending buffer */\n        flush_pending(strm);\n        if (s->pending != 0) {\n            s->last_flush = -1;\n            return Z_OK;\n        }\n    }\n#endif\n\n    /* Start a new block or continue the current one.\n     */\n    if (strm->avail_in != 0 || s->lookahead != 0 ||\n        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {\n        block_state bstate;\n\n        bstate = s->level == 0 ? deflate_stored(s, flush) :\n                 s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :\n                 s->strategy == Z_RLE ? deflate_rle(s, flush) :\n                 (*(configuration_table[s->level].func))(s, flush);\n\n        if (bstate == finish_started || bstate == finish_done) {\n            s->status = FINISH_STATE;\n        }\n        if (bstate == need_more || bstate == finish_started) {\n            if (strm->avail_out == 0) {\n                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */\n            }\n            return Z_OK;\n            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n             * of deflate should use the same flush parameter to make sure\n             * that the flush is complete. So we don't have to output an\n             * empty block here, this will be done at next call. This also\n             * ensures that for a very small output buffer, we emit at most\n             * one empty block.\n             */\n        }\n        if (bstate == block_done) {\n            if (flush == Z_PARTIAL_FLUSH) {\n                _tr_align(s);\n            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n                _tr_stored_block(s, (char*)0, 0L, 0);\n                /* For a full flush, this empty block will be recognized\n                 * as a special marker by inflate_sync().\n                 */\n                if (flush == Z_FULL_FLUSH) {\n                    CLEAR_HASH(s);             /* forget history */\n                    if (s->lookahead == 0) {\n                        s->strstart = 0;\n                        s->block_start = 0L;\n                        s->insert = 0;\n                    }\n                }\n            }\n            flush_pending(strm);\n            if (strm->avail_out == 0) {\n              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n              return Z_OK;\n            }\n        }\n    }\n\n    if (flush != Z_FINISH) return Z_OK;\n    if (s->wrap <= 0) return Z_STREAM_END;\n\n    /* Write the trailer */\n#ifdef GZIP\n    if (s->wrap == 2) {\n        put_byte(s, (Byte)(strm->adler & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));\n        put_byte(s, (Byte)(strm->total_in & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));\n    }\n    else\n#endif\n    {\n        putShortMSB(s, (uInt)(strm->adler >> 16));\n        putShortMSB(s, (uInt)(strm->adler & 0xffff));\n    }\n    flush_pending(strm);\n    /* If avail_out is zero, the application will call deflate again\n     * to flush the rest.\n     */\n    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */\n    return s->pending != 0 ? Z_OK : Z_STREAM_END;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateEnd (strm)\n    z_streamp strm;\n{\n    int status;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n\n    status = strm->state->status;\n\n    /* Deallocate in reverse order of allocations: */\n    TRY_FREE(strm, strm->state->pending_buf);\n    TRY_FREE(strm, strm->state->head);\n    TRY_FREE(strm, strm->state->prev);\n    TRY_FREE(strm, strm->state->window);\n\n    ZFREE(strm, strm->state);\n    strm->state = Z_NULL;\n\n    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;\n}\n\n/* =========================================================================\n * Copy the source state to the destination state.\n * To simplify the source, this is not supported for 16-bit MSDOS (which\n * doesn't have enough memory anyway to duplicate compression states).\n */\nint ZEXPORT deflateCopy (dest, source)\n    z_streamp dest;\n    z_streamp source;\n{\n#ifdef MAXSEG_64K\n    return Z_STREAM_ERROR;\n#else\n    deflate_state *ds;\n    deflate_state *ss;\n    ushf *overlay;\n\n\n    if (deflateStateCheck(source) || dest == Z_NULL) {\n        return Z_STREAM_ERROR;\n    }\n\n    ss = source->state;\n\n    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));\n\n    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));\n    if (ds == Z_NULL) return Z_MEM_ERROR;\n    dest->state = (struct internal_state FAR *) ds;\n    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));\n    ds->strm = dest;\n\n    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));\n    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));\n    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));\n    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);\n    ds->pending_buf = (uchf *) overlay;\n\n    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||\n        ds->pending_buf == Z_NULL) {\n        deflateEnd (dest);\n        return Z_MEM_ERROR;\n    }\n    /* following zmemcpy do not work for 16-bit MSDOS */\n    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));\n    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));\n    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));\n    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);\n\n    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);\n    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);\n    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;\n\n    ds->l_desc.dyn_tree = ds->dyn_ltree;\n    ds->d_desc.dyn_tree = ds->dyn_dtree;\n    ds->bl_desc.dyn_tree = ds->bl_tree;\n\n    return Z_OK;\n#endif /* MAXSEG_64K */\n}\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->next_in buffer and copying from it.\n * (See also flush_pending()).\n */\nlocal unsigned read_buf(strm, buf, size)\n    z_streamp strm;\n    Bytef *buf;\n    unsigned size;\n{\n    unsigned len = strm->avail_in;\n\n    if (len > size) len = size;\n    if (len == 0) return 0;\n\n    strm->avail_in  -= len;\n\n    zmemcpy(buf, strm->next_in, len);\n    if (strm->state->wrap == 1) {\n        strm->adler = adler32(strm->adler, buf, len);\n    }\n#ifdef GZIP\n    else if (strm->state->wrap == 2) {\n        strm->adler = crc32(strm->adler, buf, len);\n    }\n#endif\n    strm->next_in  += len;\n    strm->total_in += len;\n\n    return len;\n}\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nlocal void lm_init (s)\n    deflate_state *s;\n{\n    s->window_size = (ulg)2L*s->w_size;\n\n    CLEAR_HASH(s);\n\n    /* Set the default configuration parameters:\n     */\n    s->max_lazy_match   = configuration_table[s->level].max_lazy;\n    s->good_match       = configuration_table[s->level].good_length;\n    s->nice_match       = configuration_table[s->level].nice_length;\n    s->max_chain_length = configuration_table[s->level].max_chain;\n\n    s->strstart = 0;\n    s->block_start = 0L;\n    s->lookahead = 0;\n    s->insert = 0;\n    s->match_length = s->prev_length = MIN_MATCH-1;\n    s->match_available = 0;\n    s->ins_h = 0;\n#ifndef FASTEST\n#ifdef ASMV\n    match_init(); /* initialize the asm code */\n#endif\n#endif\n}\n\n#ifndef FASTEST\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\n#ifndef ASMV\n/* For 80x86 and 680x0, an optimized version will be provided in match.asm or\n * match.S. The code will be functionally equivalent.\n */\nlocal uInt longest_match(s, cur_match)\n    deflate_state *s;\n    IPos cur_match;                             /* current match */\n{\n    unsigned chain_length = s->max_chain_length;/* max hash chain length */\n    register Bytef *scan = s->window + s->strstart; /* current string */\n    register Bytef *match;                      /* matched string */\n    register int len;                           /* length of current match */\n    int best_len = (int)s->prev_length;         /* best match length so far */\n    int nice_match = s->nice_match;             /* stop if match long enough */\n    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?\n        s->strstart - (IPos)MAX_DIST(s) : NIL;\n    /* Stop when cur_match becomes <= limit. To simplify the code,\n     * we prevent matches with the string of window index 0.\n     */\n    Posf *prev = s->prev;\n    uInt wmask = s->w_mask;\n\n#ifdef UNALIGNED_OK\n    /* Compare two bytes at a time. Note: this is not always beneficial.\n     * Try with and without -DUNALIGNED_OK to check.\n     */\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;\n    register ush scan_start = *(ushf*)scan;\n    register ush scan_end   = *(ushf*)(scan+best_len-1);\n#else\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH;\n    register Byte scan_end1  = scan[best_len-1];\n    register Byte scan_end   = scan[best_len];\n#endif\n\n    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n     * It is easy to get rid of this optimization if necessary.\n     */\n    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n    /* Do not waste too much time if we already have a good match: */\n    if (s->prev_length >= s->good_match) {\n        chain_length >>= 2;\n    }\n    /* Do not look for matches beyond the end of the input. This is necessary\n     * to make deflate deterministic.\n     */\n    if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;\n\n    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n    do {\n        Assert(cur_match < s->strstart, \"no future\");\n        match = s->window + cur_match;\n\n        /* Skip to next match if the match length cannot increase\n         * or if the match length is less than 2.  Note that the checks below\n         * for insufficient lookahead only occur occasionally for performance\n         * reasons.  Therefore uninitialized memory will be accessed, and\n         * conditional jumps will be made that depend on those values.\n         * However the length of the match is limited to the lookahead, so\n         * the output of deflate is not affected by the uninitialized values.\n         */\n#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)\n        /* This code assumes sizeof(unsigned short) == 2. Do not use\n         * UNALIGNED_OK if your compiler uses a different size.\n         */\n        if (*(ushf*)(match+best_len-1) != scan_end ||\n            *(ushf*)match != scan_start) continue;\n\n        /* It is not necessary to compare scan[2] and match[2] since they are\n         * always equal when the other bytes match, given that the hash keys\n         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at\n         * strstart+3, +5, ... up to strstart+257. We check for insufficient\n         * lookahead only every 4th comparison; the 128th check will be made\n         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is\n         * necessary to put more guard bytes at the end of the window, or\n         * to check more often for insufficient lookahead.\n         */\n        Assert(scan[2] == match[2], \"scan[2]?\");\n        scan++, match++;\n        do {\n        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 scan < strend);\n        /* The funny \"do {}\" generates better code on most compilers */\n\n        /* Here, scan <= window+strstart+257 */\n        Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n        if (*scan == *match) scan++;\n\n        len = (MAX_MATCH - 1) - (int)(strend-scan);\n        scan = strend - (MAX_MATCH-1);\n\n#else /* UNALIGNED_OK */\n\n        if (match[best_len]   != scan_end  ||\n            match[best_len-1] != scan_end1 ||\n            *match            != *scan     ||\n            *++match          != scan[1])      continue;\n\n        /* The check at best_len-1 can be removed because it will be made\n         * again later. (This heuristic is not always a win.)\n         * It is not necessary to compare scan[2] and match[2] since they\n         * are always equal when the other bytes match, given that\n         * the hash keys are equal and that HASH_BITS >= 8.\n         */\n        scan += 2, match++;\n        Assert(*scan == *match, \"match[2]?\");\n\n        /* We check for insufficient lookahead only every 8th comparison;\n         * the 256th check will be made at strstart+258.\n         */\n        do {\n        } while (*++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 scan < strend);\n\n        Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n        len = MAX_MATCH - (int)(strend - scan);\n        scan = strend - MAX_MATCH;\n\n#endif /* UNALIGNED_OK */\n\n        if (len > best_len) {\n            s->match_start = cur_match;\n            best_len = len;\n            if (len >= nice_match) break;\n#ifdef UNALIGNED_OK\n            scan_end = *(ushf*)(scan+best_len-1);\n#else\n            scan_end1  = scan[best_len-1];\n            scan_end   = scan[best_len];\n#endif\n        }\n    } while ((cur_match = prev[cur_match & wmask]) > limit\n             && --chain_length != 0);\n\n    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;\n    return s->lookahead;\n}\n#endif /* ASMV */\n\n#else /* FASTEST */\n\n/* ---------------------------------------------------------------------------\n * Optimized version for FASTEST only\n */\nlocal uInt longest_match(s, cur_match)\n    deflate_state *s;\n    IPos cur_match;                             /* current match */\n{\n    register Bytef *scan = s->window + s->strstart; /* current string */\n    register Bytef *match;                       /* matched string */\n    register int len;                           /* length of current match */\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH;\n\n    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n     * It is easy to get rid of this optimization if necessary.\n     */\n    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n    Assert(cur_match < s->strstart, \"no future\");\n\n    match = s->window + cur_match;\n\n    /* Return failure if the match length is less than 2:\n     */\n    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;\n\n    /* The check at best_len-1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2, match += 2;\n    Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart+258.\n     */\n    do {\n    } while (*++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             scan < strend);\n\n    Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n    len = MAX_MATCH - (int)(strend - scan);\n\n    if (len < MIN_MATCH) return MIN_MATCH - 1;\n\n    s->match_start = cur_match;\n    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;\n}\n\n#endif /* FASTEST */\n\n#ifdef ZLIB_DEBUG\n\n#define EQUAL 0\n/* result of memcmp for equal strings */\n\n/* ===========================================================================\n * Check that the match at match_start is indeed a match.\n */\nlocal void check_match(s, start, match, length)\n    deflate_state *s;\n    IPos start, match;\n    int length;\n{\n    /* check that the match is indeed a match */\n    if (zmemcmp(s->window + match,\n                s->window + start, length) != EQUAL) {\n        fprintf(stderr, \" start %u, match %u, length %d\\n\",\n                start, match, length);\n        do {\n            fprintf(stderr, \"%c%c\", s->window[match++], s->window[start++]);\n        } while (--length != 0);\n        z_error(\"invalid match\");\n    }\n    if (z_verbose > 1) {\n        fprintf(stderr,\"\\\\[%d,%d]\", start-match, length);\n        do { putc(s->window[start++], stderr); } while (--length != 0);\n    }\n}\n#else\n#  define check_match(s, start, match, length)\n#endif /* ZLIB_DEBUG */\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nlocal void fill_window(s)\n    deflate_state *s;\n{\n    unsigned n;\n    unsigned more;    /* Amount of free space at the end of the window. */\n    uInt wsize = s->w_size;\n\n    Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n    do {\n        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);\n\n        /* Deal with !@#$% 64K limit: */\n        if (sizeof(int) <= 2) {\n            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n                more = wsize;\n\n            } else if (more == (unsigned)(-1)) {\n                /* Very unlikely, but possible on 16 bit machine if\n                 * strstart == 0 && lookahead == 1 (input done a byte at time)\n                 */\n                more--;\n            }\n        }\n\n        /* If the window is almost full and there is insufficient lookahead,\n         * move the upper half to the lower one to make room in the upper half.\n         */\n        if (s->strstart >= wsize+MAX_DIST(s)) {\n\n            zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more);\n            s->match_start -= wsize;\n            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */\n            s->block_start -= (long) wsize;\n            slide_hash(s);\n            more += wsize;\n        }\n        if (s->strm->avail_in == 0) break;\n\n        /* If there was no sliding:\n         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n         *    more == window_size - lookahead - strstart\n         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n         * => more >= window_size - 2*WSIZE + 2\n         * In the BIG_MEM or MMAP case (not yet supported),\n         *   window_size == input_size + MIN_LOOKAHEAD  &&\n         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n         * Otherwise, window_size == 2*WSIZE so more >= 2.\n         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n         */\n        Assert(more >= 2, \"more < 2\");\n\n        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);\n        s->lookahead += n;\n\n        /* Initialize the hash value now that we have some input: */\n        if (s->lookahead + s->insert >= MIN_MATCH) {\n            uInt str = s->strstart - s->insert;\n            s->ins_h = s->window[str];\n            UPDATE_HASH(s, s->ins_h, s->window[str + 1]);\n#if MIN_MATCH != 3\n            Call UPDATE_HASH() MIN_MATCH-3 more times\n#endif\n            while (s->insert) {\n                UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);\n#ifndef FASTEST\n                s->prev[str & s->w_mask] = s->head[s->ins_h];\n#endif\n                s->head[s->ins_h] = (Pos)str;\n                str++;\n                s->insert--;\n                if (s->lookahead + s->insert < MIN_MATCH)\n                    break;\n            }\n        }\n        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n         * but this is not important since only literal bytes will be emitted.\n         */\n\n    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);\n\n    /* If the WIN_INIT bytes after the end of the current data have never been\n     * written, then zero those bytes in order to avoid memory check reports of\n     * the use of uninitialized (or uninitialised as Julian writes) bytes by\n     * the longest match routines.  Update the high water mark for the next\n     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n     */\n    if (s->high_water < s->window_size) {\n        ulg curr = s->strstart + (ulg)(s->lookahead);\n        ulg init;\n\n        if (s->high_water < curr) {\n            /* Previous high water mark below current data -- zero WIN_INIT\n             * bytes or up to end of window, whichever is less.\n             */\n            init = s->window_size - curr;\n            if (init > WIN_INIT)\n                init = WIN_INIT;\n            zmemzero(s->window + curr, (unsigned)init);\n            s->high_water = curr + init;\n        }\n        else if (s->high_water < (ulg)curr + WIN_INIT) {\n            /* High water mark at or above current data, but below current data\n             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n             * to end of window, whichever is less.\n             */\n            init = (ulg)curr + WIN_INIT - s->high_water;\n            if (init > s->window_size - s->high_water)\n                init = s->window_size - s->high_water;\n            zmemzero(s->window + s->high_water, (unsigned)init);\n            s->high_water += init;\n        }\n    }\n\n    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n           \"not enough room for search\");\n}\n\n/* ===========================================================================\n * Flush the current block, with given end-of-file flag.\n * IN assertion: strstart is set to the end of the current match.\n */\n#define FLUSH_BLOCK_ONLY(s, last) { \\\n   _tr_flush_block(s, (s->block_start >= 0L ? \\\n                   (charf *)&s->window[(unsigned)s->block_start] : \\\n                   (charf *)Z_NULL), \\\n                (ulg)((long)s->strstart - s->block_start), \\\n                (last)); \\\n   s->block_start = s->strstart; \\\n   flush_pending(s->strm); \\\n   Tracev((stderr,\"[FLUSH]\")); \\\n}\n\n/* Same but force premature exit if necessary. */\n#define FLUSH_BLOCK(s, last) { \\\n   FLUSH_BLOCK_ONLY(s, last); \\\n   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \\\n}\n\n/* Maximum stored block length in deflate format (not including header). */\n#define MAX_STORED 65535\n\n/* Minimum of a and b. */\n#define MIN(a, b) ((a) > (b) ? (b) : (a))\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n *\n * In case deflateParams() is used to later switch to a non-zero compression\n * level, s->matches (otherwise unused when storing) keeps track of the number\n * of hash table slides to perform. If s->matches is 1, then one hash table\n * slide will be done when switching. If s->matches is 2, the maximum value\n * allowed here, then the hash table will be cleared, since two or more slides\n * is the same as a clear.\n *\n * deflate_stored() is written to minimize the number of times an input byte is\n * copied. It is most efficient with large input and output buffers, which\n * maximizes the opportunites to have a single copy from next_in to next_out.\n */\nlocal block_state deflate_stored(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    /* Smallest worthy block size when not flushing or finishing. By default\n     * this is 32K. This can be as small as 507 bytes for memLevel == 1. For\n     * large input and output buffers, the stored block size will be larger.\n     */\n    unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);\n\n    /* Copy as many min_block or larger stored blocks directly to next_out as\n     * possible. If flushing, copy the remaining available input to next_out as\n     * stored blocks, if there is enough space.\n     */\n    unsigned len, left, have, last = 0;\n    unsigned used = s->strm->avail_in;\n    do {\n        /* Set len to the maximum size block that we can copy directly with the\n         * available input data and output space. Set left to how much of that\n         * would be copied from what's left in the window.\n         */\n        len = MAX_STORED;       /* maximum deflate stored block length */\n        have = (s->bi_valid + 42) >> 3;         /* number of header bytes */\n        if (s->strm->avail_out < have)          /* need room for header */\n            break;\n            /* maximum stored block length that will fit in avail_out: */\n        have = s->strm->avail_out - have;\n        left = s->strstart - s->block_start;    /* bytes left in window */\n        if (len > (ulg)left + s->strm->avail_in)\n            len = left + s->strm->avail_in;     /* limit len to the input */\n        if (len > have)\n            len = have;                         /* limit len to the output */\n\n        /* If the stored block would be less than min_block in length, or if\n         * unable to copy all of the available input when flushing, then try\n         * copying to the window and the pending buffer instead. Also don't\n         * write an empty block when flushing -- deflate() does that.\n         */\n        if (len < min_block && ((len == 0 && flush != Z_FINISH) ||\n                                flush == Z_NO_FLUSH ||\n                                len != left + s->strm->avail_in))\n            break;\n\n        /* Make a dummy stored block in pending to get the header bytes,\n         * including any pending bits. This also updates the debugging counts.\n         */\n        last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;\n        _tr_stored_block(s, (char *)0, 0L, last);\n\n        /* Replace the lengths in the dummy stored block with len. */\n        s->pending_buf[s->pending - 4] = len;\n        s->pending_buf[s->pending - 3] = len >> 8;\n        s->pending_buf[s->pending - 2] = ~len;\n        s->pending_buf[s->pending - 1] = ~len >> 8;\n\n        /* Write the stored block header bytes. */\n        flush_pending(s->strm);\n\n#ifdef ZLIB_DEBUG\n        /* Update debugging counts for the data about to be copied. */\n        s->compressed_len += len << 3;\n        s->bits_sent += len << 3;\n#endif\n\n        /* Copy uncompressed bytes from the window to next_out. */\n        if (left) {\n            if (left > len)\n                left = len;\n            zmemcpy(s->strm->next_out, s->window + s->block_start, left);\n            s->strm->next_out += left;\n            s->strm->avail_out -= left;\n            s->strm->total_out += left;\n            s->block_start += left;\n            len -= left;\n        }\n\n        /* Copy uncompressed bytes directly from next_in to next_out, updating\n         * the check value.\n         */\n        if (len) {\n            read_buf(s->strm, s->strm->next_out, len);\n            s->strm->next_out += len;\n            s->strm->avail_out -= len;\n            s->strm->total_out += len;\n        }\n    } while (last == 0);\n\n    /* Update the sliding window with the last s->w_size bytes of the copied\n     * data, or append all of the copied data to the existing window if less\n     * than s->w_size bytes were copied. Also update the number of bytes to\n     * insert in the hash tables, in the event that deflateParams() switches to\n     * a non-zero compression level.\n     */\n    used -= s->strm->avail_in;      /* number of input bytes directly copied */\n    if (used) {\n        /* If any input was used, then no unused input remains in the window,\n         * therefore s->block_start == s->strstart.\n         */\n        if (used >= s->w_size) {    /* supplant the previous history */\n            s->matches = 2;         /* clear hash */\n            zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);\n            s->strstart = s->w_size;\n        }\n        else {\n            if (s->window_size - s->strstart <= used) {\n                /* Slide the window down. */\n                s->strstart -= s->w_size;\n                zmemcpy(s->window, s->window + s->w_size, s->strstart);\n                if (s->matches < 2)\n                    s->matches++;   /* add a pending slide_hash() */\n            }\n            zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);\n            s->strstart += used;\n        }\n        s->block_start = s->strstart;\n        s->insert += MIN(used, s->w_size - s->insert);\n    }\n    if (s->high_water < s->strstart)\n        s->high_water = s->strstart;\n\n    /* If the last block was written to next_out, then done. */\n    if (last)\n        return finish_done;\n\n    /* If flushing and all input has been consumed, then done. */\n    if (flush != Z_NO_FLUSH && flush != Z_FINISH &&\n        s->strm->avail_in == 0 && (long)s->strstart == s->block_start)\n        return block_done;\n\n    /* Fill the window with any remaining input. */\n    have = s->window_size - s->strstart - 1;\n    if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {\n        /* Slide the window down. */\n        s->block_start -= s->w_size;\n        s->strstart -= s->w_size;\n        zmemcpy(s->window, s->window + s->w_size, s->strstart);\n        if (s->matches < 2)\n            s->matches++;           /* add a pending slide_hash() */\n        have += s->w_size;          /* more space now */\n    }\n    if (have > s->strm->avail_in)\n        have = s->strm->avail_in;\n    if (have) {\n        read_buf(s->strm, s->window + s->strstart, have);\n        s->strstart += have;\n    }\n    if (s->high_water < s->strstart)\n        s->high_water = s->strstart;\n\n    /* There was not enough avail_out to write a complete worthy or flushed\n     * stored block to next_out. Write a stored block to pending instead, if we\n     * have enough input for a worthy block, or if flushing and there is enough\n     * room for the remaining input as a stored block in the pending buffer.\n     */\n    have = (s->bi_valid + 42) >> 3;         /* number of header bytes */\n        /* maximum stored block length that will fit in pending: */\n    have = MIN(s->pending_buf_size - have, MAX_STORED);\n    min_block = MIN(have, s->w_size);\n    left = s->strstart - s->block_start;\n    if (left >= min_block ||\n        ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&\n         s->strm->avail_in == 0 && left <= have)) {\n        len = MIN(left, have);\n        last = flush == Z_FINISH && s->strm->avail_in == 0 &&\n               len == left ? 1 : 0;\n        _tr_stored_block(s, (charf *)s->window + s->block_start, len, last);\n        s->block_start += len;\n        flush_pending(s->strm);\n    }\n\n    /* We've done all we can with the available input and output. */\n    return last ? finish_started : need_more;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nlocal block_state deflate_fast(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    IPos hash_head;       /* head of the hash chain */\n    int bflush;           /* set if current block must be flushed */\n\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the next match, plus MIN_MATCH bytes to insert the\n         * string following the next match.\n         */\n        if (s->lookahead < MIN_LOOKAHEAD) {\n            fill_window(s);\n            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* Insert the string window[strstart .. strstart+2] in the\n         * dictionary, and set hash_head to the head of the hash chain:\n         */\n        hash_head = NIL;\n        if (s->lookahead >= MIN_MATCH) {\n            INSERT_STRING(s, s->strstart, hash_head);\n        }\n\n        /* Find the longest match, discarding those <= prev_length.\n         * At this point we have always match_length < MIN_MATCH\n         */\n        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {\n            /* To simplify the code, we prevent matches with the string\n             * of window index 0 (in particular we have to avoid a match\n             * of the string with itself at the start of the input file).\n             */\n            s->match_length = longest_match (s, hash_head);\n            /* longest_match() sets match_start */\n        }\n        if (s->match_length >= MIN_MATCH) {\n            check_match(s, s->strstart, s->match_start, s->match_length);\n\n            _tr_tally_dist(s, s->strstart - s->match_start,\n                           s->match_length - MIN_MATCH, bflush);\n\n            s->lookahead -= s->match_length;\n\n            /* Insert new strings in the hash table only if the match length\n             * is not too large. This saves time but degrades compression.\n             */\n#ifndef FASTEST\n            if (s->match_length <= s->max_insert_length &&\n                s->lookahead >= MIN_MATCH) {\n                s->match_length--; /* string at strstart already in table */\n                do {\n                    s->strstart++;\n                    INSERT_STRING(s, s->strstart, hash_head);\n                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n                     * always MIN_MATCH bytes ahead.\n                     */\n                } while (--s->match_length != 0);\n                s->strstart++;\n            } else\n#endif\n            {\n                s->strstart += s->match_length;\n                s->match_length = 0;\n                s->ins_h = s->window[s->strstart];\n                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);\n#if MIN_MATCH != 3\n                Call UPDATE_HASH() MIN_MATCH-3 more times\n#endif\n                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n                 * matter since it will be recomputed at next deflate call.\n                 */\n            }\n        } else {\n            /* No match, output a literal byte */\n            Tracevv((stderr,\"%c\", s->window[s->strstart]));\n            _tr_tally_lit (s, s->window[s->strstart], bflush);\n            s->lookahead--;\n            s->strstart++;\n        }\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n\n#ifndef FASTEST\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nlocal block_state deflate_slow(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    IPos hash_head;          /* head of hash chain */\n    int bflush;              /* set if current block must be flushed */\n\n    /* Process the input block. */\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the next match, plus MIN_MATCH bytes to insert the\n         * string following the next match.\n         */\n        if (s->lookahead < MIN_LOOKAHEAD) {\n            fill_window(s);\n            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* Insert the string window[strstart .. strstart+2] in the\n         * dictionary, and set hash_head to the head of the hash chain:\n         */\n        hash_head = NIL;\n        if (s->lookahead >= MIN_MATCH) {\n            INSERT_STRING(s, s->strstart, hash_head);\n        }\n\n        /* Find the longest match, discarding those <= prev_length.\n         */\n        s->prev_length = s->match_length, s->prev_match = s->match_start;\n        s->match_length = MIN_MATCH-1;\n\n        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&\n            s->strstart - hash_head <= MAX_DIST(s)) {\n            /* To simplify the code, we prevent matches with the string\n             * of window index 0 (in particular we have to avoid a match\n             * of the string with itself at the start of the input file).\n             */\n            s->match_length = longest_match (s, hash_head);\n            /* longest_match() sets match_start */\n\n            if (s->match_length <= 5 && (s->strategy == Z_FILTERED\n#if TOO_FAR <= 32767\n                || (s->match_length == MIN_MATCH &&\n                    s->strstart - s->match_start > TOO_FAR)\n#endif\n                )) {\n\n                /* If prev_match is also MIN_MATCH, match_start is garbage\n                 * but we will ignore the current match anyway.\n                 */\n                s->match_length = MIN_MATCH-1;\n            }\n        }\n        /* If there was a match at the previous step and the current\n         * match is not better, output the previous match:\n         */\n        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {\n            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;\n            /* Do not insert strings in hash table beyond this. */\n\n            check_match(s, s->strstart-1, s->prev_match, s->prev_length);\n\n            _tr_tally_dist(s, s->strstart -1 - s->prev_match,\n                           s->prev_length - MIN_MATCH, bflush);\n\n            /* Insert in hash table all strings up to the end of the match.\n             * strstart-1 and strstart are already inserted. If there is not\n             * enough lookahead, the last two strings are not inserted in\n             * the hash table.\n             */\n            s->lookahead -= s->prev_length-1;\n            s->prev_length -= 2;\n            do {\n                if (++s->strstart <= max_insert) {\n                    INSERT_STRING(s, s->strstart, hash_head);\n                }\n            } while (--s->prev_length != 0);\n            s->match_available = 0;\n            s->match_length = MIN_MATCH-1;\n            s->strstart++;\n\n            if (bflush) FLUSH_BLOCK(s, 0);\n\n        } else if (s->match_available) {\n            /* If there was no match at the previous position, output a\n             * single literal. If there was a match but the current match\n             * is longer, truncate the previous match to a single literal.\n             */\n            Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n            _tr_tally_lit(s, s->window[s->strstart-1], bflush);\n            if (bflush) {\n                FLUSH_BLOCK_ONLY(s, 0);\n            }\n            s->strstart++;\n            s->lookahead--;\n            if (s->strm->avail_out == 0) return need_more;\n        } else {\n            /* There is no previous match to compare with, wait for\n             * the next step to decide.\n             */\n            s->match_available = 1;\n            s->strstart++;\n            s->lookahead--;\n        }\n    }\n    Assert (flush != Z_NO_FLUSH, \"no flush?\");\n    if (s->match_available) {\n        Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n        _tr_tally_lit(s, s->window[s->strstart-1], bflush);\n        s->match_available = 0;\n    }\n    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n#endif /* FASTEST */\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nlocal block_state deflate_rle(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    int bflush;             /* set if current block must be flushed */\n    uInt prev;              /* byte at distance one to match */\n    Bytef *scan, *strend;   /* scan goes up to strend for length of run */\n\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the longest run, plus one for the unrolled loop.\n         */\n        if (s->lookahead <= MAX_MATCH) {\n            fill_window(s);\n            if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* See how many times the previous byte repeats */\n        s->match_length = 0;\n        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {\n            scan = s->window + s->strstart - 1;\n            prev = *scan;\n            if (prev == *++scan && prev == *++scan && prev == *++scan) {\n                strend = s->window + s->strstart + MAX_MATCH;\n                do {\n                } while (prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         scan < strend);\n                s->match_length = MAX_MATCH - (uInt)(strend - scan);\n                if (s->match_length > s->lookahead)\n                    s->match_length = s->lookahead;\n            }\n            Assert(scan <= s->window+(uInt)(s->window_size-1), \"wild scan\");\n        }\n\n        /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n        if (s->match_length >= MIN_MATCH) {\n            check_match(s, s->strstart, s->strstart - 1, s->match_length);\n\n            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);\n\n            s->lookahead -= s->match_length;\n            s->strstart += s->match_length;\n            s->match_length = 0;\n        } else {\n            /* No match, output a literal byte */\n            Tracevv((stderr,\"%c\", s->window[s->strstart]));\n            _tr_tally_lit (s, s->window[s->strstart], bflush);\n            s->lookahead--;\n            s->strstart++;\n        }\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = 0;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nlocal block_state deflate_huff(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    int bflush;             /* set if current block must be flushed */\n\n    for (;;) {\n        /* Make sure that we have a literal to write. */\n        if (s->lookahead == 0) {\n            fill_window(s);\n            if (s->lookahead == 0) {\n                if (flush == Z_NO_FLUSH)\n                    return need_more;\n                break;      /* flush the current block */\n            }\n        }\n\n        /* Output a literal byte */\n        s->match_length = 0;\n        Tracevv((stderr,\"%c\", s->window[s->strstart]));\n        _tr_tally_lit (s, s->window[s->strstart], bflush);\n        s->lookahead--;\n        s->strstart++;\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = 0;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n"
  },
  {
    "path": "deps/CascLib/src/zlib/deflate.h",
    "content": "/* deflate.h -- internal compression state\n * Copyright (C) 1995-2016 Jean-loup Gailly\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* @(#) $Id$ */\n\n#ifndef DEFLATE_H\n#define DEFLATE_H\n\n#include \"zutil.h\"\n\n/* define NO_GZIP when compiling if you want to disable gzip header and\n   trailer creation by deflate().  NO_GZIP would be used to avoid linking in\n   the crc code when it is not needed.  For shared libraries, gzip encoding\n   should be left enabled. */\n#ifndef NO_GZIP\n#  define GZIP\n#endif\n\n/* ===========================================================================\n * Internal compression state.\n */\n\n#define LENGTH_CODES 29\n/* number of length codes, not counting the special END_BLOCK code */\n\n#define LITERALS  256\n/* number of literal bytes 0..255 */\n\n#define L_CODES (LITERALS+1+LENGTH_CODES)\n/* number of Literal or Length codes, including the END_BLOCK code */\n\n#define D_CODES   30\n/* number of distance codes */\n\n#define BL_CODES  19\n/* number of codes used to transfer the bit lengths */\n\n#define HEAP_SIZE (2*L_CODES+1)\n/* maximum heap size */\n\n#define MAX_BITS 15\n/* All codes must not exceed MAX_BITS bits */\n\n#define Buf_size 16\n/* size of bit buffer in bi_buf */\n\n#define INIT_STATE    42    /* zlib header -> BUSY_STATE */\n#ifdef GZIP\n#  define GZIP_STATE  57    /* gzip header -> BUSY_STATE | EXTRA_STATE */\n#endif\n#define EXTRA_STATE   69    /* gzip extra block -> NAME_STATE */\n#define NAME_STATE    73    /* gzip file name -> COMMENT_STATE */\n#define COMMENT_STATE 91    /* gzip comment -> HCRC_STATE */\n#define HCRC_STATE   103    /* gzip header CRC -> BUSY_STATE */\n#define BUSY_STATE   113    /* deflate -> FINISH_STATE */\n#define FINISH_STATE 666    /* stream complete */\n/* Stream status */\n\n\n/* Data structure describing a single value and its code string. */\ntypedef struct ct_data_s {\n    union {\n        ush  freq;       /* frequency count */\n        ush  code;       /* bit string */\n    } fc;\n    union {\n        ush  dad;        /* father node in Huffman tree */\n        ush  len;        /* length of bit string */\n    } dl;\n} FAR ct_data;\n\n#define Freq fc.freq\n#define Code fc.code\n#define Dad  dl.dad\n#define Len  dl.len\n\ntypedef struct static_tree_desc_s  static_tree_desc;\n\ntypedef struct tree_desc_s {\n    ct_data *dyn_tree;           /* the dynamic tree */\n    int     max_code;            /* largest code with non zero frequency */\n    const static_tree_desc *stat_desc;  /* the corresponding static tree */\n} FAR tree_desc;\n\ntypedef ush Pos;\ntypedef Pos FAR Posf;\ntypedef unsigned IPos;\n\n/* A Pos is an index in the character window. We use short instead of int to\n * save space in the various tables. IPos is used only for parameter passing.\n */\n\ntypedef struct internal_state {\n    z_streamp strm;      /* pointer back to this zlib stream */\n    int   status;        /* as the name implies */\n    Bytef *pending_buf;  /* output still pending */\n    ulg   pending_buf_size; /* size of pending_buf */\n    Bytef *pending_out;  /* next pending byte to output to the stream */\n    ulg   pending;       /* nb of bytes in the pending buffer */\n    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */\n    gz_headerp  gzhead;  /* gzip header information to write */\n    ulg   gzindex;       /* where in extra, name, or comment */\n    Byte  method;        /* can only be DEFLATED */\n    int   last_flush;    /* value of flush param for previous deflate call */\n\n                /* used by deflate.c: */\n\n    uInt  w_size;        /* LZ77 window size (32K by default) */\n    uInt  w_bits;        /* log2(w_size)  (8..16) */\n    uInt  w_mask;        /* w_size - 1 */\n\n    Bytef *window;\n    /* Sliding window. Input bytes are read into the second half of the window,\n     * and move to the first half later to keep a dictionary of at least wSize\n     * bytes. With this organization, matches are limited to a distance of\n     * wSize-MAX_MATCH bytes, but this ensures that IO is always\n     * performed with a length multiple of the block size. Also, it limits\n     * the window size to 64K, which is quite useful on MSDOS.\n     * To do: use the user input buffer as sliding window.\n     */\n\n    ulg window_size;\n    /* Actual size of window: 2*wSize, except when the user input buffer\n     * is directly used as sliding window.\n     */\n\n    Posf *prev;\n    /* Link to older string with same hash index. To limit the size of this\n     * array to 64K, this link is maintained only for the last 32K strings.\n     * An index in this array is thus a window index modulo 32K.\n     */\n\n    Posf *head; /* Heads of the hash chains or NIL. */\n\n    uInt  ins_h;          /* hash index of string to be inserted */\n    uInt  hash_size;      /* number of elements in hash table */\n    uInt  hash_bits;      /* log2(hash_size) */\n    uInt  hash_mask;      /* hash_size-1 */\n\n    uInt  hash_shift;\n    /* Number of bits by which ins_h must be shifted at each input\n     * step. It must be such that after MIN_MATCH steps, the oldest\n     * byte no longer takes part in the hash key, that is:\n     *   hash_shift * MIN_MATCH >= hash_bits\n     */\n\n    long block_start;\n    /* Window position at the beginning of the current output block. Gets\n     * negative when the window is moved backwards.\n     */\n\n    uInt match_length;           /* length of best match */\n    IPos prev_match;             /* previous match */\n    int match_available;         /* set if previous match exists */\n    uInt strstart;               /* start of string to insert */\n    uInt match_start;            /* start of matching string */\n    uInt lookahead;              /* number of valid bytes ahead in window */\n\n    uInt prev_length;\n    /* Length of the best match at previous step. Matches not greater than this\n     * are discarded. This is used in the lazy match evaluation.\n     */\n\n    uInt max_chain_length;\n    /* To speed up deflation, hash chains are never searched beyond this\n     * length.  A higher limit improves compression ratio but degrades the\n     * speed.\n     */\n\n    uInt max_lazy_match;\n    /* Attempt to find a better match only when the current match is strictly\n     * smaller than this value. This mechanism is used only for compression\n     * levels >= 4.\n     */\n#   define max_insert_length  max_lazy_match\n    /* Insert new strings in the hash table only if the match length is not\n     * greater than this length. This saves time but degrades compression.\n     * max_insert_length is used only for compression levels <= 3.\n     */\n\n    int level;    /* compression level (1..9) */\n    int strategy; /* favor or force Huffman coding*/\n\n    uInt good_match;\n    /* Use a faster search when the previous match is longer than this */\n\n    int nice_match; /* Stop searching when current match exceeds this */\n\n                /* used by trees.c: */\n    /* Didn't use ct_data typedef below to suppress compiler warning */\n    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n    struct tree_desc_s l_desc;               /* desc. for literal tree */\n    struct tree_desc_s d_desc;               /* desc. for distance tree */\n    struct tree_desc_s bl_desc;              /* desc. for bit length tree */\n\n    ush bl_count[MAX_BITS+1];\n    /* number of codes at each bit length for an optimal tree */\n\n    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n    int heap_len;               /* number of elements in the heap */\n    int heap_max;               /* element of largest frequency */\n    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n     * The same heap array is used to build all trees.\n     */\n\n    uch depth[2*L_CODES+1];\n    /* Depth of each subtree used as tie breaker for trees of equal frequency\n     */\n\n    uchf *l_buf;          /* buffer for literals or lengths */\n\n    uInt  lit_bufsize;\n    /* Size of match buffer for literals/lengths.  There are 4 reasons for\n     * limiting lit_bufsize to 64K:\n     *   - frequencies can be kept in 16 bit counters\n     *   - if compression is not successful for the first block, all input\n     *     data is still in the window so we can still emit a stored block even\n     *     when input comes from standard input.  (This can also be done for\n     *     all blocks if lit_bufsize is not greater than 32K.)\n     *   - if compression is not successful for a file smaller than 64K, we can\n     *     even emit a stored file instead of a stored block (saving 5 bytes).\n     *     This is applicable only for zip (not gzip or zlib).\n     *   - creating new Huffman trees less frequently may not provide fast\n     *     adaptation to changes in the input data statistics. (Take for\n     *     example a binary file with poorly compressible code followed by\n     *     a highly compressible string table.) Smaller buffer sizes give\n     *     fast adaptation but have of course the overhead of transmitting\n     *     trees more frequently.\n     *   - I can't count above 4\n     */\n\n    uInt last_lit;      /* running index in l_buf */\n\n    ushf *d_buf;\n    /* Buffer for distances. To simplify the code, d_buf and l_buf have\n     * the same number of elements. To use different lengths, an extra flag\n     * array would be necessary.\n     */\n\n    ulg opt_len;        /* bit length of current block with optimal trees */\n    ulg static_len;     /* bit length of current block with static trees */\n    uInt matches;       /* number of string matches in current block */\n    uInt insert;        /* bytes at end of window left to insert */\n\n#ifdef ZLIB_DEBUG\n    ulg compressed_len; /* total bit length of compressed file mod 2^32 */\n    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */\n#endif\n\n    ush bi_buf;\n    /* Output buffer. bits are inserted starting at the bottom (least\n     * significant bits).\n     */\n    int bi_valid;\n    /* Number of valid bits in bi_buf.  All bits above the last valid bit\n     * are always zero.\n     */\n\n    ulg high_water;\n    /* High water mark offset in window for initialized bytes -- bytes above\n     * this are set to zero in order to avoid memory check warnings when\n     * longest match routines access bytes past the input.  This is then\n     * updated to the new high water mark.\n     */\n\n} FAR deflate_state;\n\n/* Output a byte on the stream.\n * IN assertion: there is enough room in pending_buf.\n */\n#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}\n\n\n#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)\n/* Minimum amount of lookahead, except at the end of the input file.\n * See deflate.c for comments about the MIN_MATCH+1.\n */\n\n#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)\n/* In order to simplify the code, particularly on 16 bit machines, match\n * distances are limited to MAX_DIST instead of WSIZE.\n */\n\n#define WIN_INIT MAX_MATCH\n/* Number of bytes after end of data in window to initialize in order to avoid\n   memory checker errors from longest match routines */\n\n        /* in trees.c */\nvoid ZLIB_INTERNAL _tr_init OF((deflate_state *s));\nint ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));\nvoid ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,\n                        ulg stored_len, int last));\nvoid ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));\nvoid ZLIB_INTERNAL _tr_align OF((deflate_state *s));\nvoid ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,\n                        ulg stored_len, int last));\n\n#define d_code(dist) \\\n   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])\n/* Mapping from a distance to a distance code. dist is the distance - 1 and\n * must not have side effects. _dist_code[256] and _dist_code[257] are never\n * used.\n */\n\n#ifndef ZLIB_DEBUG\n/* Inline versions of _tr_tally for speed: */\n\n#if defined(GEN_TREES_H) || !defined(STDC)\n  extern uch ZLIB_INTERNAL _length_code[];\n  extern uch ZLIB_INTERNAL _dist_code[];\n#else\n  extern const uch ZLIB_INTERNAL _length_code[];\n  extern const uch ZLIB_INTERNAL _dist_code[];\n#endif\n\n# define _tr_tally_lit(s, c, flush) \\\n  { uch cc = (c); \\\n    s->d_buf[s->last_lit] = 0; \\\n    s->l_buf[s->last_lit++] = cc; \\\n    s->dyn_ltree[cc].Freq++; \\\n    flush = (s->last_lit == s->lit_bufsize-1); \\\n   }\n# define _tr_tally_dist(s, distance, length, flush) \\\n  { uch len = (uch)(length); \\\n    ush dist = (ush)(distance); \\\n    s->d_buf[s->last_lit] = dist; \\\n    s->l_buf[s->last_lit++] = len; \\\n    dist--; \\\n    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \\\n    s->dyn_dtree[d_code(dist)].Freq++; \\\n    flush = (s->last_lit == s->lit_bufsize-1); \\\n  }\n#else\n# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)\n# define _tr_tally_dist(s, distance, length, flush) \\\n              flush = _tr_tally(s, distance, length)\n#endif\n\n#endif /* DEFLATE_H */\n"
  },
  {
    "path": "deps/CascLib/src/zlib/gzguts.h",
    "content": "/* gzguts.h -- zlib internal header definitions for gz* operations\n * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#ifdef _LARGEFILE64_SOURCE\n#  ifndef _LARGEFILE_SOURCE\n#    define _LARGEFILE_SOURCE 1\n#  endif\n#  ifdef _FILE_OFFSET_BITS\n#    undef _FILE_OFFSET_BITS\n#  endif\n#endif\n\n#ifdef HAVE_HIDDEN\n#  define ZLIB_INTERNAL __attribute__((visibility (\"hidden\")))\n#else\n#  define ZLIB_INTERNAL\n#endif\n\n#include <stdio.h>\n#include \"zlib.h\"\n#ifdef STDC\n#  include <string.h>\n#  include <stdlib.h>\n#  include <limits.h>\n#endif\n\n#ifndef _POSIX_SOURCE\n#  define _POSIX_SOURCE\n#endif\n#include <fcntl.h>\n\n#ifdef _WIN32\n#  include <stddef.h>\n#endif\n\n#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)\n#  include <io.h>\n#endif\n\n#if defined(_WIN32) || defined(__CYGWIN__)\n#  define WIDECHAR\n#endif\n\n#ifdef WINAPI_FAMILY\n#  define open _open\n#  define read _read\n#  define write _write\n#  define close _close\n#endif\n\n#ifdef NO_DEFLATE       /* for compatibility with old definition */\n#  define NO_GZCOMPRESS\n#endif\n\n#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#if defined(__CYGWIN__)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#ifndef HAVE_VSNPRINTF\n#  ifdef MSDOS\n/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),\n   but for now we just assume it doesn't. */\n#    define NO_vsnprintf\n#  endif\n#  ifdef __TURBOC__\n#    define NO_vsnprintf\n#  endif\n#  ifdef WIN32\n/* In Win32, vsnprintf is available as the \"non-ANSI\" _vsnprintf. */\n#    if !defined(vsnprintf) && !defined(NO_vsnprintf)\n#      if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )\n#         define vsnprintf _vsnprintf\n#      endif\n#    endif\n#  endif\n#  ifdef __SASC\n#    define NO_vsnprintf\n#  endif\n#  ifdef VMS\n#    define NO_vsnprintf\n#  endif\n#  ifdef __OS400__\n#    define NO_vsnprintf\n#  endif\n#  ifdef __MVS__\n#    define NO_vsnprintf\n#  endif\n#endif\n\n/* unlike snprintf (which is required in C99), _snprintf does not guarantee\n   null termination of the result -- however this is only used in gzlib.c where\n   the result is assured to fit in the space provided */\n#if defined(_MSC_VER) && _MSC_VER < 1900\n#  define snprintf _snprintf\n#endif\n\n#ifndef local\n#  define local static\n#endif\n/* since \"static\" is used to mean two completely different things in C, we\n   define \"local\" for the non-static meaning of \"static\", for readability\n   (compile with -Dlocal if your debugger can't find static symbols) */\n\n/* gz* functions always use library allocation functions */\n#ifndef STDC\n  extern voidp  malloc OF((uInt size));\n  extern void   free   OF((voidpf ptr));\n#endif\n\n/* get errno and strerror definition */\n#if defined UNDER_CE\n#  include <windows.h>\n#  define zstrerror() gz_strwinerror((DWORD)GetLastError())\n#else\n#  ifndef NO_STRERROR\n#    include <errno.h>\n#    define zstrerror() strerror(errno)\n#  else\n#    define zstrerror() \"stdio error (consult errno)\"\n#  endif\n#endif\n\n/* provide prototypes for these when building zlib without LFS */\n#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0\n    ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));\n    ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));\n    ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));\n    ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));\n#endif\n\n/* default memLevel */\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n\n/* default i/o buffer size -- double this for output when reading (this and\n   twice this must be able to fit in an unsigned type) */\n#define GZBUFSIZE 8192\n\n/* gzip modes, also provide a little integrity check on the passed structure */\n#define GZ_NONE 0\n#define GZ_READ 7247\n#define GZ_WRITE 31153\n#define GZ_APPEND 1     /* mode set to GZ_WRITE after the file is opened */\n\n/* values for gz_state how */\n#define LOOK 0      /* look for a gzip header */\n#define COPY 1      /* copy input directly */\n#define GZIP 2      /* decompress a gzip stream */\n\n/* internal gzip file state data structure */\ntypedef struct {\n        /* exposed contents for gzgetc() macro */\n    struct gzFile_s x;      /* \"x\" for exposed */\n                            /* x.have: number of bytes available at x.next */\n                            /* x.next: next output data to deliver or write */\n                            /* x.pos: current position in uncompressed data */\n        /* used for both reading and writing */\n    int mode;               /* see gzip modes above */\n    int fd;                 /* file descriptor */\n    char *path;             /* path or fd for error messages */\n    unsigned size;          /* buffer size, zero if not allocated yet */\n    unsigned want;          /* requested buffer size, default is GZBUFSIZE */\n    unsigned char *in;      /* input buffer (double-sized when writing) */\n    unsigned char *out;     /* output buffer (double-sized when reading) */\n    int direct;             /* 0 if processing gzip, 1 if transparent */\n        /* just for reading */\n    int how;                /* 0: get header, 1: copy, 2: decompress */\n    z_off64_t start;        /* where the gzip data started, for rewinding */\n    int eof;                /* true if end of input file reached */\n    int past;               /* true if read requested past end */\n        /* just for writing */\n    int level;              /* compression level */\n    int strategy;           /* compression strategy */\n        /* seek request */\n    z_off64_t skip;         /* amount to skip (already rewound if backwards) */\n    int seek;               /* true if seek request pending */\n        /* error information */\n    int err;                /* error code */\n    char *msg;              /* error message */\n        /* zlib inflate or deflate stream */\n    z_stream strm;          /* stream structure in-place (not a pointer) */\n} gz_state;\ntypedef gz_state FAR *gz_statep;\n\n/* shared functions */\nvoid ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));\n#if defined UNDER_CE\nchar ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));\n#endif\n\n/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t\n   value -- needed when comparing unsigned to z_off64_t, which is signed\n   (possible z_off64_t types off_t, off64_t, and long are all signed) */\n#ifdef INT_MAX\n#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)\n#else\nunsigned ZLIB_INTERNAL gz_intmax OF((void));\n#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())\n#endif\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inffast.c",
    "content": "/* inffast.c -- fast decoding\n * Copyright (C) 1995-2017 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n#include \"inflate.h\"\n#include \"inffast.h\"\n\n#ifdef ASMINF\n#  pragma message(\"Assembler code may have bugs -- use at your own risk\")\n#else\n\n/*\n   Decode literal, length, and distance codes and write out the resulting\n   literal and match bytes until either not enough input or output is\n   available, an end-of-block is encountered, or a data error is encountered.\n   When large enough input and output buffers are supplied to inflate(), for\n   example, a 16K input buffer and a 64K output buffer, more than 95% of the\n   inflate execution time is spent in this routine.\n\n   Entry assumptions:\n\n        state->mode == LEN\n        strm->avail_in >= 6\n        strm->avail_out >= 258\n        start >= strm->avail_out\n        state->bits < 8\n\n   On return, state->mode is one of:\n\n        LEN -- ran out of enough output space or enough available input\n        TYPE -- reached end of block code, inflate() to interpret next block\n        BAD -- error in block data\n\n   Notes:\n\n    - The maximum input bits used by a length/distance pair is 15 bits for the\n      length code, 5 bits for the length extra, 15 bits for the distance code,\n      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.\n      Therefore if strm->avail_in >= 6, then there is enough input to avoid\n      checking for available input while decoding.\n\n    - The maximum bytes that a single length/distance pair can output is 258\n      bytes, which is the maximum length that can be coded.  inflate_fast()\n      requires strm->avail_out >= 258 for each loop to avoid checking for\n      output space.\n */\nvoid ZLIB_INTERNAL inflate_fast(strm, start)\nz_streamp strm;\nunsigned start;         /* inflate()'s starting value for strm->avail_out */\n{\n    struct inflate_state FAR *state;\n    z_const unsigned char FAR *in;      /* local strm->next_in */\n    z_const unsigned char FAR *last;    /* have enough input while in < last */\n    unsigned char FAR *out;     /* local strm->next_out */\n    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */\n    unsigned char FAR *end;     /* while out < end, enough space available */\n#ifdef INFLATE_STRICT\n    unsigned dmax;              /* maximum distance from zlib header */\n#endif\n    unsigned wsize;             /* window size or zero if not using window */\n    unsigned whave;             /* valid bytes in the window */\n    unsigned wnext;             /* window write index */\n    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */\n    unsigned long hold;         /* local strm->hold */\n    unsigned bits;              /* local strm->bits */\n    code const FAR *lcode;      /* local strm->lencode */\n    code const FAR *dcode;      /* local strm->distcode */\n    unsigned lmask;             /* mask for first level of length codes */\n    unsigned dmask;             /* mask for first level of distance codes */\n    code here;                  /* retrieved table entry */\n    unsigned op;                /* code bits, operation, extra bits, or */\n                                /*  window position, window bytes to copy */\n    unsigned len;               /* match length, unused bytes */\n    unsigned dist;              /* match distance */\n    unsigned char FAR *from;    /* where to copy match from */\n\n    /* copy state to local variables */\n    state = (struct inflate_state FAR *)strm->state;\n    in = strm->next_in;\n    last = in + (strm->avail_in - 5);\n    out = strm->next_out;\n    beg = out - (start - strm->avail_out);\n    end = out + (strm->avail_out - 257);\n#ifdef INFLATE_STRICT\n    dmax = state->dmax;\n#endif\n    wsize = state->wsize;\n    whave = state->whave;\n    wnext = state->wnext;\n    window = state->window;\n    hold = state->hold;\n    bits = state->bits;\n    lcode = state->lencode;\n    dcode = state->distcode;\n    lmask = (1U << state->lenbits) - 1;\n    dmask = (1U << state->distbits) - 1;\n\n    /* decode literals and length/distances until end-of-block or not enough\n       input data or output space */\n    do {\n        if (bits < 15) {\n            hold += (unsigned long)(*in++) << bits;\n            bits += 8;\n            hold += (unsigned long)(*in++) << bits;\n            bits += 8;\n        }\n        here = lcode[hold & lmask];\n      dolen:\n        op = (unsigned)(here.bits);\n        hold >>= op;\n        bits -= op;\n        op = (unsigned)(here.op);\n        if (op == 0) {                          /* literal */\n            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n                    \"inflate:         literal '%c'\\n\" :\n                    \"inflate:         literal 0x%02x\\n\", here.val));\n            *out++ = (unsigned char)(here.val);\n        }\n        else if (op & 16) {                     /* length base */\n            len = (unsigned)(here.val);\n            op &= 15;                           /* number of extra bits */\n            if (op) {\n                if (bits < op) {\n                    hold += (unsigned long)(*in++) << bits;\n                    bits += 8;\n                }\n                len += (unsigned)hold & ((1U << op) - 1);\n                hold >>= op;\n                bits -= op;\n            }\n            Tracevv((stderr, \"inflate:         length %u\\n\", len));\n            if (bits < 15) {\n                hold += (unsigned long)(*in++) << bits;\n                bits += 8;\n                hold += (unsigned long)(*in++) << bits;\n                bits += 8;\n            }\n            here = dcode[hold & dmask];\n          dodist:\n            op = (unsigned)(here.bits);\n            hold >>= op;\n            bits -= op;\n            op = (unsigned)(here.op);\n            if (op & 16) {                      /* distance base */\n                dist = (unsigned)(here.val);\n                op &= 15;                       /* number of extra bits */\n                if (bits < op) {\n                    hold += (unsigned long)(*in++) << bits;\n                    bits += 8;\n                    if (bits < op) {\n                        hold += (unsigned long)(*in++) << bits;\n                        bits += 8;\n                    }\n                }\n                dist += (unsigned)hold & ((1U << op) - 1);\n#ifdef INFLATE_STRICT\n                if (dist > dmax) {\n                    strm->msg = (char *)\"invalid distance too far back\";\n                    state->mode = BAD;\n                    break;\n                }\n#endif\n                hold >>= op;\n                bits -= op;\n                Tracevv((stderr, \"inflate:         distance %u\\n\", dist));\n                op = (unsigned)(out - beg);     /* max distance in output */\n                if (dist > op) {                /* see if copy from window */\n                    op = dist - op;             /* distance back in window */\n                    if (op > whave) {\n                        if (state->sane) {\n                            strm->msg =\n                                (char *)\"invalid distance too far back\";\n                            state->mode = BAD;\n                            break;\n                        }\n#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n                        if (len <= op - whave) {\n                            do {\n                                *out++ = 0;\n                            } while (--len);\n                            continue;\n                        }\n                        len -= op - whave;\n                        do {\n                            *out++ = 0;\n                        } while (--op > whave);\n                        if (op == 0) {\n                            from = out - dist;\n                            do {\n                                *out++ = *from++;\n                            } while (--len);\n                            continue;\n                        }\n#endif\n                    }\n                    from = window;\n                    if (wnext == 0) {           /* very common case */\n                        from += wsize - op;\n                        if (op < len) {         /* some from window */\n                            len -= op;\n                            do {\n                                *out++ = *from++;\n                            } while (--op);\n                            from = out - dist;  /* rest from output */\n                        }\n                    }\n                    else if (wnext < op) {      /* wrap around window */\n                        from += wsize + wnext - op;\n                        op -= wnext;\n                        if (op < len) {         /* some from end of window */\n                            len -= op;\n                            do {\n                                *out++ = *from++;\n                            } while (--op);\n                            from = window;\n                            if (wnext < len) {  /* some from start of window */\n                                op = wnext;\n                                len -= op;\n                                do {\n                                    *out++ = *from++;\n                                } while (--op);\n                                from = out - dist;      /* rest from output */\n                            }\n                        }\n                    }\n                    else {                      /* contiguous in window */\n                        from += wnext - op;\n                        if (op < len) {         /* some from window */\n                            len -= op;\n                            do {\n                                *out++ = *from++;\n                            } while (--op);\n                            from = out - dist;  /* rest from output */\n                        }\n                    }\n                    while (len > 2) {\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        len -= 3;\n                    }\n                    if (len) {\n                        *out++ = *from++;\n                        if (len > 1)\n                            *out++ = *from++;\n                    }\n                }\n                else {\n                    from = out - dist;          /* copy direct from output */\n                    do {                        /* minimum length is three */\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        len -= 3;\n                    } while (len > 2);\n                    if (len) {\n                        *out++ = *from++;\n                        if (len > 1)\n                            *out++ = *from++;\n                    }\n                }\n            }\n            else if ((op & 64) == 0) {          /* 2nd level distance code */\n                here = dcode[here.val + (hold & ((1U << op) - 1))];\n                goto dodist;\n            }\n            else {\n                strm->msg = (char *)\"invalid distance code\";\n                state->mode = BAD;\n                break;\n            }\n        }\n        else if ((op & 64) == 0) {              /* 2nd level length code */\n            here = lcode[here.val + (hold & ((1U << op) - 1))];\n            goto dolen;\n        }\n        else if (op & 32) {                     /* end-of-block */\n            Tracevv((stderr, \"inflate:         end of block\\n\"));\n            state->mode = TYPE;\n            break;\n        }\n        else {\n            strm->msg = (char *)\"invalid literal/length code\";\n            state->mode = BAD;\n            break;\n        }\n    } while (in < last && out < end);\n\n    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */\n    len = bits >> 3;\n    in -= len;\n    bits -= len << 3;\n    hold &= (1U << bits) - 1;\n\n    /* update state and return */\n    strm->next_in = in;\n    strm->next_out = out;\n    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));\n    strm->avail_out = (unsigned)(out < end ?\n                                 257 + (end - out) : 257 - (out - end));\n    state->hold = hold;\n    state->bits = bits;\n    return;\n}\n\n/*\n   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):\n   - Using bit fields for code structure\n   - Different op definition to avoid & for extra bits (do & for table bits)\n   - Three separate decoding do-loops for direct, window, and wnext == 0\n   - Special case for distance > 1 copies to do overlapped load and store copy\n   - Explicit branch predictions (based on measured branch probabilities)\n   - Deferring match copy and interspersed it with decoding subsequent codes\n   - Swapping literal/length else\n   - Swapping window/direct else\n   - Larger unrolled copy loops (three is about right)\n   - Moving len -= 3 statement into middle of loop\n */\n\n#endif /* !ASMINF */\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inffast.h",
    "content": "/* inffast.h -- header to use inffast.c\n * Copyright (C) 1995-2003, 2010 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\nvoid ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inffixed.h",
    "content": "    /* inffixed.h -- table for decoding fixed codes\n     * Generated automatically by makefixed().\n     */\n\n    /* WARNING: this file should *not* be used by applications.\n       It is part of the implementation of this library and is\n       subject to change. Applications should only use zlib.h.\n     */\n\n    static const code lenfix[512] = {\n        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},\n        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},\n        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},\n        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},\n        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},\n        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},\n        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},\n        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},\n        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},\n        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},\n        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},\n        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},\n        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},\n        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},\n        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},\n        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},\n        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},\n        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},\n        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},\n        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},\n        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},\n        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},\n        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},\n        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},\n        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},\n        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},\n        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},\n        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},\n        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},\n        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},\n        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},\n        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},\n        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},\n        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},\n        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},\n        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},\n        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},\n        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},\n        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},\n        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},\n        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},\n        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},\n        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},\n        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},\n        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},\n        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},\n        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},\n        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},\n        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},\n        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},\n        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},\n        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},\n        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},\n        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},\n        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},\n        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},\n        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},\n        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},\n        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},\n        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},\n        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},\n        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},\n        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},\n        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},\n        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},\n        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},\n        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},\n        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},\n        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},\n        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},\n        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},\n        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},\n        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},\n        {0,9,255}\n    };\n\n    static const code distfix[32] = {\n        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},\n        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},\n        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},\n        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},\n        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},\n        {22,5,193},{64,5,0}\n    };\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inflate.c",
    "content": "/* inflate.c -- zlib decompression\n * Copyright (C) 1995-2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n * Change history:\n *\n * 1.2.beta0    24 Nov 2002\n * - First version -- complete rewrite of inflate to simplify code, avoid\n *   creation of window when not needed, minimize use of window when it is\n *   needed, make inffast.c even faster, implement gzip decoding, and to\n *   improve code readability and style over the previous zlib inflate code\n *\n * 1.2.beta1    25 Nov 2002\n * - Use pointers for available input and output checking in inffast.c\n * - Remove input and output counters in inffast.c\n * - Change inffast.c entry and loop from avail_in >= 7 to >= 6\n * - Remove unnecessary second byte pull from length extra in inffast.c\n * - Unroll direct copy to three copies per loop in inffast.c\n *\n * 1.2.beta2    4 Dec 2002\n * - Change external routine names to reduce potential conflicts\n * - Correct filename to inffixed.h for fixed tables in inflate.c\n * - Make hbuf[] unsigned char to match parameter type in inflate.c\n * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)\n *   to avoid negation problem on Alphas (64 bit) in inflate.c\n *\n * 1.2.beta3    22 Dec 2002\n * - Add comments on state->bits assertion in inffast.c\n * - Add comments on op field in inftrees.h\n * - Fix bug in reuse of allocated window after inflateReset()\n * - Remove bit fields--back to byte structure for speed\n * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths\n * - Change post-increments to pre-increments in inflate_fast(), PPC biased?\n * - Add compile time option, POSTINC, to use post-increments instead (Intel?)\n * - Make MATCH copy in inflate() much faster for when inflate_fast() not used\n * - Use local copies of stream next and avail values, as well as local bit\n *   buffer and bit count in inflate()--for speed when inflate_fast() not used\n *\n * 1.2.beta4    1 Jan 2003\n * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings\n * - Move a comment on output buffer sizes from inffast.c to inflate.c\n * - Add comments in inffast.c to introduce the inflate_fast() routine\n * - Rearrange window copies in inflate_fast() for speed and simplification\n * - Unroll last copy for window match in inflate_fast()\n * - Use local copies of window variables in inflate_fast() for speed\n * - Pull out common wnext == 0 case for speed in inflate_fast()\n * - Make op and len in inflate_fast() unsigned for consistency\n * - Add FAR to lcode and dcode declarations in inflate_fast()\n * - Simplified bad distance check in inflate_fast()\n * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new\n *   source file infback.c to provide a call-back interface to inflate for\n *   programs like gzip and unzip -- uses window as output buffer to avoid\n *   window copying\n *\n * 1.2.beta5    1 Jan 2003\n * - Improved inflateBack() interface to allow the caller to provide initial\n *   input in strm.\n * - Fixed stored blocks bug in inflateBack()\n *\n * 1.2.beta6    4 Jan 2003\n * - Added comments in inffast.c on effectiveness of POSTINC\n * - Typecasting all around to reduce compiler warnings\n * - Changed loops from while (1) or do {} while (1) to for (;;), again to\n *   make compilers happy\n * - Changed type of window in inflateBackInit() to unsigned char *\n *\n * 1.2.beta7    27 Jan 2003\n * - Changed many types to unsigned or unsigned short to avoid warnings\n * - Added inflateCopy() function\n *\n * 1.2.0        9 Mar 2003\n * - Changed inflateBack() interface to provide separate opaque descriptors\n *   for the in() and out() functions\n * - Changed inflateBack() argument and in_func typedef to swap the length\n *   and buffer address return values for the input function\n * - Check next_in and next_out for Z_NULL on entry to inflate()\n *\n * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n#include \"inflate.h\"\n#include \"inffast.h\"\n\n#ifdef MAKEFIXED\n#  ifndef BUILDFIXED\n#    define BUILDFIXED\n#  endif\n#endif\n\n/* function prototypes */\nlocal int inflateStateCheck OF((z_streamp strm));\nlocal void fixedtables OF((struct inflate_state FAR *state));\nlocal int updatewindow OF((z_streamp strm, const unsigned char FAR *end,\n                           unsigned copy));\n#ifdef BUILDFIXED\n   void makefixed OF((void));\n#endif\nlocal unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,\n                              unsigned len));\n\nlocal int inflateStateCheck(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n    if (strm == Z_NULL ||\n        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)\n        return 1;\n    state = (struct inflate_state FAR *)strm->state;\n    if (state == Z_NULL || state->strm != strm ||\n        state->mode < HEAD || state->mode > SYNC)\n        return 1;\n    return 0;\n}\n\nint ZEXPORT inflateResetKeep(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    strm->total_in = strm->total_out = state->total = 0;\n    strm->msg = Z_NULL;\n    if (state->wrap)        /* to support ill-conceived Java test suite */\n        strm->adler = state->wrap & 1;\n    state->mode = HEAD;\n    state->last = 0;\n    state->havedict = 0;\n    state->dmax = 32768U;\n    state->head = Z_NULL;\n    state->hold = 0;\n    state->bits = 0;\n    state->lencode = state->distcode = state->next = state->codes;\n    state->sane = 1;\n    state->back = -1;\n    Tracev((stderr, \"inflate: reset\\n\"));\n    return Z_OK;\n}\n\nint ZEXPORT inflateReset(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    state->wsize = 0;\n    state->whave = 0;\n    state->wnext = 0;\n    return inflateResetKeep(strm);\n}\n\nint ZEXPORT inflateReset2(strm, windowBits)\nz_streamp strm;\nint windowBits;\n{\n    int wrap;\n    struct inflate_state FAR *state;\n\n    /* get the state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* extract wrap request from windowBits parameter */\n    if (windowBits < 0) {\n        wrap = 0;\n        windowBits = -windowBits;\n    }\n    else {\n        wrap = (windowBits >> 4) + 5;\n#ifdef GUNZIP\n        if (windowBits < 48)\n            windowBits &= 15;\n#endif\n    }\n\n    /* set number of window bits, free window if different */\n    if (windowBits && (windowBits < 8 || windowBits > 15))\n        return Z_STREAM_ERROR;\n    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {\n        ZFREE(strm, state->window);\n        state->window = Z_NULL;\n    }\n\n    /* update state and reset the rest of it */\n    state->wrap = wrap;\n    state->wbits = (unsigned)windowBits;\n    return inflateReset(strm);\n}\n\nint ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)\nz_streamp strm;\nint windowBits;\nconst char *version;\nint stream_size;\n{\n    int ret;\n    struct inflate_state FAR *state;\n\n    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||\n        stream_size != (int)(sizeof(z_stream)))\n        return Z_VERSION_ERROR;\n    if (strm == Z_NULL) return Z_STREAM_ERROR;\n    strm->msg = Z_NULL;                 /* in case we return an error */\n    if (strm->zalloc == (alloc_func)0) {\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zalloc = zcalloc;\n        strm->opaque = (voidpf)0;\n#endif\n    }\n    if (strm->zfree == (free_func)0)\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zfree = zcfree;\n#endif\n    state = (struct inflate_state FAR *)\n            ZALLOC(strm, 1, sizeof(struct inflate_state));\n    if (state == Z_NULL) return Z_MEM_ERROR;\n    Tracev((stderr, \"inflate: allocated\\n\"));\n    strm->state = (struct internal_state FAR *)state;\n    state->strm = strm;\n    state->window = Z_NULL;\n    state->mode = HEAD;     /* to pass state test in inflateReset2() */\n    ret = inflateReset2(strm, windowBits);\n    if (ret != Z_OK) {\n        ZFREE(strm, state);\n        strm->state = Z_NULL;\n    }\n    return ret;\n}\n\nint ZEXPORT inflateInit_(strm, version, stream_size)\nz_streamp strm;\nconst char *version;\nint stream_size;\n{\n    return inflateInit2_(strm, DEF_WBITS, version, stream_size);\n}\n\nint ZEXPORT inflatePrime(strm, bits, value)\nz_streamp strm;\nint bits;\nint value;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (bits < 0) {\n        state->hold = 0;\n        state->bits = 0;\n        return Z_OK;\n    }\n    if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;\n    value &= (1L << bits) - 1;\n    state->hold += (unsigned)value << state->bits;\n    state->bits += (uInt)bits;\n    return Z_OK;\n}\n\n/*\n   Return state with length and distance decoding tables and index sizes set to\n   fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n   If BUILDFIXED is defined, then instead this routine builds the tables the\n   first time it's called, and returns those tables the first time and\n   thereafter.  This reduces the size of the code by about 2K bytes, in\n   exchange for a little execution time.  However, BUILDFIXED should not be\n   used for threaded applications, since the rewriting of the tables and virgin\n   may not be thread-safe.\n */\nlocal void fixedtables(state)\nstruct inflate_state FAR *state;\n{\n#ifdef BUILDFIXED\n    static int virgin = 1;\n    static code *lenfix, *distfix;\n    static code fixed[544];\n\n    /* build fixed huffman tables if first call (may not be thread safe) */\n    if (virgin) {\n        unsigned sym, bits;\n        static code *next;\n\n        /* literal/length table */\n        sym = 0;\n        while (sym < 144) state->lens[sym++] = 8;\n        while (sym < 256) state->lens[sym++] = 9;\n        while (sym < 280) state->lens[sym++] = 7;\n        while (sym < 288) state->lens[sym++] = 8;\n        next = fixed;\n        lenfix = next;\n        bits = 9;\n        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);\n\n        /* distance table */\n        sym = 0;\n        while (sym < 32) state->lens[sym++] = 5;\n        distfix = next;\n        bits = 5;\n        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);\n\n        /* do this just once */\n        virgin = 0;\n    }\n#else /* !BUILDFIXED */\n#   include \"inffixed.h\"\n#endif /* BUILDFIXED */\n    state->lencode = lenfix;\n    state->lenbits = 9;\n    state->distcode = distfix;\n    state->distbits = 5;\n}\n\n#ifdef MAKEFIXED\n#include <stdio.h>\n\n/*\n   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also\n   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes\n   those tables to stdout, which would be piped to inffixed.h.  A small program\n   can simply call makefixed to do this:\n\n    void makefixed(void);\n\n    int main(void)\n    {\n        makefixed();\n        return 0;\n    }\n\n   Then that can be linked with zlib built with MAKEFIXED defined and run:\n\n    a.out > inffixed.h\n */\nvoid makefixed()\n{\n    unsigned low, size;\n    struct inflate_state state;\n\n    fixedtables(&state);\n    puts(\"    /* inffixed.h -- table for decoding fixed codes\");\n    puts(\"     * Generated automatically by makefixed().\");\n    puts(\"     */\");\n    puts(\"\");\n    puts(\"    /* WARNING: this file should *not* be used by applications.\");\n    puts(\"       It is part of the implementation of this library and is\");\n    puts(\"       subject to change. Applications should only use zlib.h.\");\n    puts(\"     */\");\n    puts(\"\");\n    size = 1U << 9;\n    printf(\"    static const code lenfix[%u] = {\", size);\n    low = 0;\n    for (;;) {\n        if ((low % 7) == 0) printf(\"\\n        \");\n        printf(\"{%u,%u,%d}\", (low & 127) == 99 ? 64 : state.lencode[low].op,\n               state.lencode[low].bits, state.lencode[low].val);\n        if (++low == size) break;\n        putchar(',');\n    }\n    puts(\"\\n    };\");\n    size = 1U << 5;\n    printf(\"\\n    static const code distfix[%u] = {\", size);\n    low = 0;\n    for (;;) {\n        if ((low % 6) == 0) printf(\"\\n        \");\n        printf(\"{%u,%u,%d}\", state.distcode[low].op, state.distcode[low].bits,\n               state.distcode[low].val);\n        if (++low == size) break;\n        putchar(',');\n    }\n    puts(\"\\n    };\");\n}\n#endif /* MAKEFIXED */\n\n/*\n   Update the window with the last wsize (normally 32K) bytes written before\n   returning.  If window does not exist yet, create it.  This is only called\n   when a window is already in use, or when output has been written during this\n   inflate call, but the end of the deflate stream has not been reached yet.\n   It is also called to create a window for dictionary data when a dictionary\n   is loaded.\n\n   Providing output buffers larger than 32K to inflate() should provide a speed\n   advantage, since only the last 32K of output is copied to the sliding window\n   upon return from inflate(), and since all distances after the first 32K of\n   output will fall in the output data, making match copies simpler and faster.\n   The advantage may be dependent on the size of the processor's data caches.\n */\nlocal int updatewindow(strm, end, copy)\nz_streamp strm;\nconst Bytef *end;\nunsigned copy;\n{\n    struct inflate_state FAR *state;\n    unsigned dist;\n\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* if it hasn't been done already, allocate space for the window */\n    if (state->window == Z_NULL) {\n        state->window = (unsigned char FAR *)\n                        ZALLOC(strm, 1U << state->wbits,\n                               sizeof(unsigned char));\n        if (state->window == Z_NULL) return 1;\n    }\n\n    /* if window not in use yet, initialize */\n    if (state->wsize == 0) {\n        state->wsize = 1U << state->wbits;\n        state->wnext = 0;\n        state->whave = 0;\n    }\n\n    /* copy state->wsize or less output bytes into the circular window */\n    if (copy >= state->wsize) {\n        zmemcpy(state->window, end - state->wsize, state->wsize);\n        state->wnext = 0;\n        state->whave = state->wsize;\n    }\n    else {\n        dist = state->wsize - state->wnext;\n        if (dist > copy) dist = copy;\n        zmemcpy(state->window + state->wnext, end - copy, dist);\n        copy -= dist;\n        if (copy) {\n            zmemcpy(state->window, end - copy, copy);\n            state->wnext = copy;\n            state->whave = state->wsize;\n        }\n        else {\n            state->wnext += dist;\n            if (state->wnext == state->wsize) state->wnext = 0;\n            if (state->whave < state->wsize) state->whave += dist;\n        }\n    }\n    return 0;\n}\n\n/* Macros for inflate(): */\n\n/* check function to use adler32() for zlib or crc32() for gzip */\n#ifdef GUNZIP\n#  define UPDATE(check, buf, len) \\\n    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))\n#else\n#  define UPDATE(check, buf, len) adler32(check, buf, len)\n#endif\n\n/* check macros for header crc */\n#ifdef GUNZIP\n#  define CRC2(check, word) \\\n    do { \\\n        hbuf[0] = (unsigned char)(word); \\\n        hbuf[1] = (unsigned char)((word) >> 8); \\\n        check = crc32(check, hbuf, 2); \\\n    } while (0)\n\n#  define CRC4(check, word) \\\n    do { \\\n        hbuf[0] = (unsigned char)(word); \\\n        hbuf[1] = (unsigned char)((word) >> 8); \\\n        hbuf[2] = (unsigned char)((word) >> 16); \\\n        hbuf[3] = (unsigned char)((word) >> 24); \\\n        check = crc32(check, hbuf, 4); \\\n    } while (0)\n#endif\n\n/* Load registers with state in inflate() for speed */\n#define LOAD() \\\n    do { \\\n        put = strm->next_out; \\\n        left = strm->avail_out; \\\n        next = strm->next_in; \\\n        have = strm->avail_in; \\\n        hold = state->hold; \\\n        bits = state->bits; \\\n    } while (0)\n\n/* Restore state from registers in inflate() */\n#define RESTORE() \\\n    do { \\\n        strm->next_out = put; \\\n        strm->avail_out = left; \\\n        strm->next_in = next; \\\n        strm->avail_in = have; \\\n        state->hold = hold; \\\n        state->bits = bits; \\\n    } while (0)\n\n/* Clear the input bit accumulator */\n#define INITBITS() \\\n    do { \\\n        hold = 0; \\\n        bits = 0; \\\n    } while (0)\n\n/* Get a byte of input into the bit accumulator, or return from inflate()\n   if there is no input available. */\n#define PULLBYTE() \\\n    do { \\\n        if (have == 0) goto inf_leave; \\\n        have--; \\\n        hold += (unsigned long)(*next++) << bits; \\\n        bits += 8; \\\n    } while (0)\n\n/* Assure that there are at least n bits in the bit accumulator.  If there is\n   not enough available input to do that, then return from inflate(). */\n#define NEEDBITS(n) \\\n    do { \\\n        while (bits < (unsigned)(n)) \\\n            PULLBYTE(); \\\n    } while (0)\n\n/* Return the low n bits of the bit accumulator (n < 16) */\n#define BITS(n) \\\n    ((unsigned)hold & ((1U << (n)) - 1))\n\n/* Remove n bits from the bit accumulator */\n#define DROPBITS(n) \\\n    do { \\\n        hold >>= (n); \\\n        bits -= (unsigned)(n); \\\n    } while (0)\n\n/* Remove zero to seven bits as needed to go to a byte boundary */\n#define BYTEBITS() \\\n    do { \\\n        hold >>= bits & 7; \\\n        bits -= bits & 7; \\\n    } while (0)\n\n/*\n   inflate() uses a state machine to process as much input data and generate as\n   much output data as possible before returning.  The state machine is\n   structured roughly as follows:\n\n    for (;;) switch (state) {\n    ...\n    case STATEn:\n        if (not enough input data or output space to make progress)\n            return;\n        ... make progress ...\n        state = STATEm;\n        break;\n    ...\n    }\n\n   so when inflate() is called again, the same case is attempted again, and\n   if the appropriate resources are provided, the machine proceeds to the\n   next state.  The NEEDBITS() macro is usually the way the state evaluates\n   whether it can proceed or should return.  NEEDBITS() does the return if\n   the requested bits are not available.  The typical use of the BITS macros\n   is:\n\n        NEEDBITS(n);\n        ... do something with BITS(n) ...\n        DROPBITS(n);\n\n   where NEEDBITS(n) either returns from inflate() if there isn't enough\n   input left to load n bits into the accumulator, or it continues.  BITS(n)\n   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops\n   the low n bits off the accumulator.  INITBITS() clears the accumulator\n   and sets the number of available bits to zero.  BYTEBITS() discards just\n   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()\n   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.\n\n   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return\n   if there is no input available.  The decoding of variable length codes uses\n   PULLBYTE() directly in order to pull just enough bytes to decode the next\n   code, and no more.\n\n   Some states loop until they get enough input, making sure that enough\n   state information is maintained to continue the loop where it left off\n   if NEEDBITS() returns in the loop.  For example, want, need, and keep\n   would all have to actually be part of the saved state in case NEEDBITS()\n   returns:\n\n    case STATEw:\n        while (want < need) {\n            NEEDBITS(n);\n            keep[want++] = BITS(n);\n            DROPBITS(n);\n        }\n        state = STATEx;\n    case STATEx:\n\n   As shown above, if the next state is also the next case, then the break\n   is omitted.\n\n   A state may also return if there is not enough output space available to\n   complete that state.  Those states are copying stored data, writing a\n   literal byte, and copying a matching string.\n\n   When returning, a \"goto inf_leave\" is used to update the total counters,\n   update the check value, and determine whether any progress has been made\n   during that inflate() call in order to return the proper return code.\n   Progress is defined as a change in either strm->avail_in or strm->avail_out.\n   When there is a window, goto inf_leave will update the window with the last\n   output written.  If a goto inf_leave occurs in the middle of decompression\n   and there is no window currently, goto inf_leave will create one and copy\n   output to the window for the next call of inflate().\n\n   In this implementation, the flush parameter of inflate() only affects the\n   return code (per zlib.h).  inflate() always writes as much as possible to\n   strm->next_out, given the space available and the provided input--the effect\n   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers\n   the allocation of and copying into a sliding window until necessary, which\n   provides the effect documented in zlib.h for Z_FINISH when the entire input\n   stream available.  So the only thing the flush parameter actually does is:\n   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it\n   will return Z_BUF_ERROR if it has not reached the end of the stream.\n */\n\nint ZEXPORT inflate(strm, flush)\nz_streamp strm;\nint flush;\n{\n    struct inflate_state FAR *state;\n    z_const unsigned char FAR *next;    /* next input */\n    unsigned char FAR *put;     /* next output */\n    unsigned have, left;        /* available input and output */\n    unsigned long hold;         /* bit buffer */\n    unsigned bits;              /* bits in bit buffer */\n    unsigned in, out;           /* save starting available input and output */\n    unsigned copy;              /* number of stored or match bytes to copy */\n    unsigned char FAR *from;    /* where to copy match bytes from */\n    code here;                  /* current decoding table entry */\n    code last;                  /* parent table entry */\n    unsigned len;               /* length to copy for repeats, bits to drop */\n    int ret;                    /* return code */\n#ifdef GUNZIP\n    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */\n#endif\n    static const unsigned short order[19] = /* permutation of code lengths */\n        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\n\n    if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||\n        (strm->next_in == Z_NULL && strm->avail_in != 0))\n        return Z_STREAM_ERROR;\n\n    state = (struct inflate_state FAR *)strm->state;\n    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */\n    LOAD();\n    in = have;\n    out = left;\n    ret = Z_OK;\n    for (;;)\n        switch (state->mode) {\n        case HEAD:\n            if (state->wrap == 0) {\n                state->mode = TYPEDO;\n                break;\n            }\n            NEEDBITS(16);\n#ifdef GUNZIP\n            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */\n                if (state->wbits == 0)\n                    state->wbits = 15;\n                state->check = crc32(0L, Z_NULL, 0);\n                CRC2(state->check, hold);\n                INITBITS();\n                state->mode = FLAGS;\n                break;\n            }\n            state->flags = 0;           /* expect zlib header */\n            if (state->head != Z_NULL)\n                state->head->done = -1;\n            if (!(state->wrap & 1) ||   /* check if zlib header allowed */\n#else\n            if (\n#endif\n                ((BITS(8) << 8) + (hold >> 8)) % 31) {\n                strm->msg = (char *)\"incorrect header check\";\n                state->mode = BAD;\n                break;\n            }\n            if (BITS(4) != Z_DEFLATED) {\n                strm->msg = (char *)\"unknown compression method\";\n                state->mode = BAD;\n                break;\n            }\n            DROPBITS(4);\n            len = BITS(4) + 8;\n            if (state->wbits == 0)\n                state->wbits = len;\n            if (len > 15 || len > state->wbits) {\n                strm->msg = (char *)\"invalid window size\";\n                state->mode = BAD;\n                break;\n            }\n            state->dmax = 1U << len;\n            Tracev((stderr, \"inflate:   zlib header ok\\n\"));\n            strm->adler = state->check = adler32(0L, Z_NULL, 0);\n            state->mode = hold & 0x200 ? DICTID : TYPE;\n            INITBITS();\n            break;\n#ifdef GUNZIP\n        case FLAGS:\n            NEEDBITS(16);\n            state->flags = (int)(hold);\n            if ((state->flags & 0xff) != Z_DEFLATED) {\n                strm->msg = (char *)\"unknown compression method\";\n                state->mode = BAD;\n                break;\n            }\n            if (state->flags & 0xe000) {\n                strm->msg = (char *)\"unknown header flags set\";\n                state->mode = BAD;\n                break;\n            }\n            if (state->head != Z_NULL)\n                state->head->text = (int)((hold >> 8) & 1);\n            if ((state->flags & 0x0200) && (state->wrap & 4))\n                CRC2(state->check, hold);\n            INITBITS();\n            state->mode = TIME;\n        case TIME:\n            NEEDBITS(32);\n            if (state->head != Z_NULL)\n                state->head->time = hold;\n            if ((state->flags & 0x0200) && (state->wrap & 4))\n                CRC4(state->check, hold);\n            INITBITS();\n            state->mode = OS;\n        case OS:\n            NEEDBITS(16);\n            if (state->head != Z_NULL) {\n                state->head->xflags = (int)(hold & 0xff);\n                state->head->os = (int)(hold >> 8);\n            }\n            if ((state->flags & 0x0200) && (state->wrap & 4))\n                CRC2(state->check, hold);\n            INITBITS();\n            state->mode = EXLEN;\n        case EXLEN:\n            if (state->flags & 0x0400) {\n                NEEDBITS(16);\n                state->length = (unsigned)(hold);\n                if (state->head != Z_NULL)\n                    state->head->extra_len = (unsigned)hold;\n                if ((state->flags & 0x0200) && (state->wrap & 4))\n                    CRC2(state->check, hold);\n                INITBITS();\n            }\n            else if (state->head != Z_NULL)\n                state->head->extra = Z_NULL;\n            state->mode = EXTRA;\n        case EXTRA:\n            if (state->flags & 0x0400) {\n                copy = state->length;\n                if (copy > have) copy = have;\n                if (copy) {\n                    if (state->head != Z_NULL &&\n                        state->head->extra != Z_NULL) {\n                        len = state->head->extra_len - state->length;\n                        zmemcpy(state->head->extra + len, next,\n                                len + copy > state->head->extra_max ?\n                                state->head->extra_max - len : copy);\n                    }\n                    if ((state->flags & 0x0200) && (state->wrap & 4))\n                        state->check = crc32(state->check, next, copy);\n                    have -= copy;\n                    next += copy;\n                    state->length -= copy;\n                }\n                if (state->length) goto inf_leave;\n            }\n            state->length = 0;\n            state->mode = NAME;\n        case NAME:\n            if (state->flags & 0x0800) {\n                if (have == 0) goto inf_leave;\n                copy = 0;\n                do {\n                    len = (unsigned)(next[copy++]);\n                    if (state->head != Z_NULL &&\n                            state->head->name != Z_NULL &&\n                            state->length < state->head->name_max)\n                        state->head->name[state->length++] = (Bytef)len;\n                } while (len && copy < have);\n                if ((state->flags & 0x0200) && (state->wrap & 4))\n                    state->check = crc32(state->check, next, copy);\n                have -= copy;\n                next += copy;\n                if (len) goto inf_leave;\n            }\n            else if (state->head != Z_NULL)\n                state->head->name = Z_NULL;\n            state->length = 0;\n            state->mode = COMMENT;\n        case COMMENT:\n            if (state->flags & 0x1000) {\n                if (have == 0) goto inf_leave;\n                copy = 0;\n                do {\n                    len = (unsigned)(next[copy++]);\n                    if (state->head != Z_NULL &&\n                            state->head->comment != Z_NULL &&\n                            state->length < state->head->comm_max)\n                        state->head->comment[state->length++] = (Bytef)len;\n                } while (len && copy < have);\n                if ((state->flags & 0x0200) && (state->wrap & 4))\n                    state->check = crc32(state->check, next, copy);\n                have -= copy;\n                next += copy;\n                if (len) goto inf_leave;\n            }\n            else if (state->head != Z_NULL)\n                state->head->comment = Z_NULL;\n            state->mode = HCRC;\n        case HCRC:\n            if (state->flags & 0x0200) {\n                NEEDBITS(16);\n                if ((state->wrap & 4) && hold != (state->check & 0xffff)) {\n                    strm->msg = (char *)\"header crc mismatch\";\n                    state->mode = BAD;\n                    break;\n                }\n                INITBITS();\n            }\n            if (state->head != Z_NULL) {\n                state->head->hcrc = (int)((state->flags >> 9) & 1);\n                state->head->done = 1;\n            }\n            strm->adler = state->check = crc32(0L, Z_NULL, 0);\n            state->mode = TYPE;\n            break;\n#endif\n        case DICTID:\n            NEEDBITS(32);\n            strm->adler = state->check = ZSWAP32(hold);\n            INITBITS();\n            state->mode = DICT;\n        case DICT:\n            if (state->havedict == 0) {\n                RESTORE();\n                return Z_NEED_DICT;\n            }\n            strm->adler = state->check = adler32(0L, Z_NULL, 0);\n            state->mode = TYPE;\n        case TYPE:\n            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;\n        case TYPEDO:\n            if (state->last) {\n                BYTEBITS();\n                state->mode = CHECK;\n                break;\n            }\n            NEEDBITS(3);\n            state->last = BITS(1);\n            DROPBITS(1);\n            switch (BITS(2)) {\n            case 0:                             /* stored block */\n                Tracev((stderr, \"inflate:     stored block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = STORED;\n                break;\n            case 1:                             /* fixed block */\n                fixedtables(state);\n                Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = LEN_;             /* decode codes */\n                if (flush == Z_TREES) {\n                    DROPBITS(2);\n                    goto inf_leave;\n                }\n                break;\n            case 2:                             /* dynamic block */\n                Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = TABLE;\n                break;\n            case 3:\n                strm->msg = (char *)\"invalid block type\";\n                state->mode = BAD;\n            }\n            DROPBITS(2);\n            break;\n        case STORED:\n            BYTEBITS();                         /* go to byte boundary */\n            NEEDBITS(32);\n            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {\n                strm->msg = (char *)\"invalid stored block lengths\";\n                state->mode = BAD;\n                break;\n            }\n            state->length = (unsigned)hold & 0xffff;\n            Tracev((stderr, \"inflate:       stored length %u\\n\",\n                    state->length));\n            INITBITS();\n            state->mode = COPY_;\n            if (flush == Z_TREES) goto inf_leave;\n        case COPY_:\n            state->mode = COPY;\n        case COPY:\n            copy = state->length;\n            if (copy) {\n                if (copy > have) copy = have;\n                if (copy > left) copy = left;\n                if (copy == 0) goto inf_leave;\n                zmemcpy(put, next, copy);\n                have -= copy;\n                next += copy;\n                left -= copy;\n                put += copy;\n                state->length -= copy;\n                break;\n            }\n            Tracev((stderr, \"inflate:       stored end\\n\"));\n            state->mode = TYPE;\n            break;\n        case TABLE:\n            NEEDBITS(14);\n            state->nlen = BITS(5) + 257;\n            DROPBITS(5);\n            state->ndist = BITS(5) + 1;\n            DROPBITS(5);\n            state->ncode = BITS(4) + 4;\n            DROPBITS(4);\n#ifndef PKZIP_BUG_WORKAROUND\n            if (state->nlen > 286 || state->ndist > 30) {\n                strm->msg = (char *)\"too many length or distance symbols\";\n                state->mode = BAD;\n                break;\n            }\n#endif\n            Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n            state->have = 0;\n            state->mode = LENLENS;\n        case LENLENS:\n            while (state->have < state->ncode) {\n                NEEDBITS(3);\n                state->lens[order[state->have++]] = (unsigned short)BITS(3);\n                DROPBITS(3);\n            }\n            while (state->have < 19)\n                state->lens[order[state->have++]] = 0;\n            state->next = state->codes;\n            state->lencode = (const code FAR *)(state->next);\n            state->lenbits = 7;\n            ret = inflate_table(CODES, state->lens, 19, &(state->next),\n                                &(state->lenbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid code lengths set\";\n                state->mode = BAD;\n                break;\n            }\n            Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n            state->have = 0;\n            state->mode = CODELENS;\n        case CODELENS:\n            while (state->have < state->nlen + state->ndist) {\n                for (;;) {\n                    here = state->lencode[BITS(state->lenbits)];\n                    if ((unsigned)(here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                if (here.val < 16) {\n                    DROPBITS(here.bits);\n                    state->lens[state->have++] = here.val;\n                }\n                else {\n                    if (here.val == 16) {\n                        NEEDBITS(here.bits + 2);\n                        DROPBITS(here.bits);\n                        if (state->have == 0) {\n                            strm->msg = (char *)\"invalid bit length repeat\";\n                            state->mode = BAD;\n                            break;\n                        }\n                        len = state->lens[state->have - 1];\n                        copy = 3 + BITS(2);\n                        DROPBITS(2);\n                    }\n                    else if (here.val == 17) {\n                        NEEDBITS(here.bits + 3);\n                        DROPBITS(here.bits);\n                        len = 0;\n                        copy = 3 + BITS(3);\n                        DROPBITS(3);\n                    }\n                    else {\n                        NEEDBITS(here.bits + 7);\n                        DROPBITS(here.bits);\n                        len = 0;\n                        copy = 11 + BITS(7);\n                        DROPBITS(7);\n                    }\n                    if (state->have + copy > state->nlen + state->ndist) {\n                        strm->msg = (char *)\"invalid bit length repeat\";\n                        state->mode = BAD;\n                        break;\n                    }\n                    while (copy--)\n                        state->lens[state->have++] = (unsigned short)len;\n                }\n            }\n\n            /* handle error breaks in while */\n            if (state->mode == BAD) break;\n\n            /* check for end-of-block code (better have one) */\n            if (state->lens[256] == 0) {\n                strm->msg = (char *)\"invalid code -- missing end-of-block\";\n                state->mode = BAD;\n                break;\n            }\n\n            /* build code tables -- note: do not change the lenbits or distbits\n               values here (9 and 6) without reading the comments in inftrees.h\n               concerning the ENOUGH constants, which depend on those values */\n            state->next = state->codes;\n            state->lencode = (const code FAR *)(state->next);\n            state->lenbits = 9;\n            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),\n                                &(state->lenbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid literal/lengths set\";\n                state->mode = BAD;\n                break;\n            }\n            state->distcode = (const code FAR *)(state->next);\n            state->distbits = 6;\n            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,\n                            &(state->next), &(state->distbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid distances set\";\n                state->mode = BAD;\n                break;\n            }\n            Tracev((stderr, \"inflate:       codes ok\\n\"));\n            state->mode = LEN_;\n            if (flush == Z_TREES) goto inf_leave;\n        case LEN_:\n            state->mode = LEN;\n        case LEN:\n            if (have >= 6 && left >= 258) {\n                RESTORE();\n                inflate_fast(strm, out);\n                LOAD();\n                if (state->mode == TYPE)\n                    state->back = -1;\n                break;\n            }\n            state->back = 0;\n            for (;;) {\n                here = state->lencode[BITS(state->lenbits)];\n                if ((unsigned)(here.bits) <= bits) break;\n                PULLBYTE();\n            }\n            if (here.op && (here.op & 0xf0) == 0) {\n                last = here;\n                for (;;) {\n                    here = state->lencode[last.val +\n                            (BITS(last.bits + last.op) >> last.bits)];\n                    if ((unsigned)(last.bits + here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                DROPBITS(last.bits);\n                state->back += last.bits;\n            }\n            DROPBITS(here.bits);\n            state->back += here.bits;\n            state->length = (unsigned)here.val;\n            if ((int)(here.op) == 0) {\n                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n                        \"inflate:         literal '%c'\\n\" :\n                        \"inflate:         literal 0x%02x\\n\", here.val));\n                state->mode = LIT;\n                break;\n            }\n            if (here.op & 32) {\n                Tracevv((stderr, \"inflate:         end of block\\n\"));\n                state->back = -1;\n                state->mode = TYPE;\n                break;\n            }\n            if (here.op & 64) {\n                strm->msg = (char *)\"invalid literal/length code\";\n                state->mode = BAD;\n                break;\n            }\n            state->extra = (unsigned)(here.op) & 15;\n            state->mode = LENEXT;\n        case LENEXT:\n            if (state->extra) {\n                NEEDBITS(state->extra);\n                state->length += BITS(state->extra);\n                DROPBITS(state->extra);\n                state->back += state->extra;\n            }\n            Tracevv((stderr, \"inflate:         length %u\\n\", state->length));\n            state->was = state->length;\n            state->mode = DIST;\n        case DIST:\n            for (;;) {\n                here = state->distcode[BITS(state->distbits)];\n                if ((unsigned)(here.bits) <= bits) break;\n                PULLBYTE();\n            }\n            if ((here.op & 0xf0) == 0) {\n                last = here;\n                for (;;) {\n                    here = state->distcode[last.val +\n                            (BITS(last.bits + last.op) >> last.bits)];\n                    if ((unsigned)(last.bits + here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                DROPBITS(last.bits);\n                state->back += last.bits;\n            }\n            DROPBITS(here.bits);\n            state->back += here.bits;\n            if (here.op & 64) {\n                strm->msg = (char *)\"invalid distance code\";\n                state->mode = BAD;\n                break;\n            }\n            state->offset = (unsigned)here.val;\n            state->extra = (unsigned)(here.op) & 15;\n            state->mode = DISTEXT;\n        case DISTEXT:\n            if (state->extra) {\n                NEEDBITS(state->extra);\n                state->offset += BITS(state->extra);\n                DROPBITS(state->extra);\n                state->back += state->extra;\n            }\n#ifdef INFLATE_STRICT\n            if (state->offset > state->dmax) {\n                strm->msg = (char *)\"invalid distance too far back\";\n                state->mode = BAD;\n                break;\n            }\n#endif\n            Tracevv((stderr, \"inflate:         distance %u\\n\", state->offset));\n            state->mode = MATCH;\n        case MATCH:\n            if (left == 0) goto inf_leave;\n            copy = out - left;\n            if (state->offset > copy) {         /* copy from window */\n                copy = state->offset - copy;\n                if (copy > state->whave) {\n                    if (state->sane) {\n                        strm->msg = (char *)\"invalid distance too far back\";\n                        state->mode = BAD;\n                        break;\n                    }\n#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n                    Trace((stderr, \"inflate.c too far\\n\"));\n                    copy -= state->whave;\n                    if (copy > state->length) copy = state->length;\n                    if (copy > left) copy = left;\n                    left -= copy;\n                    state->length -= copy;\n                    do {\n                        *put++ = 0;\n                    } while (--copy);\n                    if (state->length == 0) state->mode = LEN;\n                    break;\n#endif\n                }\n                if (copy > state->wnext) {\n                    copy -= state->wnext;\n                    from = state->window + (state->wsize - copy);\n                }\n                else\n                    from = state->window + (state->wnext - copy);\n                if (copy > state->length) copy = state->length;\n            }\n            else {                              /* copy from output */\n                from = put - state->offset;\n                copy = state->length;\n            }\n            if (copy > left) copy = left;\n            left -= copy;\n            state->length -= copy;\n            do {\n                *put++ = *from++;\n            } while (--copy);\n            if (state->length == 0) state->mode = LEN;\n            break;\n        case LIT:\n            if (left == 0) goto inf_leave;\n            *put++ = (unsigned char)(state->length);\n            left--;\n            state->mode = LEN;\n            break;\n        case CHECK:\n            if (state->wrap) {\n                NEEDBITS(32);\n                out -= left;\n                strm->total_out += out;\n                state->total += out;\n                if ((state->wrap & 4) && out)\n                    strm->adler = state->check =\n                        UPDATE(state->check, put - out, out);\n                out = left;\n                if ((state->wrap & 4) && (\n#ifdef GUNZIP\n                     state->flags ? hold :\n#endif\n                     ZSWAP32(hold)) != state->check) {\n                    strm->msg = (char *)\"incorrect data check\";\n                    state->mode = BAD;\n                    break;\n                }\n                INITBITS();\n                Tracev((stderr, \"inflate:   check matches trailer\\n\"));\n            }\n#ifdef GUNZIP\n            state->mode = LENGTH;\n        case LENGTH:\n            if (state->wrap && state->flags) {\n                NEEDBITS(32);\n                if (hold != (state->total & 0xffffffffUL)) {\n                    strm->msg = (char *)\"incorrect length check\";\n                    state->mode = BAD;\n                    break;\n                }\n                INITBITS();\n                Tracev((stderr, \"inflate:   length matches trailer\\n\"));\n            }\n#endif\n            state->mode = DONE;\n        case DONE:\n            ret = Z_STREAM_END;\n            goto inf_leave;\n        case BAD:\n            ret = Z_DATA_ERROR;\n            goto inf_leave;\n        case MEM:\n            return Z_MEM_ERROR;\n        case SYNC:\n        default:\n            return Z_STREAM_ERROR;\n        }\n\n    /*\n       Return from inflate(), updating the total counts and the check value.\n       If there was no progress during the inflate() call, return a buffer\n       error.  Call updatewindow() to create and/or update the window state.\n       Note: a memory error from inflate() is non-recoverable.\n     */\n  inf_leave:\n    RESTORE();\n    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&\n            (state->mode < CHECK || flush != Z_FINISH)))\n        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {\n            state->mode = MEM;\n            return Z_MEM_ERROR;\n        }\n    in -= strm->avail_in;\n    out -= strm->avail_out;\n    strm->total_in += in;\n    strm->total_out += out;\n    state->total += out;\n    if ((state->wrap & 4) && out)\n        strm->adler = state->check =\n            UPDATE(state->check, strm->next_out - out, out);\n    strm->data_type = (int)state->bits + (state->last ? 64 : 0) +\n                      (state->mode == TYPE ? 128 : 0) +\n                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);\n    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)\n        ret = Z_BUF_ERROR;\n    return ret;\n}\n\nint ZEXPORT inflateEnd(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n    if (inflateStateCheck(strm))\n        return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (state->window != Z_NULL) ZFREE(strm, state->window);\n    ZFREE(strm, strm->state);\n    strm->state = Z_NULL;\n    Tracev((stderr, \"inflate: end\\n\"));\n    return Z_OK;\n}\n\nint ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)\nz_streamp strm;\nBytef *dictionary;\nuInt *dictLength;\n{\n    struct inflate_state FAR *state;\n\n    /* check state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* copy dictionary */\n    if (state->whave && dictionary != Z_NULL) {\n        zmemcpy(dictionary, state->window + state->wnext,\n                state->whave - state->wnext);\n        zmemcpy(dictionary + state->whave - state->wnext,\n                state->window, state->wnext);\n    }\n    if (dictLength != Z_NULL)\n        *dictLength = state->whave;\n    return Z_OK;\n}\n\nint ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)\nz_streamp strm;\nconst Bytef *dictionary;\nuInt dictLength;\n{\n    struct inflate_state FAR *state;\n    unsigned long dictid;\n    int ret;\n\n    /* check state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (state->wrap != 0 && state->mode != DICT)\n        return Z_STREAM_ERROR;\n\n    /* check for correct dictionary identifier */\n    if (state->mode == DICT) {\n        dictid = adler32(0L, Z_NULL, 0);\n        dictid = adler32(dictid, dictionary, dictLength);\n        if (dictid != state->check)\n            return Z_DATA_ERROR;\n    }\n\n    /* copy dictionary to window using updatewindow(), which will amend the\n       existing dictionary if appropriate */\n    ret = updatewindow(strm, dictionary + dictLength, dictLength);\n    if (ret) {\n        state->mode = MEM;\n        return Z_MEM_ERROR;\n    }\n    state->havedict = 1;\n    Tracev((stderr, \"inflate:   dictionary set\\n\"));\n    return Z_OK;\n}\n\nint ZEXPORT inflateGetHeader(strm, head)\nz_streamp strm;\ngz_headerp head;\n{\n    struct inflate_state FAR *state;\n\n    /* check state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;\n\n    /* save header structure */\n    state->head = head;\n    head->done = 0;\n    return Z_OK;\n}\n\n/*\n   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found\n   or when out of input.  When called, *have is the number of pattern bytes\n   found in order so far, in 0..3.  On return *have is updated to the new\n   state.  If on return *have equals four, then the pattern was found and the\n   return value is how many bytes were read including the last byte of the\n   pattern.  If *have is less than four, then the pattern has not been found\n   yet and the return value is len.  In the latter case, syncsearch() can be\n   called again with more data and the *have state.  *have is initialized to\n   zero for the first call.\n */\nlocal unsigned syncsearch(have, buf, len)\nunsigned FAR *have;\nconst unsigned char FAR *buf;\nunsigned len;\n{\n    unsigned got;\n    unsigned next;\n\n    got = *have;\n    next = 0;\n    while (next < len && got < 4) {\n        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))\n            got++;\n        else if (buf[next])\n            got = 0;\n        else\n            got = 4 - got;\n        next++;\n    }\n    *have = got;\n    return next;\n}\n\nint ZEXPORT inflateSync(strm)\nz_streamp strm;\n{\n    unsigned len;               /* number of bytes to look at or looked at */\n    unsigned long in, out;      /* temporary to save total_in and total_out */\n    unsigned char buf[4];       /* to restore bit buffer to byte string */\n    struct inflate_state FAR *state;\n\n    /* check parameters */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;\n\n    /* if first time, start search in bit buffer */\n    if (state->mode != SYNC) {\n        state->mode = SYNC;\n        state->hold <<= state->bits & 7;\n        state->bits -= state->bits & 7;\n        len = 0;\n        while (state->bits >= 8) {\n            buf[len++] = (unsigned char)(state->hold);\n            state->hold >>= 8;\n            state->bits -= 8;\n        }\n        state->have = 0;\n        syncsearch(&(state->have), buf, len);\n    }\n\n    /* search available input */\n    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);\n    strm->avail_in -= len;\n    strm->next_in += len;\n    strm->total_in += len;\n\n    /* return no joy or set up to restart inflate() on a new block */\n    if (state->have != 4) return Z_DATA_ERROR;\n    in = strm->total_in;  out = strm->total_out;\n    inflateReset(strm);\n    strm->total_in = in;  strm->total_out = out;\n    state->mode = TYPE;\n    return Z_OK;\n}\n\n/*\n   Returns true if inflate is currently at the end of a block generated by\n   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP\n   implementation to provide an additional safety check. PPP uses\n   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored\n   block. When decompressing, PPP checks that at the end of input packet,\n   inflate is waiting for these length bytes.\n */\nint ZEXPORT inflateSyncPoint(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    return state->mode == STORED && state->bits == 0;\n}\n\nint ZEXPORT inflateCopy(dest, source)\nz_streamp dest;\nz_streamp source;\n{\n    struct inflate_state FAR *state;\n    struct inflate_state FAR *copy;\n    unsigned char FAR *window;\n    unsigned wsize;\n\n    /* check input */\n    if (inflateStateCheck(source) || dest == Z_NULL)\n        return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)source->state;\n\n    /* allocate space */\n    copy = (struct inflate_state FAR *)\n           ZALLOC(source, 1, sizeof(struct inflate_state));\n    if (copy == Z_NULL) return Z_MEM_ERROR;\n    window = Z_NULL;\n    if (state->window != Z_NULL) {\n        window = (unsigned char FAR *)\n                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));\n        if (window == Z_NULL) {\n            ZFREE(source, copy);\n            return Z_MEM_ERROR;\n        }\n    }\n\n    /* copy state */\n    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));\n    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));\n    copy->strm = dest;\n    if (state->lencode >= state->codes &&\n        state->lencode <= state->codes + ENOUGH - 1) {\n        copy->lencode = copy->codes + (state->lencode - state->codes);\n        copy->distcode = copy->codes + (state->distcode - state->codes);\n    }\n    copy->next = copy->codes + (state->next - state->codes);\n    if (window != Z_NULL) {\n        wsize = 1U << state->wbits;\n        zmemcpy(window, state->window, wsize);\n    }\n    copy->window = window;\n    dest->state = (struct internal_state FAR *)copy;\n    return Z_OK;\n}\n\nint ZEXPORT inflateUndermine(strm, subvert)\nz_streamp strm;\nint subvert;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n    state->sane = !subvert;\n    return Z_OK;\n#else\n    (void)subvert;\n    state->sane = 1;\n    return Z_DATA_ERROR;\n#endif\n}\n\nint ZEXPORT inflateValidate(strm, check)\nz_streamp strm;\nint check;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (check)\n        state->wrap |= 4;\n    else\n        state->wrap &= ~4;\n    return Z_OK;\n}\n\nlong ZEXPORT inflateMark(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm))\n        return -(1L << 16);\n    state = (struct inflate_state FAR *)strm->state;\n    return (long)(((unsigned long)((long)state->back)) << 16) +\n        (state->mode == COPY ? state->length :\n            (state->mode == MATCH ? state->was - state->length : 0));\n}\n\nunsigned long ZEXPORT inflateCodesUsed(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n    if (inflateStateCheck(strm)) return (unsigned long)-1;\n    state = (struct inflate_state FAR *)strm->state;\n    return (unsigned long)(state->next - state->codes);\n}\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inflate.h",
    "content": "/* inflate.h -- internal inflate state definition\n * Copyright (C) 1995-2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n#ifndef __INFLATE_H__\n#define __INFLATE_H__\n \n/* define NO_GZIP when compiling if you want to disable gzip header and\n   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in\n   the crc code when it is not needed.  For shared libraries, gzip decoding\n   should be left enabled. */\n#ifndef NO_GZIP\n#  define GUNZIP\n#endif\n\n/* Possible inflate modes between inflate() calls */\ntypedef enum {\n    HEAD = 16180,   /* i: waiting for magic header */\n    FLAGS,      /* i: waiting for method and flags (gzip) */\n    TIME,       /* i: waiting for modification time (gzip) */\n    OS,         /* i: waiting for extra flags and operating system (gzip) */\n    EXLEN,      /* i: waiting for extra length (gzip) */\n    EXTRA,      /* i: waiting for extra bytes (gzip) */\n    NAME,       /* i: waiting for end of file name (gzip) */\n    COMMENT,    /* i: waiting for end of comment (gzip) */\n    HCRC,       /* i: waiting for header crc (gzip) */\n    DICTID,     /* i: waiting for dictionary check value */\n    DICT,       /* waiting for inflateSetDictionary() call */\n        TYPE,       /* i: waiting for type bits, including last-flag bit */\n        TYPEDO,     /* i: same, but skip check to exit inflate on new block */\n        STORED,     /* i: waiting for stored size (length and complement) */\n        COPY_,      /* i/o: same as COPY below, but only first time in */\n        COPY,       /* i/o: waiting for input or output to copy stored block */\n        TABLE,      /* i: waiting for dynamic block table lengths */\n        LENLENS,    /* i: waiting for code length code lengths */\n        CODELENS,   /* i: waiting for length/lit and distance code lengths */\n            LEN_,       /* i: same as LEN below, but only first time in */\n            LEN,        /* i: waiting for length/lit/eob code */\n            LENEXT,     /* i: waiting for length extra bits */\n            DIST,       /* i: waiting for distance code */\n            DISTEXT,    /* i: waiting for distance extra bits */\n            MATCH,      /* o: waiting for output space to copy string */\n            LIT,        /* o: waiting for output space to write literal */\n    CHECK,      /* i: waiting for 32-bit check value */\n    LENGTH,     /* i: waiting for 32-bit length (gzip) */\n    DONE,       /* finished check, done -- remain here until reset */\n    BAD,        /* got a data error -- remain here until reset */\n    MEM,        /* got an inflate() memory error -- remain here until reset */\n    SYNC        /* looking for synchronization bytes to restart inflate() */\n} inflate_mode;\n\n/*\n    State transitions between above modes -\n\n    (most modes can go to BAD or MEM on error -- not shown for clarity)\n\n    Process header:\n        HEAD -> (gzip) or (zlib) or (raw)\n        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->\n                  HCRC -> TYPE\n        (zlib) -> DICTID or TYPE\n        DICTID -> DICT -> TYPE\n        (raw) -> TYPEDO\n    Read deflate blocks:\n            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK\n            STORED -> COPY_ -> COPY -> TYPE\n            TABLE -> LENLENS -> CODELENS -> LEN_\n            LEN_ -> LEN\n    Read deflate codes in fixed or dynamic block:\n                LEN -> LENEXT or LIT or TYPE\n                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN\n                LIT -> LEN\n    Process trailer:\n        CHECK -> LENGTH -> DONE\n */\n\n/* State maintained between inflate() calls -- approximately 7K bytes, not\n   including the allocated sliding window, which is up to 32K bytes. */\nstruct inflate_state {\n    z_streamp strm;             /* pointer back to this zlib stream */\n    inflate_mode mode;          /* current inflate mode */\n    int last;                   /* true if processing last block */\n    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip,\n                                   bit 2 true to validate check value */\n    int havedict;               /* true if dictionary provided */\n    int flags;                  /* gzip header method and flags (0 if zlib) */\n    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */\n    unsigned long check;        /* protected copy of check value */\n    unsigned long total;        /* protected copy of output count */\n    gz_headerp head;            /* where to save gzip header information */\n        /* sliding window */\n    unsigned wbits;             /* log base 2 of requested window size */\n    unsigned wsize;             /* window size or zero if not using window */\n    unsigned whave;             /* valid bytes in the window */\n    unsigned wnext;             /* window write index */\n    unsigned char FAR *window;  /* allocated sliding window, if needed */\n        /* bit accumulator */\n    unsigned long hold;         /* input bit accumulator */\n    unsigned bits;              /* number of bits in \"in\" */\n        /* for string and stored block copying */\n    unsigned length;            /* literal or length of data to copy */\n    unsigned offset;            /* distance back to copy string from */\n        /* for table and code decoding */\n    unsigned extra;             /* extra bits needed */\n        /* fixed and dynamic code tables */\n    code const FAR *lencode;    /* starting table for length/literal codes */\n    code const FAR *distcode;   /* starting table for distance codes */\n    unsigned lenbits;           /* index bits for lencode */\n    unsigned distbits;          /* index bits for distcode */\n        /* dynamic table building */\n    unsigned ncode;             /* number of code length code lengths */\n    unsigned nlen;              /* number of length code lengths */\n    unsigned ndist;             /* number of distance code lengths */\n    unsigned have;              /* number of code lengths in lens[] */\n    code FAR *next;             /* next available space in codes[] */\n    unsigned short lens[320];   /* temporary storage for code lengths */\n    unsigned short work[288];   /* work area for code table building */\n    code codes[ENOUGH];         /* space for code tables */\n    int sane;                   /* if false, allow invalid distance too far */\n    int back;                   /* bits back of last unprocessed length/lit */\n    unsigned was;               /* initial length of match */\n};\n\n#endif // __INFLATE_H__\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inftrees.c",
    "content": "/* inftrees.c -- generate Huffman trees for efficient decoding\n * Copyright (C) 1995-2017 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n\n#define MAXBITS 15\n\nconst char inflate_copyright[] =\n   \" inflate 1.2.11 Copyright 1995-2017 Mark Adler \";\n/*\n  If you use the zlib library in a product, an acknowledgment is welcome\n  in the documentation of your product. If for some reason you cannot\n  include such an acknowledgment, I would appreciate that you keep this\n  copyright string in the executable of your product.\n */\n\n/*\n   Build a set of tables to decode the provided canonical Huffman code.\n   The code lengths are lens[0..codes-1].  The result starts at *table,\n   whose indices are 0..2^bits-1.  work is a writable array of at least\n   lens shorts, which is used as a work area.  type is the type of code\n   to be generated, CODES, LENS, or DISTS.  On return, zero is success,\n   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table\n   on return points to the next available entry's address.  bits is the\n   requested root table index bits, and on return it is the actual root\n   table index bits.  It will differ if the request is greater than the\n   longest code or if it is less than the shortest code.\n */\nint ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)\ncodetype type;\nunsigned short FAR *lens;\nunsigned codes;\ncode FAR * FAR *table;\nunsigned FAR *bits;\nunsigned short FAR *work;\n{\n    unsigned len;               /* a code's length in bits */\n    unsigned sym;               /* index of code symbols */\n    unsigned min, max;          /* minimum and maximum code lengths */\n    unsigned root;              /* number of index bits for root table */\n    unsigned curr;              /* number of index bits for current table */\n    unsigned drop;              /* code bits to drop for sub-table */\n    int left;                   /* number of prefix codes available */\n    unsigned used;              /* code entries in table used */\n    unsigned huff;              /* Huffman code */\n    unsigned incr;              /* for incrementing code, index */\n    unsigned fill;              /* index for replicating entries */\n    unsigned low;               /* low bits for current root entry */\n    unsigned mask;              /* mask for low root bits */\n    code here;                  /* table entry for duplication */\n    code FAR *next;             /* next available space in table */\n    const unsigned short FAR *base;     /* base value table to use */\n    const unsigned short FAR *extra;    /* extra bits table to use */\n    unsigned match;             /* use base and extra for symbol >= match */\n    unsigned short count[MAXBITS+1];    /* number of codes of each length */\n    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */\n    static const unsigned short lbase[31] = { /* Length codes 257..285 base */\n        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};\n    static const unsigned short lext[31] = { /* Length codes 257..285 extra */\n        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,\n        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};\n    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */\n        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n        8193, 12289, 16385, 24577, 0, 0};\n    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */\n        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,\n        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,\n        28, 28, 29, 29, 64, 64};\n\n    /*\n       Process a set of code lengths to create a canonical Huffman code.  The\n       code lengths are lens[0..codes-1].  Each length corresponds to the\n       symbols 0..codes-1.  The Huffman code is generated by first sorting the\n       symbols by length from short to long, and retaining the symbol order\n       for codes with equal lengths.  Then the code starts with all zero bits\n       for the first code of the shortest length, and the codes are integer\n       increments for the same length, and zeros are appended as the length\n       increases.  For the deflate format, these bits are stored backwards\n       from their more natural integer increment ordering, and so when the\n       decoding tables are built in the large loop below, the integer codes\n       are incremented backwards.\n\n       This routine assumes, but does not check, that all of the entries in\n       lens[] are in the range 0..MAXBITS.  The caller must assure this.\n       1..MAXBITS is interpreted as that code length.  zero means that that\n       symbol does not occur in this code.\n\n       The codes are sorted by computing a count of codes for each length,\n       creating from that a table of starting indices for each length in the\n       sorted table, and then entering the symbols in order in the sorted\n       table.  The sorted table is work[], with that space being provided by\n       the caller.\n\n       The length counts are used for other purposes as well, i.e. finding\n       the minimum and maximum length codes, determining if there are any\n       codes at all, checking for a valid set of lengths, and looking ahead\n       at length counts to determine sub-table sizes when building the\n       decoding tables.\n     */\n\n    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */\n    for (len = 0; len <= MAXBITS; len++)\n        count[len] = 0;\n    for (sym = 0; sym < codes; sym++)\n        count[lens[sym]]++;\n\n    /* bound code lengths, force root to be within code lengths */\n    root = *bits;\n    for (max = MAXBITS; max >= 1; max--)\n        if (count[max] != 0) break;\n    if (root > max) root = max;\n    if (max == 0) {                     /* no symbols to code at all */\n        here.op = (unsigned char)64;    /* invalid code marker */\n        here.bits = (unsigned char)1;\n        here.val = (unsigned short)0;\n        *(*table)++ = here;             /* make a table to force an error */\n        *(*table)++ = here;\n        *bits = 1;\n        return 0;     /* no symbols, but wait for decoding to report error */\n    }\n    for (min = 1; min < max; min++)\n        if (count[min] != 0) break;\n    if (root < min) root = min;\n\n    /* check for an over-subscribed or incomplete set of lengths */\n    left = 1;\n    for (len = 1; len <= MAXBITS; len++) {\n        left <<= 1;\n        left -= count[len];\n        if (left < 0) return -1;        /* over-subscribed */\n    }\n    if (left > 0 && (type == CODES || max != 1))\n        return -1;                      /* incomplete set */\n\n    /* generate offsets into symbol table for each length for sorting */\n    offs[1] = 0;\n    for (len = 1; len < MAXBITS; len++)\n        offs[len + 1] = offs[len] + count[len];\n\n    /* sort symbols by length, by symbol order within each length */\n    for (sym = 0; sym < codes; sym++)\n        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;\n\n    /*\n       Create and fill in decoding tables.  In this loop, the table being\n       filled is at next and has curr index bits.  The code being used is huff\n       with length len.  That code is converted to an index by dropping drop\n       bits off of the bottom.  For codes where len is less than drop + curr,\n       those top drop + curr - len bits are incremented through all values to\n       fill the table with replicated entries.\n\n       root is the number of index bits for the root table.  When len exceeds\n       root, sub-tables are created pointed to by the root entry with an index\n       of the low root bits of huff.  This is saved in low to check for when a\n       new sub-table should be started.  drop is zero when the root table is\n       being filled, and drop is root when sub-tables are being filled.\n\n       When a new sub-table is needed, it is necessary to look ahead in the\n       code lengths to determine what size sub-table is needed.  The length\n       counts are used for this, and so count[] is decremented as codes are\n       entered in the tables.\n\n       used keeps track of how many table entries have been allocated from the\n       provided *table space.  It is checked for LENS and DIST tables against\n       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in\n       the initial root table size constants.  See the comments in inftrees.h\n       for more information.\n\n       sym increments through all symbols, and the loop terminates when\n       all codes of length max, i.e. all codes, have been processed.  This\n       routine permits incomplete codes, so another loop after this one fills\n       in the rest of the decoding tables with invalid code markers.\n     */\n\n    /* set up for code type */\n    switch (type) {\n    case CODES:\n        base = extra = work;    /* dummy value--not used */\n        match = 20;\n        break;\n    case LENS:\n        base = lbase;\n        extra = lext;\n        match = 257;\n        break;\n    default:    /* DISTS */\n        base = dbase;\n        extra = dext;\n        match = 0;\n    }\n\n    /* initialize state for loop */\n    huff = 0;                   /* starting code */\n    sym = 0;                    /* starting code symbol */\n    len = min;                  /* starting code length */\n    next = *table;              /* current table to fill in */\n    curr = root;                /* current table index bits */\n    drop = 0;                   /* current bits to drop from code for index */\n    low = (unsigned)(-1);       /* trigger new sub-table when len > root */\n    used = 1U << root;          /* use root table entries */\n    mask = used - 1;            /* mask for comparing low */\n\n    /* check available table space */\n    if ((type == LENS && used > ENOUGH_LENS) ||\n        (type == DISTS && used > ENOUGH_DISTS))\n        return 1;\n\n    /* process all codes and make table entries */\n    for (;;) {\n        /* create table entry */\n        here.bits = (unsigned char)(len - drop);\n        if (work[sym] + 1U < match) {\n            here.op = (unsigned char)0;\n            here.val = work[sym];\n        }\n        else if (work[sym] >= match) {\n            here.op = (unsigned char)(extra[work[sym] - match]);\n            here.val = base[work[sym] - match];\n        }\n        else {\n            here.op = (unsigned char)(32 + 64);         /* end of block */\n            here.val = 0;\n        }\n\n        /* replicate for those indices with low len bits equal to huff */\n        incr = 1U << (len - drop);\n        fill = 1U << curr;\n        min = fill;                 /* save offset to next table */\n        do {\n            fill -= incr;\n            next[(huff >> drop) + fill] = here;\n        } while (fill != 0);\n\n        /* backwards increment the len-bit code huff */\n        incr = 1U << (len - 1);\n        while (huff & incr)\n            incr >>= 1;\n        if (incr != 0) {\n            huff &= incr - 1;\n            huff += incr;\n        }\n        else\n            huff = 0;\n\n        /* go to next symbol, update count, len */\n        sym++;\n        if (--(count[len]) == 0) {\n            if (len == max) break;\n            len = lens[work[sym]];\n        }\n\n        /* create new sub-table if needed */\n        if (len > root && (huff & mask) != low) {\n            /* if first time, transition to sub-tables */\n            if (drop == 0)\n                drop = root;\n\n            /* increment past last table */\n            next += min;            /* here min is 1 << curr */\n\n            /* determine length of next table */\n            curr = len - drop;\n            left = (int)(1 << curr);\n            while (curr + drop < max) {\n                left -= count[curr + drop];\n                if (left <= 0) break;\n                curr++;\n                left <<= 1;\n            }\n\n            /* check for enough space */\n            used += 1U << curr;\n            if ((type == LENS && used > ENOUGH_LENS) ||\n                (type == DISTS && used > ENOUGH_DISTS))\n                return 1;\n\n            /* point entry in root table to sub-table */\n            low = huff & mask;\n            (*table)[low].op = (unsigned char)curr;\n            (*table)[low].bits = (unsigned char)root;\n            (*table)[low].val = (unsigned short)(next - *table);\n        }\n    }\n\n    /* fill in remaining table entry if code is incomplete (guaranteed to have\n       at most one remaining entry, since if the code is incomplete, the\n       maximum code length that was allowed to get this far is one bit) */\n    if (huff != 0) {\n        here.op = (unsigned char)64;            /* invalid code marker */\n        here.bits = (unsigned char)(len - drop);\n        here.val = (unsigned short)0;\n        next[huff] = here;\n    }\n\n    /* set return parameters */\n    *table += used;\n    *bits = root;\n    return 0;\n}\n"
  },
  {
    "path": "deps/CascLib/src/zlib/inftrees.h",
    "content": "/* inftrees.h -- header to use inftrees.c\n * Copyright (C) 1995-2005, 2010 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n#ifndef __INFTREES_H_ \n#define __INFTREES_H_ \n \n/* Structure for decoding tables.  Each entry provides either the\n   information needed to do the operation requested by the code that\n   indexed that table entry, or it provides a pointer to another\n   table that indexes more bits of the code.  op indicates whether\n   the entry is a pointer to another table, a literal, a length or\n   distance, an end-of-block, or an invalid code.  For a table\n   pointer, the low four bits of op is the number of index bits of\n   that table.  For a length or distance, the low four bits of op\n   is the number of extra bits to get after the code.  bits is\n   the number of bits in this code or part of the code to drop off\n   of the bit buffer.  val is the actual byte to output in the case\n   of a literal, the base length or distance, or the offset from\n   the current table to the next table.  Each entry is four bytes. */\ntypedef struct {\n    unsigned char op;           /* operation, extra bits, table bits */\n    unsigned char bits;         /* bits in this part of the code */\n    unsigned short val;         /* offset in table or code value */\n} code;\n\n/* op values as set by inflate_table():\n    00000000 - literal\n    0000tttt - table link, tttt != 0 is the number of table index bits\n    0001eeee - length or distance, eeee is the number of extra bits\n    01100000 - end of block\n    01000000 - invalid code\n */\n\n/* Maximum size of the dynamic table.  The maximum number of code structures is\n   1444, which is the sum of 852 for literal/length codes and 592 for distance\n   codes.  These values were found by exhaustive searches using the program\n   examples/enough.c found in the zlib distribtution.  The arguments to that\n   program are the number of symbols, the initial root table size, and the\n   maximum bit length of a code.  \"enough 286 9 15\" for literal/length codes\n   returns returns 852, and \"enough 30 6 15\" for distance codes returns 592.\n   The initial root table size (9 or 6) is found in the fifth argument of the\n   inflate_table() calls in inflate.c and infback.c.  If the root table size is\n   changed, then these maximum sizes would be need to be recalculated and\n   updated. */\n#define ENOUGH_LENS 852\n#define ENOUGH_DISTS 592\n#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)\n\n/* Type of code to build for inflate_table() */\ntypedef enum {\n    CODES,\n    LENS,\n    DISTS\n} codetype;\n\nint ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,\n                             unsigned codes, code FAR * FAR *table,\n                             unsigned FAR *bits, unsigned short FAR *work));\n\n#endif  // __INFTREES_H_ \n"
  },
  {
    "path": "deps/CascLib/src/zlib/trees.c",
    "content": "/* trees.c -- output deflated data using Huffman coding\n * Copyright (C) 1995-2017 Jean-loup Gailly\n * detect_data_type() function provided freely by Cosmin Truta, 2006\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n *  ALGORITHM\n *\n *      The \"deflation\" process uses several Huffman trees. The more\n *      common source values are represented by shorter bit sequences.\n *\n *      Each code tree is stored in a compressed form which is itself\n * a Huffman encoding of the lengths of all the code strings (in\n * ascending order by source values).  The actual code strings are\n * reconstructed from the lengths in the inflate process, as described\n * in the deflate specification.\n *\n *  REFERENCES\n *\n *      Deutsch, L.P.,\"'Deflate' Compressed Data Format Specification\".\n *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc\n *\n *      Storer, James A.\n *          Data Compression:  Methods and Theory, pp. 49-50.\n *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.\n *\n *      Sedgewick, R.\n *          Algorithms, p290.\n *          Addison-Wesley, 1983. ISBN 0-201-06672-6.\n */\n\n/* @(#) $Id$ */\n\n/* #define GEN_TREES_H */\n\n#include \"deflate.h\"\n\n#ifdef ZLIB_DEBUG\n#  include <ctype.h>\n#endif\n\n/* ===========================================================================\n * Constants\n */\n\n#define MAX_BL_BITS 7\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\n#define END_BLOCK 256\n/* end of block literal code */\n\n#define REP_3_6      16\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\n#define REPZ_3_10    17\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\n#define REPZ_11_138  18\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\nlocal const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */\n   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};\n\nlocal const int extra_dbits[D_CODES] /* extra bits for each distance code */\n   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nlocal const int extra_blbits[BL_CODES]/* extra bits for each bit length code */\n   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};\n\nlocal const uch bl_order[BL_CODES]\n   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n#define DIST_CODE_LEN  512 /* see definition of array dist_code below */\n\n#if defined(GEN_TREES_H) || !defined(STDC)\n/* non ANSI compilers may not accept trees.h */\n\nlocal ct_data static_ltree[L_CODES+2];\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nlocal ct_data static_dtree[D_CODES];\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nuch _dist_code[DIST_CODE_LEN];\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nuch _length_code[MAX_MATCH-MIN_MATCH+1];\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nlocal int base_length[LENGTH_CODES];\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nlocal int base_dist[D_CODES];\n/* First normalized distance for each code (0 = distance of 1) */\n\n#else\n#  include \"trees.h\"\n#endif /* GEN_TREES_H */\n\nstruct static_tree_desc_s {\n    const ct_data *static_tree;  /* static tree or NULL */\n    const intf *extra_bits;      /* extra bits for each code or NULL */\n    int     extra_base;          /* base index for extra_bits */\n    int     elems;               /* max number of elements in the tree */\n    int     max_length;          /* max bit length for the codes */\n};\n\nlocal const static_tree_desc  static_l_desc =\n{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};\n\nlocal const static_tree_desc  static_d_desc =\n{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};\n\nlocal const static_tree_desc  static_bl_desc =\n{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};\n\n/* ===========================================================================\n * Local (static) routines in this file.\n */\n\nlocal void tr_static_init OF((void));\nlocal void init_block     OF((deflate_state *s));\nlocal void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));\nlocal void gen_bitlen     OF((deflate_state *s, tree_desc *desc));\nlocal void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));\nlocal void build_tree     OF((deflate_state *s, tree_desc *desc));\nlocal void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));\nlocal void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));\nlocal int  build_bl_tree  OF((deflate_state *s));\nlocal void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,\n                              int blcodes));\nlocal void compress_block OF((deflate_state *s, const ct_data *ltree,\n                              const ct_data *dtree));\nlocal int  detect_data_type OF((deflate_state *s));\nlocal unsigned bi_reverse OF((unsigned value, int length));\nlocal void bi_windup      OF((deflate_state *s));\nlocal void bi_flush       OF((deflate_state *s));\n\n#ifdef GEN_TREES_H\nlocal void gen_trees_header OF((void));\n#endif\n\n#ifndef ZLIB_DEBUG\n#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)\n   /* Send a code of the given tree. c and tree must not have side effects */\n\n#else /* !ZLIB_DEBUG */\n#  define send_code(s, c, tree) \\\n     { if (z_verbose>2) fprintf(stderr,\"\\ncd %3d \",(c)); \\\n       send_bits(s, tree[c].Code, tree[c].Len); }\n#endif\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\n#define put_short(s, w) { \\\n    put_byte(s, (uch)((w) & 0xff)); \\\n    put_byte(s, (uch)((ush)(w) >> 8)); \\\n}\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\n#ifdef ZLIB_DEBUG\nlocal void send_bits      OF((deflate_state *s, int value, int length));\n\nlocal void send_bits(s, value, length)\n    deflate_state *s;\n    int value;  /* value to send */\n    int length; /* number of bits */\n{\n    Tracevv((stderr,\" l %2d v %4x \", length, value));\n    Assert(length > 0 && length <= 15, \"invalid length\");\n    s->bits_sent += (ulg)length;\n\n    /* If not enough room in bi_buf, use (valid) bits from bi_buf and\n     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))\n     * unused bits in value.\n     */\n    if (s->bi_valid > (int)Buf_size - length) {\n        s->bi_buf |= (ush)value << s->bi_valid;\n        put_short(s, s->bi_buf);\n        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);\n        s->bi_valid += length - Buf_size;\n    } else {\n        s->bi_buf |= (ush)value << s->bi_valid;\n        s->bi_valid += length;\n    }\n}\n#else /* !ZLIB_DEBUG */\n\n#define send_bits(s, value, length) \\\n{ int len = length;\\\n  if (s->bi_valid > (int)Buf_size - len) {\\\n    int val = (int)value;\\\n    s->bi_buf |= (ush)val << s->bi_valid;\\\n    put_short(s, s->bi_buf);\\\n    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\\\n    s->bi_valid += len - Buf_size;\\\n  } else {\\\n    s->bi_buf |= (ush)(value) << s->bi_valid;\\\n    s->bi_valid += len;\\\n  }\\\n}\n#endif /* ZLIB_DEBUG */\n\n\n/* the arguments must not have side effects */\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nlocal void tr_static_init()\n{\n#if defined(GEN_TREES_H) || !defined(STDC)\n    static int static_init_done = 0;\n    int n;        /* iterates over tree elements */\n    int bits;     /* bit counter */\n    int length;   /* length value */\n    int code;     /* code value */\n    int dist;     /* distance index */\n    ush bl_count[MAX_BITS+1];\n    /* number of codes at each bit length for an optimal tree */\n\n    if (static_init_done) return;\n\n    /* For some embedded targets, global variables are not initialized: */\n#ifdef NO_INIT_GLOBAL_POINTERS\n    static_l_desc.static_tree = static_ltree;\n    static_l_desc.extra_bits = extra_lbits;\n    static_d_desc.static_tree = static_dtree;\n    static_d_desc.extra_bits = extra_dbits;\n    static_bl_desc.extra_bits = extra_blbits;\n#endif\n\n    /* Initialize the mapping length (0..255) -> length code (0..28) */\n    length = 0;\n    for (code = 0; code < LENGTH_CODES-1; code++) {\n        base_length[code] = length;\n        for (n = 0; n < (1<<extra_lbits[code]); n++) {\n            _length_code[length++] = (uch)code;\n        }\n    }\n    Assert (length == 256, \"tr_static_init: length != 256\");\n    /* Note that the length 255 (match length 258) can be represented\n     * in two different ways: code 284 + 5 bits or code 285, so we\n     * overwrite length_code[255] to use the best encoding:\n     */\n    _length_code[length-1] = (uch)code;\n\n    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n    dist = 0;\n    for (code = 0 ; code < 16; code++) {\n        base_dist[code] = dist;\n        for (n = 0; n < (1<<extra_dbits[code]); n++) {\n            _dist_code[dist++] = (uch)code;\n        }\n    }\n    Assert (dist == 256, \"tr_static_init: dist != 256\");\n    dist >>= 7; /* from now on, all distances are divided by 128 */\n    for ( ; code < D_CODES; code++) {\n        base_dist[code] = dist << 7;\n        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {\n            _dist_code[256 + dist++] = (uch)code;\n        }\n    }\n    Assert (dist == 256, \"tr_static_init: 256+dist != 512\");\n\n    /* Construct the codes of the static literal tree */\n    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;\n    n = 0;\n    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;\n    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;\n    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;\n    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;\n    /* Codes 286 and 287 do not exist, but we must include them in the\n     * tree construction to get a canonical Huffman tree (longest code\n     * all ones)\n     */\n    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);\n\n    /* The static distance tree is trivial: */\n    for (n = 0; n < D_CODES; n++) {\n        static_dtree[n].Len = 5;\n        static_dtree[n].Code = bi_reverse((unsigned)n, 5);\n    }\n    static_init_done = 1;\n\n#  ifdef GEN_TREES_H\n    gen_trees_header();\n#  endif\n#endif /* defined(GEN_TREES_H) || !defined(STDC) */\n}\n\n/* ===========================================================================\n * Genererate the file trees.h describing the static trees.\n */\n#ifdef GEN_TREES_H\n#  ifndef ZLIB_DEBUG\n#    include <stdio.h>\n#  endif\n\n#  define SEPARATOR(i, last, width) \\\n      ((i) == (last)? \"\\n};\\n\\n\" :    \\\n       ((i) % (width) == (width)-1 ? \",\\n\" : \", \"))\n\nvoid gen_trees_header()\n{\n    FILE *header = fopen(\"trees.h\", \"w\");\n    int i;\n\n    Assert (header != NULL, \"Can't open trees.h\");\n    fprintf(header,\n            \"/* header created automatically with -DGEN_TREES_H */\\n\\n\");\n\n    fprintf(header, \"local const ct_data static_ltree[L_CODES+2] = {\\n\");\n    for (i = 0; i < L_CODES+2; i++) {\n        fprintf(header, \"{{%3u},{%3u}}%s\", static_ltree[i].Code,\n                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));\n    }\n\n    fprintf(header, \"local const ct_data static_dtree[D_CODES] = {\\n\");\n    for (i = 0; i < D_CODES; i++) {\n        fprintf(header, \"{{%2u},{%2u}}%s\", static_dtree[i].Code,\n                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));\n    }\n\n    fprintf(header, \"const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\\n\");\n    for (i = 0; i < DIST_CODE_LEN; i++) {\n        fprintf(header, \"%2u%s\", _dist_code[i],\n                SEPARATOR(i, DIST_CODE_LEN-1, 20));\n    }\n\n    fprintf(header,\n        \"const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\\n\");\n    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {\n        fprintf(header, \"%2u%s\", _length_code[i],\n                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));\n    }\n\n    fprintf(header, \"local const int base_length[LENGTH_CODES] = {\\n\");\n    for (i = 0; i < LENGTH_CODES; i++) {\n        fprintf(header, \"%1u%s\", base_length[i],\n                SEPARATOR(i, LENGTH_CODES-1, 20));\n    }\n\n    fprintf(header, \"local const int base_dist[D_CODES] = {\\n\");\n    for (i = 0; i < D_CODES; i++) {\n        fprintf(header, \"%5u%s\", base_dist[i],\n                SEPARATOR(i, D_CODES-1, 10));\n    }\n\n    fclose(header);\n}\n#endif /* GEN_TREES_H */\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nvoid ZLIB_INTERNAL _tr_init(s)\n    deflate_state *s;\n{\n    tr_static_init();\n\n    s->l_desc.dyn_tree = s->dyn_ltree;\n    s->l_desc.stat_desc = &static_l_desc;\n\n    s->d_desc.dyn_tree = s->dyn_dtree;\n    s->d_desc.stat_desc = &static_d_desc;\n\n    s->bl_desc.dyn_tree = s->bl_tree;\n    s->bl_desc.stat_desc = &static_bl_desc;\n\n    s->bi_buf = 0;\n    s->bi_valid = 0;\n#ifdef ZLIB_DEBUG\n    s->compressed_len = 0L;\n    s->bits_sent = 0L;\n#endif\n\n    /* Initialize the first block of the first file: */\n    init_block(s);\n}\n\n/* ===========================================================================\n * Initialize a new block.\n */\nlocal void init_block(s)\n    deflate_state *s;\n{\n    int n; /* iterates over tree elements */\n\n    /* Initialize the trees. */\n    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;\n    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;\n    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;\n\n    s->dyn_ltree[END_BLOCK].Freq = 1;\n    s->opt_len = s->static_len = 0L;\n    s->last_lit = s->matches = 0;\n}\n\n#define SMALLEST 1\n/* Index within the heap array of least frequent node in the Huffman tree */\n\n\n/* ===========================================================================\n * Remove the smallest element from the heap and recreate the heap with\n * one less element. Updates heap and heap_len.\n */\n#define pqremove(s, tree, top) \\\n{\\\n    top = s->heap[SMALLEST]; \\\n    s->heap[SMALLEST] = s->heap[s->heap_len--]; \\\n    pqdownheap(s, tree, SMALLEST); \\\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\n#define smaller(tree, n, m, depth) \\\n   (tree[n].Freq < tree[m].Freq || \\\n   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nlocal void pqdownheap(s, tree, k)\n    deflate_state *s;\n    ct_data *tree;  /* the tree to restore */\n    int k;               /* node to move down */\n{\n    int v = s->heap[k];\n    int j = k << 1;  /* left son of k */\n    while (j <= s->heap_len) {\n        /* Set j to the smallest of the two sons: */\n        if (j < s->heap_len &&\n            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {\n            j++;\n        }\n        /* Exit if v is smaller than both sons */\n        if (smaller(tree, v, s->heap[j], s->depth)) break;\n\n        /* Exchange v with the smallest son */\n        s->heap[k] = s->heap[j];  k = j;\n\n        /* And continue down the tree, setting j to the left son of k */\n        j <<= 1;\n    }\n    s->heap[k] = v;\n}\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nlocal void gen_bitlen(s, desc)\n    deflate_state *s;\n    tree_desc *desc;    /* the tree descriptor */\n{\n    ct_data *tree        = desc->dyn_tree;\n    int max_code         = desc->max_code;\n    const ct_data *stree = desc->stat_desc->static_tree;\n    const intf *extra    = desc->stat_desc->extra_bits;\n    int base             = desc->stat_desc->extra_base;\n    int max_length       = desc->stat_desc->max_length;\n    int h;              /* heap index */\n    int n, m;           /* iterate over the tree elements */\n    int bits;           /* bit length */\n    int xbits;          /* extra bits */\n    ush f;              /* frequency */\n    int overflow = 0;   /* number of elements with bit length too large */\n\n    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;\n\n    /* In a first pass, compute the optimal bit lengths (which may\n     * overflow in the case of the bit length tree).\n     */\n    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */\n\n    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {\n        n = s->heap[h];\n        bits = tree[tree[n].Dad].Len + 1;\n        if (bits > max_length) bits = max_length, overflow++;\n        tree[n].Len = (ush)bits;\n        /* We overwrite tree[n].Dad which is no longer needed */\n\n        if (n > max_code) continue; /* not a leaf node */\n\n        s->bl_count[bits]++;\n        xbits = 0;\n        if (n >= base) xbits = extra[n-base];\n        f = tree[n].Freq;\n        s->opt_len += (ulg)f * (unsigned)(bits + xbits);\n        if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);\n    }\n    if (overflow == 0) return;\n\n    Tracev((stderr,\"\\nbit length overflow\\n\"));\n    /* This happens for example on obj2 and pic of the Calgary corpus */\n\n    /* Find the first bit length which could increase: */\n    do {\n        bits = max_length-1;\n        while (s->bl_count[bits] == 0) bits--;\n        s->bl_count[bits]--;      /* move one leaf down the tree */\n        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */\n        s->bl_count[max_length]--;\n        /* The brother of the overflow item also moves one step up,\n         * but this does not affect bl_count[max_length]\n         */\n        overflow -= 2;\n    } while (overflow > 0);\n\n    /* Now recompute all bit lengths, scanning in increasing frequency.\n     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n     * lengths instead of fixing only the wrong ones. This idea is taken\n     * from 'ar' written by Haruhiko Okumura.)\n     */\n    for (bits = max_length; bits != 0; bits--) {\n        n = s->bl_count[bits];\n        while (n != 0) {\n            m = s->heap[--h];\n            if (m > max_code) continue;\n            if ((unsigned) tree[m].Len != (unsigned) bits) {\n                Tracev((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n                s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;\n                tree[m].Len = (ush)bits;\n            }\n            n--;\n        }\n    }\n}\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nlocal void gen_codes (tree, max_code, bl_count)\n    ct_data *tree;             /* the tree to decorate */\n    int max_code;              /* largest code with non zero frequency */\n    ushf *bl_count;            /* number of codes at each bit length */\n{\n    ush next_code[MAX_BITS+1]; /* next code value for each bit length */\n    unsigned code = 0;         /* running code value */\n    int bits;                  /* bit index */\n    int n;                     /* code index */\n\n    /* The distribution counts are first used to generate the code values\n     * without bit reversal.\n     */\n    for (bits = 1; bits <= MAX_BITS; bits++) {\n        code = (code + bl_count[bits-1]) << 1;\n        next_code[bits] = (ush)code;\n    }\n    /* Check that the bit counts in bl_count are consistent. The last code\n     * must be all ones.\n     */\n    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,\n            \"inconsistent bit counts\");\n    Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n    for (n = 0;  n <= max_code; n++) {\n        int len = tree[n].Len;\n        if (len == 0) continue;\n        /* Now reverse the bits */\n        tree[n].Code = (ush)bi_reverse(next_code[len]++, len);\n\n        Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));\n    }\n}\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nlocal void build_tree(s, desc)\n    deflate_state *s;\n    tree_desc *desc; /* the tree descriptor */\n{\n    ct_data *tree         = desc->dyn_tree;\n    const ct_data *stree  = desc->stat_desc->static_tree;\n    int elems             = desc->stat_desc->elems;\n    int n, m;          /* iterate over heap elements */\n    int max_code = -1; /* largest code with non zero frequency */\n    int node;          /* new node being created */\n\n    /* Construct the initial heap, with least frequent element in\n     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].\n     * heap[0] is not used.\n     */\n    s->heap_len = 0, s->heap_max = HEAP_SIZE;\n\n    for (n = 0; n < elems; n++) {\n        if (tree[n].Freq != 0) {\n            s->heap[++(s->heap_len)] = max_code = n;\n            s->depth[n] = 0;\n        } else {\n            tree[n].Len = 0;\n        }\n    }\n\n    /* The pkzip format requires that at least one distance code exists,\n     * and that at least one bit should be sent even if there is only one\n     * possible code. So to avoid special checks later on we force at least\n     * two codes of non zero frequency.\n     */\n    while (s->heap_len < 2) {\n        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);\n        tree[node].Freq = 1;\n        s->depth[node] = 0;\n        s->opt_len--; if (stree) s->static_len -= stree[node].Len;\n        /* node is 0 or 1 so it does not have extra bits */\n    }\n    desc->max_code = max_code;\n\n    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,\n     * establish sub-heaps of increasing lengths:\n     */\n    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);\n\n    /* Construct the Huffman tree by repeatedly combining the least two\n     * frequent nodes.\n     */\n    node = elems;              /* next internal node of the tree */\n    do {\n        pqremove(s, tree, n);  /* n = node of least frequency */\n        m = s->heap[SMALLEST]; /* m = node of next least frequency */\n\n        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */\n        s->heap[--(s->heap_max)] = m;\n\n        /* Create a new node father of n and m */\n        tree[node].Freq = tree[n].Freq + tree[m].Freq;\n        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?\n                                s->depth[n] : s->depth[m]) + 1);\n        tree[n].Dad = tree[m].Dad = (ush)node;\n#ifdef DUMP_BL_TREE\n        if (tree == s->bl_tree) {\n            fprintf(stderr,\"\\nnode %d(%d), sons %d(%d) %d(%d)\",\n                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);\n        }\n#endif\n        /* and insert the new node in the heap */\n        s->heap[SMALLEST] = node++;\n        pqdownheap(s, tree, SMALLEST);\n\n    } while (s->heap_len >= 2);\n\n    s->heap[--(s->heap_max)] = s->heap[SMALLEST];\n\n    /* At this point, the fields freq and dad are set. We can now\n     * generate the bit lengths.\n     */\n    gen_bitlen(s, (tree_desc *)desc);\n\n    /* The field len is now set, we can generate the bit codes */\n    gen_codes ((ct_data *)tree, max_code, s->bl_count);\n}\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nlocal void scan_tree (s, tree, max_code)\n    deflate_state *s;\n    ct_data *tree;   /* the tree to be scanned */\n    int max_code;    /* and its largest code of non zero frequency */\n{\n    int n;                     /* iterates over all tree elements */\n    int prevlen = -1;          /* last emitted length */\n    int curlen;                /* length of current code */\n    int nextlen = tree[0].Len; /* length of next code */\n    int count = 0;             /* repeat count of the current code */\n    int max_count = 7;         /* max repeat count */\n    int min_count = 4;         /* min repeat count */\n\n    if (nextlen == 0) max_count = 138, min_count = 3;\n    tree[max_code+1].Len = (ush)0xffff; /* guard */\n\n    for (n = 0; n <= max_code; n++) {\n        curlen = nextlen; nextlen = tree[n+1].Len;\n        if (++count < max_count && curlen == nextlen) {\n            continue;\n        } else if (count < min_count) {\n            s->bl_tree[curlen].Freq += count;\n        } else if (curlen != 0) {\n            if (curlen != prevlen) s->bl_tree[curlen].Freq++;\n            s->bl_tree[REP_3_6].Freq++;\n        } else if (count <= 10) {\n            s->bl_tree[REPZ_3_10].Freq++;\n        } else {\n            s->bl_tree[REPZ_11_138].Freq++;\n        }\n        count = 0; prevlen = curlen;\n        if (nextlen == 0) {\n            max_count = 138, min_count = 3;\n        } else if (curlen == nextlen) {\n            max_count = 6, min_count = 3;\n        } else {\n            max_count = 7, min_count = 4;\n        }\n    }\n}\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nlocal void send_tree (s, tree, max_code)\n    deflate_state *s;\n    ct_data *tree; /* the tree to be scanned */\n    int max_code;       /* and its largest code of non zero frequency */\n{\n    int n;                     /* iterates over all tree elements */\n    int prevlen = -1;          /* last emitted length */\n    int curlen;                /* length of current code */\n    int nextlen = tree[0].Len; /* length of next code */\n    int count = 0;             /* repeat count of the current code */\n    int max_count = 7;         /* max repeat count */\n    int min_count = 4;         /* min repeat count */\n\n    /* tree[max_code+1].Len = -1; */  /* guard already set */\n    if (nextlen == 0) max_count = 138, min_count = 3;\n\n    for (n = 0; n <= max_code; n++) {\n        curlen = nextlen; nextlen = tree[n+1].Len;\n        if (++count < max_count && curlen == nextlen) {\n            continue;\n        } else if (count < min_count) {\n            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);\n\n        } else if (curlen != 0) {\n            if (curlen != prevlen) {\n                send_code(s, curlen, s->bl_tree); count--;\n            }\n            Assert(count >= 3 && count <= 6, \" 3_6?\");\n            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);\n\n        } else if (count <= 10) {\n            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);\n\n        } else {\n            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);\n        }\n        count = 0; prevlen = curlen;\n        if (nextlen == 0) {\n            max_count = 138, min_count = 3;\n        } else if (curlen == nextlen) {\n            max_count = 6, min_count = 3;\n        } else {\n            max_count = 7, min_count = 4;\n        }\n    }\n}\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nlocal int build_bl_tree(s)\n    deflate_state *s;\n{\n    int max_blindex;  /* index of last bit length code of non zero freq */\n\n    /* Determine the bit length frequencies for literal and distance trees */\n    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);\n    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);\n\n    /* Build the bit length tree: */\n    build_tree(s, (tree_desc *)(&(s->bl_desc)));\n    /* opt_len now includes the length of the tree representations, except\n     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.\n     */\n\n    /* Determine the number of bit length codes to send. The pkzip format\n     * requires that at least 4 bit length codes be sent. (appnote.txt says\n     * 3 but the actual value used is 4.)\n     */\n    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {\n        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;\n    }\n    /* Update opt_len to include the bit length tree and counts */\n    s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;\n    Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n            s->opt_len, s->static_len));\n\n    return max_blindex;\n}\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nlocal void send_all_trees(s, lcodes, dcodes, blcodes)\n    deflate_state *s;\n    int lcodes, dcodes, blcodes; /* number of codes for each tree */\n{\n    int rank;                    /* index in bl_order */\n\n    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n            \"too many codes\");\n    Tracev((stderr, \"\\nbl counts: \"));\n    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */\n    send_bits(s, dcodes-1,   5);\n    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */\n    for (rank = 0; rank < blcodes; rank++) {\n        Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);\n    }\n    Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */\n    Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */\n    Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n/* ===========================================================================\n * Send a stored block\n */\nvoid ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)\n    deflate_state *s;\n    charf *buf;       /* input block */\n    ulg stored_len;   /* length of input block */\n    int last;         /* one if this is the last block for a file */\n{\n    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */\n    bi_windup(s);        /* align on byte boundary */\n    put_short(s, (ush)stored_len);\n    put_short(s, (ush)~stored_len);\n    zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);\n    s->pending += stored_len;\n#ifdef ZLIB_DEBUG\n    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;\n    s->compressed_len += (stored_len + 4) << 3;\n    s->bits_sent += 2*16;\n    s->bits_sent += stored_len<<3;\n#endif\n}\n\n/* ===========================================================================\n * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)\n */\nvoid ZLIB_INTERNAL _tr_flush_bits(s)\n    deflate_state *s;\n{\n    bi_flush(s);\n}\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nvoid ZLIB_INTERNAL _tr_align(s)\n    deflate_state *s;\n{\n    send_bits(s, STATIC_TREES<<1, 3);\n    send_code(s, END_BLOCK, static_ltree);\n#ifdef ZLIB_DEBUG\n    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */\n#endif\n    bi_flush(s);\n}\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and write out the encoded block.\n */\nvoid ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)\n    deflate_state *s;\n    charf *buf;       /* input block, or NULL if too old */\n    ulg stored_len;   /* length of input block */\n    int last;         /* one if this is the last block for a file */\n{\n    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */\n    int max_blindex = 0;  /* index of last bit length code of non zero freq */\n\n    /* Build the Huffman trees unless a stored block is forced */\n    if (s->level > 0) {\n\n        /* Check if the file is binary or text */\n        if (s->strm->data_type == Z_UNKNOWN)\n            s->strm->data_type = detect_data_type(s);\n\n        /* Construct the literal and distance trees */\n        build_tree(s, (tree_desc *)(&(s->l_desc)));\n        Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n                s->static_len));\n\n        build_tree(s, (tree_desc *)(&(s->d_desc)));\n        Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n                s->static_len));\n        /* At this point, opt_len and static_len are the total bit lengths of\n         * the compressed block data, excluding the tree representations.\n         */\n\n        /* Build the bit length tree for the above two trees, and get the index\n         * in bl_order of the last bit length code to send.\n         */\n        max_blindex = build_bl_tree(s);\n\n        /* Determine the best encoding. Compute the block lengths in bytes. */\n        opt_lenb = (s->opt_len+3+7)>>3;\n        static_lenb = (s->static_len+3+7)>>3;\n\n        Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n                s->last_lit));\n\n        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;\n\n    } else {\n        Assert(buf != (char*)0, \"lost buf\");\n        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n    }\n\n#ifdef FORCE_STORED\n    if (buf != (char*)0) { /* force stored block */\n#else\n    if (stored_len+4 <= opt_lenb && buf != (char*)0) {\n                       /* 4: two words for the lengths */\n#endif\n        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n         * Otherwise we can't have processed more than WSIZE input bytes since\n         * the last block flush, because compression would have been\n         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n         * transform a block into a stored block.\n         */\n        _tr_stored_block(s, buf, stored_len, last);\n\n#ifdef FORCE_STATIC\n    } else if (static_lenb >= 0) { /* force static trees */\n#else\n    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {\n#endif\n        send_bits(s, (STATIC_TREES<<1)+last, 3);\n        compress_block(s, (const ct_data *)static_ltree,\n                       (const ct_data *)static_dtree);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 3 + s->static_len;\n#endif\n    } else {\n        send_bits(s, (DYN_TREES<<1)+last, 3);\n        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,\n                       max_blindex+1);\n        compress_block(s, (const ct_data *)s->dyn_ltree,\n                       (const ct_data *)s->dyn_dtree);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 3 + s->opt_len;\n#endif\n    }\n    Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n    /* The above check is made mod 2^32, for files larger than 512 MB\n     * and uLong implemented on 32 bits.\n     */\n    init_block(s);\n\n    if (last) {\n        bi_windup(s);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 7;  /* align on byte boundary */\n#endif\n    }\n    Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len>>3,\n           s->compressed_len-7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nint ZLIB_INTERNAL _tr_tally (s, dist, lc)\n    deflate_state *s;\n    unsigned dist;  /* distance of matched string */\n    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */\n{\n    s->d_buf[s->last_lit] = (ush)dist;\n    s->l_buf[s->last_lit++] = (uch)lc;\n    if (dist == 0) {\n        /* lc is the unmatched char */\n        s->dyn_ltree[lc].Freq++;\n    } else {\n        s->matches++;\n        /* Here, lc is the match length - MIN_MATCH */\n        dist--;             /* dist = match distance - 1 */\n        Assert((ush)dist < (ush)MAX_DIST(s) &&\n               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n               (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;\n        s->dyn_dtree[d_code(dist)].Freq++;\n    }\n\n#ifdef TRUNCATE_BLOCK\n    /* Try to guess if it is profitable to stop the current block here */\n    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {\n        /* Compute an upper bound for the compressed length */\n        ulg out_length = (ulg)s->last_lit*8L;\n        ulg in_length = (ulg)((long)s->strstart - s->block_start);\n        int dcode;\n        for (dcode = 0; dcode < D_CODES; dcode++) {\n            out_length += (ulg)s->dyn_dtree[dcode].Freq *\n                (5L+extra_dbits[dcode]);\n        }\n        out_length >>= 3;\n        Tracev((stderr,\"\\nlast_lit %u, in %ld, out ~%ld(%ld%%) \",\n               s->last_lit, in_length, out_length,\n               100L - out_length*100L/in_length));\n        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;\n    }\n#endif\n    return (s->last_lit == s->lit_bufsize-1);\n    /* We avoid equality with lit_bufsize because of wraparound at 64K\n     * on 16 bit machines and because stored blocks are restricted to\n     * 64K-1 bytes.\n     */\n}\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nlocal void compress_block(s, ltree, dtree)\n    deflate_state *s;\n    const ct_data *ltree; /* literal tree */\n    const ct_data *dtree; /* distance tree */\n{\n    unsigned dist;      /* distance of matched string */\n    int lc;             /* match length or unmatched char (if dist == 0) */\n    unsigned lx = 0;    /* running index in l_buf */\n    unsigned code;      /* the code to send */\n    int extra;          /* number of extra bits to send */\n\n    if (s->last_lit != 0) do {\n        dist = s->d_buf[lx];\n        lc = s->l_buf[lx++];\n        if (dist == 0) {\n            send_code(s, lc, ltree); /* send a literal byte */\n            Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n        } else {\n            /* Here, lc is the match length - MIN_MATCH */\n            code = _length_code[lc];\n            send_code(s, code+LITERALS+1, ltree); /* send the length code */\n            extra = extra_lbits[code];\n            if (extra != 0) {\n                lc -= base_length[code];\n                send_bits(s, lc, extra);       /* send the extra length bits */\n            }\n            dist--; /* dist is now the match distance - 1 */\n            code = d_code(dist);\n            Assert (code < D_CODES, \"bad d_code\");\n\n            send_code(s, code, dtree);       /* send the distance code */\n            extra = extra_dbits[code];\n            if (extra != 0) {\n                dist -= (unsigned)base_dist[code];\n                send_bits(s, dist, extra);   /* send the extra distance bits */\n            }\n        } /* literal or match pair ? */\n\n        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */\n        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,\n               \"pendingBuf overflow\");\n\n    } while (lx < s->last_lit);\n\n    send_code(s, END_BLOCK, ltree);\n}\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"black list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"white list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nlocal int detect_data_type(s)\n    deflate_state *s;\n{\n    /* black_mask is the bit mask of black-listed bytes\n     * set bits 0..6, 14..25, and 28..31\n     * 0xf3ffc07f = binary 11110011111111111100000001111111\n     */\n    unsigned long black_mask = 0xf3ffc07fUL;\n    int n;\n\n    /* Check for non-textual (\"black-listed\") bytes. */\n    for (n = 0; n <= 31; n++, black_mask >>= 1)\n        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))\n            return Z_BINARY;\n\n    /* Check for textual (\"white-listed\") bytes. */\n    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0\n            || s->dyn_ltree[13].Freq != 0)\n        return Z_TEXT;\n    for (n = 32; n < LITERALS; n++)\n        if (s->dyn_ltree[n].Freq != 0)\n            return Z_TEXT;\n\n    /* There are no \"black-listed\" or \"white-listed\" bytes:\n     * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n     */\n    return Z_BINARY;\n}\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nlocal unsigned bi_reverse(code, len)\n    unsigned code; /* the value to invert */\n    int len;       /* its bit length */\n{\n    register unsigned res = 0;\n    do {\n        res |= code & 1;\n        code >>= 1, res <<= 1;\n    } while (--len > 0);\n    return res >> 1;\n}\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nlocal void bi_flush(s)\n    deflate_state *s;\n{\n    if (s->bi_valid == 16) {\n        put_short(s, s->bi_buf);\n        s->bi_buf = 0;\n        s->bi_valid = 0;\n    } else if (s->bi_valid >= 8) {\n        put_byte(s, (Byte)s->bi_buf);\n        s->bi_buf >>= 8;\n        s->bi_valid -= 8;\n    }\n}\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nlocal void bi_windup(s)\n    deflate_state *s;\n{\n    if (s->bi_valid > 8) {\n        put_short(s, s->bi_buf);\n    } else if (s->bi_valid > 0) {\n        put_byte(s, (Byte)s->bi_buf);\n    }\n    s->bi_buf = 0;\n    s->bi_valid = 0;\n#ifdef ZLIB_DEBUG\n    s->bits_sent = (s->bits_sent+7) & ~7;\n#endif\n}\n"
  },
  {
    "path": "deps/CascLib/src/zlib/trees.h",
    "content": "/* header created automatically with -DGEN_TREES_H */\n\nlocal const ct_data static_ltree[L_CODES+2] = {\n{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},\n{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},\n{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},\n{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},\n{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},\n{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},\n{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},\n{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},\n{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},\n{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},\n{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},\n{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},\n{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},\n{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},\n{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},\n{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},\n{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},\n{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},\n{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},\n{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},\n{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},\n{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},\n{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},\n{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},\n{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},\n{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},\n{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},\n{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},\n{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},\n{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},\n{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},\n{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},\n{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},\n{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},\n{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},\n{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},\n{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},\n{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},\n{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},\n{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},\n{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},\n{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},\n{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},\n{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},\n{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},\n{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},\n{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},\n{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},\n{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},\n{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},\n{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},\n{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},\n{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},\n{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},\n{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},\n{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},\n{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},\n{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}\n};\n\nlocal const ct_data static_dtree[D_CODES] = {\n{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},\n{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},\n{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},\n{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},\n{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},\n{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}\n};\n\nconst uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,\n 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,\n10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,\n11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,\n12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,\n13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,\n13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,\n18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,\n23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29\n};\n\nconst uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,\n13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,\n17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,\n19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,\n21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,\n22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,\n23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,\n25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28\n};\n\nlocal const int base_length[LENGTH_CODES] = {\n0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,\n64, 80, 96, 112, 128, 160, 192, 224, 0\n};\n\nlocal const int base_dist[D_CODES] = {\n    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,\n   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,\n 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576\n};\n\n"
  },
  {
    "path": "deps/CascLib/src/zlib/zconf.h",
    "content": "/* zconf.h -- configuration of the zlib compression library\n * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZCONF_H\n#define ZCONF_H\n\n/*\n * If you *really* need a unique prefix for all types and library functions,\n * compile with -DZ_PREFIX. The \"standard\" zlib should be compiled without it.\n * Even better than compiling with -DZ_PREFIX would be to use configure to set\n * this permanently in zconf.h using \"./configure --zprefix\".\n */\n#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */\n#  define Z_PREFIX_SET\n\n/* all linked symbols and init macros */\n#  define _dist_code            z__dist_code\n#  define _length_code          z__length_code\n#  define _tr_align             z__tr_align\n#  define _tr_flush_bits        z__tr_flush_bits\n#  define _tr_flush_block       z__tr_flush_block\n#  define _tr_init              z__tr_init\n#  define _tr_stored_block      z__tr_stored_block\n#  define _tr_tally             z__tr_tally\n#  define adler32               z_adler32\n#  define adler32_combine       z_adler32_combine\n#  define adler32_combine64     z_adler32_combine64\n#  define adler32_z             z_adler32_z\n#  ifndef Z_SOLO\n#    define compress              z_compress\n#    define compress2             z_compress2\n#    define compressBound         z_compressBound\n#  endif\n#  define crc32                 z_crc32\n#  define crc32_combine         z_crc32_combine\n#  define crc32_combine64       z_crc32_combine64\n#  define crc32_z               z_crc32_z\n#  define deflate               z_deflate\n#  define deflateBound          z_deflateBound\n#  define deflateCopy           z_deflateCopy\n#  define deflateEnd            z_deflateEnd\n#  define deflateGetDictionary  z_deflateGetDictionary\n#  define deflateInit           z_deflateInit\n#  define deflateInit2          z_deflateInit2\n#  define deflateInit2_         z_deflateInit2_\n#  define deflateInit_          z_deflateInit_\n#  define deflateParams         z_deflateParams\n#  define deflatePending        z_deflatePending\n#  define deflatePrime          z_deflatePrime\n#  define deflateReset          z_deflateReset\n#  define deflateResetKeep      z_deflateResetKeep\n#  define deflateSetDictionary  z_deflateSetDictionary\n#  define deflateSetHeader      z_deflateSetHeader\n#  define deflateTune           z_deflateTune\n#  define deflate_copyright     z_deflate_copyright\n#  define get_crc_table         z_get_crc_table\n#  ifndef Z_SOLO\n#    define gz_error              z_gz_error\n#    define gz_intmax             z_gz_intmax\n#    define gz_strwinerror        z_gz_strwinerror\n#    define gzbuffer              z_gzbuffer\n#    define gzclearerr            z_gzclearerr\n#    define gzclose               z_gzclose\n#    define gzclose_r             z_gzclose_r\n#    define gzclose_w             z_gzclose_w\n#    define gzdirect              z_gzdirect\n#    define gzdopen               z_gzdopen\n#    define gzeof                 z_gzeof\n#    define gzerror               z_gzerror\n#    define gzflush               z_gzflush\n#    define gzfread               z_gzfread\n#    define gzfwrite              z_gzfwrite\n#    define gzgetc                z_gzgetc\n#    define gzgetc_               z_gzgetc_\n#    define gzgets                z_gzgets\n#    define gzoffset              z_gzoffset\n#    define gzoffset64            z_gzoffset64\n#    define gzopen                z_gzopen\n#    define gzopen64              z_gzopen64\n#    ifdef _WIN32\n#      define gzopen_w              z_gzopen_w\n#    endif\n#    define gzprintf              z_gzprintf\n#    define gzputc                z_gzputc\n#    define gzputs                z_gzputs\n#    define gzread                z_gzread\n#    define gzrewind              z_gzrewind\n#    define gzseek                z_gzseek\n#    define gzseek64              z_gzseek64\n#    define gzsetparams           z_gzsetparams\n#    define gztell                z_gztell\n#    define gztell64              z_gztell64\n#    define gzungetc              z_gzungetc\n#    define gzvprintf             z_gzvprintf\n#    define gzwrite               z_gzwrite\n#  endif\n#  define inflate               z_inflate\n#  define inflateBack           z_inflateBack\n#  define inflateBackEnd        z_inflateBackEnd\n#  define inflateBackInit       z_inflateBackInit\n#  define inflateBackInit_      z_inflateBackInit_\n#  define inflateCodesUsed      z_inflateCodesUsed\n#  define inflateCopy           z_inflateCopy\n#  define inflateEnd            z_inflateEnd\n#  define inflateGetDictionary  z_inflateGetDictionary\n#  define inflateGetHeader      z_inflateGetHeader\n#  define inflateInit           z_inflateInit\n#  define inflateInit2          z_inflateInit2\n#  define inflateInit2_         z_inflateInit2_\n#  define inflateInit_          z_inflateInit_\n#  define inflateMark           z_inflateMark\n#  define inflatePrime          z_inflatePrime\n#  define inflateReset          z_inflateReset\n#  define inflateReset2         z_inflateReset2\n#  define inflateResetKeep      z_inflateResetKeep\n#  define inflateSetDictionary  z_inflateSetDictionary\n#  define inflateSync           z_inflateSync\n#  define inflateSyncPoint      z_inflateSyncPoint\n#  define inflateUndermine      z_inflateUndermine\n#  define inflateValidate       z_inflateValidate\n#  define inflate_copyright     z_inflate_copyright\n#  define inflate_fast          z_inflate_fast\n#  define inflate_table         z_inflate_table\n#  ifndef Z_SOLO\n#    define uncompress            z_uncompress\n#    define uncompress2           z_uncompress2\n#  endif\n#  define zError                z_zError\n#  ifndef Z_SOLO\n#    define zcalloc               z_zcalloc\n#    define zcfree                z_zcfree\n#  endif\n#  define zlibCompileFlags      z_zlibCompileFlags\n#  define zlibVersion           z_zlibVersion\n\n/* all zlib typedefs in zlib.h and zconf.h */\n#  define Byte                  z_Byte\n#  define Bytef                 z_Bytef\n#  define alloc_func            z_alloc_func\n#  define charf                 z_charf\n#  define free_func             z_free_func\n#  ifndef Z_SOLO\n#    define gzFile                z_gzFile\n#  endif\n#  define gz_header             z_gz_header\n#  define gz_headerp            z_gz_headerp\n#  define in_func               z_in_func\n#  define intf                  z_intf\n#  define out_func              z_out_func\n#  define uInt                  z_uInt\n#  define uIntf                 z_uIntf\n#  define uLong                 z_uLong\n#  define uLongf                z_uLongf\n#  define voidp                 z_voidp\n#  define voidpc                z_voidpc\n#  define voidpf                z_voidpf\n\n/* all zlib structs in zlib.h and zconf.h */\n#  define gz_header_s           z_gz_header_s\n#  define internal_state        z_internal_state\n\n#endif\n\n#if defined(__MSDOS__) && !defined(MSDOS)\n#  define MSDOS\n#endif\n#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)\n#  define OS2\n#endif\n#if defined(_WINDOWS) && !defined(WINDOWS)\n#  define WINDOWS\n#endif\n#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)\n#  ifndef WIN32\n#    define WIN32\n#  endif\n#endif\n#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)\n#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)\n#    ifndef SYS16BIT\n#      define SYS16BIT\n#    endif\n#  endif\n#endif\n\n/*\n * Compile with -DMAXSEG_64K if the alloc function cannot allocate more\n * than 64k bytes at a time (needed on systems with 16-bit int).\n */\n#ifdef SYS16BIT\n#  define MAXSEG_64K\n#endif\n#ifdef MSDOS\n#  define UNALIGNED_OK\n#endif\n\n#ifdef __STDC_VERSION__\n#  ifndef STDC\n#    define STDC\n#  endif\n#  if __STDC_VERSION__ >= 199901L\n#    ifndef STDC99\n#      define STDC99\n#    endif\n#  endif\n#endif\n#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))\n#  define STDC\n#endif\n\n#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */\n#  define STDC\n#endif\n\n#ifndef STDC\n#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */\n#    define const       /* note: need a more gentle solution here */\n#  endif\n#endif\n\n#if defined(ZLIB_CONST) && !defined(z_const)\n#  define z_const const\n#else\n#  define z_const\n#endif\n\n#ifdef Z_SOLO\n   typedef unsigned long z_size_t;\n#else\n#  define z_longlong long long\n#  if defined(NO_SIZE_T)\n     typedef unsigned NO_SIZE_T z_size_t;\n#  elif defined(STDC)\n#    include <stddef.h>\n     typedef size_t z_size_t;\n#  else\n     typedef unsigned long z_size_t;\n#  endif\n#  undef z_longlong\n#endif\n\n/* Maximum value for memLevel in deflateInit2 */\n#ifndef MAX_MEM_LEVEL\n#  ifdef MAXSEG_64K\n#    define MAX_MEM_LEVEL 8\n#  else\n#    define MAX_MEM_LEVEL 9\n#  endif\n#endif\n\n/* Maximum value for windowBits in deflateInit2 and inflateInit2.\n * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files\n * created by gzip. (Files created by minigzip can still be extracted by\n * gzip.)\n */\n#ifndef MAX_WBITS\n#  define MAX_WBITS   15 /* 32K LZ77 window */\n#endif\n\n/* The memory requirements for deflate are (in bytes):\n            (1 << (windowBits+2)) +  (1 << (memLevel+9))\n that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)\n plus a few kilobytes for small objects. For example, if you want to reduce\n the default memory requirements from 256K to 128K, compile with\n     make CFLAGS=\"-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7\"\n Of course this will generally degrade compression (there's no free lunch).\n\n   The memory requirements for inflate are (in bytes) 1 << windowBits\n that is, 32K for windowBits=15 (default value) plus about 7 kilobytes\n for small objects.\n*/\n\n                        /* Type declarations */\n\n#ifndef OF /* function prototypes */\n#  ifdef STDC\n#    define OF(args)  args\n#  else\n#    define OF(args)  ()\n#  endif\n#endif\n\n#ifndef Z_ARG /* function prototypes for stdarg */\n#  if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#    define Z_ARG(args)  args\n#  else\n#    define Z_ARG(args)  ()\n#  endif\n#endif\n\n/* The following definitions for FAR are needed only for MSDOS mixed\n * model programming (small or medium model with some far allocations).\n * This was tested only with MSC; for other MSDOS compilers you may have\n * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,\n * just define FAR to be empty.\n */\n#ifdef SYS16BIT\n#  if defined(M_I86SM) || defined(M_I86MM)\n     /* MSC small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef _MSC_VER\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#  if (defined(__SMALL__) || defined(__MEDIUM__))\n     /* Turbo C small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef __BORLANDC__\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#endif\n\n#if defined(WINDOWS) || defined(WIN32)\n   /* If building or using zlib as a DLL, define ZLIB_DLL.\n    * This is not mandatory, but it offers a little performance increase.\n    */\n#  ifdef ZLIB_DLL\n#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))\n#      ifdef ZLIB_INTERNAL\n#        define ZEXTERN extern __declspec(dllexport)\n#      else\n#        define ZEXTERN extern __declspec(dllimport)\n#      endif\n#    endif\n#  endif  /* ZLIB_DLL */\n   /* If building or using zlib with the WINAPI/WINAPIV calling convention,\n    * define ZLIB_WINAPI.\n    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.\n    */\n#  ifdef ZLIB_WINAPI\n#    ifdef FAR\n#      undef FAR\n#    endif\n#    include <windows.h>\n     /* No need for _export, use ZLIB.DEF instead. */\n     /* For complete Windows compatibility, use WINAPI, not __stdcall. */\n#    define ZEXPORT WINAPI\n#    ifdef WIN32\n#      define ZEXPORTVA WINAPIV\n#    else\n#      define ZEXPORTVA FAR CDECL\n#    endif\n#  endif\n#endif\n\n#if defined (__BEOS__)\n#  ifdef ZLIB_DLL\n#    ifdef ZLIB_INTERNAL\n#      define ZEXPORT   __declspec(dllexport)\n#      define ZEXPORTVA __declspec(dllexport)\n#    else\n#      define ZEXPORT   __declspec(dllimport)\n#      define ZEXPORTVA __declspec(dllimport)\n#    endif\n#  endif\n#endif\n\n#ifndef ZEXTERN\n#  define ZEXTERN extern\n#endif\n#ifndef ZEXPORT\n#  define ZEXPORT\n#endif\n#ifndef ZEXPORTVA\n#  define ZEXPORTVA\n#endif\n\n#ifndef FAR\n#  define FAR\n#endif\n\n#if !defined(__MACTYPES__)\ntypedef unsigned char  Byte;  /* 8 bits */\n#endif\ntypedef unsigned int   uInt;  /* 16 bits or more */\ntypedef unsigned long  uLong; /* 32 bits or more */\n\n#ifdef SMALL_MEDIUM\n   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */\n#  define Bytef Byte FAR\n#else\n   typedef Byte  FAR Bytef;\n#endif\ntypedef char  FAR charf;\ntypedef int   FAR intf;\ntypedef uInt  FAR uIntf;\ntypedef uLong FAR uLongf;\n\n#ifdef STDC\n   typedef void const *voidpc;\n   typedef void FAR   *voidpf;\n   typedef void       *voidp;\n#else\n   typedef Byte const *voidpc;\n   typedef Byte FAR   *voidpf;\n   typedef Byte       *voidp;\n#endif\n\n#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)\n#  include <limits.h>\n#  if (UINT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned\n#  elif (ULONG_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned long\n#  elif (USHRT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned short\n#  endif\n#endif\n\n#ifdef Z_U4\n   typedef Z_U4 z_crc_t;\n#else\n   typedef unsigned long z_crc_t;\n#endif\n\n#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_UNISTD_H\n#endif\n\n#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_STDARG_H\n#endif\n\n#ifdef STDC\n#  ifndef Z_SOLO\n#    include <sys/types.h>      /* for off_t */\n#  endif\n#endif\n\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\n#    include <stdarg.h>         /* for va_list */\n#  endif\n#endif\n\n#ifdef _WIN32\n#  ifndef Z_SOLO\n#    include <stddef.h>         /* for wchar_t */\n#  endif\n#endif\n\n/* a little trick to accommodate both \"#define _LARGEFILE64_SOURCE\" and\n * \"#define _LARGEFILE64_SOURCE 1\" as requesting 64-bit operations, (even\n * though the former does not conform to the LFS document), but considering\n * both \"#undef _LARGEFILE64_SOURCE\" and \"#define _LARGEFILE64_SOURCE 0\" as\n * equivalently requesting no 64-bit operations\n */\n#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1\n#  undef _LARGEFILE64_SOURCE\n#endif\n\n#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)\n#  define Z_HAVE_UNISTD_H\n#endif\n#ifndef Z_SOLO\n#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)\n#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */\n#    ifdef VMS\n#      include <unixio.h>       /* for off_t */\n#    endif\n#    ifndef z_off_t\n#      define z_off_t off_t\n#    endif\n#  endif\n#endif\n\n#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0\n#  define Z_LFS64\n#endif\n\n#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)\n#  define Z_LARGE64\n#endif\n\n#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)\n#  define Z_WANT64\n#endif\n\n#if !defined(SEEK_SET) && !defined(Z_SOLO)\n#  define SEEK_SET        0       /* Seek from beginning of file.  */\n#  define SEEK_CUR        1       /* Seek from current position.  */\n#  define SEEK_END        2       /* Set file pointer to EOF plus \"offset\" */\n#endif\n\n#ifndef z_off_t\n#  define z_off_t long\n#endif\n\n#if !defined(_WIN32) && defined(Z_LARGE64)\n#  define z_off64_t off64_t\n#else\n#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)\n#    define z_off64_t __int64\n#  else\n#    define z_off64_t z_off_t\n#  endif\n#endif\n\n/* MVS linker does not support external names larger than 8 bytes */\n#if defined(__MVS__)\n  #pragma map(deflateInit_,\"DEIN\")\n  #pragma map(deflateInit2_,\"DEIN2\")\n  #pragma map(deflateEnd,\"DEEND\")\n  #pragma map(deflateBound,\"DEBND\")\n  #pragma map(inflateInit_,\"ININ\")\n  #pragma map(inflateInit2_,\"ININ2\")\n  #pragma map(inflateEnd,\"INEND\")\n  #pragma map(inflateSync,\"INSY\")\n  #pragma map(inflateSetDictionary,\"INSEDI\")\n  #pragma map(compressBound,\"CMBND\")\n  #pragma map(inflate_table,\"INTABL\")\n  #pragma map(inflate_fast,\"INFA\")\n  #pragma map(inflate_copyright,\"INCOPY\")\n#endif\n\n#endif /* ZCONF_H */\n"
  },
  {
    "path": "deps/CascLib/src/zlib/zlib.h",
    "content": "/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.2.11, January 15th, 2017\n\n  Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n\n#ifndef ZLIB_H\n#define ZLIB_H\n\n#include \"zconf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZLIB_VERSION \"1.2.11\"\n#define ZLIB_VERNUM 0x12b0\n#define ZLIB_VER_MAJOR 1\n#define ZLIB_VER_MINOR 2\n#define ZLIB_VER_REVISION 11\n#define ZLIB_VER_SUBREVISION 0\n\n/*\n    The 'zlib' compression library provides in-memory compression and\n  decompression functions, including integrity checks of the uncompressed data.\n  This version of the library supports only one compression method (deflation)\n  but other algorithms will be added later and will have the same stream\n  interface.\n\n    Compression can be done in a single step if the buffers are large enough,\n  or can be done by repeated calls of the compression function.  In the latter\n  case, the application must provide more input and/or consume the output\n  (providing more output space) before each call.\n\n    The compressed data format used by default by the in-memory functions is\n  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped\n  around a deflate stream, which is itself documented in RFC 1951.\n\n    The library also supports reading and writing files in gzip (.gz) format\n  with an interface similar to that of stdio using the functions that start\n  with \"gz\".  The gzip format is different from the zlib format.  gzip is a\n  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.\n\n    This library can optionally read and write gzip and raw deflate streams in\n  memory as well.\n\n    The zlib format was designed to be compact and fast for use in memory\n  and on communications channels.  The gzip format was designed for single-\n  file compression on file systems, has a larger header than zlib to maintain\n  directory information, and uses a different, slower check method than zlib.\n\n    The library does not install any signal handler.  The decoder checks\n  the consistency of the compressed data, so the library should never crash\n  even in the case of corrupted input.\n*/\n\ntypedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));\ntypedef void   (*free_func)  OF((voidpf opaque, voidpf address));\n\nstruct internal_state;\n\ntypedef struct z_stream_s {\n    z_const Bytef *next_in;     /* next input byte */\n    uInt     avail_in;  /* number of bytes available at next_in */\n    uLong    total_in;  /* total number of input bytes read so far */\n\n    Bytef    *next_out; /* next output byte will go here */\n    uInt     avail_out; /* remaining free space at next_out */\n    uLong    total_out; /* total number of bytes output so far */\n\n    z_const char *msg;  /* last error message, NULL if no error */\n    struct internal_state FAR *state; /* not visible by applications */\n\n    alloc_func zalloc;  /* used to allocate the internal state */\n    free_func  zfree;   /* used to free the internal state */\n    voidpf     opaque;  /* private data object passed to zalloc and zfree */\n\n    int     data_type;  /* best guess about the data type: binary or text\n                           for deflate, or the decoding state for inflate */\n    uLong   adler;      /* Adler-32 or CRC-32 value of the uncompressed data */\n    uLong   reserved;   /* reserved for future use */\n} z_stream;\n\ntypedef z_stream FAR *z_streamp;\n\n/*\n     gzip header information passed to and from zlib routines.  See RFC 1952\n  for more details on the meanings of these fields.\n*/\ntypedef struct gz_header_s {\n    int     text;       /* true if compressed data believed to be text */\n    uLong   time;       /* modification time */\n    int     xflags;     /* extra flags (not used when writing a gzip file) */\n    int     os;         /* operating system */\n    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */\n    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */\n    uInt    extra_max;  /* space at extra (only when reading header) */\n    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */\n    uInt    name_max;   /* space at name (only when reading header) */\n    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */\n    uInt    comm_max;   /* space at comment (only when reading header) */\n    int     hcrc;       /* true if there was or will be a header crc */\n    int     done;       /* true when done reading gzip header (not used\n                           when writing a gzip file) */\n} gz_header;\n\ntypedef gz_header FAR *gz_headerp;\n\n/*\n     The application must update next_in and avail_in when avail_in has dropped\n   to zero.  It must update next_out and avail_out when avail_out has dropped\n   to zero.  The application must initialize zalloc, zfree and opaque before\n   calling the init function.  All other fields are set by the compression\n   library and must not be updated by the application.\n\n     The opaque value provided by the application will be passed as the first\n   parameter for calls of zalloc and zfree.  This can be useful for custom\n   memory management.  The compression library attaches no meaning to the\n   opaque value.\n\n     zalloc must return Z_NULL if there is not enough memory for the object.\n   If zlib is used in a multi-threaded application, zalloc and zfree must be\n   thread safe.  In that case, zlib is thread-safe.  When zalloc and zfree are\n   Z_NULL on entry to the initialization function, they are set to internal\n   routines that use the standard library functions malloc() and free().\n\n     On 16-bit systems, the functions zalloc and zfree must be able to allocate\n   exactly 65536 bytes, but will not be required to allocate more than this if\n   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers\n   returned by zalloc for objects of exactly 65536 bytes *must* have their\n   offset normalized to zero.  The default allocation function provided by this\n   library ensures this (see zutil.c).  To reduce memory requirements and avoid\n   any allocation of 64K objects, at the expense of compression ratio, compile\n   the library with -DMAX_WBITS=14 (see zconf.h).\n\n     The fields total_in and total_out can be used for statistics or progress\n   reports.  After compression, total_in holds the total size of the\n   uncompressed data and may be saved for use by the decompressor (particularly\n   if the decompressor wants to decompress everything in a single step).\n*/\n\n                        /* constants */\n\n#define Z_NO_FLUSH      0\n#define Z_PARTIAL_FLUSH 1\n#define Z_SYNC_FLUSH    2\n#define Z_FULL_FLUSH    3\n#define Z_FINISH        4\n#define Z_BLOCK         5\n#define Z_TREES         6\n/* Allowed flush values; see deflate() and inflate() below for details */\n\n#define Z_OK            0\n#define Z_STREAM_END    1\n#define Z_NEED_DICT     2\n#define Z_ERRNO        (-1)\n#define Z_STREAM_ERROR (-2)\n#define Z_DATA_ERROR   (-3)\n#define Z_MEM_ERROR    (-4)\n#define Z_BUF_ERROR    (-5)\n#define Z_VERSION_ERROR (-6)\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\n\n#define Z_NO_COMPRESSION         0\n#define Z_BEST_SPEED             1\n#define Z_BEST_COMPRESSION       9\n#define Z_DEFAULT_COMPRESSION  (-1)\n/* compression levels */\n\n#define Z_FILTERED            1\n#define Z_HUFFMAN_ONLY        2\n#define Z_RLE                 3\n#define Z_FIXED               4\n#define Z_DEFAULT_STRATEGY    0\n/* compression strategy; see deflateInit2() below for details */\n\n#define Z_BINARY   0\n#define Z_TEXT     1\n#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */\n#define Z_UNKNOWN  2\n/* Possible values of the data_type field for deflate() */\n\n#define Z_DEFLATED   8\n/* The deflate compression method (the only one supported in this version) */\n\n#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */\n\n#define zlib_version zlibVersion()\n/* for compatibility with versions < 1.0.2 */\n\n\n                        /* basic functions */\n\nZEXTERN const char * ZEXPORT zlibVersion OF((void));\n/* The application can compare zlibVersion and ZLIB_VERSION for consistency.\n   If the first character differs, the library code actually used is not\n   compatible with the zlib.h header file used by the application.  This check\n   is automatically made by deflateInit and inflateInit.\n */\n\n/*\nZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));\n\n     Initializes the internal stream state for compression.  The fields\n   zalloc, zfree and opaque must be initialized before by the caller.  If\n   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default\n   allocation functions.\n\n     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:\n   1 gives best speed, 9 gives best compression, 0 gives no compression at all\n   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION\n   requests a default compromise between speed and compression (currently\n   equivalent to level 6).\n\n     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if level is not a valid compression level, or\n   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible\n   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null\n   if there is no error message.  deflateInit does not perform any compression:\n   this will be done by deflate().\n*/\n\n\nZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));\n/*\n    deflate compresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n    The detailed semantics are as follows.  deflate performs one or both of the\n  following actions:\n\n  - Compress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), next_in and avail_in are updated and\n    processing will resume at this point for the next call of deflate().\n\n  - Generate more output starting at next_out and update next_out and avail_out\n    accordingly.  This action is forced if the parameter flush is non zero.\n    Forcing flush frequently degrades the compression ratio, so this parameter\n    should be set only when necessary.  Some output may be provided even if\n    flush is zero.\n\n    Before the call of deflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating avail_in or avail_out accordingly; avail_out should\n  never be zero before the call.  The application can consume the compressed\n  output when it wants, for example when the output buffer is full (avail_out\n  == 0), or after each call of deflate().  If deflate returns Z_OK and with\n  zero avail_out, it must be called again after making room in the output\n  buffer because there might be more output pending. See deflatePending(),\n  which can be used if desired to determine whether or not there is more ouput\n  in that case.\n\n    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to\n  decide how much data to accumulate before producing output, in order to\n  maximize compression.\n\n    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is\n  flushed to the output buffer and the output is aligned on a byte boundary, so\n  that the decompressor can get all input data available so far.  (In\n  particular avail_in is zero after the call if enough output space has been\n  provided before the call.) Flushing may degrade compression for some\n  compression algorithms and so it should be used only when necessary.  This\n  completes the current deflate block and follows it with an empty stored block\n  that is three bits plus filler bits to the next byte, followed by four bytes\n  (00 00 ff ff).\n\n    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the\n  output buffer, but the output is not aligned to a byte boundary.  All of the\n  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.\n  This completes the current deflate block and follows it with an empty fixed\n  codes block that is 10 bits long.  This assures that enough bytes are output\n  in order for the decompressor to finish the block before the empty fixed\n  codes block.\n\n    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as\n  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to\n  seven bits of the current block are held to be written as the next byte after\n  the next deflate block is completed.  In this case, the decompressor may not\n  be provided enough bits at this point in order to complete decompression of\n  the data provided so far to the compressor.  It may need to wait for the next\n  block to be emitted.  This is for advanced applications that need to control\n  the emission of deflate blocks.\n\n    If flush is set to Z_FULL_FLUSH, all output is flushed as with\n  Z_SYNC_FLUSH, and the compression state is reset so that decompression can\n  restart from this point if previous compressed data has been damaged or if\n  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade\n  compression.\n\n    If deflate returns with avail_out == 0, this function must be called again\n  with the same value of the flush parameter and more output space (updated\n  avail_out), until the flush is complete (deflate returns with non-zero\n  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that\n  avail_out is greater than six to avoid repeated flush markers due to\n  avail_out == 0 on return.\n\n    If the parameter flush is set to Z_FINISH, pending input is processed,\n  pending output is flushed and deflate returns with Z_STREAM_END if there was\n  enough output space.  If deflate returns with Z_OK or Z_BUF_ERROR, this\n  function must be called again with Z_FINISH and more output space (updated\n  avail_out) but no more input data, until it returns with Z_STREAM_END or an\n  error.  After deflate has returned Z_STREAM_END, the only possible operations\n  on the stream are deflateReset or deflateEnd.\n\n    Z_FINISH can be used in the first deflate call after deflateInit if all the\n  compression is to be done in a single step.  In order to complete in one\n  call, avail_out must be at least the value returned by deflateBound (see\n  below).  Then deflate is guaranteed to return Z_STREAM_END.  If not enough\n  output space is provided, deflate will not return Z_STREAM_END, and it must\n  be called again as described above.\n\n    deflate() sets strm->adler to the Adler-32 checksum of all input read\n  so far (that is, total_in bytes).  If a gzip stream is being generated, then\n  strm->adler will be the CRC-32 checksum of the input read so far.  (See\n  deflateInit2 below.)\n\n    deflate() may update strm->data_type if it can make a good guess about\n  the input data type (Z_BINARY or Z_TEXT).  If in doubt, the data is\n  considered binary.  This field is only for information purposes and does not\n  affect the compression algorithm in any manner.\n\n    deflate() returns Z_OK if some progress has been made (more input\n  processed or more output produced), Z_STREAM_END if all input has been\n  consumed and all output has been produced (only when flush is set to\n  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example\n  if next_in or next_out was Z_NULL or the state was inadvertently written over\n  by the application), or Z_BUF_ERROR if no progress is possible (for example\n  avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not fatal, and\n  deflate() can be called again with more input and more output space to\n  continue compressing.\n*/\n\n\nZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the\n   stream state was inconsistent, Z_DATA_ERROR if the stream was freed\n   prematurely (some input or output was discarded).  In the error case, msg\n   may be set but then points to a static string (which must not be\n   deallocated).\n*/\n\n\n/*\nZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));\n\n     Initializes the internal stream state for decompression.  The fields\n   next_in, avail_in, zalloc, zfree and opaque must be initialized before by\n   the caller.  In the current version of inflate, the provided input is not\n   read or consumed.  The allocation of a sliding window will be deferred to\n   the first call of inflate (if the decompression does not complete on the\n   first call).  If zalloc and zfree are set to Z_NULL, inflateInit updates\n   them to use default allocation functions.\n\n     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit does not perform any decompression.\n   Actual decompression will be done by inflate().  So next_in, and avail_in,\n   next_out, and avail_out are unused and unchanged.  The current\n   implementation of inflateInit() does not process any header information --\n   that is deferred until inflate() is called.\n*/\n\n\nZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));\n/*\n    inflate decompresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n  The detailed semantics are as follows.  inflate performs one or both of the\n  following actions:\n\n  - Decompress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), then next_in and avail_in are updated\n    accordingly, and processing will resume at this point for the next call of\n    inflate().\n\n  - Generate more output starting at next_out and update next_out and avail_out\n    accordingly.  inflate() provides as much output as possible, until there is\n    no more input data or no more space in the output buffer (see below about\n    the flush parameter).\n\n    Before the call of inflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating the next_* and avail_* values accordingly.  If the\n  caller of inflate() does not provide both available input and available\n  output space, it is possible that there will be no progress made.  The\n  application can consume the uncompressed output when it wants, for example\n  when the output buffer is full (avail_out == 0), or after each call of\n  inflate().  If inflate returns Z_OK and with zero avail_out, it must be\n  called again after making room in the output buffer because there might be\n  more output pending.\n\n    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,\n  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much\n  output as possible to the output buffer.  Z_BLOCK requests that inflate()\n  stop if and when it gets to the next deflate block boundary.  When decoding\n  the zlib or gzip format, this will cause inflate() to return immediately\n  after the header and before the first block.  When doing a raw inflate,\n  inflate() will go ahead and process the first block, and will return when it\n  gets to the end of that block, or when it runs out of data.\n\n    The Z_BLOCK option assists in appending to or combining deflate streams.\n  To assist in this, on return inflate() always sets strm->data_type to the\n  number of unused bits in the last byte taken from strm->next_in, plus 64 if\n  inflate() is currently decoding the last block in the deflate stream, plus\n  128 if inflate() returned immediately after decoding an end-of-block code or\n  decoding the complete header up to just before the first byte of the deflate\n  stream.  The end-of-block will not be indicated until all of the uncompressed\n  data from that block has been written to strm->next_out.  The number of\n  unused bits may in general be greater than seven, except when bit 7 of\n  data_type is set, in which case the number of unused bits will be less than\n  eight.  data_type is set as noted here every time inflate() returns for all\n  flush options, and so can be used to determine the amount of currently\n  consumed input in bits.\n\n    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the\n  end of each deflate block header is reached, before any actual data in that\n  block is decoded.  This allows the caller to determine the length of the\n  deflate block header for later use in random access within a deflate block.\n  256 is added to the value of strm->data_type when inflate() returns\n  immediately after reaching the end of the deflate block header.\n\n    inflate() should normally be called until it returns Z_STREAM_END or an\n  error.  However if all decompression is to be performed in a single step (a\n  single call of inflate), the parameter flush should be set to Z_FINISH.  In\n  this case all pending input is processed and all pending output is flushed;\n  avail_out must be large enough to hold all of the uncompressed data for the\n  operation to complete.  (The size of the uncompressed data may have been\n  saved by the compressor for this purpose.)  The use of Z_FINISH is not\n  required to perform an inflation in one step.  However it may be used to\n  inform inflate that a faster approach can be used for the single inflate()\n  call.  Z_FINISH also informs inflate to not maintain a sliding window if the\n  stream completes, which reduces inflate's memory footprint.  If the stream\n  does not complete, either because not all of the stream is provided or not\n  enough output space is provided, then a sliding window will be allocated and\n  inflate() can be called again to continue the operation as if Z_NO_FLUSH had\n  been used.\n\n     In this implementation, inflate() always flushes as much output as\n  possible to the output buffer, and always uses the faster approach on the\n  first call.  So the effects of the flush parameter in this implementation are\n  on the return value of inflate() as noted below, when inflate() returns early\n  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of\n  memory for a sliding window when Z_FINISH is used.\n\n     If a preset dictionary is needed after this call (see inflateSetDictionary\n  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary\n  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets\n  strm->adler to the Adler-32 checksum of all output produced so far (that is,\n  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described\n  below.  At the end of the stream, inflate() checks that its computed Adler-32\n  checksum is equal to that saved by the compressor and returns Z_STREAM_END\n  only if the checksum is correct.\n\n    inflate() can decompress and check either zlib-wrapped or gzip-wrapped\n  deflate data.  The header type is detected automatically, if requested when\n  initializing with inflateInit2().  Any information contained in the gzip\n  header is not retained unless inflateGetHeader() is used.  When processing\n  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output\n  produced so far.  The CRC-32 is checked against the gzip trailer, as is the\n  uncompressed length, modulo 2^32.\n\n    inflate() returns Z_OK if some progress has been made (more input processed\n  or more output produced), Z_STREAM_END if the end of the compressed data has\n  been reached and all uncompressed output has been produced, Z_NEED_DICT if a\n  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was\n  corrupted (input stream not conforming to the zlib format or incorrect check\n  value, in which case strm->msg points to a string with a more specific\n  error), Z_STREAM_ERROR if the stream structure was inconsistent (for example\n  next_in or next_out was Z_NULL, or the state was inadvertently written over\n  by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR\n  if no progress was possible or if there was not enough room in the output\n  buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and\n  inflate() can be called again with more input and more output space to\n  continue decompressing.  If Z_DATA_ERROR is returned, the application may\n  then call inflateSync() to look for a good compression block if a partial\n  recovery of the data is to be attempted.\n*/\n\n\nZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state\n   was inconsistent.\n*/\n\n\n                        /* Advanced functions */\n\n/*\n    The following functions are needed only in some special applications.\n*/\n\n/*\nZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,\n                                     int  level,\n                                     int  method,\n                                     int  windowBits,\n                                     int  memLevel,\n                                     int  strategy));\n\n     This is another version of deflateInit with more compression options.  The\n   fields next_in, zalloc, zfree and opaque must be initialized before by the\n   caller.\n\n     The method parameter is the compression method.  It must be Z_DEFLATED in\n   this version of the library.\n\n     The windowBits parameter is the base two logarithm of the window size\n   (the size of the history buffer).  It should be in the range 8..15 for this\n   version of the library.  Larger values of this parameter result in better\n   compression at the expense of memory usage.  The default value is 15 if\n   deflateInit is used instead.\n\n     For the current implementation of deflate(), a windowBits value of 8 (a\n   window size of 256 bytes) is not supported.  As a result, a request for 8\n   will result in 9 (a 512-byte window).  In that case, providing 8 to\n   inflateInit2() will result in an error when the zlib header with 9 is\n   checked against the initialization of inflate().  The remedy is to not use 8\n   with deflateInit2() with this initialization, or at least in that case use 9\n   with inflateInit2().\n\n     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits\n   determines the window size.  deflate() will then generate raw deflate data\n   with no zlib header or trailer, and will not compute a check value.\n\n     windowBits can also be greater than 15 for optional gzip encoding.  Add\n   16 to windowBits to write a simple gzip header and trailer around the\n   compressed data instead of a zlib wrapper.  The gzip header will have no\n   file name, no extra data, no comment, no modification time (set to zero), no\n   header crc, and the operating system will be set to the appropriate value,\n   if the operating system was determined at compile time.  If a gzip stream is\n   being written, strm->adler is a CRC-32 instead of an Adler-32.\n\n     For raw deflate or gzip encoding, a request for a 256-byte window is\n   rejected as invalid, since only the zlib header provides a means of\n   transmitting the window size to the decompressor.\n\n     The memLevel parameter specifies how much memory should be allocated\n   for the internal compression state.  memLevel=1 uses minimum memory but is\n   slow and reduces compression ratio; memLevel=9 uses maximum memory for\n   optimal speed.  The default value is 8.  See zconf.h for total memory usage\n   as a function of windowBits and memLevel.\n\n     The strategy parameter is used to tune the compression algorithm.  Use the\n   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a\n   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no\n   string match), or Z_RLE to limit match distances to one (run-length\n   encoding).  Filtered data consists mostly of small values with a somewhat\n   random distribution.  In this case, the compression algorithm is tuned to\n   compress them better.  The effect of Z_FILTERED is to force more Huffman\n   coding and less string matching; it is somewhat intermediate between\n   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as\n   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The\n   strategy parameter only affects the compression ratio but not the\n   correctness of the compressed output even if it is not set appropriately.\n   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler\n   decoder for special applications.\n\n     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid\n   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is\n   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is\n   set to null if there is no error message.  deflateInit2 does not perform any\n   compression: this will be done by deflate().\n*/\n\nZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,\n                                             const Bytef *dictionary,\n                                             uInt  dictLength));\n/*\n     Initializes the compression dictionary from the given byte sequence\n   without producing any compressed output.  When using the zlib format, this\n   function must be called immediately after deflateInit, deflateInit2 or\n   deflateReset, and before any call of deflate.  When doing raw deflate, this\n   function must be called either before any call of deflate, or immediately\n   after the completion of a deflate block, i.e. after all input has been\n   consumed and all output has been delivered when using any of the flush\n   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The\n   compressor and decompressor must use exactly the same dictionary (see\n   inflateSetDictionary).\n\n     The dictionary should consist of strings (byte sequences) that are likely\n   to be encountered later in the data to be compressed, with the most commonly\n   used strings preferably put towards the end of the dictionary.  Using a\n   dictionary is most useful when the data to be compressed is short and can be\n   predicted with good accuracy; the data can then be compressed better than\n   with the default empty dictionary.\n\n     Depending on the size of the compression data structures selected by\n   deflateInit or deflateInit2, a part of the dictionary may in effect be\n   discarded, for example if the dictionary is larger than the window size\n   provided in deflateInit or deflateInit2.  Thus the strings most likely to be\n   useful should be put at the end of the dictionary, not at the front.  In\n   addition, the current implementation of deflate will use at most the window\n   size minus 262 bytes of the provided dictionary.\n\n     Upon return of this function, strm->adler is set to the Adler-32 value\n   of the dictionary; the decompressor may later use this value to determine\n   which dictionary has been used by the compressor.  (The Adler-32 value\n   applies to the whole dictionary even if only a subset of the dictionary is\n   actually used by the compressor.) If a raw deflate was requested, then the\n   Adler-32 value is not computed and strm->adler is not set.\n\n     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent (for example if deflate has already been called for this stream\n   or if not at a block boundary for raw deflate).  deflateSetDictionary does\n   not perform any compression: this will be done by deflate().\n*/\n\nZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,\n                                             Bytef *dictionary,\n                                             uInt  *dictLength));\n/*\n     Returns the sliding dictionary being maintained by deflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If deflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similary, if dictLength is Z_NULL, then it is not set.\n\n     deflateGetDictionary() may return a length less than the window size, even\n   when more than the window size in input has been provided. It may return up\n   to 258 bytes less in that case, due to how zlib's implementation of deflate\n   manages the sliding window and lookahead for matches, where matches can be\n   up to 258 bytes long. If the application needs the last window-size bytes of\n   input, then that would need to be saved by the application outside of zlib.\n\n     deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\nZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,\n                                    z_streamp source));\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when several compression strategies will be\n   tried, for example when there are several ways of pre-processing the input\n   data with a filter.  The streams that will be discarded should then be freed\n   by calling deflateEnd.  Note that deflateCopy duplicates the internal\n   compression state which can be quite large, so this strategy is slow and can\n   consume lots of memory.\n\n     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\nZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));\n/*\n     This function is equivalent to deflateEnd followed by deflateInit, but\n   does not free and reallocate the internal compression state.  The stream\n   will leave the compression level and any other attributes that may have been\n   set unchanged.\n\n     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\nZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,\n                                      int level,\n                                      int strategy));\n/*\n     Dynamically update the compression level and compression strategy.  The\n   interpretation of level and strategy is as in deflateInit2().  This can be\n   used to switch between compression and straight copy of the input data, or\n   to switch to a different kind of input data requiring a different strategy.\n   If the compression approach (which is a function of the level) or the\n   strategy is changed, and if any input has been consumed in a previous\n   deflate() call, then the input available so far is compressed with the old\n   level and strategy using deflate(strm, Z_BLOCK).  There are three approaches\n   for the compression levels 0, 1..3, and 4..9 respectively.  The new level\n   and strategy will take effect at the next call of deflate().\n\n     If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does\n   not have enough output space to complete, then the parameter change will not\n   take effect.  In this case, deflateParams() can be called again with the\n   same parameters and more output space to try again.\n\n     In order to assure a change in the parameters on the first try, the\n   deflate stream should be flushed using deflate() with Z_BLOCK or other flush\n   request until strm.avail_out is not zero, before calling deflateParams().\n   Then no more input data should be provided before the deflateParams() call.\n   If this is done, the old level and strategy will be applied to the data\n   compressed before deflateParams(), and the new level and strategy will be\n   applied to the the data compressed after deflateParams().\n\n     deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream\n   state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if\n   there was not enough output space to complete the compression of the\n   available input data before a change in the strategy or approach.  Note that\n   in the case of a Z_BUF_ERROR, the parameters are not changed.  A return\n   value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be\n   retried with more output space.\n*/\n\nZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,\n                                    int good_length,\n                                    int max_lazy,\n                                    int nice_length,\n                                    int max_chain));\n/*\n     Fine tune deflate's internal compression parameters.  This should only be\n   used by someone who understands the algorithm used by zlib's deflate for\n   searching for the best matching string, and even then only by the most\n   fanatic optimizer trying to squeeze out the last compressed bit for their\n   specific input data.  Read the deflate.c source code for the meaning of the\n   max_lazy, good_length, nice_length, and max_chain parameters.\n\n     deflateTune() can be called after deflateInit() or deflateInit2(), and\n   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.\n */\n\nZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,\n                                       uLong sourceLen));\n/*\n     deflateBound() returns an upper bound on the compressed size after\n   deflation of sourceLen bytes.  It must be called after deflateInit() or\n   deflateInit2(), and after deflateSetHeader(), if used.  This would be used\n   to allocate an output buffer for deflation in a single pass, and so would be\n   called before deflate().  If that first deflate() call is provided the\n   sourceLen input bytes, an output buffer allocated to the size returned by\n   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed\n   to return Z_STREAM_END.  Note that it is possible for the compressed size to\n   be larger than the value returned by deflateBound() if flush options other\n   than Z_FINISH or Z_NO_FLUSH are used.\n*/\n\nZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,\n                                       unsigned *pending,\n                                       int *bits));\n/*\n     deflatePending() returns the number of bytes and bits of output that have\n   been generated, but not yet provided in the available output.  The bytes not\n   provided would be due to the available output space having being consumed.\n   The number of bits of output not provided are between 0 and 7, where they\n   await more bits to join them in order to fill out a full byte.  If pending\n   or bits are Z_NULL, then those values are not set.\n\n     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n */\n\nZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,\n                                     int bits,\n                                     int value));\n/*\n     deflatePrime() inserts bits in the deflate output stream.  The intent\n   is that this function is used to start off the deflate output with the bits\n   leftover from a previous deflate stream when appending to it.  As such, this\n   function can only be used for raw deflate, and must be used before the first\n   deflate() call after a deflateInit2() or deflateReset().  bits must be less\n   than or equal to 16, and that many of the least significant bits of value\n   will be inserted in the output.\n\n     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough\n   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the\n   source stream state was inconsistent.\n*/\n\nZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,\n                                         gz_headerp head));\n/*\n     deflateSetHeader() provides gzip header information for when a gzip\n   stream is requested by deflateInit2().  deflateSetHeader() may be called\n   after deflateInit2() or deflateReset() and before the first call of\n   deflate().  The text, time, os, extra field, name, and comment information\n   in the provided gz_header structure are written to the gzip header (xflag is\n   ignored -- the extra flags are set according to the compression level).  The\n   caller must assure that, if not Z_NULL, name and comment are terminated with\n   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are\n   available there.  If hcrc is true, a gzip header crc is included.  Note that\n   the current versions of the command-line version of gzip (up through version\n   1.3.x) do not support header crc's, and will report that it is a \"multi-part\n   gzip file\" and give up.\n\n     If deflateSetHeader is not used, the default gzip header has text false,\n   the time set to zero, and os set to 255, with no extra, name, or comment\n   fields.  The gzip header is returned to the default state by deflateReset().\n\n     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\nZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,\n                                     int  windowBits));\n\n     This is another version of inflateInit with an extra parameter.  The\n   fields next_in, avail_in, zalloc, zfree and opaque must be initialized\n   before by the caller.\n\n     The windowBits parameter is the base two logarithm of the maximum window\n   size (the size of the history buffer).  It should be in the range 8..15 for\n   this version of the library.  The default value is 15 if inflateInit is used\n   instead.  windowBits must be greater than or equal to the windowBits value\n   provided to deflateInit2() while compressing, or it must be equal to 15 if\n   deflateInit2() was not used.  If a compressed stream with a larger window\n   size is given as input, inflate() will return with the error code\n   Z_DATA_ERROR instead of trying to allocate a larger window.\n\n     windowBits can also be zero to request that inflate use the window size in\n   the zlib header of the compressed stream.\n\n     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits\n   determines the window size.  inflate() will then process raw deflate data,\n   not looking for a zlib or gzip header, not generating a check value, and not\n   looking for any check values for comparison at the end of the stream.  This\n   is for use with other formats that use the deflate compressed data format\n   such as zip.  Those formats provide their own check values.  If a custom\n   format is developed using the raw deflate format for compressed data, it is\n   recommended that a check value such as an Adler-32 or a CRC-32 be applied to\n   the uncompressed data as is done in the zlib, gzip, and zip formats.  For\n   most applications, the zlib format should be used as is.  Note that comments\n   above on the use in deflateInit2() applies to the magnitude of windowBits.\n\n     windowBits can also be greater than 15 for optional gzip decoding.  Add\n   32 to windowBits to enable zlib and gzip decoding with automatic header\n   detection, or add 16 to decode only the gzip format (the zlib format will\n   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a\n   CRC-32 instead of an Adler-32.  Unlike the gunzip utility and gzread() (see\n   below), inflate() will not automatically decode concatenated gzip streams.\n   inflate() will return Z_STREAM_END at the end of the gzip stream.  The state\n   would need to be reset to continue decoding a subsequent gzip stream.\n\n     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit2 does not perform any decompression\n   apart from possibly reading the zlib header if present: actual decompression\n   will be done by inflate().  (So next_in and avail_in may be modified, but\n   next_out and avail_out are unused and unchanged.) The current implementation\n   of inflateInit2() does not process any header information -- that is\n   deferred until inflate() is called.\n*/\n\nZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,\n                                             const Bytef *dictionary,\n                                             uInt  dictLength));\n/*\n     Initializes the decompression dictionary from the given uncompressed byte\n   sequence.  This function must be called immediately after a call of inflate,\n   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor\n   can be determined from the Adler-32 value returned by that call of inflate.\n   The compressor and decompressor must use exactly the same dictionary (see\n   deflateSetDictionary).  For raw inflate, this function can be called at any\n   time to set the dictionary.  If the provided dictionary is smaller than the\n   window and there is already data in the window, then the provided dictionary\n   will amend what's there.  The application must insure that the dictionary\n   that was used for compression is provided.\n\n     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the\n   expected one (incorrect Adler-32 value).  inflateSetDictionary does not\n   perform any decompression: this will be done by subsequent calls of\n   inflate().\n*/\n\nZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,\n                                             Bytef *dictionary,\n                                             uInt  *dictLength));\n/*\n     Returns the sliding dictionary being maintained by inflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If inflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similary, if dictLength is Z_NULL, then it is not set.\n\n     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\nZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));\n/*\n     Skips invalid compressed data until a possible full flush point (see above\n   for the description of deflate with Z_FULL_FLUSH) can be found, or until all\n   available input is skipped.  No output is provided.\n\n     inflateSync searches for a 00 00 FF FF pattern in the compressed data.\n   All full flush points have this pattern, but not all occurrences of this\n   pattern are full flush points.\n\n     inflateSync returns Z_OK if a possible full flush point has been found,\n   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point\n   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.\n   In the success case, the application may save the current current value of\n   total_in which indicates where valid compressed data was found.  In the\n   error case, the application may repeatedly call inflateSync, providing more\n   input each time, until success or end of the input data.\n*/\n\nZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,\n                                    z_streamp source));\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when randomly accessing a large stream.  The\n   first pass through the stream can periodically record the inflate state,\n   allowing restarting inflate at those points when randomly accessing the\n   stream.\n\n     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\nZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));\n/*\n     This function is equivalent to inflateEnd followed by inflateInit,\n   but does not free and reallocate the internal decompression state.  The\n   stream will keep attributes that may have been set by inflateInit2.\n\n     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\nZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,\n                                      int windowBits));\n/*\n     This function is the same as inflateReset, but it also permits changing\n   the wrap and window size requests.  The windowBits parameter is interpreted\n   the same as it is for inflateInit2.  If the window size is changed, then the\n   memory allocated for the window is freed, and the window will be reallocated\n   by inflate() if needed.\n\n     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL), or if\n   the windowBits parameter is invalid.\n*/\n\nZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,\n                                     int bits,\n                                     int value));\n/*\n     This function inserts bits in the inflate input stream.  The intent is\n   that this function is used to start inflating at a bit position in the\n   middle of a byte.  The provided bits will be used before any bytes are used\n   from next_in.  This function should only be used with raw inflate, and\n   should be used before the first inflate() call after inflateInit2() or\n   inflateReset().  bits must be less than or equal to 16, and that many of the\n   least significant bits of value will be inserted in the input.\n\n     If bits is negative, then the input stream bit buffer is emptied.  Then\n   inflatePrime() can be called again to put bits in the buffer.  This is used\n   to clear out bits leftover after feeding inflate a block description prior\n   to feeding inflate codes.\n\n     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\nZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));\n/*\n     This function returns two values, one in the lower 16 bits of the return\n   value, and the other in the remaining upper bits, obtained by shifting the\n   return value down 16 bits.  If the upper value is -1 and the lower value is\n   zero, then inflate() is currently decoding information outside of a block.\n   If the upper value is -1 and the lower value is non-zero, then inflate is in\n   the middle of a stored block, with the lower value equaling the number of\n   bytes from the input remaining to copy.  If the upper value is not -1, then\n   it is the number of bits back from the current bit position in the input of\n   the code (literal or length/distance pair) currently being processed.  In\n   that case the lower value is the number of bytes already emitted for that\n   code.\n\n     A code is being processed if inflate is waiting for more input to complete\n   decoding of the code, or if it has completed decoding but is waiting for\n   more output space to write the literal or match data.\n\n     inflateMark() is used to mark locations in the input data for random\n   access, which may be at bit positions, and to note those cases where the\n   output of a code may span boundaries of random access blocks.  The current\n   location in the input stream can be determined from avail_in and data_type\n   as noted in the description for the Z_BLOCK flush parameter for inflate.\n\n     inflateMark returns the value noted above, or -65536 if the provided\n   source stream state was inconsistent.\n*/\n\nZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,\n                                         gz_headerp head));\n/*\n     inflateGetHeader() requests that gzip header information be stored in the\n   provided gz_header structure.  inflateGetHeader() may be called after\n   inflateInit2() or inflateReset(), and before the first call of inflate().\n   As inflate() processes the gzip stream, head->done is zero until the header\n   is completed, at which time head->done is set to one.  If a zlib stream is\n   being decoded, then head->done is set to -1 to indicate that there will be\n   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be\n   used to force inflate() to return immediately after header processing is\n   complete and before any actual data is decompressed.\n\n     The text, time, xflags, and os fields are filled in with the gzip header\n   contents.  hcrc is set to true if there is a header CRC.  (The header CRC\n   was valid if done is set to one.) If extra is not Z_NULL, then extra_max\n   contains the maximum number of bytes to write to extra.  Once done is true,\n   extra_len contains the actual extra field length, and extra contains the\n   extra field, or that field truncated if extra_max is less than extra_len.\n   If name is not Z_NULL, then up to name_max characters are written there,\n   terminated with a zero unless the length is greater than name_max.  If\n   comment is not Z_NULL, then up to comm_max characters are written there,\n   terminated with a zero unless the length is greater than comm_max.  When any\n   of extra, name, or comment are not Z_NULL and the respective field is not\n   present in the header, then that field is set to Z_NULL to signal its\n   absence.  This allows the use of deflateSetHeader() with the returned\n   structure to duplicate the header.  However if those fields are set to\n   allocated memory, then the application will need to save those pointers\n   elsewhere so that they can be eventually freed.\n\n     If inflateGetHeader is not used, then the header information is simply\n   discarded.  The header is always checked for validity, including the header\n   CRC if present.  inflateReset() will reset the process to discard the header\n   information.  The application would need to call inflateGetHeader() again to\n   retrieve the header from the next gzip stream.\n\n     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\nZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,\n                                        unsigned char FAR *window));\n\n     Initialize the internal stream state for decompression using inflateBack()\n   calls.  The fields zalloc, zfree and opaque in strm must be initialized\n   before the call.  If zalloc and zfree are Z_NULL, then the default library-\n   derived memory allocation routines are used.  windowBits is the base two\n   logarithm of the window size, in the range 8..15.  window is a caller\n   supplied buffer of that size.  Except for special applications where it is\n   assured that deflate was used with small window sizes, windowBits must be 15\n   and a 32K byte window must be supplied to be able to decompress general\n   deflate streams.\n\n     See inflateBack() for the usage of these routines.\n\n     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of\n   the parameters are invalid, Z_MEM_ERROR if the internal state could not be\n   allocated, or Z_VERSION_ERROR if the version of the library does not match\n   the version of the header file.\n*/\n\ntypedef unsigned (*in_func) OF((void FAR *,\n                                z_const unsigned char FAR * FAR *));\ntypedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));\n\nZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,\n                                    in_func in, void FAR *in_desc,\n                                    out_func out, void FAR *out_desc));\n/*\n     inflateBack() does a raw inflate with a single call using a call-back\n   interface for input and output.  This is potentially more efficient than\n   inflate() for file i/o applications, in that it avoids copying between the\n   output and the sliding window by simply making the window itself the output\n   buffer.  inflate() can be faster on modern CPUs when used with large\n   buffers.  inflateBack() trusts the application to not change the output\n   buffer passed by the output function, at least until inflateBack() returns.\n\n     inflateBackInit() must be called first to allocate the internal state\n   and to initialize the state with the user-provided window buffer.\n   inflateBack() may then be used multiple times to inflate a complete, raw\n   deflate stream with each call.  inflateBackEnd() is then called to free the\n   allocated state.\n\n     A raw deflate stream is one with no zlib or gzip header or trailer.\n   This routine would normally be used in a utility that reads zip or gzip\n   files and writes out uncompressed files.  The utility would decode the\n   header and process the trailer on its own, hence this routine expects only\n   the raw deflate stream to decompress.  This is different from the default\n   behavior of inflate(), which expects a zlib header and trailer around the\n   deflate stream.\n\n     inflateBack() uses two subroutines supplied by the caller that are then\n   called by inflateBack() for input and output.  inflateBack() calls those\n   routines until it reads a complete deflate stream and writes out all of the\n   uncompressed data, or until it encounters an error.  The function's\n   parameters and return types are defined above in the in_func and out_func\n   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the\n   number of bytes of provided input, and a pointer to that input in buf.  If\n   there is no input available, in() must return zero -- buf is ignored in that\n   case -- and inflateBack() will return a buffer error.  inflateBack() will\n   call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].\n   out() should return zero on success, or non-zero on failure.  If out()\n   returns non-zero, inflateBack() will return with an error.  Neither in() nor\n   out() are permitted to change the contents of the window provided to\n   inflateBackInit(), which is also the buffer that out() uses to write from.\n   The length written by out() will be at most the window size.  Any non-zero\n   amount of input may be provided by in().\n\n     For convenience, inflateBack() can be provided input on the first call by\n   setting strm->next_in and strm->avail_in.  If that input is exhausted, then\n   in() will be called.  Therefore strm->next_in must be initialized before\n   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called\n   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in\n   must also be initialized, and then if strm->avail_in is not zero, input will\n   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].\n\n     The in_desc and out_desc parameters of inflateBack() is passed as the\n   first parameter of in() and out() respectively when they are called.  These\n   descriptors can be optionally used to pass any information that the caller-\n   supplied in() and out() functions need to do their job.\n\n     On return, inflateBack() will set strm->next_in and strm->avail_in to\n   pass back any unused input that was provided by the last in() call.  The\n   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR\n   if in() or out() returned an error, Z_DATA_ERROR if there was a format error\n   in the deflate stream (in which case strm->msg is set to indicate the nature\n   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.\n   In the case of Z_BUF_ERROR, an input or output error can be distinguished\n   using strm->next_in which will be Z_NULL only if in() returned an error.  If\n   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning\n   non-zero.  (in() will always be called before out(), so strm->next_in is\n   assured to be defined if out() returns non-zero.)  Note that inflateBack()\n   cannot return Z_OK.\n*/\n\nZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));\n/*\n     All memory allocated by inflateBackInit() is freed.\n\n     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream\n   state was inconsistent.\n*/\n\nZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));\n/* Return flags indicating compile-time options.\n\n    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:\n     1.0: size of uInt\n     3.2: size of uLong\n     5.4: size of voidpf (pointer)\n     7.6: size of z_off_t\n\n    Compiler, assembler, and debug options:\n     8: ZLIB_DEBUG\n     9: ASMV or ASMINF -- use ASM code\n     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention\n     11: 0 (reserved)\n\n    One-time table building (smaller code, but not thread-safe if true):\n     12: BUILDFIXED -- build static block decoding tables when needed\n     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed\n     14,15: 0 (reserved)\n\n    Library content (indicates missing functionality):\n     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking\n                          deflate code when not needed)\n     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect\n                    and decode gzip streams (to avoid linking crc code)\n     18-19: 0 (reserved)\n\n    Operation variations (changes in library functionality):\n     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate\n     21: FASTEST -- deflate algorithm with only one, lowest compression level\n     22,23: 0 (reserved)\n\n    The sprintf variant used by gzprintf (zero is best):\n     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format\n     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!\n     26: 0 = returns value, 1 = void -- 1 means inferred string length returned\n\n    Remainder:\n     27-31: 0 (reserved)\n */\n\n#ifndef Z_SOLO\n\n                        /* utility functions */\n\n/*\n     The following utility functions are implemented on top of the basic\n   stream-oriented functions.  To simplify the interface, some default options\n   are assumed (compression level and memory usage, standard memory allocation\n   functions).  The source code of these utility functions can be modified if\n   you need special options.\n*/\n\nZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,\n                                 const Bytef *source, uLong sourceLen));\n/*\n     Compresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed data.  compress() is equivalent to compress2() with a level\n   parameter of Z_DEFAULT_COMPRESSION.\n\n     compress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer.\n*/\n\nZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,\n                                  const Bytef *source, uLong sourceLen,\n                                  int level));\n/*\n     Compresses the source buffer into the destination buffer.  The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer.  Upon entry, destLen is the total size of the\n   destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed data.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\n\nZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));\n/*\n     compressBound() returns an upper bound on the compressed size after\n   compress() or compress2() on sourceLen bytes.  It would be used before a\n   compress() or compress2() call to allocate the destination buffer.\n*/\n\nZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,\n                                   const Bytef *source, uLong sourceLen));\n/*\n     Decompresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be large enough to hold the entire\n   uncompressed data.  (The size of the uncompressed data must have been saved\n   previously by the compressor and transmitted to the decompressor by some\n   mechanism outside the scope of this compression library.) Upon exit, destLen\n   is the actual size of the uncompressed data.\n\n     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In\n   the case where there is not enough room, uncompress() will fill the output\n   buffer with the uncompressed data up to that point.\n*/\n\nZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest,   uLongf *destLen,\n                                    const Bytef *source, uLong *sourceLen));\n/*\n     Same as uncompress, except that sourceLen is a pointer, where the\n   length of the source is *sourceLen.  On return, *sourceLen is the number of\n   source bytes consumed.\n*/\n\n                        /* gzip file access functions */\n\n/*\n     This library supports reading and writing files in gzip (.gz) format with\n   an interface similar to that of stdio, using the functions that start with\n   \"gz\".  The gzip format is different from the zlib format.  gzip is a gzip\n   wrapper, documented in RFC 1952, wrapped around a deflate stream.\n*/\n\ntypedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */\n\n/*\nZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));\n\n     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as\n   in fopen (\"rb\" or \"wb\") but can also include a compression level (\"wb9\") or\n   a strategy: 'f' for filtered data as in \"wb6f\", 'h' for Huffman-only\n   compression as in \"wb1h\", 'R' for run-length encoding as in \"wb1R\", or 'F'\n   for fixed code compression as in \"wb9F\".  (See the description of\n   deflateInit2 for more information about the strategy parameter.)  'T' will\n   request transparent writing or appending with no compression and not using\n   the gzip format.\n\n     \"a\" can be used instead of \"w\" to request that the gzip stream that will\n   be written be appended to the file.  \"+\" will result in an error, since\n   reading and writing to the same gzip file is not supported.  The addition of\n   \"x\" when writing will create the file exclusively, which fails if the file\n   already exists.  On systems that support it, the addition of \"e\" when\n   reading or writing will set the flag to close the file on an execve() call.\n\n     These functions, as well as gzip, will read and decode a sequence of gzip\n   streams in a file.  The append function of gzopen() can be used to create\n   such a file.  (Also see gzflush() for another way to do this.)  When\n   appending, gzopen does not test whether the file begins with a gzip stream,\n   nor does it look for the end of the gzip streams to begin appending.  gzopen\n   will simply append a gzip stream to the existing file.\n\n     gzopen can be used to read a file which is not in gzip format; in this\n   case gzread will directly read from the file without decompression.  When\n   reading, this will be detected automatically by looking for the magic two-\n   byte gzip header.\n\n     gzopen returns NULL if the file could not be opened, if there was\n   insufficient memory to allocate the gzFile state, or if an invalid mode was\n   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).\n   errno can be checked to determine if the reason gzopen failed was that the\n   file could not be opened.\n*/\n\nZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));\n/*\n     gzdopen associates a gzFile with the file descriptor fd.  File descriptors\n   are obtained from calls like open, dup, creat, pipe or fileno (if the file\n   has been previously opened with fopen).  The mode parameter is as in gzopen.\n\n     The next call of gzclose on the returned gzFile will also close the file\n   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor\n   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,\n   mode);.  The duplicated descriptor should be saved to avoid a leak, since\n   gzdopen does not close fd if it fails.  If you are using fileno() to get the\n   file descriptor from a FILE *, then you will have to use dup() to avoid\n   double-close()ing the file descriptor.  Both gzclose() and fclose() will\n   close the associated file descriptor, so they need to have different file\n   descriptors.\n\n     gzdopen returns NULL if there was insufficient memory to allocate the\n   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not\n   provided, or '+' was provided), or if fd is -1.  The file descriptor is not\n   used until the next gz* read, write, seek, or close operation, so gzdopen\n   will not detect if fd is invalid (unless fd is -1).\n*/\n\nZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));\n/*\n     Set the internal buffer size used by this library's functions.  The\n   default buffer size is 8192 bytes.  This function must be called after\n   gzopen() or gzdopen(), and before any other calls that read or write the\n   file.  The buffer memory allocation is always deferred to the first read or\n   write.  Three times that size in buffer space is allocated.  A larger buffer\n   size of, for example, 64K or 128K bytes will noticeably increase the speed\n   of decompression (reading).\n\n     The new buffer size also affects the maximum length for gzprintf().\n\n     gzbuffer() returns 0 on success, or -1 on failure, such as being called\n   too late.\n*/\n\nZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));\n/*\n     Dynamically update the compression level or strategy.  See the description\n   of deflateInit2 for the meaning of these parameters.  Previously provided\n   data is flushed before the parameter change.\n\n     gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not\n   opened for writing, Z_ERRNO if there is an error writing the flushed data,\n   or Z_MEM_ERROR if there is a memory allocation error.\n*/\n\nZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));\n/*\n     Reads the given number of uncompressed bytes from the compressed file.  If\n   the input file is not in gzip format, gzread copies the given number of\n   bytes into the buffer directly from the file.\n\n     After reaching the end of a gzip stream in the input, gzread will continue\n   to read, looking for another gzip stream.  Any number of gzip streams may be\n   concatenated in the input file, and will all be decompressed by gzread().\n   If something other than a gzip stream is encountered after a gzip stream,\n   that remaining trailing garbage is ignored (and no error is returned).\n\n     gzread can be used to read a gzip file that is being concurrently written.\n   Upon reaching the end of the input, gzread will return with the available\n   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then\n   gzclearerr can be used to clear the end of file indicator in order to permit\n   gzread to be tried again.  Z_OK indicates that a gzip stream was completed\n   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the\n   middle of a gzip stream.  Note that gzread does not return -1 in the event\n   of an incomplete gzip stream.  This error is deferred until gzclose(), which\n   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip\n   stream.  Alternatively, gzerror can be used before gzclose to detect this\n   case.\n\n     gzread returns the number of uncompressed bytes actually read, less than\n   len for end of file, or -1 for error.  If len is too large to fit in an int,\n   then nothing is read, -1 is returned, and the error state is set to\n   Z_STREAM_ERROR.\n*/\n\nZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,\n                                     gzFile file));\n/*\n     Read up to nitems items of size size from file to buf, otherwise operating\n   as gzread() does.  This duplicates the interface of stdio's fread(), with\n   size_t request and return types.  If the library defines size_t, then\n   z_size_t is identical to size_t.  If not, then z_size_t is an unsigned\n   integer type that can contain a pointer.\n\n     gzfread() returns the number of full items read of size size, or zero if\n   the end of the file was reached and a full item could not be read, or if\n   there was an error.  gzerror() must be consulted if zero is returned in\n   order to determine if there was an error.  If the multiplication of size and\n   nitems overflows, i.e. the product does not fit in a z_size_t, then nothing\n   is read, zero is returned, and the error state is set to Z_STREAM_ERROR.\n\n     In the event that the end of file is reached and only a partial item is\n   available at the end, i.e. the remaining uncompressed data length is not a\n   multiple of size, then the final partial item is nevetheless read into buf\n   and the end-of-file flag is set.  The length of the partial item read is not\n   provided, but could be inferred from the result of gztell().  This behavior\n   is the same as the behavior of fread() implementations in common libraries,\n   but it prevents the direct use of gzfread() to read a concurrently written\n   file, reseting and retrying on end-of-file, when size is not 1.\n*/\n\nZEXTERN int ZEXPORT gzwrite OF((gzFile file,\n                                voidpc buf, unsigned len));\n/*\n     Writes the given number of uncompressed bytes into the compressed file.\n   gzwrite returns the number of uncompressed bytes written or 0 in case of\n   error.\n*/\n\nZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,\n                                      z_size_t nitems, gzFile file));\n/*\n     gzfwrite() writes nitems items of size size from buf to file, duplicating\n   the interface of stdio's fwrite(), with size_t request and return types.  If\n   the library defines size_t, then z_size_t is identical to size_t.  If not,\n   then z_size_t is an unsigned integer type that can contain a pointer.\n\n     gzfwrite() returns the number of full items written of size size, or zero\n   if there was an error.  If the multiplication of size and nitems overflows,\n   i.e. the product does not fit in a z_size_t, then nothing is written, zero\n   is returned, and the error state is set to Z_STREAM_ERROR.\n*/\n\nZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));\n/*\n     Converts, formats, and writes the arguments to the compressed file under\n   control of the format string, as in fprintf.  gzprintf returns the number of\n   uncompressed bytes actually written, or a negative zlib error code in case\n   of error.  The number of uncompressed bytes written is limited to 8191, or\n   one less than the buffer size given to gzbuffer().  The caller should assure\n   that this limit is not exceeded.  If it is exceeded, then gzprintf() will\n   return an error (0) with nothing written.  In this case, there may also be a\n   buffer overflow with unpredictable consequences, which is possible only if\n   zlib was compiled with the insecure functions sprintf() or vsprintf()\n   because the secure snprintf() or vsnprintf() functions were not available.\n   This can be determined using zlibCompileFlags().\n*/\n\nZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));\n/*\n     Writes the given null-terminated string to the compressed file, excluding\n   the terminating null character.\n\n     gzputs returns the number of characters written, or -1 in case of error.\n*/\n\nZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));\n/*\n     Reads bytes from the compressed file until len-1 characters are read, or a\n   newline character is read and transferred to buf, or an end-of-file\n   condition is encountered.  If any characters are read or if len == 1, the\n   string is terminated with a null character.  If no characters are read due\n   to an end-of-file or len < 1, then the buffer is left untouched.\n\n     gzgets returns buf which is a null-terminated string, or it returns NULL\n   for end-of-file or in case of error.  If there was an error, the contents at\n   buf are indeterminate.\n*/\n\nZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));\n/*\n     Writes c, converted to an unsigned char, into the compressed file.  gzputc\n   returns the value that was written, or -1 in case of error.\n*/\n\nZEXTERN int ZEXPORT gzgetc OF((gzFile file));\n/*\n     Reads one byte from the compressed file.  gzgetc returns this byte or -1\n   in case of end of file or error.  This is implemented as a macro for speed.\n   As such, it does not do all of the checking the other functions do.  I.e.\n   it does not check to see if file is NULL, nor whether the structure file\n   points to has been clobbered or not.\n*/\n\nZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));\n/*\n     Push one character back onto the stream to be read as the first character\n   on the next read.  At least one character of push-back is allowed.\n   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will\n   fail if c is -1, and may fail if a character has been pushed but not read\n   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the\n   output buffer size of pushed characters is allowed.  (See gzbuffer above.)\n   The pushed character will be discarded if the stream is repositioned with\n   gzseek() or gzrewind().\n*/\n\nZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));\n/*\n     Flushes all pending output into the compressed file.  The parameter flush\n   is as in the deflate() function.  The return value is the zlib error number\n   (see function gzerror below).  gzflush is only permitted when writing.\n\n     If the flush parameter is Z_FINISH, the remaining data is written and the\n   gzip stream is completed in the output.  If gzwrite() is called again, a new\n   gzip stream will be started in the output.  gzread() is able to read such\n   concatenated gzip streams.\n\n     gzflush should be called only when strictly necessary because it will\n   degrade compression if called too often.\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,\n                                   z_off_t offset, int whence));\n\n     Sets the starting position for the next gzread or gzwrite on the given\n   compressed file.  The offset represents a number of bytes in the\n   uncompressed data stream.  The whence parameter is defined as in lseek(2);\n   the value SEEK_END is not supported.\n\n     If the file is opened for reading, this function is emulated but can be\n   extremely slow.  If the file is opened for writing, only forward seeks are\n   supported; gzseek then compresses a sequence of zeroes up to the new\n   starting position.\n\n     gzseek returns the resulting offset location as measured in bytes from\n   the beginning of the uncompressed stream, or -1 in case of error, in\n   particular if the file is opened for writing and the new starting position\n   would be before the current position.\n*/\n\nZEXTERN int ZEXPORT    gzrewind OF((gzFile file));\n/*\n     Rewinds the given file. This function is supported only for reading.\n\n     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));\n\n     Returns the starting position for the next gzread or gzwrite on the given\n   compressed file.  This position represents a number of bytes in the\n   uncompressed data stream, and is zero when starting, even if appending or\n   reading a gzip stream from the middle of a file using gzdopen().\n\n     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));\n\n     Returns the current offset in the file being read or written.  This offset\n   includes the count of bytes that precede the gzip stream, for example when\n   appending or when using gzdopen() for reading.  When reading, the offset\n   does not include as yet unused buffered input.  This information can be used\n   for a progress indicator.  On error, gzoffset() returns -1.\n*/\n\nZEXTERN int ZEXPORT gzeof OF((gzFile file));\n/*\n     Returns true (1) if the end-of-file indicator has been set while reading,\n   false (0) otherwise.  Note that the end-of-file indicator is set only if the\n   read tried to go past the end of the input, but came up short.  Therefore,\n   just like feof(), gzeof() may return false even if there is no more data to\n   read, in the event that the last read request was for the exact number of\n   bytes remaining in the input file.  This will happen if the input file size\n   is an exact multiple of the buffer size.\n\n     If gzeof() returns true, then the read functions will return no more data,\n   unless the end-of-file indicator is reset by gzclearerr() and the input file\n   has grown since the previous end of file was detected.\n*/\n\nZEXTERN int ZEXPORT gzdirect OF((gzFile file));\n/*\n     Returns true (1) if file is being copied directly while reading, or false\n   (0) if file is a gzip stream being decompressed.\n\n     If the input file is empty, gzdirect() will return true, since the input\n   does not contain a gzip stream.\n\n     If gzdirect() is used immediately after gzopen() or gzdopen() it will\n   cause buffers to be allocated to allow reading the file to determine if it\n   is a gzip file.  Therefore if gzbuffer() is used, it should be called before\n   gzdirect().\n\n     When writing, gzdirect() returns true (1) if transparent writing was\n   requested (\"wT\" for the gzopen() mode), or false (0) otherwise.  (Note:\n   gzdirect() is not needed when writing.  Transparent writing must be\n   explicitly requested, so the application already knows the answer.  When\n   linking statically, using gzdirect() will include all of the zlib code for\n   gzip file reading and decompression, which may not be desired.)\n*/\n\nZEXTERN int ZEXPORT    gzclose OF((gzFile file));\n/*\n     Flushes all pending output if necessary, closes the compressed file and\n   deallocates the (de)compression state.  Note that once file is closed, you\n   cannot call gzerror with file, since its structures have been deallocated.\n   gzclose must not be called more than once on the same file, just as free\n   must not be called more than once on the same allocation.\n\n     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a\n   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the\n   last read ended in the middle of a gzip stream, or Z_OK on success.\n*/\n\nZEXTERN int ZEXPORT gzclose_r OF((gzFile file));\nZEXTERN int ZEXPORT gzclose_w OF((gzFile file));\n/*\n     Same as gzclose(), but gzclose_r() is only for use when reading, and\n   gzclose_w() is only for use when writing or appending.  The advantage to\n   using these instead of gzclose() is that they avoid linking in zlib\n   compression or decompression code that is not used when only reading or only\n   writing respectively.  If gzclose() is used, then both compression and\n   decompression code will be included the application when linking to a static\n   zlib library.\n*/\n\nZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));\n/*\n     Returns the error message for the last error which occurred on the given\n   compressed file.  errnum is set to zlib error number.  If an error occurred\n   in the file system and not in the compression library, errnum is set to\n   Z_ERRNO and the application may consult errno to get the exact error code.\n\n     The application must not modify the returned string.  Future calls to\n   this function may invalidate the previously returned string.  If file is\n   closed, then the string previously returned by gzerror will no longer be\n   available.\n\n     gzerror() should be used to distinguish errors from end-of-file for those\n   functions above that do not distinguish those cases in their return values.\n*/\n\nZEXTERN void ZEXPORT gzclearerr OF((gzFile file));\n/*\n     Clears the error and end-of-file flags for file.  This is analogous to the\n   clearerr() function in stdio.  This is useful for continuing to read a gzip\n   file that is being written concurrently.\n*/\n\n#endif /* !Z_SOLO */\n\n                        /* checksum functions */\n\n/*\n     These functions are not related to compression but are exported\n   anyway because they might be useful in applications using the compression\n   library.\n*/\n\nZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));\n/*\n     Update a running Adler-32 checksum with the bytes buf[0..len-1] and\n   return the updated checksum.  If buf is Z_NULL, this function returns the\n   required initial value for the checksum.\n\n     An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed\n   much faster.\n\n   Usage example:\n\n     uLong adler = adler32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       adler = adler32(adler, buffer, length);\n     }\n     if (adler != original_adler) error();\n*/\n\nZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,\n                                    z_size_t len));\n/*\n     Same as adler32(), but with a size_t length.\n*/\n\n/*\nZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,\n                                          z_off_t len2));\n\n     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1\n   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for\n   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of\n   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note\n   that the z_off_t type (like off_t) is a signed integer.  If len2 is\n   negative, the result has no meaning or utility.\n*/\n\nZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));\n/*\n     Update a running CRC-32 with the bytes buf[0..len-1] and return the\n   updated CRC-32.  If buf is Z_NULL, this function returns the required\n   initial value for the crc.  Pre- and post-conditioning (one's complement) is\n   performed within this function so it shouldn't be done by the application.\n\n   Usage example:\n\n     uLong crc = crc32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       crc = crc32(crc, buffer, length);\n     }\n     if (crc != original_crc) error();\n*/\n\nZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,\n                                  z_size_t len));\n/*\n     Same as crc32(), but with a size_t length.\n*/\n\n/*\nZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));\n\n     Combine two CRC-32 check values into one.  For two sequences of bytes,\n   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were\n   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32\n   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and\n   len2.\n*/\n\n\n                        /* various hacks, don't look :) */\n\n/* deflateInit and inflateInit are macros to allow checking the zlib version\n * and the compiler's view of z_stream:\n */\nZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,\n                                     const char *version, int stream_size));\nZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,\n                                     const char *version, int stream_size));\nZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,\n                                      int windowBits, int memLevel,\n                                      int strategy, const char *version,\n                                      int stream_size));\nZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,\n                                      const char *version, int stream_size));\nZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,\n                                         unsigned char FAR *window,\n                                         const char *version,\n                                         int stream_size));\n#ifdef Z_PREFIX_SET\n#  define z_deflateInit(strm, level) \\\n          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_inflateInit(strm) \\\n          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_inflateInit2(strm, windowBits) \\\n          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                        (int)sizeof(z_stream))\n#  define z_inflateBackInit(strm, windowBits, window) \\\n          inflateBackInit_((strm), (windowBits), (window), \\\n                           ZLIB_VERSION, (int)sizeof(z_stream))\n#else\n#  define deflateInit(strm, level) \\\n          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define inflateInit(strm) \\\n          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define inflateInit2(strm, windowBits) \\\n          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                        (int)sizeof(z_stream))\n#  define inflateBackInit(strm, windowBits, window) \\\n          inflateBackInit_((strm), (windowBits), (window), \\\n                           ZLIB_VERSION, (int)sizeof(z_stream))\n#endif\n\n#ifndef Z_SOLO\n\n/* gzgetc() macro and its supporting function and exposed data structure.  Note\n * that the real internal state is much larger than the exposed structure.\n * This abbreviated structure exposes just enough for the gzgetc() macro.  The\n * user should not mess with these exposed elements, since their names or\n * behavior could change in the future, perhaps even capriciously.  They can\n * only be used by the gzgetc() macro.  You have been warned.\n */\nstruct gzFile_s {\n    unsigned have;\n    unsigned char *next;\n    z_off64_t pos;\n};\nZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */\n#ifdef Z_PREFIX_SET\n#  undef z_gzgetc\n#  define z_gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))\n#else\n#  define gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))\n#endif\n\n/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or\n * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if\n * both are true, the application gets the *64 functions, and the regular\n * functions are changed to 64 bits) -- in case these are set on systems\n * without large file support, _LFS64_LARGEFILE must also be true\n */\n#ifdef Z_LARGE64\n   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));\n   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));\n   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));\n   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));\n   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));\n   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));\n#endif\n\n#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)\n#  ifdef Z_PREFIX_SET\n#    define z_gzopen z_gzopen64\n#    define z_gzseek z_gzseek64\n#    define z_gztell z_gztell64\n#    define z_gzoffset z_gzoffset64\n#    define z_adler32_combine z_adler32_combine64\n#    define z_crc32_combine z_crc32_combine64\n#  else\n#    define gzopen gzopen64\n#    define gzseek gzseek64\n#    define gztell gztell64\n#    define gzoffset gzoffset64\n#    define adler32_combine adler32_combine64\n#    define crc32_combine crc32_combine64\n#  endif\n#  ifndef Z_LARGE64\n     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));\n     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));\n     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));\n     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));\n     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));\n     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));\n#  endif\n#else\n   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));\n   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));\n   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));\n   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));\n   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));\n   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));\n#endif\n\n#else /* Z_SOLO */\n\n   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));\n   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));\n\n#endif /* !Z_SOLO */\n\n/* undocumented functions */\nZEXTERN const char   * ZEXPORT zError           OF((int));\nZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));\nZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));\nZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));\nZEXTERN int            ZEXPORT inflateValidate OF((z_streamp, int));\nZEXTERN unsigned long  ZEXPORT inflateCodesUsed OF ((z_streamp));\nZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));\nZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));\n#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)\nZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,\n                                            const char *mode));\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\nZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,\n                                                  const char *format,\n                                                  va_list va));\n#  endif\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZLIB_H */\n"
  },
  {
    "path": "deps/CascLib/src/zlib/zutil.c",
    "content": "/* zutil.c -- target dependent utility functions for the compression library\n * Copyright (C) 1995-2017 Jean-loup Gailly\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#include \"zutil.h\"\n#ifndef Z_SOLO\n#  include \"gzguts.h\"\n#endif\n\nz_const char * const z_errmsg[10] = {\n    (z_const char *)\"need dictionary\",     /* Z_NEED_DICT       2  */\n    (z_const char *)\"stream end\",          /* Z_STREAM_END      1  */\n    (z_const char *)\"\",                    /* Z_OK              0  */\n    (z_const char *)\"file error\",          /* Z_ERRNO         (-1) */\n    (z_const char *)\"stream error\",        /* Z_STREAM_ERROR  (-2) */\n    (z_const char *)\"data error\",          /* Z_DATA_ERROR    (-3) */\n    (z_const char *)\"insufficient memory\", /* Z_MEM_ERROR     (-4) */\n    (z_const char *)\"buffer error\",        /* Z_BUF_ERROR     (-5) */\n    (z_const char *)\"incompatible version\",/* Z_VERSION_ERROR (-6) */\n    (z_const char *)\"\"\n};\n\n\nconst char * ZEXPORT zlibVersion()\n{\n    return ZLIB_VERSION;\n}\n\nuLong ZEXPORT zlibCompileFlags()\n{\n    uLong flags;\n\n    flags = 0;\n    switch ((int)(sizeof(uInt))) {\n    case 2:     break;\n    case 4:     flags += 1;     break;\n    case 8:     flags += 2;     break;\n    default:    flags += 3;\n    }\n    switch ((int)(sizeof(uLong))) {\n    case 2:     break;\n    case 4:     flags += 1 << 2;        break;\n    case 8:     flags += 2 << 2;        break;\n    default:    flags += 3 << 2;\n    }\n    switch ((int)(sizeof(voidpf))) {\n    case 2:     break;\n    case 4:     flags += 1 << 4;        break;\n    case 8:     flags += 2 << 4;        break;\n    default:    flags += 3 << 4;\n    }\n    switch ((int)(sizeof(z_off_t))) {\n    case 2:     break;\n    case 4:     flags += 1 << 6;        break;\n    case 8:     flags += 2 << 6;        break;\n    default:    flags += 3 << 6;\n    }\n#ifdef ZLIB_DEBUG\n    flags += 1 << 8;\n#endif\n#if defined(ASMV) || defined(ASMINF)\n    flags += 1 << 9;\n#endif\n#ifdef ZLIB_WINAPI\n    flags += 1 << 10;\n#endif\n#ifdef BUILDFIXED\n    flags += 1 << 12;\n#endif\n#ifdef DYNAMIC_CRC_TABLE\n    flags += 1 << 13;\n#endif\n#ifdef NO_GZCOMPRESS\n    flags += 1L << 16;\n#endif\n#ifdef NO_GZIP\n    flags += 1L << 17;\n#endif\n#ifdef PKZIP_BUG_WORKAROUND\n    flags += 1L << 20;\n#endif\n#ifdef FASTEST\n    flags += 1L << 21;\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifdef NO_vsnprintf\n    flags += 1L << 25;\n#    ifdef HAS_vsprintf_void\n    flags += 1L << 26;\n#    endif\n#  else\n#    ifdef HAS_vsnprintf_void\n    flags += 1L << 26;\n#    endif\n#  endif\n#else\n    flags += 1L << 24;\n#  ifdef NO_snprintf\n    flags += 1L << 25;\n#    ifdef HAS_sprintf_void\n    flags += 1L << 26;\n#    endif\n#  else\n#    ifdef HAS_snprintf_void\n    flags += 1L << 26;\n#    endif\n#  endif\n#endif\n    return flags;\n}\n\n#ifdef ZLIB_DEBUG\n#include <stdlib.h>\n#  ifndef verbose\n#    define verbose 0\n#  endif\nint ZLIB_INTERNAL z_verbose = verbose;\n\nvoid ZLIB_INTERNAL z_error (m)\n    char *m;\n{\n    fprintf(stderr, \"%s\\n\", m);\n    exit(1);\n}\n#endif\n\n/* exported to allow conversion of error code to string for compress() and\n * uncompress()\n */\nconst char * ZEXPORT zError(err)\n    int err;\n{\n    return ERR_MSG(err);\n}\n\n#if defined(_WIN32_WCE)\n    /* The Microsoft C Run-Time Library for Windows CE doesn't have\n     * errno.  We define it as a global variable to simplify porting.\n     * Its value is always 0 and should not be used.\n     */\n    int errno = 0;\n#endif\n\n#ifndef HAVE_MEMCPY\n\nvoid ZLIB_INTERNAL zmemcpy(dest, source, len)\n    Bytef* dest;\n    const Bytef* source;\n    uInt  len;\n{\n    if (len == 0) return;\n    do {\n        *dest++ = *source++; /* ??? to be unrolled */\n    } while (--len != 0);\n}\n\nint ZLIB_INTERNAL zmemcmp(s1, s2, len)\n    const Bytef* s1;\n    const Bytef* s2;\n    uInt  len;\n{\n    uInt j;\n\n    for (j = 0; j < len; j++) {\n        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;\n    }\n    return 0;\n}\n\nvoid ZLIB_INTERNAL zmemzero(dest, len)\n    Bytef* dest;\n    uInt  len;\n{\n    if (len == 0) return;\n    do {\n        *dest++ = 0;  /* ??? to be unrolled */\n    } while (--len != 0);\n}\n#endif\n\n#ifndef Z_SOLO\n\n#ifdef SYS16BIT\n\n#ifdef __TURBOC__\n/* Turbo C in 16-bit mode */\n\n#  define MY_ZCALLOC\n\n/* Turbo C malloc() does not allow dynamic allocation of 64K bytes\n * and farmalloc(64K) returns a pointer with an offset of 8, so we\n * must fix the pointer. Warning: the pointer must be put back to its\n * original form in order to free it, use zcfree().\n */\n\n#define MAX_PTR 10\n/* 10*64K = 640K */\n\nlocal int next_ptr = 0;\n\ntypedef struct ptr_table_s {\n    voidpf org_ptr;\n    voidpf new_ptr;\n} ptr_table;\n\nlocal ptr_table table[MAX_PTR];\n/* This table is used to remember the original form of pointers\n * to large buffers (64K). Such pointers are normalized with a zero offset.\n * Since MSDOS is not a preemptive multitasking OS, this table is not\n * protected from concurrent access. This hack doesn't work anyway on\n * a protected system like OS/2. Use Microsoft C instead.\n */\n\nvoidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)\n{\n    voidpf buf;\n    ulg bsize = (ulg)items*size;\n\n    (void)opaque;\n\n    /* If we allocate less than 65520 bytes, we assume that farmalloc\n     * will return a usable pointer which doesn't have to be normalized.\n     */\n    if (bsize < 65520L) {\n        buf = farmalloc(bsize);\n        if (*(ush*)&buf != 0) return buf;\n    } else {\n        buf = farmalloc(bsize + 16L);\n    }\n    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;\n    table[next_ptr].org_ptr = buf;\n\n    /* Normalize the pointer to seg:0 */\n    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;\n    *(ush*)&buf = 0;\n    table[next_ptr++].new_ptr = buf;\n    return buf;\n}\n\nvoid ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)\n{\n    int n;\n\n    (void)opaque;\n\n    if (*(ush*)&ptr != 0) { /* object < 64K */\n        farfree(ptr);\n        return;\n    }\n    /* Find the original pointer */\n    for (n = 0; n < next_ptr; n++) {\n        if (ptr != table[n].new_ptr) continue;\n\n        farfree(table[n].org_ptr);\n        while (++n < next_ptr) {\n            table[n-1] = table[n];\n        }\n        next_ptr--;\n        return;\n    }\n    Assert(0, \"zcfree: ptr not found\");\n}\n\n#endif /* __TURBOC__ */\n\n\n#ifdef M_I86\n/* Microsoft C in 16-bit mode */\n\n#  define MY_ZCALLOC\n\n#if (!defined(_MSC_VER) || (_MSC_VER <= 600))\n#  define _halloc  halloc\n#  define _hfree   hfree\n#endif\n\nvoidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)\n{\n    (void)opaque;\n    return _halloc((long)items, size);\n}\n\nvoid ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)\n{\n    (void)opaque;\n    _hfree(ptr);\n}\n\n#endif /* M_I86 */\n\n#endif /* SYS16BIT */\n\n\n#ifndef MY_ZCALLOC /* Any system without a special alloc function */\n\n#ifndef STDC\nextern voidp  malloc OF((uInt size));\nextern voidp  calloc OF((uInt items, uInt size));\nextern void   free   OF((voidpf ptr));\n#endif\n\nvoidpf ZLIB_INTERNAL zcalloc (opaque, items, size)\n    voidpf opaque;\n    unsigned items;\n    unsigned size;\n{\n    (void)opaque;\n    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :\n                              (voidpf)calloc(items, size);\n}\n\nvoid ZLIB_INTERNAL zcfree (opaque, ptr)\n    voidpf opaque;\n    voidpf ptr;\n{\n    (void)opaque;\n    free(ptr);\n}\n\n#endif /* MY_ZCALLOC */\n\n#endif /* !Z_SOLO */\n"
  },
  {
    "path": "deps/CascLib/src/zlib/zutil.h",
    "content": "/* zutil.h -- internal interface and configuration of the compression library\n * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZUTIL_H\n#define ZUTIL_H\n\n#ifdef HAVE_HIDDEN\n#  define ZLIB_INTERNAL __attribute__((visibility (\"hidden\")))\n#else\n#  define ZLIB_INTERNAL\n#endif\n\n#include \"zlib.h\"\n\n#if defined(STDC) && !defined(Z_SOLO)\n#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))\n#    include <stddef.h>\n#  endif\n#  include <string.h>\n#  include <stdlib.h>\n#endif\n\n#ifdef Z_SOLO\n   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */\n#endif\n\n#ifndef local\n#  define local static\n#endif\n/* since \"static\" is used to mean two completely different things in C, we\n   define \"local\" for the non-static meaning of \"static\", for readability\n   (compile with -Dlocal if your debugger can't find static symbols) */\n\ntypedef unsigned char  uch;\ntypedef uch FAR uchf;\ntypedef unsigned short ush;\ntypedef ush FAR ushf;\ntypedef unsigned long  ulg;\n\nextern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */\n/* (size given to avoid silly warnings with Visual C++) */\n\n#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]\n\n#define ERR_RETURN(strm,err) \\\n  return (strm->msg = ERR_MSG(err), (err))\n/* To be used only when the state is known to be valid */\n\n        /* common constants */\n\n#ifndef DEF_WBITS\n#  define DEF_WBITS MAX_WBITS\n#endif\n/* default windowBits for decompression. MAX_WBITS is for compression only */\n\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n/* default memLevel */\n\n#define STORED_BLOCK 0\n#define STATIC_TREES 1\n#define DYN_TREES    2\n/* The three kinds of block type */\n\n#define MIN_MATCH  3\n#define MAX_MATCH  258\n/* The minimum and maximum match lengths */\n\n#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */\n\n        /* target dependencies */\n\n#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))\n#  define OS_CODE  0x00\n#  ifndef Z_SOLO\n#    if defined(__TURBOC__) || defined(__BORLANDC__)\n#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))\n         /* Allow compilation with ANSI keywords only enabled */\n         void _Cdecl farfree( void *block );\n         void *_Cdecl farmalloc( unsigned long nbytes );\n#      else\n#        include <alloc.h>\n#      endif\n#    else /* MSC or DJGPP */\n#      include <malloc.h>\n#    endif\n#  endif\n#endif\n\n#ifdef AMIGA\n#  define OS_CODE  1\n#endif\n\n#if defined(VAXC) || defined(VMS)\n#  define OS_CODE  2\n#  define F_OPEN(name, mode) \\\n     fopen((name), (mode), \"mbc=60\", \"ctx=stm\", \"rfm=fix\", \"mrs=512\")\n#endif\n\n#ifdef __370__\n#  if __TARGET_LIB__ < 0x20000000\n#    define OS_CODE 4\n#  elif __TARGET_LIB__ < 0x40000000\n#    define OS_CODE 11\n#  else\n#    define OS_CODE 8\n#  endif\n#endif\n\n#if defined(ATARI) || defined(atarist)\n#  define OS_CODE  5\n#endif\n\n#ifdef OS2\n#  define OS_CODE  6\n#  if defined(M_I86) && !defined(Z_SOLO)\n#    include <malloc.h>\n#  endif\n#endif\n\n#if defined(MACOS) || defined(TARGET_OS_MAC)\n#  define OS_CODE  7\n#  ifndef Z_SOLO\n#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os\n#      include <unix.h> /* for fdopen */\n#    else\n#      ifndef fdopen\n#        define fdopen(fd,mode) NULL /* No fdopen() */\n#      endif\n#    endif\n#  endif\n#endif\n\n#ifdef __acorn\n#  define OS_CODE 13\n#endif\n\n#if defined(WIN32) && !defined(__CYGWIN__)\n#  define OS_CODE  10\n#endif\n\n#ifdef _BEOS_\n#  define OS_CODE  16\n#endif\n\n#ifdef __TOS_OS400__\n#  define OS_CODE 18\n#endif\n\n#ifdef __APPLE__\n#  define OS_CODE 19\n#endif\n\n#if defined(_BEOS_) || defined(RISCOS)\n#  define fdopen(fd,mode) NULL /* No fdopen() */\n#endif\n\n#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX\n#  if defined(_WIN32_WCE)\n#    define fdopen(fd,mode) NULL /* No fdopen() */\n#    ifndef _PTRDIFF_T_DEFINED\n       typedef int ptrdiff_t;\n#      define _PTRDIFF_T_DEFINED\n#    endif\n#  else\n#    define fdopen(fd,type)  _fdopen(fd,type)\n#  endif\n#endif\n\n#if defined(__BORLANDC__) && !defined(MSDOS)\n  #pragma warn -8004\n  #pragma warn -8008\n  #pragma warn -8066\n#endif\n\n/* provide prototypes for these when building zlib without LFS */\n#if !defined(_WIN32) && \\\n    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)\n    ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));\n    ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));\n#endif\n\n        /* common defaults */\n\n#ifndef OS_CODE\n#  define OS_CODE  3     /* assume Unix */\n#endif\n\n#ifndef F_OPEN\n#  define F_OPEN(name, mode) fopen((name), (mode))\n#endif\n\n         /* functions */\n\n#if defined(pyr) || defined(Z_SOLO)\n#  define NO_MEMCPY\n#endif\n#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)\n /* Use our own functions for small and medium model with MSC <= 5.0.\n  * You may have to use the same strategy for Borland C (untested).\n  * The __SC__ check is for Symantec.\n  */\n#  define NO_MEMCPY\n#endif\n#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)\n#  define HAVE_MEMCPY\n#endif\n#ifdef HAVE_MEMCPY\n#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */\n#    define zmemcpy _fmemcpy\n#    define zmemcmp _fmemcmp\n#    define zmemzero(dest, len) _fmemset(dest, 0, len)\n#  else\n#    define zmemcpy memcpy\n#    define zmemcmp memcmp\n#    define zmemzero(dest, len) memset(dest, 0, len)\n#  endif\n#else\n   void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));\n   int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));\n   void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));\n#endif\n\n/* Diagnostic functions */\n#ifdef ZLIB_DEBUG\n#  include <stdio.h>\n   extern int ZLIB_INTERNAL z_verbose;\n   extern void ZLIB_INTERNAL z_error OF((char *m));\n#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}\n#  define Trace(x) {if (z_verbose>=0) fprintf x ;}\n#  define Tracev(x) {if (z_verbose>0) fprintf x ;}\n#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}\n#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}\n#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}\n#else\n#  define Assert(cond,msg)\n#  define Trace(x)\n#  define Tracev(x)\n#  define Tracevv(x)\n#  define Tracec(c,x)\n#  define Tracecv(c,x)\n#endif\n\n#ifndef Z_SOLO\n   voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,\n                                    unsigned size));\n   void ZLIB_INTERNAL zcfree  OF((voidpf opaque, voidpf ptr));\n#endif\n\n#define ZALLOC(strm, items, size) \\\n           (*((strm)->zalloc))((strm)->opaque, (items), (size))\n#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))\n#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}\n\n/* Reverse the bytes in a 32-bit value */\n#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \\\n                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))\n\n#endif /* ZUTIL_H */\n"
  },
  {
    "path": "deps/glad/CMakeLists.txt",
    "content": "add_library(glad STATIC EXCLUDE_FROM_ALL src/glad.c src/glad_wgl.c)\ntarget_include_directories(glad PUBLIC include)\n"
  },
  {
    "path": "deps/glad/include/KHR/khrplatform.h",
    "content": "#ifndef __khrplatform_h_\n#define __khrplatform_h_\n\n/*\n** Copyright (c) 2008-2018 The Khronos Group Inc.\n**\n** Permission is hereby granted, free of charge, to any person obtaining a\n** copy of this software and/or associated documentation files (the\n** \"Materials\"), to deal in the Materials without restriction, including\n** without limitation the rights to use, copy, modify, merge, publish,\n** distribute, sublicense, and/or sell copies of the Materials, and to\n** permit persons to whom the Materials are furnished to do so, subject to\n** the following conditions:\n**\n** The above copyright notice and this permission notice shall be included\n** in all copies or substantial portions of the Materials.\n**\n** THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\n*/\n\n/* Khronos platform-specific types and definitions.\n *\n * The master copy of khrplatform.h is maintained in the Khronos EGL\n * Registry repository at https://github.com/KhronosGroup/EGL-Registry\n * The last semantic modification to khrplatform.h was at commit ID:\n *      67a3e0864c2d75ea5287b9f3d2eb74a745936692\n *\n * Adopters may modify this file to suit their platform. Adopters are\n * encouraged to submit platform specific modifications to the Khronos\n * group so that they can be included in future versions of this file.\n * Please submit changes by filing pull requests or issues on\n * the EGL Registry repository linked above.\n *\n *\n * See the Implementer's Guidelines for information about where this file\n * should be located on your system and for more details of its use:\n *    http://www.khronos.org/registry/implementers_guide.pdf\n *\n * This file should be included as\n *        #include <KHR/khrplatform.h>\n * by Khronos client API header files that use its types and defines.\n *\n * The types in khrplatform.h should only be used to define API-specific types.\n *\n * Types defined in khrplatform.h:\n *    khronos_int8_t              signed   8  bit\n *    khronos_uint8_t             unsigned 8  bit\n *    khronos_int16_t             signed   16 bit\n *    khronos_uint16_t            unsigned 16 bit\n *    khronos_int32_t             signed   32 bit\n *    khronos_uint32_t            unsigned 32 bit\n *    khronos_int64_t             signed   64 bit\n *    khronos_uint64_t            unsigned 64 bit\n *    khronos_intptr_t            signed   same number of bits as a pointer\n *    khronos_uintptr_t           unsigned same number of bits as a pointer\n *    khronos_ssize_t             signed   size\n *    khronos_usize_t             unsigned size\n *    khronos_float_t             signed   32 bit floating point\n *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds\n *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in\n *                                         nanoseconds\n *    khronos_stime_nanoseconds_t signed time interval in nanoseconds\n *    khronos_boolean_enum_t      enumerated boolean type. This should\n *      only be used as a base type when a client API's boolean type is\n *      an enum. Client APIs which use an integer or other type for\n *      booleans cannot use this as the base type for their boolean.\n *\n * Tokens defined in khrplatform.h:\n *\n *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.\n *\n *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.\n *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.\n *\n * Calling convention macros defined in this file:\n *    KHRONOS_APICALL\n *    KHRONOS_APIENTRY\n *    KHRONOS_APIATTRIBUTES\n *\n * These may be used in function prototypes as:\n *\n *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(\n *                                  int arg1,\n *                                  int arg2) KHRONOS_APIATTRIBUTES;\n */\n\n#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)\n#   define KHRONOS_STATIC 1\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APICALL\n *-------------------------------------------------------------------------\n * This precedes the return type of the function in the function prototype.\n */\n#if defined(KHRONOS_STATIC)\n    /* If the preprocessor constant KHRONOS_STATIC is defined, make the\n     * header compatible with static linking. */\n#   define KHRONOS_APICALL\n#elif defined(_WIN32)\n#   define KHRONOS_APICALL __declspec(dllimport)\n#elif defined (__SYMBIAN32__)\n#   define KHRONOS_APICALL IMPORT_C\n#elif defined(__ANDROID__)\n#   define KHRONOS_APICALL __attribute__((visibility(\"default\")))\n#else\n#   define KHRONOS_APICALL\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIENTRY\n *-------------------------------------------------------------------------\n * This follows the return type of the function  and precedes the function\n * name in the function prototype.\n */\n#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)\n    /* Win32 but not WinCE */\n#   define KHRONOS_APIENTRY __stdcall\n#else\n#   define KHRONOS_APIENTRY\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIATTRIBUTES\n *-------------------------------------------------------------------------\n * This follows the closing parenthesis of the function prototype arguments.\n */\n#if defined (__ARMCC_2__)\n#define KHRONOS_APIATTRIBUTES __softfp\n#else\n#define KHRONOS_APIATTRIBUTES\n#endif\n\n/*-------------------------------------------------------------------------\n * basic type definitions\n *-----------------------------------------------------------------------*/\n#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)\n\n\n/*\n * Using <stdint.h>\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(__VMS ) || defined(__sgi)\n\n/*\n * Using <inttypes.h>\n */\n#include <inttypes.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)\n\n/*\n * Win32\n */\ntypedef __int32                 khronos_int32_t;\ntypedef unsigned __int32        khronos_uint32_t;\ntypedef __int64                 khronos_int64_t;\ntypedef unsigned __int64        khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(__sun__) || defined(__digital__)\n\n/*\n * Sun or Digital\n */\ntypedef int                     khronos_int32_t;\ntypedef unsigned int            khronos_uint32_t;\n#if defined(__arch64__) || defined(_LP64)\ntypedef long int                khronos_int64_t;\ntypedef unsigned long int       khronos_uint64_t;\n#else\ntypedef long long int           khronos_int64_t;\ntypedef unsigned long long int  khronos_uint64_t;\n#endif /* __arch64__ */\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif 0\n\n/*\n * Hypothetical platform with no float or int64 support\n */\ntypedef int                     khronos_int32_t;\ntypedef unsigned int            khronos_uint32_t;\n#define KHRONOS_SUPPORT_INT64   0\n#define KHRONOS_SUPPORT_FLOAT   0\n\n#else\n\n/*\n * Generic fallback\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#endif\n\n\n/*\n * Types that are (so far) the same on all platforms\n */\ntypedef signed   char          khronos_int8_t;\ntypedef unsigned char          khronos_uint8_t;\ntypedef signed   short int     khronos_int16_t;\ntypedef unsigned short int     khronos_uint16_t;\n\n/*\n * Types that differ between LLP64 and LP64 architectures - in LLP64,\n * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears\n * to be the only LLP64 architecture in current use.\n */\n#ifdef _WIN64\ntypedef signed   long long int khronos_intptr_t;\ntypedef unsigned long long int khronos_uintptr_t;\ntypedef signed   long long int khronos_ssize_t;\ntypedef unsigned long long int khronos_usize_t;\n#else\ntypedef signed   long  int     khronos_intptr_t;\ntypedef unsigned long  int     khronos_uintptr_t;\ntypedef signed   long  int     khronos_ssize_t;\ntypedef unsigned long  int     khronos_usize_t;\n#endif\n\n#if KHRONOS_SUPPORT_FLOAT\n/*\n * Float type\n */\ntypedef          float         khronos_float_t;\n#endif\n\n#if KHRONOS_SUPPORT_INT64\n/* Time types\n *\n * These types can be used to represent a time interval in nanoseconds or\n * an absolute Unadjusted System Time.  Unadjusted System Time is the number\n * of nanoseconds since some arbitrary system event (e.g. since the last\n * time the system booted).  The Unadjusted System Time is an unsigned\n * 64 bit value that wraps back to 0 every 584 years.  Time intervals\n * may be either signed or unsigned.\n */\ntypedef khronos_uint64_t       khronos_utime_nanoseconds_t;\ntypedef khronos_int64_t        khronos_stime_nanoseconds_t;\n#endif\n\n/*\n * Dummy value used to pad enum types to 32 bits.\n */\n#ifndef KHRONOS_MAX_ENUM\n#define KHRONOS_MAX_ENUM 0x7FFFFFFF\n#endif\n\n/*\n * Enumerated boolean type\n *\n * Values other than zero should be considered to be true.  Therefore\n * comparisons should not be made against KHRONOS_TRUE.\n */\ntypedef enum {\n    KHRONOS_FALSE = 0,\n    KHRONOS_TRUE  = 1,\n    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM\n} khronos_boolean_enum_t;\n\n#endif /* __khrplatform_h_ */\n"
  },
  {
    "path": "deps/glad/include/glad/glad.h",
    "content": "/*\n\n    OpenGL loader generated by glad 0.1.34 on Sat Oct 30 06:22:17 2021.\n\n    Language/Generator: C/C++\n    Specification: gl\n    APIs: gl=3.3\n    Profile: core\n    Extensions:\n        \n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n    Reproducible: False\n\n    Commandline:\n        --profile=\"core\" --api=\"gl=3.3\" --generator=\"c\" --spec=\"gl\" --extensions=\"\"\n    Online:\n        https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3\n*/\n\n\n#ifndef __glad_h_\n#define __glad_h_\n\n#ifdef __gl_h_\n#error OpenGL header already included, remove this include, glad already provides it\n#endif\n#define __gl_h_\n\n#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)\n#define APIENTRY __stdcall\n#endif\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n\n#ifndef GLAPIENTRY\n#define GLAPIENTRY APIENTRY\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct gladGLversionStruct {\n    int major;\n    int minor;\n};\n\ntypedef void* (* GLADloadproc)(const char *name);\n\n#ifndef GLAPI\n# if defined(GLAD_GLAPI_EXPORT)\n#  if defined(_WIN32) || defined(__CYGWIN__)\n#   if defined(GLAD_GLAPI_EXPORT_BUILD)\n#    if defined(__GNUC__)\n#     define GLAPI __attribute__ ((dllexport)) extern\n#    else\n#     define GLAPI __declspec(dllexport) extern\n#    endif\n#   else\n#    if defined(__GNUC__)\n#     define GLAPI __attribute__ ((dllimport)) extern\n#    else\n#     define GLAPI __declspec(dllimport) extern\n#    endif\n#   endif\n#  elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD)\n#   define GLAPI __attribute__ ((visibility (\"default\"))) extern\n#  else\n#   define GLAPI extern\n#  endif\n# else\n#  define GLAPI extern\n# endif\n#endif\n\nGLAPI struct gladGLversionStruct GLVersion;\n\nGLAPI int gladLoadGL(void);\n\nGLAPI int gladLoadGLLoader(GLADloadproc);\n\n#include <KHR/khrplatform.h>\ntypedef unsigned int GLenum;\ntypedef unsigned char GLboolean;\ntypedef unsigned int GLbitfield;\ntypedef void GLvoid;\ntypedef khronos_int8_t GLbyte;\ntypedef khronos_uint8_t GLubyte;\ntypedef khronos_int16_t GLshort;\ntypedef khronos_uint16_t GLushort;\ntypedef int GLint;\ntypedef unsigned int GLuint;\ntypedef khronos_int32_t GLclampx;\ntypedef int GLsizei;\ntypedef khronos_float_t GLfloat;\ntypedef khronos_float_t GLclampf;\ntypedef double GLdouble;\ntypedef double GLclampd;\ntypedef void *GLeglClientBufferEXT;\ntypedef void *GLeglImageOES;\ntypedef char GLchar;\ntypedef char GLcharARB;\n#ifdef __APPLE__\ntypedef void *GLhandleARB;\n#else\ntypedef unsigned int GLhandleARB;\n#endif\ntypedef khronos_uint16_t GLhalf;\ntypedef khronos_uint16_t GLhalfARB;\ntypedef khronos_int32_t GLfixed;\ntypedef khronos_intptr_t GLintptr;\ntypedef khronos_intptr_t GLintptrARB;\ntypedef khronos_ssize_t GLsizeiptr;\ntypedef khronos_ssize_t GLsizeiptrARB;\ntypedef khronos_int64_t GLint64;\ntypedef khronos_int64_t GLint64EXT;\ntypedef khronos_uint64_t GLuint64;\ntypedef khronos_uint64_t GLuint64EXT;\ntypedef struct __GLsync *GLsync;\nstruct _cl_context;\nstruct _cl_event;\ntypedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\ntypedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\ntypedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\ntypedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);\ntypedef unsigned short GLhalfNV;\ntypedef GLintptr GLvdpauSurfaceNV;\ntypedef void (APIENTRY *GLVULKANPROCNV)(void);\n#define GL_DEPTH_BUFFER_BIT 0x00000100\n#define GL_STENCIL_BUFFER_BIT 0x00000400\n#define GL_COLOR_BUFFER_BIT 0x00004000\n#define GL_FALSE 0\n#define GL_TRUE 1\n#define GL_POINTS 0x0000\n#define GL_LINES 0x0001\n#define GL_LINE_LOOP 0x0002\n#define GL_LINE_STRIP 0x0003\n#define GL_TRIANGLES 0x0004\n#define GL_TRIANGLE_STRIP 0x0005\n#define GL_TRIANGLE_FAN 0x0006\n#define GL_NEVER 0x0200\n#define GL_LESS 0x0201\n#define GL_EQUAL 0x0202\n#define GL_LEQUAL 0x0203\n#define GL_GREATER 0x0204\n#define GL_NOTEQUAL 0x0205\n#define GL_GEQUAL 0x0206\n#define GL_ALWAYS 0x0207\n#define GL_ZERO 0\n#define GL_ONE 1\n#define GL_SRC_COLOR 0x0300\n#define GL_ONE_MINUS_SRC_COLOR 0x0301\n#define GL_SRC_ALPHA 0x0302\n#define GL_ONE_MINUS_SRC_ALPHA 0x0303\n#define GL_DST_ALPHA 0x0304\n#define GL_ONE_MINUS_DST_ALPHA 0x0305\n#define GL_DST_COLOR 0x0306\n#define GL_ONE_MINUS_DST_COLOR 0x0307\n#define GL_SRC_ALPHA_SATURATE 0x0308\n#define GL_NONE 0\n#define GL_FRONT_LEFT 0x0400\n#define GL_FRONT_RIGHT 0x0401\n#define GL_BACK_LEFT 0x0402\n#define GL_BACK_RIGHT 0x0403\n#define GL_FRONT 0x0404\n#define GL_BACK 0x0405\n#define GL_LEFT 0x0406\n#define GL_RIGHT 0x0407\n#define GL_FRONT_AND_BACK 0x0408\n#define GL_NO_ERROR 0\n#define GL_INVALID_ENUM 0x0500\n#define GL_INVALID_VALUE 0x0501\n#define GL_INVALID_OPERATION 0x0502\n#define GL_OUT_OF_MEMORY 0x0505\n#define GL_CW 0x0900\n#define GL_CCW 0x0901\n#define GL_POINT_SIZE 0x0B11\n#define GL_POINT_SIZE_RANGE 0x0B12\n#define GL_POINT_SIZE_GRANULARITY 0x0B13\n#define GL_LINE_SMOOTH 0x0B20\n#define GL_LINE_WIDTH 0x0B21\n#define GL_LINE_WIDTH_RANGE 0x0B22\n#define GL_LINE_WIDTH_GRANULARITY 0x0B23\n#define GL_POLYGON_MODE 0x0B40\n#define GL_POLYGON_SMOOTH 0x0B41\n#define GL_CULL_FACE 0x0B44\n#define GL_CULL_FACE_MODE 0x0B45\n#define GL_FRONT_FACE 0x0B46\n#define GL_DEPTH_RANGE 0x0B70\n#define GL_DEPTH_TEST 0x0B71\n#define GL_DEPTH_WRITEMASK 0x0B72\n#define GL_DEPTH_CLEAR_VALUE 0x0B73\n#define GL_DEPTH_FUNC 0x0B74\n#define GL_STENCIL_TEST 0x0B90\n#define GL_STENCIL_CLEAR_VALUE 0x0B91\n#define GL_STENCIL_FUNC 0x0B92\n#define GL_STENCIL_VALUE_MASK 0x0B93\n#define GL_STENCIL_FAIL 0x0B94\n#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95\n#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96\n#define GL_STENCIL_REF 0x0B97\n#define GL_STENCIL_WRITEMASK 0x0B98\n#define GL_VIEWPORT 0x0BA2\n#define GL_DITHER 0x0BD0\n#define GL_BLEND_DST 0x0BE0\n#define GL_BLEND_SRC 0x0BE1\n#define GL_BLEND 0x0BE2\n#define GL_LOGIC_OP_MODE 0x0BF0\n#define GL_DRAW_BUFFER 0x0C01\n#define GL_READ_BUFFER 0x0C02\n#define GL_SCISSOR_BOX 0x0C10\n#define GL_SCISSOR_TEST 0x0C11\n#define GL_COLOR_CLEAR_VALUE 0x0C22\n#define GL_COLOR_WRITEMASK 0x0C23\n#define GL_DOUBLEBUFFER 0x0C32\n#define GL_STEREO 0x0C33\n#define GL_LINE_SMOOTH_HINT 0x0C52\n#define GL_POLYGON_SMOOTH_HINT 0x0C53\n#define GL_UNPACK_SWAP_BYTES 0x0CF0\n#define GL_UNPACK_LSB_FIRST 0x0CF1\n#define GL_UNPACK_ROW_LENGTH 0x0CF2\n#define GL_UNPACK_SKIP_ROWS 0x0CF3\n#define GL_UNPACK_SKIP_PIXELS 0x0CF4\n#define GL_UNPACK_ALIGNMENT 0x0CF5\n#define GL_PACK_SWAP_BYTES 0x0D00\n#define GL_PACK_LSB_FIRST 0x0D01\n#define GL_PACK_ROW_LENGTH 0x0D02\n#define GL_PACK_SKIP_ROWS 0x0D03\n#define GL_PACK_SKIP_PIXELS 0x0D04\n#define GL_PACK_ALIGNMENT 0x0D05\n#define GL_MAX_TEXTURE_SIZE 0x0D33\n#define GL_MAX_VIEWPORT_DIMS 0x0D3A\n#define GL_SUBPIXEL_BITS 0x0D50\n#define GL_TEXTURE_1D 0x0DE0\n#define GL_TEXTURE_2D 0x0DE1\n#define GL_TEXTURE_WIDTH 0x1000\n#define GL_TEXTURE_HEIGHT 0x1001\n#define GL_TEXTURE_BORDER_COLOR 0x1004\n#define GL_DONT_CARE 0x1100\n#define GL_FASTEST 0x1101\n#define GL_NICEST 0x1102\n#define GL_BYTE 0x1400\n#define GL_UNSIGNED_BYTE 0x1401\n#define GL_SHORT 0x1402\n#define GL_UNSIGNED_SHORT 0x1403\n#define GL_INT 0x1404\n#define GL_UNSIGNED_INT 0x1405\n#define GL_FLOAT 0x1406\n#define GL_CLEAR 0x1500\n#define GL_AND 0x1501\n#define GL_AND_REVERSE 0x1502\n#define GL_COPY 0x1503\n#define GL_AND_INVERTED 0x1504\n#define GL_NOOP 0x1505\n#define GL_XOR 0x1506\n#define GL_OR 0x1507\n#define GL_NOR 0x1508\n#define GL_EQUIV 0x1509\n#define GL_INVERT 0x150A\n#define GL_OR_REVERSE 0x150B\n#define GL_COPY_INVERTED 0x150C\n#define GL_OR_INVERTED 0x150D\n#define GL_NAND 0x150E\n#define GL_SET 0x150F\n#define GL_TEXTURE 0x1702\n#define GL_COLOR 0x1800\n#define GL_DEPTH 0x1801\n#define GL_STENCIL 0x1802\n#define GL_STENCIL_INDEX 0x1901\n#define GL_DEPTH_COMPONENT 0x1902\n#define GL_RED 0x1903\n#define GL_GREEN 0x1904\n#define GL_BLUE 0x1905\n#define GL_ALPHA 0x1906\n#define GL_RGB 0x1907\n#define GL_RGBA 0x1908\n#define GL_POINT 0x1B00\n#define GL_LINE 0x1B01\n#define GL_FILL 0x1B02\n#define GL_KEEP 0x1E00\n#define GL_REPLACE 0x1E01\n#define GL_INCR 0x1E02\n#define GL_DECR 0x1E03\n#define GL_VENDOR 0x1F00\n#define GL_RENDERER 0x1F01\n#define GL_VERSION 0x1F02\n#define GL_EXTENSIONS 0x1F03\n#define GL_NEAREST 0x2600\n#define GL_LINEAR 0x2601\n#define GL_NEAREST_MIPMAP_NEAREST 0x2700\n#define GL_LINEAR_MIPMAP_NEAREST 0x2701\n#define GL_NEAREST_MIPMAP_LINEAR 0x2702\n#define GL_LINEAR_MIPMAP_LINEAR 0x2703\n#define GL_TEXTURE_MAG_FILTER 0x2800\n#define GL_TEXTURE_MIN_FILTER 0x2801\n#define GL_TEXTURE_WRAP_S 0x2802\n#define GL_TEXTURE_WRAP_T 0x2803\n#define GL_REPEAT 0x2901\n#define GL_COLOR_LOGIC_OP 0x0BF2\n#define GL_POLYGON_OFFSET_UNITS 0x2A00\n#define GL_POLYGON_OFFSET_POINT 0x2A01\n#define GL_POLYGON_OFFSET_LINE 0x2A02\n#define GL_POLYGON_OFFSET_FILL 0x8037\n#define GL_POLYGON_OFFSET_FACTOR 0x8038\n#define GL_TEXTURE_BINDING_1D 0x8068\n#define GL_TEXTURE_BINDING_2D 0x8069\n#define GL_TEXTURE_INTERNAL_FORMAT 0x1003\n#define GL_TEXTURE_RED_SIZE 0x805C\n#define GL_TEXTURE_GREEN_SIZE 0x805D\n#define GL_TEXTURE_BLUE_SIZE 0x805E\n#define GL_TEXTURE_ALPHA_SIZE 0x805F\n#define GL_DOUBLE 0x140A\n#define GL_PROXY_TEXTURE_1D 0x8063\n#define GL_PROXY_TEXTURE_2D 0x8064\n#define GL_R3_G3_B2 0x2A10\n#define GL_RGB4 0x804F\n#define GL_RGB5 0x8050\n#define GL_RGB8 0x8051\n#define GL_RGB10 0x8052\n#define GL_RGB12 0x8053\n#define GL_RGB16 0x8054\n#define GL_RGBA2 0x8055\n#define GL_RGBA4 0x8056\n#define GL_RGB5_A1 0x8057\n#define GL_RGBA8 0x8058\n#define GL_RGB10_A2 0x8059\n#define GL_RGBA12 0x805A\n#define GL_RGBA16 0x805B\n#define GL_UNSIGNED_BYTE_3_3_2 0x8032\n#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033\n#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034\n#define GL_UNSIGNED_INT_8_8_8_8 0x8035\n#define GL_UNSIGNED_INT_10_10_10_2 0x8036\n#define GL_TEXTURE_BINDING_3D 0x806A\n#define GL_PACK_SKIP_IMAGES 0x806B\n#define GL_PACK_IMAGE_HEIGHT 0x806C\n#define GL_UNPACK_SKIP_IMAGES 0x806D\n#define GL_UNPACK_IMAGE_HEIGHT 0x806E\n#define GL_TEXTURE_3D 0x806F\n#define GL_PROXY_TEXTURE_3D 0x8070\n#define GL_TEXTURE_DEPTH 0x8071\n#define GL_TEXTURE_WRAP_R 0x8072\n#define GL_MAX_3D_TEXTURE_SIZE 0x8073\n#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362\n#define GL_UNSIGNED_SHORT_5_6_5 0x8363\n#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364\n#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365\n#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366\n#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367\n#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368\n#define GL_BGR 0x80E0\n#define GL_BGRA 0x80E1\n#define GL_MAX_ELEMENTS_VERTICES 0x80E8\n#define GL_MAX_ELEMENTS_INDICES 0x80E9\n#define GL_CLAMP_TO_EDGE 0x812F\n#define GL_TEXTURE_MIN_LOD 0x813A\n#define GL_TEXTURE_MAX_LOD 0x813B\n#define GL_TEXTURE_BASE_LEVEL 0x813C\n#define GL_TEXTURE_MAX_LEVEL 0x813D\n#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12\n#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13\n#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22\n#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23\n#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E\n#define GL_TEXTURE0 0x84C0\n#define GL_TEXTURE1 0x84C1\n#define GL_TEXTURE2 0x84C2\n#define GL_TEXTURE3 0x84C3\n#define GL_TEXTURE4 0x84C4\n#define GL_TEXTURE5 0x84C5\n#define GL_TEXTURE6 0x84C6\n#define GL_TEXTURE7 0x84C7\n#define GL_TEXTURE8 0x84C8\n#define GL_TEXTURE9 0x84C9\n#define GL_TEXTURE10 0x84CA\n#define GL_TEXTURE11 0x84CB\n#define GL_TEXTURE12 0x84CC\n#define GL_TEXTURE13 0x84CD\n#define GL_TEXTURE14 0x84CE\n#define GL_TEXTURE15 0x84CF\n#define GL_TEXTURE16 0x84D0\n#define GL_TEXTURE17 0x84D1\n#define GL_TEXTURE18 0x84D2\n#define GL_TEXTURE19 0x84D3\n#define GL_TEXTURE20 0x84D4\n#define GL_TEXTURE21 0x84D5\n#define GL_TEXTURE22 0x84D6\n#define GL_TEXTURE23 0x84D7\n#define GL_TEXTURE24 0x84D8\n#define GL_TEXTURE25 0x84D9\n#define GL_TEXTURE26 0x84DA\n#define GL_TEXTURE27 0x84DB\n#define GL_TEXTURE28 0x84DC\n#define GL_TEXTURE29 0x84DD\n#define GL_TEXTURE30 0x84DE\n#define GL_TEXTURE31 0x84DF\n#define GL_ACTIVE_TEXTURE 0x84E0\n#define GL_MULTISAMPLE 0x809D\n#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE 0x809F\n#define GL_SAMPLE_COVERAGE 0x80A0\n#define GL_SAMPLE_BUFFERS 0x80A8\n#define GL_SAMPLES 0x80A9\n#define GL_SAMPLE_COVERAGE_VALUE 0x80AA\n#define GL_SAMPLE_COVERAGE_INVERT 0x80AB\n#define GL_TEXTURE_CUBE_MAP 0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C\n#define GL_COMPRESSED_RGB 0x84ED\n#define GL_COMPRESSED_RGBA 0x84EE\n#define GL_TEXTURE_COMPRESSION_HINT 0x84EF\n#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0\n#define GL_TEXTURE_COMPRESSED 0x86A1\n#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2\n#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3\n#define GL_CLAMP_TO_BORDER 0x812D\n#define GL_BLEND_DST_RGB 0x80C8\n#define GL_BLEND_SRC_RGB 0x80C9\n#define GL_BLEND_DST_ALPHA 0x80CA\n#define GL_BLEND_SRC_ALPHA 0x80CB\n#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128\n#define GL_DEPTH_COMPONENT16 0x81A5\n#define GL_DEPTH_COMPONENT24 0x81A6\n#define GL_DEPTH_COMPONENT32 0x81A7\n#define GL_MIRRORED_REPEAT 0x8370\n#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD\n#define GL_TEXTURE_LOD_BIAS 0x8501\n#define GL_INCR_WRAP 0x8507\n#define GL_DECR_WRAP 0x8508\n#define GL_TEXTURE_DEPTH_SIZE 0x884A\n#define GL_TEXTURE_COMPARE_MODE 0x884C\n#define GL_TEXTURE_COMPARE_FUNC 0x884D\n#define GL_BLEND_COLOR 0x8005\n#define GL_BLEND_EQUATION 0x8009\n#define GL_CONSTANT_COLOR 0x8001\n#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002\n#define GL_CONSTANT_ALPHA 0x8003\n#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004\n#define GL_FUNC_ADD 0x8006\n#define GL_FUNC_REVERSE_SUBTRACT 0x800B\n#define GL_FUNC_SUBTRACT 0x800A\n#define GL_MIN 0x8007\n#define GL_MAX 0x8008\n#define GL_BUFFER_SIZE 0x8764\n#define GL_BUFFER_USAGE 0x8765\n#define GL_QUERY_COUNTER_BITS 0x8864\n#define GL_CURRENT_QUERY 0x8865\n#define GL_QUERY_RESULT 0x8866\n#define GL_QUERY_RESULT_AVAILABLE 0x8867\n#define GL_ARRAY_BUFFER 0x8892\n#define GL_ELEMENT_ARRAY_BUFFER 0x8893\n#define GL_ARRAY_BUFFER_BINDING 0x8894\n#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895\n#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F\n#define GL_READ_ONLY 0x88B8\n#define GL_WRITE_ONLY 0x88B9\n#define GL_READ_WRITE 0x88BA\n#define GL_BUFFER_ACCESS 0x88BB\n#define GL_BUFFER_MAPPED 0x88BC\n#define GL_BUFFER_MAP_POINTER 0x88BD\n#define GL_STREAM_DRAW 0x88E0\n#define GL_STREAM_READ 0x88E1\n#define GL_STREAM_COPY 0x88E2\n#define GL_STATIC_DRAW 0x88E4\n#define GL_STATIC_READ 0x88E5\n#define GL_STATIC_COPY 0x88E6\n#define GL_DYNAMIC_DRAW 0x88E8\n#define GL_DYNAMIC_READ 0x88E9\n#define GL_DYNAMIC_COPY 0x88EA\n#define GL_SAMPLES_PASSED 0x8914\n#define GL_SRC1_ALPHA 0x8589\n#define GL_BLEND_EQUATION_RGB 0x8009\n#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622\n#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623\n#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624\n#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625\n#define GL_CURRENT_VERTEX_ATTRIB 0x8626\n#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642\n#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645\n#define GL_STENCIL_BACK_FUNC 0x8800\n#define GL_STENCIL_BACK_FAIL 0x8801\n#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802\n#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803\n#define GL_MAX_DRAW_BUFFERS 0x8824\n#define GL_DRAW_BUFFER0 0x8825\n#define GL_DRAW_BUFFER1 0x8826\n#define GL_DRAW_BUFFER2 0x8827\n#define GL_DRAW_BUFFER3 0x8828\n#define GL_DRAW_BUFFER4 0x8829\n#define GL_DRAW_BUFFER5 0x882A\n#define GL_DRAW_BUFFER6 0x882B\n#define GL_DRAW_BUFFER7 0x882C\n#define GL_DRAW_BUFFER8 0x882D\n#define GL_DRAW_BUFFER9 0x882E\n#define GL_DRAW_BUFFER10 0x882F\n#define GL_DRAW_BUFFER11 0x8830\n#define GL_DRAW_BUFFER12 0x8831\n#define GL_DRAW_BUFFER13 0x8832\n#define GL_DRAW_BUFFER14 0x8833\n#define GL_DRAW_BUFFER15 0x8834\n#define GL_BLEND_EQUATION_ALPHA 0x883D\n#define GL_MAX_VERTEX_ATTRIBS 0x8869\n#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A\n#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872\n#define GL_FRAGMENT_SHADER 0x8B30\n#define GL_VERTEX_SHADER 0x8B31\n#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49\n#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A\n#define GL_MAX_VARYING_FLOATS 0x8B4B\n#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C\n#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D\n#define GL_SHADER_TYPE 0x8B4F\n#define GL_FLOAT_VEC2 0x8B50\n#define GL_FLOAT_VEC3 0x8B51\n#define GL_FLOAT_VEC4 0x8B52\n#define GL_INT_VEC2 0x8B53\n#define GL_INT_VEC3 0x8B54\n#define GL_INT_VEC4 0x8B55\n#define GL_BOOL 0x8B56\n#define GL_BOOL_VEC2 0x8B57\n#define GL_BOOL_VEC3 0x8B58\n#define GL_BOOL_VEC4 0x8B59\n#define GL_FLOAT_MAT2 0x8B5A\n#define GL_FLOAT_MAT3 0x8B5B\n#define GL_FLOAT_MAT4 0x8B5C\n#define GL_SAMPLER_1D 0x8B5D\n#define GL_SAMPLER_2D 0x8B5E\n#define GL_SAMPLER_3D 0x8B5F\n#define GL_SAMPLER_CUBE 0x8B60\n#define GL_SAMPLER_1D_SHADOW 0x8B61\n#define GL_SAMPLER_2D_SHADOW 0x8B62\n#define GL_DELETE_STATUS 0x8B80\n#define GL_COMPILE_STATUS 0x8B81\n#define GL_LINK_STATUS 0x8B82\n#define GL_VALIDATE_STATUS 0x8B83\n#define GL_INFO_LOG_LENGTH 0x8B84\n#define GL_ATTACHED_SHADERS 0x8B85\n#define GL_ACTIVE_UNIFORMS 0x8B86\n#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87\n#define GL_SHADER_SOURCE_LENGTH 0x8B88\n#define GL_ACTIVE_ATTRIBUTES 0x8B89\n#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A\n#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B\n#define GL_SHADING_LANGUAGE_VERSION 0x8B8C\n#define GL_CURRENT_PROGRAM 0x8B8D\n#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0\n#define GL_LOWER_LEFT 0x8CA1\n#define GL_UPPER_LEFT 0x8CA2\n#define GL_STENCIL_BACK_REF 0x8CA3\n#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4\n#define GL_STENCIL_BACK_WRITEMASK 0x8CA5\n#define GL_PIXEL_PACK_BUFFER 0x88EB\n#define GL_PIXEL_UNPACK_BUFFER 0x88EC\n#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED\n#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF\n#define GL_FLOAT_MAT2x3 0x8B65\n#define GL_FLOAT_MAT2x4 0x8B66\n#define GL_FLOAT_MAT3x2 0x8B67\n#define GL_FLOAT_MAT3x4 0x8B68\n#define GL_FLOAT_MAT4x2 0x8B69\n#define GL_FLOAT_MAT4x3 0x8B6A\n#define GL_SRGB 0x8C40\n#define GL_SRGB8 0x8C41\n#define GL_SRGB_ALPHA 0x8C42\n#define GL_SRGB8_ALPHA8 0x8C43\n#define GL_COMPRESSED_SRGB 0x8C48\n#define GL_COMPRESSED_SRGB_ALPHA 0x8C49\n#define GL_COMPARE_REF_TO_TEXTURE 0x884E\n#define GL_CLIP_DISTANCE0 0x3000\n#define GL_CLIP_DISTANCE1 0x3001\n#define GL_CLIP_DISTANCE2 0x3002\n#define GL_CLIP_DISTANCE3 0x3003\n#define GL_CLIP_DISTANCE4 0x3004\n#define GL_CLIP_DISTANCE5 0x3005\n#define GL_CLIP_DISTANCE6 0x3006\n#define GL_CLIP_DISTANCE7 0x3007\n#define GL_MAX_CLIP_DISTANCES 0x0D32\n#define GL_MAJOR_VERSION 0x821B\n#define GL_MINOR_VERSION 0x821C\n#define GL_NUM_EXTENSIONS 0x821D\n#define GL_CONTEXT_FLAGS 0x821E\n#define GL_COMPRESSED_RED 0x8225\n#define GL_COMPRESSED_RG 0x8226\n#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001\n#define GL_RGBA32F 0x8814\n#define GL_RGB32F 0x8815\n#define GL_RGBA16F 0x881A\n#define GL_RGB16F 0x881B\n#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD\n#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF\n#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904\n#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905\n#define GL_CLAMP_READ_COLOR 0x891C\n#define GL_FIXED_ONLY 0x891D\n#define GL_MAX_VARYING_COMPONENTS 0x8B4B\n#define GL_TEXTURE_1D_ARRAY 0x8C18\n#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19\n#define GL_TEXTURE_2D_ARRAY 0x8C1A\n#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B\n#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C\n#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D\n#define GL_R11F_G11F_B10F 0x8C3A\n#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B\n#define GL_RGB9_E5 0x8C3D\n#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E\n#define GL_TEXTURE_SHARED_SIZE 0x8C3F\n#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76\n#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80\n#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83\n#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84\n#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85\n#define GL_PRIMITIVES_GENERATED 0x8C87\n#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88\n#define GL_RASTERIZER_DISCARD 0x8C89\n#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B\n#define GL_INTERLEAVED_ATTRIBS 0x8C8C\n#define GL_SEPARATE_ATTRIBS 0x8C8D\n#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E\n#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F\n#define GL_RGBA32UI 0x8D70\n#define GL_RGB32UI 0x8D71\n#define GL_RGBA16UI 0x8D76\n#define GL_RGB16UI 0x8D77\n#define GL_RGBA8UI 0x8D7C\n#define GL_RGB8UI 0x8D7D\n#define GL_RGBA32I 0x8D82\n#define GL_RGB32I 0x8D83\n#define GL_RGBA16I 0x8D88\n#define GL_RGB16I 0x8D89\n#define GL_RGBA8I 0x8D8E\n#define GL_RGB8I 0x8D8F\n#define GL_RED_INTEGER 0x8D94\n#define GL_GREEN_INTEGER 0x8D95\n#define GL_BLUE_INTEGER 0x8D96\n#define GL_RGB_INTEGER 0x8D98\n#define GL_RGBA_INTEGER 0x8D99\n#define GL_BGR_INTEGER 0x8D9A\n#define GL_BGRA_INTEGER 0x8D9B\n#define GL_SAMPLER_1D_ARRAY 0x8DC0\n#define GL_SAMPLER_2D_ARRAY 0x8DC1\n#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3\n#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4\n#define GL_SAMPLER_CUBE_SHADOW 0x8DC5\n#define GL_UNSIGNED_INT_VEC2 0x8DC6\n#define GL_UNSIGNED_INT_VEC3 0x8DC7\n#define GL_UNSIGNED_INT_VEC4 0x8DC8\n#define GL_INT_SAMPLER_1D 0x8DC9\n#define GL_INT_SAMPLER_2D 0x8DCA\n#define GL_INT_SAMPLER_3D 0x8DCB\n#define GL_INT_SAMPLER_CUBE 0x8DCC\n#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE\n#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF\n#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1\n#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2\n#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3\n#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4\n#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6\n#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7\n#define GL_QUERY_WAIT 0x8E13\n#define GL_QUERY_NO_WAIT 0x8E14\n#define GL_QUERY_BY_REGION_WAIT 0x8E15\n#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16\n#define GL_BUFFER_ACCESS_FLAGS 0x911F\n#define GL_BUFFER_MAP_LENGTH 0x9120\n#define GL_BUFFER_MAP_OFFSET 0x9121\n#define GL_DEPTH_COMPONENT32F 0x8CAC\n#define GL_DEPTH32F_STENCIL8 0x8CAD\n#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD\n#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506\n#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210\n#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211\n#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212\n#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213\n#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214\n#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215\n#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216\n#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217\n#define GL_FRAMEBUFFER_DEFAULT 0x8218\n#define GL_FRAMEBUFFER_UNDEFINED 0x8219\n#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A\n#define GL_MAX_RENDERBUFFER_SIZE 0x84E8\n#define GL_DEPTH_STENCIL 0x84F9\n#define GL_UNSIGNED_INT_24_8 0x84FA\n#define GL_DEPTH24_STENCIL8 0x88F0\n#define GL_TEXTURE_STENCIL_SIZE 0x88F1\n#define GL_TEXTURE_RED_TYPE 0x8C10\n#define GL_TEXTURE_GREEN_TYPE 0x8C11\n#define GL_TEXTURE_BLUE_TYPE 0x8C12\n#define GL_TEXTURE_ALPHA_TYPE 0x8C13\n#define GL_TEXTURE_DEPTH_TYPE 0x8C16\n#define GL_UNSIGNED_NORMALIZED 0x8C17\n#define GL_FRAMEBUFFER_BINDING 0x8CA6\n#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6\n#define GL_RENDERBUFFER_BINDING 0x8CA7\n#define GL_READ_FRAMEBUFFER 0x8CA8\n#define GL_DRAW_FRAMEBUFFER 0x8CA9\n#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA\n#define GL_RENDERBUFFER_SAMPLES 0x8CAB\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4\n#define GL_FRAMEBUFFER_COMPLETE 0x8CD5\n#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6\n#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7\n#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB\n#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC\n#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD\n#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF\n#define GL_COLOR_ATTACHMENT0 0x8CE0\n#define GL_COLOR_ATTACHMENT1 0x8CE1\n#define GL_COLOR_ATTACHMENT2 0x8CE2\n#define GL_COLOR_ATTACHMENT3 0x8CE3\n#define GL_COLOR_ATTACHMENT4 0x8CE4\n#define GL_COLOR_ATTACHMENT5 0x8CE5\n#define GL_COLOR_ATTACHMENT6 0x8CE6\n#define GL_COLOR_ATTACHMENT7 0x8CE7\n#define GL_COLOR_ATTACHMENT8 0x8CE8\n#define GL_COLOR_ATTACHMENT9 0x8CE9\n#define GL_COLOR_ATTACHMENT10 0x8CEA\n#define GL_COLOR_ATTACHMENT11 0x8CEB\n#define GL_COLOR_ATTACHMENT12 0x8CEC\n#define GL_COLOR_ATTACHMENT13 0x8CED\n#define GL_COLOR_ATTACHMENT14 0x8CEE\n#define GL_COLOR_ATTACHMENT15 0x8CEF\n#define GL_COLOR_ATTACHMENT16 0x8CF0\n#define GL_COLOR_ATTACHMENT17 0x8CF1\n#define GL_COLOR_ATTACHMENT18 0x8CF2\n#define GL_COLOR_ATTACHMENT19 0x8CF3\n#define GL_COLOR_ATTACHMENT20 0x8CF4\n#define GL_COLOR_ATTACHMENT21 0x8CF5\n#define GL_COLOR_ATTACHMENT22 0x8CF6\n#define GL_COLOR_ATTACHMENT23 0x8CF7\n#define GL_COLOR_ATTACHMENT24 0x8CF8\n#define GL_COLOR_ATTACHMENT25 0x8CF9\n#define GL_COLOR_ATTACHMENT26 0x8CFA\n#define GL_COLOR_ATTACHMENT27 0x8CFB\n#define GL_COLOR_ATTACHMENT28 0x8CFC\n#define GL_COLOR_ATTACHMENT29 0x8CFD\n#define GL_COLOR_ATTACHMENT30 0x8CFE\n#define GL_COLOR_ATTACHMENT31 0x8CFF\n#define GL_DEPTH_ATTACHMENT 0x8D00\n#define GL_STENCIL_ATTACHMENT 0x8D20\n#define GL_FRAMEBUFFER 0x8D40\n#define GL_RENDERBUFFER 0x8D41\n#define GL_RENDERBUFFER_WIDTH 0x8D42\n#define GL_RENDERBUFFER_HEIGHT 0x8D43\n#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44\n#define GL_STENCIL_INDEX1 0x8D46\n#define GL_STENCIL_INDEX4 0x8D47\n#define GL_STENCIL_INDEX8 0x8D48\n#define GL_STENCIL_INDEX16 0x8D49\n#define GL_RENDERBUFFER_RED_SIZE 0x8D50\n#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51\n#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52\n#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53\n#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54\n#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55\n#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56\n#define GL_MAX_SAMPLES 0x8D57\n#define GL_FRAMEBUFFER_SRGB 0x8DB9\n#define GL_HALF_FLOAT 0x140B\n#define GL_MAP_READ_BIT 0x0001\n#define GL_MAP_WRITE_BIT 0x0002\n#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004\n#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008\n#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010\n#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020\n#define GL_COMPRESSED_RED_RGTC1 0x8DBB\n#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC\n#define GL_COMPRESSED_RG_RGTC2 0x8DBD\n#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE\n#define GL_RG 0x8227\n#define GL_RG_INTEGER 0x8228\n#define GL_R8 0x8229\n#define GL_R16 0x822A\n#define GL_RG8 0x822B\n#define GL_RG16 0x822C\n#define GL_R16F 0x822D\n#define GL_R32F 0x822E\n#define GL_RG16F 0x822F\n#define GL_RG32F 0x8230\n#define GL_R8I 0x8231\n#define GL_R8UI 0x8232\n#define GL_R16I 0x8233\n#define GL_R16UI 0x8234\n#define GL_R32I 0x8235\n#define GL_R32UI 0x8236\n#define GL_RG8I 0x8237\n#define GL_RG8UI 0x8238\n#define GL_RG16I 0x8239\n#define GL_RG16UI 0x823A\n#define GL_RG32I 0x823B\n#define GL_RG32UI 0x823C\n#define GL_VERTEX_ARRAY_BINDING 0x85B5\n#define GL_SAMPLER_2D_RECT 0x8B63\n#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64\n#define GL_SAMPLER_BUFFER 0x8DC2\n#define GL_INT_SAMPLER_2D_RECT 0x8DCD\n#define GL_INT_SAMPLER_BUFFER 0x8DD0\n#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5\n#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8\n#define GL_TEXTURE_BUFFER 0x8C2A\n#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B\n#define GL_TEXTURE_BINDING_BUFFER 0x8C2C\n#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D\n#define GL_TEXTURE_RECTANGLE 0x84F5\n#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6\n#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7\n#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8\n#define GL_R8_SNORM 0x8F94\n#define GL_RG8_SNORM 0x8F95\n#define GL_RGB8_SNORM 0x8F96\n#define GL_RGBA8_SNORM 0x8F97\n#define GL_R16_SNORM 0x8F98\n#define GL_RG16_SNORM 0x8F99\n#define GL_RGB16_SNORM 0x8F9A\n#define GL_RGBA16_SNORM 0x8F9B\n#define GL_SIGNED_NORMALIZED 0x8F9C\n#define GL_PRIMITIVE_RESTART 0x8F9D\n#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E\n#define GL_COPY_READ_BUFFER 0x8F36\n#define GL_COPY_WRITE_BUFFER 0x8F37\n#define GL_UNIFORM_BUFFER 0x8A11\n#define GL_UNIFORM_BUFFER_BINDING 0x8A28\n#define GL_UNIFORM_BUFFER_START 0x8A29\n#define GL_UNIFORM_BUFFER_SIZE 0x8A2A\n#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B\n#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C\n#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D\n#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E\n#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F\n#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30\n#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31\n#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32\n#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33\n#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34\n#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35\n#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36\n#define GL_UNIFORM_TYPE 0x8A37\n#define GL_UNIFORM_SIZE 0x8A38\n#define GL_UNIFORM_NAME_LENGTH 0x8A39\n#define GL_UNIFORM_BLOCK_INDEX 0x8A3A\n#define GL_UNIFORM_OFFSET 0x8A3B\n#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C\n#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D\n#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E\n#define GL_UNIFORM_BLOCK_BINDING 0x8A3F\n#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40\n#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41\n#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42\n#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46\n#define GL_INVALID_INDEX 0xFFFFFFFF\n#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001\n#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002\n#define GL_LINES_ADJACENCY 0x000A\n#define GL_LINE_STRIP_ADJACENCY 0x000B\n#define GL_TRIANGLES_ADJACENCY 0x000C\n#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D\n#define GL_PROGRAM_POINT_SIZE 0x8642\n#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29\n#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7\n#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8\n#define GL_GEOMETRY_SHADER 0x8DD9\n#define GL_GEOMETRY_VERTICES_OUT 0x8916\n#define GL_GEOMETRY_INPUT_TYPE 0x8917\n#define GL_GEOMETRY_OUTPUT_TYPE 0x8918\n#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF\n#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0\n#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1\n#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122\n#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123\n#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124\n#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125\n#define GL_CONTEXT_PROFILE_MASK 0x9126\n#define GL_DEPTH_CLAMP 0x864F\n#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C\n#define GL_FIRST_VERTEX_CONVENTION 0x8E4D\n#define GL_LAST_VERTEX_CONVENTION 0x8E4E\n#define GL_PROVOKING_VERTEX 0x8E4F\n#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F\n#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111\n#define GL_OBJECT_TYPE 0x9112\n#define GL_SYNC_CONDITION 0x9113\n#define GL_SYNC_STATUS 0x9114\n#define GL_SYNC_FLAGS 0x9115\n#define GL_SYNC_FENCE 0x9116\n#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117\n#define GL_UNSIGNALED 0x9118\n#define GL_SIGNALED 0x9119\n#define GL_ALREADY_SIGNALED 0x911A\n#define GL_TIMEOUT_EXPIRED 0x911B\n#define GL_CONDITION_SATISFIED 0x911C\n#define GL_WAIT_FAILED 0x911D\n#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF\n#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001\n#define GL_SAMPLE_POSITION 0x8E50\n#define GL_SAMPLE_MASK 0x8E51\n#define GL_SAMPLE_MASK_VALUE 0x8E52\n#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59\n#define GL_TEXTURE_2D_MULTISAMPLE 0x9100\n#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101\n#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102\n#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103\n#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104\n#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105\n#define GL_TEXTURE_SAMPLES 0x9106\n#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107\n#define GL_SAMPLER_2D_MULTISAMPLE 0x9108\n#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109\n#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A\n#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B\n#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C\n#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D\n#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E\n#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F\n#define GL_MAX_INTEGER_SAMPLES 0x9110\n#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE\n#define GL_SRC1_COLOR 0x88F9\n#define GL_ONE_MINUS_SRC1_COLOR 0x88FA\n#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB\n#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC\n#define GL_ANY_SAMPLES_PASSED 0x8C2F\n#define GL_SAMPLER_BINDING 0x8919\n#define GL_RGB10_A2UI 0x906F\n#define GL_TEXTURE_SWIZZLE_R 0x8E42\n#define GL_TEXTURE_SWIZZLE_G 0x8E43\n#define GL_TEXTURE_SWIZZLE_B 0x8E44\n#define GL_TEXTURE_SWIZZLE_A 0x8E45\n#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46\n#define GL_TIME_ELAPSED 0x88BF\n#define GL_TIMESTAMP 0x8E28\n#define GL_INT_2_10_10_10_REV 0x8D9F\n#ifndef GL_VERSION_1_0\n#define GL_VERSION_1_0 1\nGLAPI int GLAD_GL_VERSION_1_0;\ntypedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode);\nGLAPI PFNGLCULLFACEPROC glad_glCullFace;\n#define glCullFace glad_glCullFace\ntypedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode);\nGLAPI PFNGLFRONTFACEPROC glad_glFrontFace;\n#define glFrontFace glad_glFrontFace\ntypedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode);\nGLAPI PFNGLHINTPROC glad_glHint;\n#define glHint glad_glHint\ntypedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width);\nGLAPI PFNGLLINEWIDTHPROC glad_glLineWidth;\n#define glLineWidth glad_glLineWidth\ntypedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size);\nGLAPI PFNGLPOINTSIZEPROC glad_glPointSize;\n#define glPointSize glad_glPointSize\ntypedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);\nGLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode;\n#define glPolygonMode glad_glPolygonMode\ntypedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLSCISSORPROC glad_glScissor;\n#define glScissor glad_glScissor\ntypedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);\nGLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf;\n#define glTexParameterf glad_glTexParameterf\ntypedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params);\nGLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;\n#define glTexParameterfv glad_glTexParameterfv\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);\nGLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri;\n#define glTexParameteri glad_glTexParameteri\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params);\nGLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;\n#define glTexParameteriv glad_glTexParameteriv\ntypedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D;\n#define glTexImage1D glad_glTexImage1D\ntypedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D;\n#define glTexImage2D glad_glTexImage2D\ntypedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf);\nGLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer;\n#define glDrawBuffer glad_glDrawBuffer\ntypedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask);\nGLAPI PFNGLCLEARPROC glad_glClear;\n#define glClear glad_glClear\ntypedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI PFNGLCLEARCOLORPROC glad_glClearColor;\n#define glClearColor glad_glClearColor\ntypedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s);\nGLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil;\n#define glClearStencil glad_glClearStencil\ntypedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth);\nGLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth;\n#define glClearDepth glad_glClearDepth\ntypedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask);\nGLAPI PFNGLSTENCILMASKPROC glad_glStencilMask;\n#define glStencilMask glad_glStencilMask\ntypedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\nGLAPI PFNGLCOLORMASKPROC glad_glColorMask;\n#define glColorMask glad_glColorMask\ntypedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag);\nGLAPI PFNGLDEPTHMASKPROC glad_glDepthMask;\n#define glDepthMask glad_glDepthMask\ntypedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap);\nGLAPI PFNGLDISABLEPROC glad_glDisable;\n#define glDisable glad_glDisable\ntypedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap);\nGLAPI PFNGLENABLEPROC glad_glEnable;\n#define glEnable glad_glEnable\ntypedef void (APIENTRYP PFNGLFINISHPROC)(void);\nGLAPI PFNGLFINISHPROC glad_glFinish;\n#define glFinish glad_glFinish\ntypedef void (APIENTRYP PFNGLFLUSHPROC)(void);\nGLAPI PFNGLFLUSHPROC glad_glFlush;\n#define glFlush glad_glFlush\ntypedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);\nGLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc;\n#define glBlendFunc glad_glBlendFunc\ntypedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode);\nGLAPI PFNGLLOGICOPPROC glad_glLogicOp;\n#define glLogicOp glad_glLogicOp\ntypedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);\nGLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc;\n#define glStencilFunc glad_glStencilFunc\ntypedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);\nGLAPI PFNGLSTENCILOPPROC glad_glStencilOp;\n#define glStencilOp glad_glStencilOp\ntypedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func);\nGLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc;\n#define glDepthFunc glad_glDepthFunc\ntypedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);\nGLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref;\n#define glPixelStoref glad_glPixelStoref\ntypedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);\nGLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei;\n#define glPixelStorei glad_glPixelStorei\ntypedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src);\nGLAPI PFNGLREADBUFFERPROC glad_glReadBuffer;\n#define glReadBuffer glad_glReadBuffer\ntypedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);\nGLAPI PFNGLREADPIXELSPROC glad_glReadPixels;\n#define glReadPixels glad_glReadPixels\ntypedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data);\nGLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv;\n#define glGetBooleanv glad_glGetBooleanv\ntypedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data);\nGLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev;\n#define glGetDoublev glad_glGetDoublev\ntypedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void);\nGLAPI PFNGLGETERRORPROC glad_glGetError;\n#define glGetError glad_glGetError\ntypedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data);\nGLAPI PFNGLGETFLOATVPROC glad_glGetFloatv;\n#define glGetFloatv glad_glGetFloatv\ntypedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data);\nGLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv;\n#define glGetIntegerv glad_glGetIntegerv\ntypedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name);\nGLAPI PFNGLGETSTRINGPROC glad_glGetString;\n#define glGetString glad_glGetString\ntypedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\nGLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage;\n#define glGetTexImage glad_glGetTexImage\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;\n#define glGetTexParameterfv glad_glGetTexParameterfv\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;\n#define glGetTexParameteriv glad_glGetTexParameteriv\ntypedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;\n#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv\ntypedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;\n#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv\ntypedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap);\nGLAPI PFNGLISENABLEDPROC glad_glIsEnabled;\n#define glIsEnabled glad_glIsEnabled\ntypedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f);\nGLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange;\n#define glDepthRange glad_glDepthRange\ntypedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLVIEWPORTPROC glad_glViewport;\n#define glViewport glad_glViewport\n#endif\n#ifndef GL_VERSION_1_1\n#define GL_VERSION_1_1 1\nGLAPI int GLAD_GL_VERSION_1_1;\ntypedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);\nGLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays;\n#define glDrawArrays glad_glDrawArrays\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices);\nGLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements;\n#define glDrawElements glad_glDrawElements\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);\nGLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;\n#define glPolygonOffset glad_glPolygonOffset\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\nGLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;\n#define glCopyTexImage1D glad_glCopyTexImage1D\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\nGLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;\n#define glCopyTexImage2D glad_glCopyTexImage2D\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;\n#define glCopyTexSubImage1D glad_glCopyTexSubImage1D\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;\n#define glCopyTexSubImage2D glad_glCopyTexSubImage2D\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;\n#define glTexSubImage1D glad_glTexSubImage1D\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;\n#define glTexSubImage2D glad_glTexSubImage2D\ntypedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);\nGLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture;\n#define glBindTexture glad_glBindTexture\ntypedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures);\nGLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures;\n#define glDeleteTextures glad_glDeleteTextures\ntypedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures);\nGLAPI PFNGLGENTEXTURESPROC glad_glGenTextures;\n#define glGenTextures glad_glGenTextures\ntypedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture);\nGLAPI PFNGLISTEXTUREPROC glad_glIsTexture;\n#define glIsTexture glad_glIsTexture\n#endif\n#ifndef GL_VERSION_1_2\n#define GL_VERSION_1_2 1\nGLAPI int GLAD_GL_VERSION_1_2;\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);\nGLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;\n#define glDrawRangeElements glad_glDrawRangeElements\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D;\n#define glTexImage3D glad_glTexImage3D\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;\n#define glTexSubImage3D glad_glTexSubImage3D\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;\n#define glCopyTexSubImage3D glad_glCopyTexSubImage3D\n#endif\n#ifndef GL_VERSION_1_3\n#define GL_VERSION_1_3 1\nGLAPI int GLAD_GL_VERSION_1_3;\ntypedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture);\nGLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture;\n#define glActiveTexture glad_glActiveTexture\ntypedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);\nGLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;\n#define glSampleCoverage glad_glSampleCoverage\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;\n#define glCompressedTexImage3D glad_glCompressedTexImage3D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;\n#define glCompressedTexImage2D glad_glCompressedTexImage2D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;\n#define glCompressedTexImage1D glad_glCompressedTexImage1D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;\n#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;\n#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;\n#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img);\nGLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;\n#define glGetCompressedTexImage glad_glGetCompressedTexImage\n#endif\n#ifndef GL_VERSION_1_4\n#define GL_VERSION_1_4 1\nGLAPI int GLAD_GL_VERSION_1_4;\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\nGLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;\n#define glBlendFuncSeparate glad_glBlendFuncSeparate\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);\nGLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;\n#define glMultiDrawArrays glad_glMultiDrawArrays\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);\nGLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;\n#define glMultiDrawElements glad_glMultiDrawElements\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);\nGLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;\n#define glPointParameterf glad_glPointParameterf\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params);\nGLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;\n#define glPointParameterfv glad_glPointParameterfv\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);\nGLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;\n#define glPointParameteri glad_glPointParameteri\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params);\nGLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;\n#define glPointParameteriv glad_glPointParameteriv\ntypedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI PFNGLBLENDCOLORPROC glad_glBlendColor;\n#define glBlendColor glad_glBlendColor\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode);\nGLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation;\n#define glBlendEquation glad_glBlendEquation\n#endif\n#ifndef GL_VERSION_1_5\n#define GL_VERSION_1_5 1\nGLAPI int GLAD_GL_VERSION_1_5;\ntypedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids);\nGLAPI PFNGLGENQUERIESPROC glad_glGenQueries;\n#define glGenQueries glad_glGenQueries\ntypedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids);\nGLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries;\n#define glDeleteQueries glad_glDeleteQueries\ntypedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id);\nGLAPI PFNGLISQUERYPROC glad_glIsQuery;\n#define glIsQuery glad_glIsQuery\ntypedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);\nGLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery;\n#define glBeginQuery glad_glBeginQuery\ntypedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target);\nGLAPI PFNGLENDQUERYPROC glad_glEndQuery;\n#define glEndQuery glad_glEndQuery\ntypedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv;\n#define glGetQueryiv glad_glGetQueryiv\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params);\nGLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;\n#define glGetQueryObjectiv glad_glGetQueryObjectiv\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params);\nGLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;\n#define glGetQueryObjectuiv glad_glGetQueryObjectuiv\ntypedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);\nGLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer;\n#define glBindBuffer glad_glBindBuffer\ntypedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers);\nGLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;\n#define glDeleteBuffers glad_glDeleteBuffers\ntypedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers);\nGLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers;\n#define glGenBuffers glad_glGenBuffers\ntypedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer);\nGLAPI PFNGLISBUFFERPROC glad_glIsBuffer;\n#define glIsBuffer glad_glIsBuffer\ntypedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage);\nGLAPI PFNGLBUFFERDATAPROC glad_glBufferData;\n#define glBufferData glad_glBufferData\ntypedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;\n#define glBufferSubData glad_glBufferSubData\ntypedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data);\nGLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;\n#define glGetBufferSubData glad_glGetBufferSubData\ntypedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);\nGLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer;\n#define glMapBuffer glad_glMapBuffer\ntypedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target);\nGLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;\n#define glUnmapBuffer glad_glUnmapBuffer\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;\n#define glGetBufferParameteriv glad_glGetBufferParameteriv\ntypedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params);\nGLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;\n#define glGetBufferPointerv glad_glGetBufferPointerv\n#endif\n#ifndef GL_VERSION_2_0\n#define GL_VERSION_2_0 1\nGLAPI int GLAD_GL_VERSION_2_0;\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);\nGLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;\n#define glBlendEquationSeparate glad_glBlendEquationSeparate\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs);\nGLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;\n#define glDrawBuffers glad_glDrawBuffers\ntypedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\nGLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;\n#define glStencilOpSeparate glad_glStencilOpSeparate\ntypedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);\nGLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;\n#define glStencilFuncSeparate glad_glStencilFuncSeparate\ntypedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);\nGLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;\n#define glStencilMaskSeparate glad_glStencilMaskSeparate\ntypedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);\nGLAPI PFNGLATTACHSHADERPROC glad_glAttachShader;\n#define glAttachShader glad_glAttachShader\ntypedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name);\nGLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;\n#define glBindAttribLocation glad_glBindAttribLocation\ntypedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader);\nGLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader;\n#define glCompileShader glad_glCompileShader\ntypedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void);\nGLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram;\n#define glCreateProgram glad_glCreateProgram\ntypedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type);\nGLAPI PFNGLCREATESHADERPROC glad_glCreateShader;\n#define glCreateShader glad_glCreateShader\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program);\nGLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;\n#define glDeleteProgram glad_glDeleteProgram\ntypedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader);\nGLAPI PFNGLDELETESHADERPROC glad_glDeleteShader;\n#define glDeleteShader glad_glDeleteShader\ntypedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);\nGLAPI PFNGLDETACHSHADERPROC glad_glDetachShader;\n#define glDetachShader glad_glDetachShader\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);\nGLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;\n#define glDisableVertexAttribArray glad_glDisableVertexAttribArray\ntypedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);\nGLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;\n#define glEnableVertexAttribArray glad_glEnableVertexAttribArray\ntypedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\nGLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;\n#define glGetActiveAttrib glad_glGetActiveAttrib\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\nGLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;\n#define glGetActiveUniform glad_glGetActiveUniform\ntypedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);\nGLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;\n#define glGetAttachedShaders glad_glGetAttachedShaders\ntypedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name);\nGLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;\n#define glGetAttribLocation glad_glGetAttribLocation\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params);\nGLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;\n#define glGetProgramiv glad_glGetProgramiv\ntypedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\nGLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;\n#define glGetProgramInfoLog glad_glGetProgramInfoLog\ntypedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params);\nGLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv;\n#define glGetShaderiv glad_glGetShaderiv\ntypedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\nGLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;\n#define glGetShaderInfoLog glad_glGetShaderInfoLog\ntypedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);\nGLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;\n#define glGetShaderSource glad_glGetShaderSource\ntypedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name);\nGLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;\n#define glGetUniformLocation glad_glGetUniformLocation\ntypedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params);\nGLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;\n#define glGetUniformfv glad_glGetUniformfv\ntypedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params);\nGLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;\n#define glGetUniformiv glad_glGetUniformiv\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params);\nGLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;\n#define glGetVertexAttribdv glad_glGetVertexAttribdv\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;\n#define glGetVertexAttribfv glad_glGetVertexAttribfv\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params);\nGLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;\n#define glGetVertexAttribiv glad_glGetVertexAttribiv\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer);\nGLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;\n#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program);\nGLAPI PFNGLISPROGRAMPROC glad_glIsProgram;\n#define glIsProgram glad_glIsProgram\ntypedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader);\nGLAPI PFNGLISSHADERPROC glad_glIsShader;\n#define glIsShader glad_glIsShader\ntypedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program);\nGLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram;\n#define glLinkProgram glad_glLinkProgram\ntypedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);\nGLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource;\n#define glShaderSource glad_glShaderSource\ntypedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program);\nGLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram;\n#define glUseProgram glad_glUseProgram\ntypedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);\nGLAPI PFNGLUNIFORM1FPROC glad_glUniform1f;\n#define glUniform1f glad_glUniform1f\ntypedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);\nGLAPI PFNGLUNIFORM2FPROC glad_glUniform2f;\n#define glUniform2f glad_glUniform2f\ntypedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\nGLAPI PFNGLUNIFORM3FPROC glad_glUniform3f;\n#define glUniform3f glad_glUniform3f\ntypedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\nGLAPI PFNGLUNIFORM4FPROC glad_glUniform4f;\n#define glUniform4f glad_glUniform4f\ntypedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0);\nGLAPI PFNGLUNIFORM1IPROC glad_glUniform1i;\n#define glUniform1i glad_glUniform1i\ntypedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);\nGLAPI PFNGLUNIFORM2IPROC glad_glUniform2i;\n#define glUniform2i glad_glUniform2i\ntypedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);\nGLAPI PFNGLUNIFORM3IPROC glad_glUniform3i;\n#define glUniform3i glad_glUniform3i\ntypedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\nGLAPI PFNGLUNIFORM4IPROC glad_glUniform4i;\n#define glUniform4i glad_glUniform4i\ntypedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv;\n#define glUniform1fv glad_glUniform1fv\ntypedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv;\n#define glUniform2fv glad_glUniform2fv\ntypedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv;\n#define glUniform3fv glad_glUniform3fv\ntypedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv;\n#define glUniform4fv glad_glUniform4fv\ntypedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv;\n#define glUniform1iv glad_glUniform1iv\ntypedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv;\n#define glUniform2iv glad_glUniform2iv\ntypedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv;\n#define glUniform3iv glad_glUniform3iv\ntypedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv;\n#define glUniform4iv glad_glUniform4iv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;\n#define glUniformMatrix2fv glad_glUniformMatrix2fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;\n#define glUniformMatrix3fv glad_glUniformMatrix3fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;\n#define glUniformMatrix4fv glad_glUniformMatrix4fv\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program);\nGLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;\n#define glValidateProgram glad_glValidateProgram\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);\nGLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;\n#define glVertexAttrib1d glad_glVertexAttrib1d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;\n#define glVertexAttrib1dv glad_glVertexAttrib1dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);\nGLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;\n#define glVertexAttrib1f glad_glVertexAttrib1f\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v);\nGLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;\n#define glVertexAttrib1fv glad_glVertexAttrib1fv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);\nGLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;\n#define glVertexAttrib1s glad_glVertexAttrib1s\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v);\nGLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;\n#define glVertexAttrib1sv glad_glVertexAttrib1sv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);\nGLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;\n#define glVertexAttrib2d glad_glVertexAttrib2d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;\n#define glVertexAttrib2dv glad_glVertexAttrib2dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);\nGLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;\n#define glVertexAttrib2f glad_glVertexAttrib2f\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v);\nGLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;\n#define glVertexAttrib2fv glad_glVertexAttrib2fv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);\nGLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;\n#define glVertexAttrib2s glad_glVertexAttrib2s\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v);\nGLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;\n#define glVertexAttrib2sv glad_glVertexAttrib2sv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;\n#define glVertexAttrib3d glad_glVertexAttrib3d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;\n#define glVertexAttrib3dv glad_glVertexAttrib3dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;\n#define glVertexAttrib3f glad_glVertexAttrib3f\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v);\nGLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;\n#define glVertexAttrib3fv glad_glVertexAttrib3fv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);\nGLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;\n#define glVertexAttrib3s glad_glVertexAttrib3s\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v);\nGLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;\n#define glVertexAttrib3sv glad_glVertexAttrib3sv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v);\nGLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;\n#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;\n#define glVertexAttrib4Niv glad_glVertexAttrib4Niv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v);\nGLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;\n#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\nGLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;\n#define glVertexAttrib4Nub glad_glVertexAttrib4Nub\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v);\nGLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;\n#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v);\nGLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;\n#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v);\nGLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;\n#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v);\nGLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;\n#define glVertexAttrib4bv glad_glVertexAttrib4bv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;\n#define glVertexAttrib4d glad_glVertexAttrib4d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;\n#define glVertexAttrib4dv glad_glVertexAttrib4dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;\n#define glVertexAttrib4f glad_glVertexAttrib4f\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v);\nGLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;\n#define glVertexAttrib4fv glad_glVertexAttrib4fv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;\n#define glVertexAttrib4iv glad_glVertexAttrib4iv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;\n#define glVertexAttrib4s glad_glVertexAttrib4s\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v);\nGLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;\n#define glVertexAttrib4sv glad_glVertexAttrib4sv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v);\nGLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;\n#define glVertexAttrib4ubv glad_glVertexAttrib4ubv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v);\nGLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;\n#define glVertexAttrib4uiv glad_glVertexAttrib4uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v);\nGLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;\n#define glVertexAttrib4usv glad_glVertexAttrib4usv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\nGLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;\n#define glVertexAttribPointer glad_glVertexAttribPointer\n#endif\n#ifndef GL_VERSION_2_1\n#define GL_VERSION_2_1 1\nGLAPI int GLAD_GL_VERSION_2_1;\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;\n#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;\n#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;\n#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;\n#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;\n#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;\n#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv\n#endif\n#ifndef GL_VERSION_3_0\n#define GL_VERSION_3_0 1\nGLAPI int GLAD_GL_VERSION_3_0;\ntypedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\nGLAPI PFNGLCOLORMASKIPROC glad_glColorMaski;\n#define glColorMaski glad_glColorMaski\ntypedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data);\nGLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;\n#define glGetBooleani_v glad_glGetBooleani_v\ntypedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data);\nGLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;\n#define glGetIntegeri_v glad_glGetIntegeri_v\ntypedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index);\nGLAPI PFNGLENABLEIPROC glad_glEnablei;\n#define glEnablei glad_glEnablei\ntypedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index);\nGLAPI PFNGLDISABLEIPROC glad_glDisablei;\n#define glDisablei glad_glDisablei\ntypedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index);\nGLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi;\n#define glIsEnabledi glad_glIsEnabledi\ntypedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);\nGLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;\n#define glBeginTransformFeedback glad_glBeginTransformFeedback\ntypedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void);\nGLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;\n#define glEndTransformFeedback glad_glEndTransformFeedback\ntypedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;\n#define glBindBufferRange glad_glBindBufferRange\ntypedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);\nGLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;\n#define glBindBufferBase glad_glBindBufferBase\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);\nGLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;\n#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\nGLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;\n#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying\ntypedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);\nGLAPI PFNGLCLAMPCOLORPROC glad_glClampColor;\n#define glClampColor glad_glClampColor\ntypedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);\nGLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;\n#define glBeginConditionalRender glad_glBeginConditionalRender\ntypedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void);\nGLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;\n#define glEndConditionalRender glad_glEndConditionalRender\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;\n#define glVertexAttribIPointer glad_glVertexAttribIPointer\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params);\nGLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;\n#define glGetVertexAttribIiv glad_glGetVertexAttribIiv\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params);\nGLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;\n#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);\nGLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;\n#define glVertexAttribI1i glad_glVertexAttribI1i\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);\nGLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;\n#define glVertexAttribI2i glad_glVertexAttribI2i\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);\nGLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;\n#define glVertexAttribI3i glad_glVertexAttribI3i\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);\nGLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;\n#define glVertexAttribI4i glad_glVertexAttribI4i\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);\nGLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;\n#define glVertexAttribI1ui glad_glVertexAttribI1ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);\nGLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;\n#define glVertexAttribI2ui glad_glVertexAttribI2ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);\nGLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;\n#define glVertexAttribI3ui glad_glVertexAttribI3ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\nGLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;\n#define glVertexAttribI4ui glad_glVertexAttribI4ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;\n#define glVertexAttribI1iv glad_glVertexAttribI1iv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;\n#define glVertexAttribI2iv glad_glVertexAttribI2iv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;\n#define glVertexAttribI3iv glad_glVertexAttribI3iv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;\n#define glVertexAttribI4iv glad_glVertexAttribI4iv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v);\nGLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;\n#define glVertexAttribI1uiv glad_glVertexAttribI1uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v);\nGLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;\n#define glVertexAttribI2uiv glad_glVertexAttribI2uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v);\nGLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;\n#define glVertexAttribI3uiv glad_glVertexAttribI3uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v);\nGLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;\n#define glVertexAttribI4uiv glad_glVertexAttribI4uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v);\nGLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;\n#define glVertexAttribI4bv glad_glVertexAttribI4bv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v);\nGLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;\n#define glVertexAttribI4sv glad_glVertexAttribI4sv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v);\nGLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;\n#define glVertexAttribI4ubv glad_glVertexAttribI4ubv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v);\nGLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;\n#define glVertexAttribI4usv glad_glVertexAttribI4usv\ntypedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params);\nGLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;\n#define glGetUniformuiv glad_glGetUniformuiv\ntypedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name);\nGLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;\n#define glBindFragDataLocation glad_glBindFragDataLocation\ntypedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name);\nGLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;\n#define glGetFragDataLocation glad_glGetFragDataLocation\ntypedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);\nGLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui;\n#define glUniform1ui glad_glUniform1ui\ntypedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);\nGLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui;\n#define glUniform2ui glad_glUniform2ui\ntypedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);\nGLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui;\n#define glUniform3ui glad_glUniform3ui\ntypedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\nGLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui;\n#define glUniform4ui glad_glUniform4ui\ntypedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;\n#define glUniform1uiv glad_glUniform1uiv\ntypedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;\n#define glUniform2uiv glad_glUniform2uiv\ntypedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;\n#define glUniform3uiv glad_glUniform3uiv\ntypedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;\n#define glUniform4uiv glad_glUniform4uiv\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params);\nGLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;\n#define glTexParameterIiv glad_glTexParameterIiv\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params);\nGLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;\n#define glTexParameterIuiv glad_glTexParameterIuiv\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;\n#define glGetTexParameterIiv glad_glGetTexParameterIiv\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params);\nGLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;\n#define glGetTexParameterIuiv glad_glGetTexParameterIuiv\ntypedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value);\nGLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;\n#define glClearBufferiv glad_glClearBufferiv\ntypedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value);\nGLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;\n#define glClearBufferuiv glad_glClearBufferuiv\ntypedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value);\nGLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;\n#define glClearBufferfv glad_glClearBufferfv\ntypedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\nGLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;\n#define glClearBufferfi glad_glClearBufferfi\ntypedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);\nGLAPI PFNGLGETSTRINGIPROC glad_glGetStringi;\n#define glGetStringi glad_glGetStringi\ntypedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);\nGLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;\n#define glIsRenderbuffer glad_glIsRenderbuffer\ntypedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);\nGLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;\n#define glBindRenderbuffer glad_glBindRenderbuffer\ntypedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers);\nGLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;\n#define glDeleteRenderbuffers glad_glDeleteRenderbuffers\ntypedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers);\nGLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;\n#define glGenRenderbuffers glad_glGenRenderbuffers\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;\n#define glRenderbufferStorage glad_glRenderbufferStorage\ntypedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;\n#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv\ntypedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);\nGLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;\n#define glIsFramebuffer glad_glIsFramebuffer\ntypedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);\nGLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;\n#define glBindFramebuffer glad_glBindFramebuffer\ntypedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers);\nGLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;\n#define glDeleteFramebuffers glad_glDeleteFramebuffers\ntypedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers);\nGLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;\n#define glGenFramebuffers glad_glGenFramebuffers\ntypedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);\nGLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;\n#define glCheckFramebufferStatus glad_glCheckFramebufferStatus\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;\n#define glFramebufferTexture1D glad_glFramebufferTexture1D\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;\n#define glFramebufferTexture2D glad_glFramebufferTexture2D\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\nGLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;\n#define glFramebufferTexture3D glad_glFramebufferTexture3D\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\nGLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;\n#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params);\nGLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;\n#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv\ntypedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target);\nGLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;\n#define glGenerateMipmap glad_glGenerateMipmap\ntypedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\nGLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;\n#define glBlitFramebuffer glad_glBlitFramebuffer\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;\n#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\nGLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;\n#define glFramebufferTextureLayer glad_glFramebufferTextureLayer\ntypedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\nGLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;\n#define glMapBufferRange glad_glMapBufferRange\ntypedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);\nGLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;\n#define glFlushMappedBufferRange glad_glFlushMappedBufferRange\ntypedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array);\nGLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;\n#define glBindVertexArray glad_glBindVertexArray\ntypedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays);\nGLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;\n#define glDeleteVertexArrays glad_glDeleteVertexArrays\ntypedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays);\nGLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;\n#define glGenVertexArrays glad_glGenVertexArrays\ntypedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array);\nGLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;\n#define glIsVertexArray glad_glIsVertexArray\n#endif\n#ifndef GL_VERSION_3_1\n#define GL_VERSION_3_1 1\nGLAPI int GLAD_GL_VERSION_3_1;\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);\nGLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;\n#define glDrawArraysInstanced glad_glDrawArraysInstanced\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);\nGLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;\n#define glDrawElementsInstanced glad_glDrawElementsInstanced\ntypedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);\nGLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer;\n#define glTexBuffer glad_glTexBuffer\ntypedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);\nGLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;\n#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex\ntypedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nGLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;\n#define glCopyBufferSubData glad_glCopyBufferSubData\ntypedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);\nGLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;\n#define glGetUniformIndices glad_glGetUniformIndices\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);\nGLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;\n#define glGetActiveUniformsiv glad_glGetActiveUniformsiv\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);\nGLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;\n#define glGetActiveUniformName glad_glGetActiveUniformName\ntypedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName);\nGLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;\n#define glGetUniformBlockIndex glad_glGetUniformBlockIndex\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);\nGLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;\n#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);\nGLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;\n#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName\ntypedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);\nGLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;\n#define glUniformBlockBinding glad_glUniformBlockBinding\n#endif\n#ifndef GL_VERSION_3_2\n#define GL_VERSION_3_2 1\nGLAPI int GLAD_GL_VERSION_3_2;\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\nGLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;\n#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\nGLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;\n#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\nGLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;\n#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);\nGLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;\n#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex\ntypedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode);\nGLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;\n#define glProvokingVertex glad_glProvokingVertex\ntypedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);\nGLAPI PFNGLFENCESYNCPROC glad_glFenceSync;\n#define glFenceSync glad_glFenceSync\ntypedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync);\nGLAPI PFNGLISSYNCPROC glad_glIsSync;\n#define glIsSync glad_glIsSync\ntypedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync);\nGLAPI PFNGLDELETESYNCPROC glad_glDeleteSync;\n#define glDeleteSync glad_glDeleteSync\ntypedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);\nGLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;\n#define glClientWaitSync glad_glClientWaitSync\ntypedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);\nGLAPI PFNGLWAITSYNCPROC glad_glWaitSync;\n#define glWaitSync glad_glWaitSync\ntypedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data);\nGLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v;\n#define glGetInteger64v glad_glGetInteger64v\ntypedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values);\nGLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv;\n#define glGetSynciv glad_glGetSynciv\ntypedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data);\nGLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;\n#define glGetInteger64i_v glad_glGetInteger64i_v\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params);\nGLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;\n#define glGetBufferParameteri64v glad_glGetBufferParameteri64v\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);\nGLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;\n#define glFramebufferTexture glad_glFramebufferTexture\ntypedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;\n#define glTexImage2DMultisample glad_glTexImage2DMultisample\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;\n#define glTexImage3DMultisample glad_glTexImage3DMultisample\ntypedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val);\nGLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;\n#define glGetMultisamplefv glad_glGetMultisamplefv\ntypedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);\nGLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski;\n#define glSampleMaski glad_glSampleMaski\n#endif\n#ifndef GL_VERSION_3_3\n#define GL_VERSION_3_3 1\nGLAPI int GLAD_GL_VERSION_3_3;\ntypedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);\nGLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;\n#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed\ntypedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name);\nGLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;\n#define glGetFragDataIndex glad_glGetFragDataIndex\ntypedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers);\nGLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers;\n#define glGenSamplers glad_glGenSamplers\ntypedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers);\nGLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;\n#define glDeleteSamplers glad_glDeleteSamplers\ntypedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler);\nGLAPI PFNGLISSAMPLERPROC glad_glIsSampler;\n#define glIsSampler glad_glIsSampler\ntypedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);\nGLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler;\n#define glBindSampler glad_glBindSampler\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);\nGLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;\n#define glSamplerParameteri glad_glSamplerParameteri\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param);\nGLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;\n#define glSamplerParameteriv glad_glSamplerParameteriv\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);\nGLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;\n#define glSamplerParameterf glad_glSamplerParameterf\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param);\nGLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;\n#define glSamplerParameterfv glad_glSamplerParameterfv\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param);\nGLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;\n#define glSamplerParameterIiv glad_glSamplerParameterIiv\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param);\nGLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;\n#define glSamplerParameterIuiv glad_glSamplerParameterIuiv\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params);\nGLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;\n#define glGetSamplerParameteriv glad_glGetSamplerParameteriv\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params);\nGLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;\n#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;\n#define glGetSamplerParameterfv glad_glGetSamplerParameterfv\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params);\nGLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;\n#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv\ntypedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);\nGLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter;\n#define glQueryCounter glad_glQueryCounter\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params);\nGLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;\n#define glGetQueryObjecti64v glad_glGetQueryObjecti64v\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params);\nGLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;\n#define glGetQueryObjectui64v glad_glGetQueryObjectui64v\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);\nGLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;\n#define glVertexAttribDivisor glad_glVertexAttribDivisor\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;\n#define glVertexAttribP1ui glad_glVertexAttribP1ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;\n#define glVertexAttribP1uiv glad_glVertexAttribP1uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;\n#define glVertexAttribP2ui glad_glVertexAttribP2ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;\n#define glVertexAttribP2uiv glad_glVertexAttribP2uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;\n#define glVertexAttribP3ui glad_glVertexAttribP3ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;\n#define glVertexAttribP3uiv glad_glVertexAttribP3uiv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;\n#define glVertexAttribP4ui glad_glVertexAttribP4ui\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;\n#define glVertexAttribP4uiv glad_glVertexAttribP4uiv\ntypedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value);\nGLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui;\n#define glVertexP2ui glad_glVertexP2ui\ntypedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value);\nGLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;\n#define glVertexP2uiv glad_glVertexP2uiv\ntypedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value);\nGLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui;\n#define glVertexP3ui glad_glVertexP3ui\ntypedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value);\nGLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;\n#define glVertexP3uiv glad_glVertexP3uiv\ntypedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value);\nGLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui;\n#define glVertexP4ui glad_glVertexP4ui\ntypedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value);\nGLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;\n#define glVertexP4uiv glad_glVertexP4uiv\ntypedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords);\nGLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;\n#define glTexCoordP1ui glad_glTexCoordP1ui\ntypedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords);\nGLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;\n#define glTexCoordP1uiv glad_glTexCoordP1uiv\ntypedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords);\nGLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;\n#define glTexCoordP2ui glad_glTexCoordP2ui\ntypedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords);\nGLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;\n#define glTexCoordP2uiv glad_glTexCoordP2uiv\ntypedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords);\nGLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;\n#define glTexCoordP3ui glad_glTexCoordP3ui\ntypedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords);\nGLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;\n#define glTexCoordP3uiv glad_glTexCoordP3uiv\ntypedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords);\nGLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;\n#define glTexCoordP4ui glad_glTexCoordP4ui\ntypedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords);\nGLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;\n#define glTexCoordP4uiv glad_glTexCoordP4uiv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords);\nGLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;\n#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);\nGLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;\n#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords);\nGLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;\n#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);\nGLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;\n#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords);\nGLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;\n#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);\nGLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;\n#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords);\nGLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;\n#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);\nGLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;\n#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv\ntypedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords);\nGLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui;\n#define glNormalP3ui glad_glNormalP3ui\ntypedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords);\nGLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;\n#define glNormalP3uiv glad_glNormalP3uiv\ntypedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color);\nGLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui;\n#define glColorP3ui glad_glColorP3ui\ntypedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color);\nGLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv;\n#define glColorP3uiv glad_glColorP3uiv\ntypedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color);\nGLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui;\n#define glColorP4ui glad_glColorP4ui\ntypedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color);\nGLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv;\n#define glColorP4uiv glad_glColorP4uiv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color);\nGLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;\n#define glSecondaryColorP3ui glad_glSecondaryColorP3ui\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color);\nGLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;\n#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "deps/glad/include/glad/glad_wgl.h",
    "content": "/*\n\n    WGL loader generated by glad 0.1.34 on Wed Nov  3 06:45:32 2021.\n\n    Language/Generator: C/C++\n    Specification: wgl\n    APIs: wgl=1.0\n    Profile: -\n    Extensions:\n        WGL_ARB_extensions_string,\n        WGL_EXT_extensions_string,\n        WGL_EXT_swap_control\n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n    Reproducible: False\n\n    Commandline:\n        --api=\"wgl=1.0\" --generator=\"c\" --spec=\"wgl\" --extensions=\"WGL_ARB_extensions_string,WGL_EXT_extensions_string,WGL_EXT_swap_control\"\n    Online:\n        https://glad.dav1d.de/#language=c&specification=wgl&loader=on&api=wgl%3D1.0&extensions=WGL_ARB_extensions_string&extensions=WGL_EXT_extensions_string&extensions=WGL_EXT_swap_control\n*/\n\n\n#ifndef WINAPI\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN 1\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX 1\n#endif\n#include <windows.h>\n#endif\n\n#include <glad/glad.h>\n\n#ifndef __glad_wglext_h_\n\n#ifdef __wglext_h_\n#error WGL header already included, remove this include, glad already provides it\n#endif\n\n#define __glad_wglext_h_\n#define __wglext_h_\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef void* (* GLADloadproc)(const char *name);\n\n#ifndef GLAPI\n# if defined(GLAD_GLAPI_EXPORT)\n#  if defined(_WIN32) || defined(__CYGWIN__)\n#   if defined(GLAD_GLAPI_EXPORT_BUILD)\n#    if defined(__GNUC__)\n#     define GLAPI __attribute__ ((dllexport)) extern\n#    else\n#     define GLAPI __declspec(dllexport) extern\n#    endif\n#   else\n#    if defined(__GNUC__)\n#     define GLAPI __attribute__ ((dllimport)) extern\n#    else\n#     define GLAPI __declspec(dllimport) extern\n#    endif\n#   endif\n#  elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD)\n#   define GLAPI __attribute__ ((visibility (\"default\"))) extern\n#  else\n#   define GLAPI extern\n#  endif\n# else\n#  define GLAPI extern\n# endif\n#endif\n\nGLAPI int gladLoadWGL(HDC hdc);\nGLAPI void gladUnloadWGL(void);\n\nGLAPI int gladLoadWGLLoader(GLADloadproc, HDC hdc);\n\nstruct _GPU_DEVICE {\n    DWORD  cb;\n    CHAR   DeviceName[32];\n    CHAR   DeviceString[128];\n    DWORD  Flags;\n    RECT   rcVirtualScreen;\n};\nDECLARE_HANDLE(HPBUFFERARB);\nDECLARE_HANDLE(HPBUFFEREXT);\nDECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);\nDECLARE_HANDLE(HPVIDEODEV);\nDECLARE_HANDLE(HPGPUNV);\nDECLARE_HANDLE(HGPUNV);\nDECLARE_HANDLE(HVIDEOINPUTDEVICENV);\ntypedef struct _GPU_DEVICE GPU_DEVICE;\ntypedef struct _GPU_DEVICE *PGPU_DEVICE;\n#ifndef WGL_ARB_extensions_string\n#define WGL_ARB_extensions_string 1\nGLAPI int GLAD_WGL_ARB_extensions_string;\ntypedef const char * (APIENTRYP PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);\nGLAPI PFNWGLGETEXTENSIONSSTRINGARBPROC glad_wglGetExtensionsStringARB;\n#define wglGetExtensionsStringARB glad_wglGetExtensionsStringARB\n#endif\n#ifndef WGL_EXT_extensions_string\n#define WGL_EXT_extensions_string 1\nGLAPI int GLAD_WGL_EXT_extensions_string;\ntypedef const char * (APIENTRYP PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);\nGLAPI PFNWGLGETEXTENSIONSSTRINGEXTPROC glad_wglGetExtensionsStringEXT;\n#define wglGetExtensionsStringEXT glad_wglGetExtensionsStringEXT\n#endif\n#ifndef WGL_EXT_swap_control\n#define WGL_EXT_swap_control 1\nGLAPI int GLAD_WGL_EXT_swap_control;\ntypedef BOOL (APIENTRYP PFNWGLSWAPINTERVALEXTPROC)(int interval);\nGLAPI PFNWGLSWAPINTERVALEXTPROC glad_wglSwapIntervalEXT;\n#define wglSwapIntervalEXT glad_wglSwapIntervalEXT\ntypedef int (APIENTRYP PFNWGLGETSWAPINTERVALEXTPROC)(void);\nGLAPI PFNWGLGETSWAPINTERVALEXTPROC glad_wglGetSwapIntervalEXT;\n#define wglGetSwapIntervalEXT glad_wglGetSwapIntervalEXT\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "deps/glad/src/glad.c",
    "content": "/*\n\n    OpenGL loader generated by glad 0.1.34 on Sat Oct 30 06:22:17 2021.\n\n    Language/Generator: C/C++\n    Specification: gl\n    APIs: gl=3.3\n    Profile: core\n    Extensions:\n        \n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n    Reproducible: False\n\n    Commandline:\n        --profile=\"core\" --api=\"gl=3.3\" --generator=\"c\" --spec=\"gl\" --extensions=\"\"\n    Online:\n        https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <glad/glad.h>\n\nstatic void* get_proc(const char *namez);\n\n#if defined(_WIN32) || defined(__CYGWIN__)\n#ifndef _WINDOWS_\n#undef APIENTRY\n#endif\n#include <windows.h>\nstatic HMODULE libGL;\n\ntypedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*);\nstatic PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;\n\n#ifdef _MSC_VER\n#ifdef __has_include\n  #if __has_include(<winapifamily.h>)\n    #define HAVE_WINAPIFAMILY 1\n  #endif\n#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_\n  #define HAVE_WINAPIFAMILY 1\n#endif\n#endif\n\n#ifdef HAVE_WINAPIFAMILY\n  #include <winapifamily.h>\n  #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n    #define IS_UWP 1\n  #endif\n#endif\n\nstatic\nint open_gl(void) {\n#ifndef IS_UWP\n    libGL = LoadLibraryW(L\"opengl32.dll\");\n    if(libGL != NULL) {\n        void (* tmp)(void);\n        tmp = (void(*)(void)) GetProcAddress(libGL, \"wglGetProcAddress\");\n        gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp;\n        return gladGetProcAddressPtr != NULL;\n    }\n#endif\n\n    return 0;\n}\n\nstatic\nvoid close_gl(void) {\n    if(libGL != NULL) {\n        FreeLibrary((HMODULE) libGL);\n        libGL = NULL;\n    }\n}\n#else\n#include <dlfcn.h>\nstatic void* libGL;\n\n#if !defined(__APPLE__) && !defined(__HAIKU__)\ntypedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);\nstatic PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;\n#endif\n\nstatic\nint open_gl(void) {\n#ifdef __APPLE__\n    static const char *NAMES[] = {\n        \"../Frameworks/OpenGL.framework/OpenGL\",\n        \"/Library/Frameworks/OpenGL.framework/OpenGL\",\n        \"/System/Library/Frameworks/OpenGL.framework/OpenGL\",\n        \"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL\"\n    };\n#else\n    static const char *NAMES[] = {\"libGL.so.1\", \"libGL.so\"};\n#endif\n\n    unsigned int index = 0;\n    for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {\n        libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);\n\n        if(libGL != NULL) {\n#if defined(__APPLE__) || defined(__HAIKU__)\n            return 1;\n#else\n            gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,\n                \"glXGetProcAddressARB\");\n            return gladGetProcAddressPtr != NULL;\n#endif\n        }\n    }\n\n    return 0;\n}\n\nstatic\nvoid close_gl(void) {\n    if(libGL != NULL) {\n        dlclose(libGL);\n        libGL = NULL;\n    }\n}\n#endif\n\nstatic\nvoid* get_proc(const char *namez) {\n    void* result = NULL;\n    if(libGL == NULL) return NULL;\n\n#if !defined(__APPLE__) && !defined(__HAIKU__)\n    if(gladGetProcAddressPtr != NULL) {\n        result = gladGetProcAddressPtr(namez);\n    }\n#endif\n    if(result == NULL) {\n#if defined(_WIN32) || defined(__CYGWIN__)\n        result = (void*)GetProcAddress((HMODULE) libGL, namez);\n#else\n        result = dlsym(libGL, namez);\n#endif\n    }\n\n    return result;\n}\n\nint gladLoadGL(void) {\n    int status = 0;\n\n    if(open_gl()) {\n        status = gladLoadGLLoader(&get_proc);\n        close_gl();\n    }\n\n    return status;\n}\n\nstruct gladGLversionStruct GLVersion = { 0, 0 };\n\n#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)\n#define _GLAD_IS_SOME_NEW_VERSION 1\n#endif\n\nstatic int max_loaded_major;\nstatic int max_loaded_minor;\n\nstatic const char *exts = NULL;\nstatic int num_exts_i = 0;\nstatic char **exts_i = NULL;\n\nstatic int get_exts(void) {\n#ifdef _GLAD_IS_SOME_NEW_VERSION\n    if(max_loaded_major < 3) {\n#endif\n        exts = (const char *)glGetString(GL_EXTENSIONS);\n#ifdef _GLAD_IS_SOME_NEW_VERSION\n    } else {\n        unsigned int index;\n\n        num_exts_i = 0;\n        glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);\n        if (num_exts_i > 0) {\n            exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i));\n        }\n\n        if (exts_i == NULL) {\n            return 0;\n        }\n\n        for(index = 0; index < (unsigned)num_exts_i; index++) {\n            const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index);\n            size_t len = strlen(gl_str_tmp);\n\n            char *local_str = (char*)malloc((len+1) * sizeof(char));\n            if(local_str != NULL) {\n                memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char));\n            }\n            exts_i[index] = local_str;\n        }\n    }\n#endif\n    return 1;\n}\n\nstatic void free_exts(void) {\n    if (exts_i != NULL) {\n        int index;\n        for(index = 0; index < num_exts_i; index++) {\n            free((char *)exts_i[index]);\n        }\n        free((void *)exts_i);\n        exts_i = NULL;\n    }\n}\n\nstatic int has_ext(const char *ext) {\n#ifdef _GLAD_IS_SOME_NEW_VERSION\n    if(max_loaded_major < 3) {\n#endif\n        const char *extensions;\n        const char *loc;\n        const char *terminator;\n        extensions = exts;\n        if(extensions == NULL || ext == NULL) {\n            return 0;\n        }\n\n        while(1) {\n            loc = strstr(extensions, ext);\n            if(loc == NULL) {\n                return 0;\n            }\n\n            terminator = loc + strlen(ext);\n            if((loc == extensions || *(loc - 1) == ' ') &&\n                (*terminator == ' ' || *terminator == '\\0')) {\n                return 1;\n            }\n            extensions = terminator;\n        }\n#ifdef _GLAD_IS_SOME_NEW_VERSION\n    } else {\n        int index;\n        if(exts_i == NULL) return 0;\n        for(index = 0; index < num_exts_i; index++) {\n            const char *e = exts_i[index];\n\n            if(exts_i[index] != NULL && strcmp(e, ext) == 0) {\n                return 1;\n            }\n        }\n    }\n#endif\n\n    return 0;\n}\nint GLAD_GL_VERSION_1_0 = 0;\nint GLAD_GL_VERSION_1_1 = 0;\nint GLAD_GL_VERSION_1_2 = 0;\nint GLAD_GL_VERSION_1_3 = 0;\nint GLAD_GL_VERSION_1_4 = 0;\nint GLAD_GL_VERSION_1_5 = 0;\nint GLAD_GL_VERSION_2_0 = 0;\nint GLAD_GL_VERSION_2_1 = 0;\nint GLAD_GL_VERSION_3_0 = 0;\nint GLAD_GL_VERSION_3_1 = 0;\nint GLAD_GL_VERSION_3_2 = 0;\nint GLAD_GL_VERSION_3_3 = 0;\nPFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;\nPFNGLATTACHSHADERPROC glad_glAttachShader = NULL;\nPFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;\nPFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;\nPFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;\nPFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;\nPFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;\nPFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;\nPFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;\nPFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;\nPFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;\nPFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;\nPFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;\nPFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;\nPFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;\nPFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;\nPFNGLBLENDCOLORPROC glad_glBlendColor = NULL;\nPFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;\nPFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;\nPFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;\nPFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;\nPFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;\nPFNGLBUFFERDATAPROC glad_glBufferData = NULL;\nPFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;\nPFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;\nPFNGLCLAMPCOLORPROC glad_glClampColor = NULL;\nPFNGLCLEARPROC glad_glClear = NULL;\nPFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;\nPFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;\nPFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;\nPFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;\nPFNGLCLEARCOLORPROC glad_glClearColor = NULL;\nPFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;\nPFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;\nPFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;\nPFNGLCOLORMASKPROC glad_glColorMask = NULL;\nPFNGLCOLORMASKIPROC glad_glColorMaski = NULL;\nPFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;\nPFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;\nPFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;\nPFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;\nPFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;\nPFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;\nPFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;\nPFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;\nPFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;\nPFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;\nPFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;\nPFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;\nPFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;\nPFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;\nPFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;\nPFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;\nPFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;\nPFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;\nPFNGLCREATESHADERPROC glad_glCreateShader = NULL;\nPFNGLCULLFACEPROC glad_glCullFace = NULL;\nPFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;\nPFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;\nPFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;\nPFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;\nPFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;\nPFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;\nPFNGLDELETESHADERPROC glad_glDeleteShader = NULL;\nPFNGLDELETESYNCPROC glad_glDeleteSync = NULL;\nPFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;\nPFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;\nPFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;\nPFNGLDEPTHMASKPROC glad_glDepthMask = NULL;\nPFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;\nPFNGLDETACHSHADERPROC glad_glDetachShader = NULL;\nPFNGLDISABLEPROC glad_glDisable = NULL;\nPFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;\nPFNGLDISABLEIPROC glad_glDisablei = NULL;\nPFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;\nPFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;\nPFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;\nPFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;\nPFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;\nPFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;\nPFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;\nPFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;\nPFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;\nPFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;\nPFNGLENABLEPROC glad_glEnable = NULL;\nPFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;\nPFNGLENABLEIPROC glad_glEnablei = NULL;\nPFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;\nPFNGLENDQUERYPROC glad_glEndQuery = NULL;\nPFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;\nPFNGLFENCESYNCPROC glad_glFenceSync = NULL;\nPFNGLFINISHPROC glad_glFinish = NULL;\nPFNGLFLUSHPROC glad_glFlush = NULL;\nPFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;\nPFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;\nPFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;\nPFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;\nPFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;\nPFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;\nPFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;\nPFNGLFRONTFACEPROC glad_glFrontFace = NULL;\nPFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;\nPFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;\nPFNGLGENQUERIESPROC glad_glGenQueries = NULL;\nPFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;\nPFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;\nPFNGLGENTEXTURESPROC glad_glGenTextures = NULL;\nPFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;\nPFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;\nPFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;\nPFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;\nPFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;\nPFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;\nPFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;\nPFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;\nPFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;\nPFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;\nPFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;\nPFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;\nPFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;\nPFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;\nPFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;\nPFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;\nPFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;\nPFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;\nPFNGLGETERRORPROC glad_glGetError = NULL;\nPFNGLGETFLOATVPROC glad_glGetFloatv = NULL;\nPFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;\nPFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;\nPFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;\nPFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;\nPFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;\nPFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;\nPFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;\nPFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;\nPFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;\nPFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;\nPFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;\nPFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;\nPFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;\nPFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;\nPFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;\nPFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;\nPFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;\nPFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;\nPFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;\nPFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;\nPFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;\nPFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;\nPFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;\nPFNGLGETSTRINGPROC glad_glGetString = NULL;\nPFNGLGETSTRINGIPROC glad_glGetStringi = NULL;\nPFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;\nPFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;\nPFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;\nPFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;\nPFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;\nPFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;\nPFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;\nPFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;\nPFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;\nPFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;\nPFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;\nPFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;\nPFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;\nPFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;\nPFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;\nPFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;\nPFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;\nPFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;\nPFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;\nPFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;\nPFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;\nPFNGLHINTPROC glad_glHint = NULL;\nPFNGLISBUFFERPROC glad_glIsBuffer = NULL;\nPFNGLISENABLEDPROC glad_glIsEnabled = NULL;\nPFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;\nPFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;\nPFNGLISPROGRAMPROC glad_glIsProgram = NULL;\nPFNGLISQUERYPROC glad_glIsQuery = NULL;\nPFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;\nPFNGLISSAMPLERPROC glad_glIsSampler = NULL;\nPFNGLISSHADERPROC glad_glIsShader = NULL;\nPFNGLISSYNCPROC glad_glIsSync = NULL;\nPFNGLISTEXTUREPROC glad_glIsTexture = NULL;\nPFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;\nPFNGLLINEWIDTHPROC glad_glLineWidth = NULL;\nPFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;\nPFNGLLOGICOPPROC glad_glLogicOp = NULL;\nPFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;\nPFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;\nPFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;\nPFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;\nPFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;\nPFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;\nPFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;\nPFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;\nPFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;\nPFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;\nPFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;\nPFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;\nPFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;\nPFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;\nPFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;\nPFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;\nPFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;\nPFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;\nPFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;\nPFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;\nPFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;\nPFNGLPOINTSIZEPROC glad_glPointSize = NULL;\nPFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;\nPFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;\nPFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;\nPFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;\nPFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;\nPFNGLREADBUFFERPROC glad_glReadBuffer = NULL;\nPFNGLREADPIXELSPROC glad_glReadPixels = NULL;\nPFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;\nPFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;\nPFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;\nPFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;\nPFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;\nPFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;\nPFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;\nPFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;\nPFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;\nPFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;\nPFNGLSCISSORPROC glad_glScissor = NULL;\nPFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;\nPFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;\nPFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;\nPFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;\nPFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;\nPFNGLSTENCILMASKPROC glad_glStencilMask = NULL;\nPFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;\nPFNGLSTENCILOPPROC glad_glStencilOp = NULL;\nPFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;\nPFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;\nPFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;\nPFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;\nPFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;\nPFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;\nPFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;\nPFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;\nPFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;\nPFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;\nPFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;\nPFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;\nPFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;\nPFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;\nPFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;\nPFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;\nPFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;\nPFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;\nPFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;\nPFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;\nPFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;\nPFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;\nPFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;\nPFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;\nPFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;\nPFNGLUNIFORM1FPROC glad_glUniform1f = NULL;\nPFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;\nPFNGLUNIFORM1IPROC glad_glUniform1i = NULL;\nPFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;\nPFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;\nPFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;\nPFNGLUNIFORM2FPROC glad_glUniform2f = NULL;\nPFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;\nPFNGLUNIFORM2IPROC glad_glUniform2i = NULL;\nPFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;\nPFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;\nPFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;\nPFNGLUNIFORM3FPROC glad_glUniform3f = NULL;\nPFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;\nPFNGLUNIFORM3IPROC glad_glUniform3i = NULL;\nPFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;\nPFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;\nPFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;\nPFNGLUNIFORM4FPROC glad_glUniform4f = NULL;\nPFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;\nPFNGLUNIFORM4IPROC glad_glUniform4i = NULL;\nPFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;\nPFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;\nPFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;\nPFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;\nPFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;\nPFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;\nPFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;\nPFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;\nPFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;\nPFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;\nPFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;\nPFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;\nPFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;\nPFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;\nPFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;\nPFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;\nPFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;\nPFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;\nPFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;\nPFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;\nPFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;\nPFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;\nPFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;\nPFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;\nPFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;\nPFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;\nPFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;\nPFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;\nPFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;\nPFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;\nPFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;\nPFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;\nPFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;\nPFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;\nPFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;\nPFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;\nPFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;\nPFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;\nPFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;\nPFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;\nPFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;\nPFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;\nPFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;\nPFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;\nPFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;\nPFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;\nPFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;\nPFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;\nPFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;\nPFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;\nPFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;\nPFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;\nPFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;\nPFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;\nPFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;\nPFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;\nPFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;\nPFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;\nPFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;\nPFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;\nPFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;\nPFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;\nPFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;\nPFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;\nPFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;\nPFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;\nPFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;\nPFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;\nPFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;\nPFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;\nPFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;\nPFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;\nPFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;\nPFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;\nPFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;\nPFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;\nPFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;\nPFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;\nPFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;\nPFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;\nPFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;\nPFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;\nPFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;\nPFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;\nPFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;\nPFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;\nPFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;\nPFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;\nPFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;\nPFNGLVIEWPORTPROC glad_glViewport = NULL;\nPFNGLWAITSYNCPROC glad_glWaitSync = NULL;\nstatic void load_GL_VERSION_1_0(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_1_0) return;\n\tglad_glCullFace = (PFNGLCULLFACEPROC)load(\"glCullFace\");\n\tglad_glFrontFace = (PFNGLFRONTFACEPROC)load(\"glFrontFace\");\n\tglad_glHint = (PFNGLHINTPROC)load(\"glHint\");\n\tglad_glLineWidth = (PFNGLLINEWIDTHPROC)load(\"glLineWidth\");\n\tglad_glPointSize = (PFNGLPOINTSIZEPROC)load(\"glPointSize\");\n\tglad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load(\"glPolygonMode\");\n\tglad_glScissor = (PFNGLSCISSORPROC)load(\"glScissor\");\n\tglad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load(\"glTexParameterf\");\n\tglad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load(\"glTexParameterfv\");\n\tglad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load(\"glTexParameteri\");\n\tglad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load(\"glTexParameteriv\");\n\tglad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load(\"glTexImage1D\");\n\tglad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load(\"glTexImage2D\");\n\tglad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load(\"glDrawBuffer\");\n\tglad_glClear = (PFNGLCLEARPROC)load(\"glClear\");\n\tglad_glClearColor = (PFNGLCLEARCOLORPROC)load(\"glClearColor\");\n\tglad_glClearStencil = (PFNGLCLEARSTENCILPROC)load(\"glClearStencil\");\n\tglad_glClearDepth = (PFNGLCLEARDEPTHPROC)load(\"glClearDepth\");\n\tglad_glStencilMask = (PFNGLSTENCILMASKPROC)load(\"glStencilMask\");\n\tglad_glColorMask = (PFNGLCOLORMASKPROC)load(\"glColorMask\");\n\tglad_glDepthMask = (PFNGLDEPTHMASKPROC)load(\"glDepthMask\");\n\tglad_glDisable = (PFNGLDISABLEPROC)load(\"glDisable\");\n\tglad_glEnable = (PFNGLENABLEPROC)load(\"glEnable\");\n\tglad_glFinish = (PFNGLFINISHPROC)load(\"glFinish\");\n\tglad_glFlush = (PFNGLFLUSHPROC)load(\"glFlush\");\n\tglad_glBlendFunc = (PFNGLBLENDFUNCPROC)load(\"glBlendFunc\");\n\tglad_glLogicOp = (PFNGLLOGICOPPROC)load(\"glLogicOp\");\n\tglad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load(\"glStencilFunc\");\n\tglad_glStencilOp = (PFNGLSTENCILOPPROC)load(\"glStencilOp\");\n\tglad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load(\"glDepthFunc\");\n\tglad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load(\"glPixelStoref\");\n\tglad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load(\"glPixelStorei\");\n\tglad_glReadBuffer = (PFNGLREADBUFFERPROC)load(\"glReadBuffer\");\n\tglad_glReadPixels = (PFNGLREADPIXELSPROC)load(\"glReadPixels\");\n\tglad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load(\"glGetBooleanv\");\n\tglad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load(\"glGetDoublev\");\n\tglad_glGetError = (PFNGLGETERRORPROC)load(\"glGetError\");\n\tglad_glGetFloatv = (PFNGLGETFLOATVPROC)load(\"glGetFloatv\");\n\tglad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load(\"glGetIntegerv\");\n\tglad_glGetString = (PFNGLGETSTRINGPROC)load(\"glGetString\");\n\tglad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load(\"glGetTexImage\");\n\tglad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load(\"glGetTexParameterfv\");\n\tglad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load(\"glGetTexParameteriv\");\n\tglad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load(\"glGetTexLevelParameterfv\");\n\tglad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load(\"glGetTexLevelParameteriv\");\n\tglad_glIsEnabled = (PFNGLISENABLEDPROC)load(\"glIsEnabled\");\n\tglad_glDepthRange = (PFNGLDEPTHRANGEPROC)load(\"glDepthRange\");\n\tglad_glViewport = (PFNGLVIEWPORTPROC)load(\"glViewport\");\n}\nstatic void load_GL_VERSION_1_1(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_1_1) return;\n\tglad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load(\"glDrawArrays\");\n\tglad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load(\"glDrawElements\");\n\tglad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load(\"glPolygonOffset\");\n\tglad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load(\"glCopyTexImage1D\");\n\tglad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load(\"glCopyTexImage2D\");\n\tglad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load(\"glCopyTexSubImage1D\");\n\tglad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load(\"glCopyTexSubImage2D\");\n\tglad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load(\"glTexSubImage1D\");\n\tglad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load(\"glTexSubImage2D\");\n\tglad_glBindTexture = (PFNGLBINDTEXTUREPROC)load(\"glBindTexture\");\n\tglad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load(\"glDeleteTextures\");\n\tglad_glGenTextures = (PFNGLGENTEXTURESPROC)load(\"glGenTextures\");\n\tglad_glIsTexture = (PFNGLISTEXTUREPROC)load(\"glIsTexture\");\n}\nstatic void load_GL_VERSION_1_2(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_1_2) return;\n\tglad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load(\"glDrawRangeElements\");\n\tglad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load(\"glTexImage3D\");\n\tglad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load(\"glTexSubImage3D\");\n\tglad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load(\"glCopyTexSubImage3D\");\n}\nstatic void load_GL_VERSION_1_3(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_1_3) return;\n\tglad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load(\"glActiveTexture\");\n\tglad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load(\"glSampleCoverage\");\n\tglad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load(\"glCompressedTexImage3D\");\n\tglad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load(\"glCompressedTexImage2D\");\n\tglad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load(\"glCompressedTexImage1D\");\n\tglad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load(\"glCompressedTexSubImage3D\");\n\tglad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load(\"glCompressedTexSubImage2D\");\n\tglad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load(\"glCompressedTexSubImage1D\");\n\tglad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load(\"glGetCompressedTexImage\");\n}\nstatic void load_GL_VERSION_1_4(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_1_4) return;\n\tglad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load(\"glBlendFuncSeparate\");\n\tglad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load(\"glMultiDrawArrays\");\n\tglad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load(\"glMultiDrawElements\");\n\tglad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load(\"glPointParameterf\");\n\tglad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load(\"glPointParameterfv\");\n\tglad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load(\"glPointParameteri\");\n\tglad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load(\"glPointParameteriv\");\n\tglad_glBlendColor = (PFNGLBLENDCOLORPROC)load(\"glBlendColor\");\n\tglad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load(\"glBlendEquation\");\n}\nstatic void load_GL_VERSION_1_5(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_1_5) return;\n\tglad_glGenQueries = (PFNGLGENQUERIESPROC)load(\"glGenQueries\");\n\tglad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load(\"glDeleteQueries\");\n\tglad_glIsQuery = (PFNGLISQUERYPROC)load(\"glIsQuery\");\n\tglad_glBeginQuery = (PFNGLBEGINQUERYPROC)load(\"glBeginQuery\");\n\tglad_glEndQuery = (PFNGLENDQUERYPROC)load(\"glEndQuery\");\n\tglad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load(\"glGetQueryiv\");\n\tglad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load(\"glGetQueryObjectiv\");\n\tglad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load(\"glGetQueryObjectuiv\");\n\tglad_glBindBuffer = (PFNGLBINDBUFFERPROC)load(\"glBindBuffer\");\n\tglad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load(\"glDeleteBuffers\");\n\tglad_glGenBuffers = (PFNGLGENBUFFERSPROC)load(\"glGenBuffers\");\n\tglad_glIsBuffer = (PFNGLISBUFFERPROC)load(\"glIsBuffer\");\n\tglad_glBufferData = (PFNGLBUFFERDATAPROC)load(\"glBufferData\");\n\tglad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load(\"glBufferSubData\");\n\tglad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load(\"glGetBufferSubData\");\n\tglad_glMapBuffer = (PFNGLMAPBUFFERPROC)load(\"glMapBuffer\");\n\tglad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load(\"glUnmapBuffer\");\n\tglad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load(\"glGetBufferParameteriv\");\n\tglad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load(\"glGetBufferPointerv\");\n}\nstatic void load_GL_VERSION_2_0(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_2_0) return;\n\tglad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load(\"glBlendEquationSeparate\");\n\tglad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load(\"glDrawBuffers\");\n\tglad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load(\"glStencilOpSeparate\");\n\tglad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load(\"glStencilFuncSeparate\");\n\tglad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load(\"glStencilMaskSeparate\");\n\tglad_glAttachShader = (PFNGLATTACHSHADERPROC)load(\"glAttachShader\");\n\tglad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load(\"glBindAttribLocation\");\n\tglad_glCompileShader = (PFNGLCOMPILESHADERPROC)load(\"glCompileShader\");\n\tglad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load(\"glCreateProgram\");\n\tglad_glCreateShader = (PFNGLCREATESHADERPROC)load(\"glCreateShader\");\n\tglad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load(\"glDeleteProgram\");\n\tglad_glDeleteShader = (PFNGLDELETESHADERPROC)load(\"glDeleteShader\");\n\tglad_glDetachShader = (PFNGLDETACHSHADERPROC)load(\"glDetachShader\");\n\tglad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load(\"glDisableVertexAttribArray\");\n\tglad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load(\"glEnableVertexAttribArray\");\n\tglad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load(\"glGetActiveAttrib\");\n\tglad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load(\"glGetActiveUniform\");\n\tglad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load(\"glGetAttachedShaders\");\n\tglad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load(\"glGetAttribLocation\");\n\tglad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load(\"glGetProgramiv\");\n\tglad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load(\"glGetProgramInfoLog\");\n\tglad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load(\"glGetShaderiv\");\n\tglad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load(\"glGetShaderInfoLog\");\n\tglad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load(\"glGetShaderSource\");\n\tglad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load(\"glGetUniformLocation\");\n\tglad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load(\"glGetUniformfv\");\n\tglad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load(\"glGetUniformiv\");\n\tglad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load(\"glGetVertexAttribdv\");\n\tglad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load(\"glGetVertexAttribfv\");\n\tglad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load(\"glGetVertexAttribiv\");\n\tglad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load(\"glGetVertexAttribPointerv\");\n\tglad_glIsProgram = (PFNGLISPROGRAMPROC)load(\"glIsProgram\");\n\tglad_glIsShader = (PFNGLISSHADERPROC)load(\"glIsShader\");\n\tglad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load(\"glLinkProgram\");\n\tglad_glShaderSource = (PFNGLSHADERSOURCEPROC)load(\"glShaderSource\");\n\tglad_glUseProgram = (PFNGLUSEPROGRAMPROC)load(\"glUseProgram\");\n\tglad_glUniform1f = (PFNGLUNIFORM1FPROC)load(\"glUniform1f\");\n\tglad_glUniform2f = (PFNGLUNIFORM2FPROC)load(\"glUniform2f\");\n\tglad_glUniform3f = (PFNGLUNIFORM3FPROC)load(\"glUniform3f\");\n\tglad_glUniform4f = (PFNGLUNIFORM4FPROC)load(\"glUniform4f\");\n\tglad_glUniform1i = (PFNGLUNIFORM1IPROC)load(\"glUniform1i\");\n\tglad_glUniform2i = (PFNGLUNIFORM2IPROC)load(\"glUniform2i\");\n\tglad_glUniform3i = (PFNGLUNIFORM3IPROC)load(\"glUniform3i\");\n\tglad_glUniform4i = (PFNGLUNIFORM4IPROC)load(\"glUniform4i\");\n\tglad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load(\"glUniform1fv\");\n\tglad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load(\"glUniform2fv\");\n\tglad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load(\"glUniform3fv\");\n\tglad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load(\"glUniform4fv\");\n\tglad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load(\"glUniform1iv\");\n\tglad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load(\"glUniform2iv\");\n\tglad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load(\"glUniform3iv\");\n\tglad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load(\"glUniform4iv\");\n\tglad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load(\"glUniformMatrix2fv\");\n\tglad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load(\"glUniformMatrix3fv\");\n\tglad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load(\"glUniformMatrix4fv\");\n\tglad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load(\"glValidateProgram\");\n\tglad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load(\"glVertexAttrib1d\");\n\tglad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load(\"glVertexAttrib1dv\");\n\tglad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load(\"glVertexAttrib1f\");\n\tglad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load(\"glVertexAttrib1fv\");\n\tglad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load(\"glVertexAttrib1s\");\n\tglad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load(\"glVertexAttrib1sv\");\n\tglad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load(\"glVertexAttrib2d\");\n\tglad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load(\"glVertexAttrib2dv\");\n\tglad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load(\"glVertexAttrib2f\");\n\tglad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load(\"glVertexAttrib2fv\");\n\tglad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load(\"glVertexAttrib2s\");\n\tglad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load(\"glVertexAttrib2sv\");\n\tglad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load(\"glVertexAttrib3d\");\n\tglad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load(\"glVertexAttrib3dv\");\n\tglad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load(\"glVertexAttrib3f\");\n\tglad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load(\"glVertexAttrib3fv\");\n\tglad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load(\"glVertexAttrib3s\");\n\tglad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load(\"glVertexAttrib3sv\");\n\tglad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load(\"glVertexAttrib4Nbv\");\n\tglad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load(\"glVertexAttrib4Niv\");\n\tglad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load(\"glVertexAttrib4Nsv\");\n\tglad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load(\"glVertexAttrib4Nub\");\n\tglad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load(\"glVertexAttrib4Nubv\");\n\tglad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load(\"glVertexAttrib4Nuiv\");\n\tglad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load(\"glVertexAttrib4Nusv\");\n\tglad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load(\"glVertexAttrib4bv\");\n\tglad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load(\"glVertexAttrib4d\");\n\tglad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load(\"glVertexAttrib4dv\");\n\tglad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load(\"glVertexAttrib4f\");\n\tglad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load(\"glVertexAttrib4fv\");\n\tglad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load(\"glVertexAttrib4iv\");\n\tglad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load(\"glVertexAttrib4s\");\n\tglad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load(\"glVertexAttrib4sv\");\n\tglad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load(\"glVertexAttrib4ubv\");\n\tglad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load(\"glVertexAttrib4uiv\");\n\tglad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load(\"glVertexAttrib4usv\");\n\tglad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load(\"glVertexAttribPointer\");\n}\nstatic void load_GL_VERSION_2_1(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_2_1) return;\n\tglad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load(\"glUniformMatrix2x3fv\");\n\tglad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load(\"glUniformMatrix3x2fv\");\n\tglad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load(\"glUniformMatrix2x4fv\");\n\tglad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load(\"glUniformMatrix4x2fv\");\n\tglad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load(\"glUniformMatrix3x4fv\");\n\tglad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load(\"glUniformMatrix4x3fv\");\n}\nstatic void load_GL_VERSION_3_0(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_3_0) return;\n\tglad_glColorMaski = (PFNGLCOLORMASKIPROC)load(\"glColorMaski\");\n\tglad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load(\"glGetBooleani_v\");\n\tglad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load(\"glGetIntegeri_v\");\n\tglad_glEnablei = (PFNGLENABLEIPROC)load(\"glEnablei\");\n\tglad_glDisablei = (PFNGLDISABLEIPROC)load(\"glDisablei\");\n\tglad_glIsEnabledi = (PFNGLISENABLEDIPROC)load(\"glIsEnabledi\");\n\tglad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load(\"glBeginTransformFeedback\");\n\tglad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load(\"glEndTransformFeedback\");\n\tglad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load(\"glBindBufferRange\");\n\tglad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load(\"glBindBufferBase\");\n\tglad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load(\"glTransformFeedbackVaryings\");\n\tglad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load(\"glGetTransformFeedbackVarying\");\n\tglad_glClampColor = (PFNGLCLAMPCOLORPROC)load(\"glClampColor\");\n\tglad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load(\"glBeginConditionalRender\");\n\tglad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load(\"glEndConditionalRender\");\n\tglad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load(\"glVertexAttribIPointer\");\n\tglad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load(\"glGetVertexAttribIiv\");\n\tglad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load(\"glGetVertexAttribIuiv\");\n\tglad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load(\"glVertexAttribI1i\");\n\tglad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load(\"glVertexAttribI2i\");\n\tglad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load(\"glVertexAttribI3i\");\n\tglad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load(\"glVertexAttribI4i\");\n\tglad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load(\"glVertexAttribI1ui\");\n\tglad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load(\"glVertexAttribI2ui\");\n\tglad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load(\"glVertexAttribI3ui\");\n\tglad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load(\"glVertexAttribI4ui\");\n\tglad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load(\"glVertexAttribI1iv\");\n\tglad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load(\"glVertexAttribI2iv\");\n\tglad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load(\"glVertexAttribI3iv\");\n\tglad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load(\"glVertexAttribI4iv\");\n\tglad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load(\"glVertexAttribI1uiv\");\n\tglad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load(\"glVertexAttribI2uiv\");\n\tglad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load(\"glVertexAttribI3uiv\");\n\tglad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load(\"glVertexAttribI4uiv\");\n\tglad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load(\"glVertexAttribI4bv\");\n\tglad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load(\"glVertexAttribI4sv\");\n\tglad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load(\"glVertexAttribI4ubv\");\n\tglad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load(\"glVertexAttribI4usv\");\n\tglad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load(\"glGetUniformuiv\");\n\tglad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load(\"glBindFragDataLocation\");\n\tglad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load(\"glGetFragDataLocation\");\n\tglad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load(\"glUniform1ui\");\n\tglad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load(\"glUniform2ui\");\n\tglad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load(\"glUniform3ui\");\n\tglad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load(\"glUniform4ui\");\n\tglad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load(\"glUniform1uiv\");\n\tglad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load(\"glUniform2uiv\");\n\tglad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load(\"glUniform3uiv\");\n\tglad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load(\"glUniform4uiv\");\n\tglad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load(\"glTexParameterIiv\");\n\tglad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load(\"glTexParameterIuiv\");\n\tglad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load(\"glGetTexParameterIiv\");\n\tglad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load(\"glGetTexParameterIuiv\");\n\tglad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load(\"glClearBufferiv\");\n\tglad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load(\"glClearBufferuiv\");\n\tglad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load(\"glClearBufferfv\");\n\tglad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load(\"glClearBufferfi\");\n\tglad_glGetStringi = (PFNGLGETSTRINGIPROC)load(\"glGetStringi\");\n\tglad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load(\"glIsRenderbuffer\");\n\tglad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load(\"glBindRenderbuffer\");\n\tglad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load(\"glDeleteRenderbuffers\");\n\tglad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load(\"glGenRenderbuffers\");\n\tglad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load(\"glRenderbufferStorage\");\n\tglad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load(\"glGetRenderbufferParameteriv\");\n\tglad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load(\"glIsFramebuffer\");\n\tglad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load(\"glBindFramebuffer\");\n\tglad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load(\"glDeleteFramebuffers\");\n\tglad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load(\"glGenFramebuffers\");\n\tglad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load(\"glCheckFramebufferStatus\");\n\tglad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load(\"glFramebufferTexture1D\");\n\tglad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load(\"glFramebufferTexture2D\");\n\tglad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load(\"glFramebufferTexture3D\");\n\tglad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load(\"glFramebufferRenderbuffer\");\n\tglad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load(\"glGetFramebufferAttachmentParameteriv\");\n\tglad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load(\"glGenerateMipmap\");\n\tglad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load(\"glBlitFramebuffer\");\n\tglad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load(\"glRenderbufferStorageMultisample\");\n\tglad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load(\"glFramebufferTextureLayer\");\n\tglad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load(\"glMapBufferRange\");\n\tglad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load(\"glFlushMappedBufferRange\");\n\tglad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load(\"glBindVertexArray\");\n\tglad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load(\"glDeleteVertexArrays\");\n\tglad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load(\"glGenVertexArrays\");\n\tglad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load(\"glIsVertexArray\");\n}\nstatic void load_GL_VERSION_3_1(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_3_1) return;\n\tglad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load(\"glDrawArraysInstanced\");\n\tglad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load(\"glDrawElementsInstanced\");\n\tglad_glTexBuffer = (PFNGLTEXBUFFERPROC)load(\"glTexBuffer\");\n\tglad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load(\"glPrimitiveRestartIndex\");\n\tglad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load(\"glCopyBufferSubData\");\n\tglad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load(\"glGetUniformIndices\");\n\tglad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load(\"glGetActiveUniformsiv\");\n\tglad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load(\"glGetActiveUniformName\");\n\tglad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load(\"glGetUniformBlockIndex\");\n\tglad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load(\"glGetActiveUniformBlockiv\");\n\tglad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load(\"glGetActiveUniformBlockName\");\n\tglad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load(\"glUniformBlockBinding\");\n\tglad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load(\"glBindBufferRange\");\n\tglad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load(\"glBindBufferBase\");\n\tglad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load(\"glGetIntegeri_v\");\n}\nstatic void load_GL_VERSION_3_2(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_3_2) return;\n\tglad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load(\"glDrawElementsBaseVertex\");\n\tglad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load(\"glDrawRangeElementsBaseVertex\");\n\tglad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load(\"glDrawElementsInstancedBaseVertex\");\n\tglad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load(\"glMultiDrawElementsBaseVertex\");\n\tglad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load(\"glProvokingVertex\");\n\tglad_glFenceSync = (PFNGLFENCESYNCPROC)load(\"glFenceSync\");\n\tglad_glIsSync = (PFNGLISSYNCPROC)load(\"glIsSync\");\n\tglad_glDeleteSync = (PFNGLDELETESYNCPROC)load(\"glDeleteSync\");\n\tglad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load(\"glClientWaitSync\");\n\tglad_glWaitSync = (PFNGLWAITSYNCPROC)load(\"glWaitSync\");\n\tglad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load(\"glGetInteger64v\");\n\tglad_glGetSynciv = (PFNGLGETSYNCIVPROC)load(\"glGetSynciv\");\n\tglad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load(\"glGetInteger64i_v\");\n\tglad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load(\"glGetBufferParameteri64v\");\n\tglad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load(\"glFramebufferTexture\");\n\tglad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load(\"glTexImage2DMultisample\");\n\tglad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load(\"glTexImage3DMultisample\");\n\tglad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load(\"glGetMultisamplefv\");\n\tglad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load(\"glSampleMaski\");\n}\nstatic void load_GL_VERSION_3_3(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_3_3) return;\n\tglad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load(\"glBindFragDataLocationIndexed\");\n\tglad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load(\"glGetFragDataIndex\");\n\tglad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load(\"glGenSamplers\");\n\tglad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load(\"glDeleteSamplers\");\n\tglad_glIsSampler = (PFNGLISSAMPLERPROC)load(\"glIsSampler\");\n\tglad_glBindSampler = (PFNGLBINDSAMPLERPROC)load(\"glBindSampler\");\n\tglad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load(\"glSamplerParameteri\");\n\tglad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load(\"glSamplerParameteriv\");\n\tglad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load(\"glSamplerParameterf\");\n\tglad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load(\"glSamplerParameterfv\");\n\tglad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load(\"glSamplerParameterIiv\");\n\tglad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load(\"glSamplerParameterIuiv\");\n\tglad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load(\"glGetSamplerParameteriv\");\n\tglad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load(\"glGetSamplerParameterIiv\");\n\tglad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load(\"glGetSamplerParameterfv\");\n\tglad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load(\"glGetSamplerParameterIuiv\");\n\tglad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load(\"glQueryCounter\");\n\tglad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load(\"glGetQueryObjecti64v\");\n\tglad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load(\"glGetQueryObjectui64v\");\n\tglad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load(\"glVertexAttribDivisor\");\n\tglad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load(\"glVertexAttribP1ui\");\n\tglad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load(\"glVertexAttribP1uiv\");\n\tglad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load(\"glVertexAttribP2ui\");\n\tglad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load(\"glVertexAttribP2uiv\");\n\tglad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load(\"glVertexAttribP3ui\");\n\tglad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load(\"glVertexAttribP3uiv\");\n\tglad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load(\"glVertexAttribP4ui\");\n\tglad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load(\"glVertexAttribP4uiv\");\n\tglad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load(\"glVertexP2ui\");\n\tglad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load(\"glVertexP2uiv\");\n\tglad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load(\"glVertexP3ui\");\n\tglad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load(\"glVertexP3uiv\");\n\tglad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load(\"glVertexP4ui\");\n\tglad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load(\"glVertexP4uiv\");\n\tglad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load(\"glTexCoordP1ui\");\n\tglad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load(\"glTexCoordP1uiv\");\n\tglad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load(\"glTexCoordP2ui\");\n\tglad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load(\"glTexCoordP2uiv\");\n\tglad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load(\"glTexCoordP3ui\");\n\tglad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load(\"glTexCoordP3uiv\");\n\tglad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load(\"glTexCoordP4ui\");\n\tglad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load(\"glTexCoordP4uiv\");\n\tglad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load(\"glMultiTexCoordP1ui\");\n\tglad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load(\"glMultiTexCoordP1uiv\");\n\tglad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load(\"glMultiTexCoordP2ui\");\n\tglad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load(\"glMultiTexCoordP2uiv\");\n\tglad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load(\"glMultiTexCoordP3ui\");\n\tglad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load(\"glMultiTexCoordP3uiv\");\n\tglad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load(\"glMultiTexCoordP4ui\");\n\tglad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load(\"glMultiTexCoordP4uiv\");\n\tglad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load(\"glNormalP3ui\");\n\tglad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load(\"glNormalP3uiv\");\n\tglad_glColorP3ui = (PFNGLCOLORP3UIPROC)load(\"glColorP3ui\");\n\tglad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load(\"glColorP3uiv\");\n\tglad_glColorP4ui = (PFNGLCOLORP4UIPROC)load(\"glColorP4ui\");\n\tglad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load(\"glColorP4uiv\");\n\tglad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load(\"glSecondaryColorP3ui\");\n\tglad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load(\"glSecondaryColorP3uiv\");\n}\nstatic int find_extensionsGL(void) {\n\tif (!get_exts()) return 0;\n\t(void)&has_ext;\n\tfree_exts();\n\treturn 1;\n}\n\nstatic void find_coreGL(void) {\n\n    /* Thank you @elmindreda\n     * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176\n     * https://github.com/glfw/glfw/blob/master/src/context.c#L36\n     */\n    int i, major, minor;\n\n    const char* version;\n    const char* prefixes[] = {\n        \"OpenGL ES-CM \",\n        \"OpenGL ES-CL \",\n        \"OpenGL ES \",\n        NULL\n    };\n\n    version = (const char*) glGetString(GL_VERSION);\n    if (!version) return;\n\n    for (i = 0;  prefixes[i];  i++) {\n        const size_t length = strlen(prefixes[i]);\n        if (strncmp(version, prefixes[i], length) == 0) {\n            version += length;\n            break;\n        }\n    }\n\n/* PR #18 */\n#ifdef _MSC_VER\n    sscanf_s(version, \"%d.%d\", &major, &minor);\n#else\n    sscanf(version, \"%d.%d\", &major, &minor);\n#endif\n\n    GLVersion.major = major; GLVersion.minor = minor;\n    max_loaded_major = major; max_loaded_minor = minor;\n\tGLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;\n\tGLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;\n\tGLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;\n\tGLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;\n\tGLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;\n\tGLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;\n\tGLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;\n\tGLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;\n\tGLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;\n\tGLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;\n\tGLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;\n\tGLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;\n\tif (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) {\n\t\tmax_loaded_major = 3;\n\t\tmax_loaded_minor = 3;\n\t}\n}\n\nint gladLoadGLLoader(GLADloadproc load) {\n\tGLVersion.major = 0; GLVersion.minor = 0;\n\tglGetString = (PFNGLGETSTRINGPROC)load(\"glGetString\");\n\tif(glGetString == NULL) return 0;\n\tif(glGetString(GL_VERSION) == NULL) return 0;\n\tfind_coreGL();\n\tload_GL_VERSION_1_0(load);\n\tload_GL_VERSION_1_1(load);\n\tload_GL_VERSION_1_2(load);\n\tload_GL_VERSION_1_3(load);\n\tload_GL_VERSION_1_4(load);\n\tload_GL_VERSION_1_5(load);\n\tload_GL_VERSION_2_0(load);\n\tload_GL_VERSION_2_1(load);\n\tload_GL_VERSION_3_0(load);\n\tload_GL_VERSION_3_1(load);\n\tload_GL_VERSION_3_2(load);\n\tload_GL_VERSION_3_3(load);\n\n\tif (!find_extensionsGL()) return 0;\n\treturn GLVersion.major != 0 || GLVersion.minor != 0;\n}\n\n"
  },
  {
    "path": "deps/glad/src/glad_wgl.c",
    "content": "/*\n\n    WGL loader generated by glad 0.1.34 on Wed Nov  3 06:45:32 2021.\n\n    Language/Generator: C/C++\n    Specification: wgl\n    APIs: wgl=1.0\n    Profile: -\n    Extensions:\n        WGL_ARB_extensions_string,\n        WGL_EXT_extensions_string,\n        WGL_EXT_swap_control\n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n    Reproducible: False\n\n    Commandline:\n        --api=\"wgl=1.0\" --generator=\"c\" --spec=\"wgl\" --extensions=\"WGL_ARB_extensions_string,WGL_EXT_extensions_string,WGL_EXT_swap_control\"\n    Online:\n        https://glad.dav1d.de/#language=c&specification=wgl&loader=on&api=wgl%3D1.0&extensions=WGL_ARB_extensions_string&extensions=WGL_EXT_extensions_string&extensions=WGL_EXT_swap_control\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <glad/glad_wgl.h>\n\nstatic void* get_proc(const char *namez);\n\n#if defined(_WIN32) || defined(__CYGWIN__)\n#ifndef _WINDOWS_\n#undef APIENTRY\n#endif\n#include <windows.h>\nstatic HMODULE libGL;\n\ntypedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*);\nstatic PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;\n\n#ifdef _MSC_VER\n#ifdef __has_include\n  #if __has_include(<winapifamily.h>)\n    #define HAVE_WINAPIFAMILY 1\n  #endif\n#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_\n  #define HAVE_WINAPIFAMILY 1\n#endif\n#endif\n\n#ifdef HAVE_WINAPIFAMILY\n  #include <winapifamily.h>\n  #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n    #define IS_UWP 1\n  #endif\n#endif\n\nstatic\nint open_wgl(void) {\n#ifndef IS_UWP\n    libGL = LoadLibraryW(L\"opengl32.dll\");\n    if(libGL != NULL) {\n        void (* tmp)(void);\n        tmp = (void(*)(void)) GetProcAddress(libGL, \"wglGetProcAddress\");\n        gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp;\n        return gladGetProcAddressPtr != NULL;\n    }\n#endif\n\n    return 0;\n}\n\nstatic\nvoid close_wgl(void) {\n    if(libGL != NULL) {\n        FreeLibrary((HMODULE) libGL);\n        libGL = NULL;\n    }\n}\n#else\n#include <dlfcn.h>\nstatic void* libGL;\n\n#if !defined(__APPLE__) && !defined(__HAIKU__)\ntypedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);\nstatic PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;\n#endif\n\nstatic\nint open_wgl(void) {\n#ifdef __APPLE__\n    static const char *NAMES[] = {\n        \"../Frameworks/OpenGL.framework/OpenGL\",\n        \"/Library/Frameworks/OpenGL.framework/OpenGL\",\n        \"/System/Library/Frameworks/OpenGL.framework/OpenGL\",\n        \"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL\"\n    };\n#else\n    static const char *NAMES[] = {\"libGL.so.1\", \"libGL.so\"};\n#endif\n\n    unsigned int index = 0;\n    for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {\n        libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);\n\n        if(libGL != NULL) {\n#if defined(__APPLE__) || defined(__HAIKU__)\n            return 1;\n#else\n            gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,\n                \"glXGetProcAddressARB\");\n            return gladGetProcAddressPtr != NULL;\n#endif\n        }\n    }\n\n    return 0;\n}\n\nstatic\nvoid close_wgl(void) {\n    if(libGL != NULL) {\n        dlclose(libGL);\n        libGL = NULL;\n    }\n}\n#endif\n\nstatic\nvoid* get_proc(const char *namez) {\n    void* result = NULL;\n    if(libGL == NULL) return NULL;\n\n#if !defined(__APPLE__) && !defined(__HAIKU__)\n    if(gladGetProcAddressPtr != NULL) {\n        result = gladGetProcAddressPtr(namez);\n    }\n#endif\n    if(result == NULL) {\n#if defined(_WIN32) || defined(__CYGWIN__)\n        result = (void*)GetProcAddress((HMODULE) libGL, namez);\n#else\n        result = dlsym(libGL, namez);\n#endif\n    }\n\n    return result;\n}\n\nint gladLoadWGL(HDC hdc) {\n    int status = 0;\n\n    if(open_wgl()) {\n        status = gladLoadWGLLoader((GLADloadproc)get_proc, hdc);\n    }\n\n    return status;\n}\n\nvoid gladUnloadGLX(void) {\n    close_wgl();\n}\n\nstatic HDC GLADWGLhdc = (HDC)INVALID_HANDLE_VALUE;\n\nstatic int get_exts(void) {\n    return 1;\n}\n\nstatic void free_exts(void) {\n    return;\n}\n\nstatic int has_ext(const char *ext) {\n    const char *terminator;\n    const char *loc;\n    const char *extensions;\n\n    if(wglGetExtensionsStringEXT == NULL && wglGetExtensionsStringARB == NULL)\n        return 0;\n\n    if(wglGetExtensionsStringARB == NULL || GLADWGLhdc == INVALID_HANDLE_VALUE)\n        extensions = wglGetExtensionsStringEXT();\n    else\n        extensions = wglGetExtensionsStringARB(GLADWGLhdc);\n\n    if(extensions == NULL || ext == NULL)\n        return 0;\n\n    while(1) {\n        loc = strstr(extensions, ext);\n        if(loc == NULL)\n            break;\n\n        terminator = loc + strlen(ext);\n        if((loc == extensions || *(loc - 1) == ' ') &&\n            (*terminator == ' ' || *terminator == '\\0'))\n        {\n            return 1;\n        }\n        extensions = terminator;\n    }\n\n    return 0;\n}\nint GLAD_WGL_VERSION_1_0 = 0;\nint GLAD_WGL_ARB_extensions_string = 0;\nint GLAD_WGL_EXT_extensions_string = 0;\nint GLAD_WGL_EXT_swap_control = 0;\nPFNWGLGETEXTENSIONSSTRINGARBPROC glad_wglGetExtensionsStringARB = NULL;\nPFNWGLGETEXTENSIONSSTRINGEXTPROC glad_wglGetExtensionsStringEXT = NULL;\nPFNWGLSWAPINTERVALEXTPROC glad_wglSwapIntervalEXT = NULL;\nPFNWGLGETSWAPINTERVALEXTPROC glad_wglGetSwapIntervalEXT = NULL;\nstatic void load_WGL_ARB_extensions_string(GLADloadproc load) {\n\tif(!GLAD_WGL_ARB_extensions_string) return;\n\tglad_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)load(\"wglGetExtensionsStringARB\");\n}\nstatic void load_WGL_EXT_extensions_string(GLADloadproc load) {\n\tif(!GLAD_WGL_EXT_extensions_string) return;\n\tglad_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)load(\"wglGetExtensionsStringEXT\");\n}\nstatic void load_WGL_EXT_swap_control(GLADloadproc load) {\n\tif(!GLAD_WGL_EXT_swap_control) return;\n\tglad_wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)load(\"wglSwapIntervalEXT\");\n\tglad_wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)load(\"wglGetSwapIntervalEXT\");\n}\nstatic int find_extensionsWGL(void) {\n\tif (!get_exts()) return 0;\n\tGLAD_WGL_ARB_extensions_string = has_ext(\"WGL_ARB_extensions_string\");\n\tGLAD_WGL_EXT_extensions_string = has_ext(\"WGL_EXT_extensions_string\");\n\tGLAD_WGL_EXT_swap_control = has_ext(\"WGL_EXT_swap_control\");\n\tfree_exts();\n\treturn 1;\n}\n\nstatic void find_coreWGL(HDC hdc) {\n\tGLADWGLhdc = hdc;\n}\n\nint gladLoadWGLLoader(GLADloadproc load, HDC hdc) {\n\twglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)load(\"wglGetExtensionsStringARB\");\n\twglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)load(\"wglGetExtensionsStringEXT\");\n\tif(wglGetExtensionsStringARB == NULL && wglGetExtensionsStringEXT == NULL) return 0;\n\tfind_coreWGL(hdc);\n\n\tif (!find_extensionsWGL()) return 0;\n\tload_WGL_ARB_extensions_string(load);\n\tload_WGL_EXT_extensions_string(load);\n\tload_WGL_EXT_swap_control(load);\n\treturn 1;\n}\n\n"
  },
  {
    "path": "deps/inih/CMakeLists.txt",
    "content": "add_library(inih STATIC EXCLUDE_FROM_ALL ini.c ini.h)\ntarget_compile_definitions(inih PRIVATE INI_ALLOW_NO_VALUE INI_CALL_HANDLER_ON_NEW_SECTION)\ntarget_include_directories(inih PUBLIC .)\nset_target_properties(inih PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\n"
  },
  {
    "path": "deps/inih/LICENSE.txt",
    "content": "\nThe \"inih\" library is distributed under the New BSD license:\n\nCopyright (c) 2009, Ben Hoyt\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Ben Hoyt nor the names of its contributors\n      may be used to endorse or promote products derived from this software\n      without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "deps/inih/README.md",
    "content": "# inih (INI Not Invented Here)\n\n[![Tests](https://github.com/benhoyt/inih/actions/workflows/tests.yml/badge.svg)](https://github.com/benhoyt/inih/actions/workflows/tests.yml)\n\n**inih (INI Not Invented Here)** is a simple [.INI file](http://en.wikipedia.org/wiki/INI_file) parser written in C. It's only a couple of pages of code, and it was designed to be _small and simple_, so it's good for embedded systems. It's also more or less compatible with Python's [ConfigParser](http://docs.python.org/library/configparser.html) style of .INI files, including RFC 822-style multi-line syntax and `name: value` entries.\n\nTo use it, just give `ini_parse()` an INI file, and it will call a callback for every `name=value` pair parsed, giving you strings for the section, name, and value. It's done this way (\"SAX style\") because it works well on low-memory embedded systems, but also because it makes for a KISS implementation.\n\nYou can also call `ini_parse_file()` to parse directly from a `FILE*` object, `ini_parse_string()` to parse data from a string, or `ini_parse_stream()` to parse using a custom fgets-style reader function for custom I/O.\n\nDownload a release, browse the source, or read about [how to use inih in a DRY style](http://blog.brush.co.nz/2009/08/xmacros/) with X-Macros.\n\n\n## Compile-time options ##\n\nYou can control various aspects of inih using preprocessor defines:\n\n### Syntax options ###\n\n  * **Multi-line entries:** By default, inih supports multi-line entries in the style of Python's ConfigParser. To disable, add `-DINI_ALLOW_MULTILINE=0`.\n  * **UTF-8 BOM:** By default, inih allows a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of INI files. To disable, add `-DINI_ALLOW_BOM=0`.\n  * **Inline comments:** By default, inih allows inline comments with the `;` character. To disable, add `-DINI_ALLOW_INLINE_COMMENTS=0`. You can also specify which character(s) start an inline comment using `INI_INLINE_COMMENT_PREFIXES`.\n  * **Start-of-line comments:** By default, inih allows both `;` and `#` to start a comment at the beginning of a line. You can override this by changing `INI_START_COMMENT_PREFIXES`.\n  * **Allow no value:** By default, inih treats a name with no value (no `=` or `:` on the line) as an error. To allow names with no values, add `-DINI_ALLOW_NO_VALUE=1`, and inih will call your handler function with value set to NULL.\n\n### Parsing options ###\n\n  * **Stop on first error:** By default, inih keeps parsing the rest of the file after an error. To stop parsing on the first error, add `-DINI_STOP_ON_FIRST_ERROR=1`.\n  * **Report line numbers:** By default, the `ini_handler` callback doesn't receive the line number as a parameter. If you need that, add `-DINI_HANDLER_LINENO=1`.\n  * **Call handler on new section:** By default, inih only calls the handler on each `name=value` pair. To detect new sections (e.g., the INI file has multiple sections with the same name), add `-DINI_CALL_HANDLER_ON_NEW_SECTION=1`. Your handler function will then be called each time a new section is encountered, with `section` set to the new section name but `name` and `value` set to NULL.\n\n### Memory options ###\n\n  * **Stack vs heap:** By default, inih creates a fixed-sized line buffer on the stack. To allocate on the heap using `malloc` instead, specify `-DINI_USE_STACK=0`.\n  * **Maximum line length:** The default maximum line length (for stack or heap) is 200 bytes. To override this, add something like `-DINI_MAX_LINE=1000`. Note that `INI_MAX_LINE` must be 3 more than the longest line (due to `\\r`, `\\n`, and the NUL).\n  * **Initial malloc size:** `INI_INITIAL_ALLOC` specifies the initial malloc size when using the heap. It defaults to 200 bytes.\n  * **Allow realloc:** By default when using the heap (`-DINI_USE_STACK=0`), inih allocates a fixed-sized buffer of `INI_INITIAL_ALLOC` bytes. To allow this to grow to `INI_MAX_LINE` bytes, doubling if needed, set `-DINI_ALLOW_REALLOC=1`.\n  * **Custom allocator:** By default when using the heap, the standard library's `malloc`, `free`, and `realloc` functions are used; to use a custom allocator, specify `-DINI_CUSTOM_ALLOCATOR=1` (and `-DINI_USE_STACK=0`). You must define and link functions named `ini_malloc`, `ini_free`, and (if `INI_ALLOW_REALLOC` is set) `ini_realloc`, which must have the same signatures as the `stdlib.h` memory allocation functions.\n\n## Simple example in C ##\n\n```c\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"../ini.h\"\n\ntypedef struct\n{\n    int version;\n    const char* name;\n    const char* email;\n} configuration;\n\nstatic int handler(void* user, const char* section, const char* name,\n                   const char* value)\n{\n    configuration* pconfig = (configuration*)user;\n\n    #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0\n    if (MATCH(\"protocol\", \"version\")) {\n        pconfig->version = atoi(value);\n    } else if (MATCH(\"user\", \"name\")) {\n        pconfig->name = strdup(value);\n    } else if (MATCH(\"user\", \"email\")) {\n        pconfig->email = strdup(value);\n    } else {\n        return 0;  /* unknown section/name, error */\n    }\n    return 1;\n}\n\nint main(int argc, char* argv[])\n{\n    configuration config;\n\n    if (ini_parse(\"test.ini\", handler, &config) < 0) {\n        printf(\"Can't load 'test.ini'\\n\");\n        return 1;\n    }\n    printf(\"Config loaded from 'test.ini': version=%d, name=%s, email=%s\\n\",\n        config.version, config.name, config.email);\n    return 0;\n}\n```\n\n\n## C++ example ##\n\nIf you're into C++ and the STL, there is also an easy-to-use [INIReader class](https://github.com/benhoyt/inih/blob/master/cpp/INIReader.h) that stores values in a `map` and lets you `Get()` them:\n\n```cpp\n#include <iostream>\n#include \"INIReader.h\"\n\nint main()\n{\n    INIReader reader(\"../examples/test.ini\");\n\n    if (reader.ParseError() < 0) {\n        std::cout << \"Can't load 'test.ini'\\n\";\n        return 1;\n    }\n    std::cout << \"Config loaded from 'test.ini': version=\"\n              << reader.GetInteger(\"protocol\", \"version\", -1) << \", name=\"\n              << reader.Get(\"user\", \"name\", \"UNKNOWN\") << \", email=\"\n              << reader.Get(\"user\", \"email\", \"UNKNOWN\") << \", pi=\"\n              << reader.GetReal(\"user\", \"pi\", -1) << \", active=\"\n              << reader.GetBoolean(\"user\", \"active\", true) << \"\\n\";\n    return 0;\n}\n```\n\nThis simple C++ API works fine, but it's not very fully-fledged. I'm not planning to work more on the C++ API at the moment, so if you want a bit more power (for example `GetSections()` and `GetFields()` functions), see these forks:\n\n  * https://github.com/Blandinium/inih\n  * https://github.com/OSSystems/inih\n\n\n## Differences from ConfigParser ##\n\nSome differences between inih and Python's [ConfigParser](http://docs.python.org/library/configparser.html) standard library module:\n\n* INI name=value pairs given above any section headers are treated as valid items with no section (section name is an empty string). In ConfigParser having no section is an error.\n* Line continuations are handled with leading whitespace on continued lines (like ConfigParser). However, instead of concatenating continued lines together, they are treated as separate values for the same key (unlike ConfigParser).\n\n\n## Platform-specific notes ##\n\n* Windows/Win32 uses UTF-16 filenames natively, so to handle Unicode paths you need to call `_wfopen()` to open a file and then `ini_parse_file()` to parse it; inih does not include `wchar_t` or Unicode handling.\n\n## Meson notes ##\n\n* The `meson.build` file is not required to use or compile inih, its main purpose is for distributions.\n* By default Meson is set up for distro installation, but this behavior can be configured for embedded use cases:\n  * with `-Ddefault_library=static` static libraries are built.\n  * with `-Ddistro_install=false` libraries, headers and pkg-config files won't be installed.\n  * with `-Dwith_INIReader=false` you can disable building the C++ library.\n* All compile-time options are implemented in Meson as well, you can take a look at [meson_options.txt](https://github.com/benhoyt/inih/blob/master/meson_options.txt) for their definition. These won't work if `distro_install` is set to `true`.\n* If you want to use inih for programs which may be shipped in a distro, consider linking against the shared libraries. The pkg-config entries are `inih` and `INIReader`.\n* In case you use inih as a Meson subproject, you can use the `inih_dep` and `INIReader_dep` dependency variables. You might want to set `default_library=static` and `distro_install=false` for the subproject. An official Wrap is provided on [WrapDB](https://wrapdb.mesonbuild.com/inih).\n* For packagers: if you want to tag the version in the pkg-config file, you will need to do this downstream. Add `version : '<version_as_int>',` after the `license` tag in the `project()` function and `version : meson.project_version(),` after the `soversion` tag in both `library()` functions.\n\n## Building from vcpkg ##\n\nYou can build and install inih using [vcpkg](https://github.com/microsoft/vcpkg/) dependency manager:\n\n    git clone https://github.com/Microsoft/vcpkg.git\n    cd vcpkg\n    ./bootstrap-vcpkg.sh\n    ./vcpkg integrate install\n    ./vcpkg install inih\n\nThe inih port in vcpkg is kept up to date by microsoft team members and community contributors.\nIf the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.\n\n## Related links ##\n\n* [Conan package for inih](https://github.com/mohamedghita/conan-inih) (Conan is a C/C++ package manager)\n"
  },
  {
    "path": "deps/inih/ini.c",
    "content": "/* inih -- simple .INI file parser\n\nSPDX-License-Identifier: BSD-3-Clause\n\nCopyright (C) 2009-2020, Ben Hoyt\n\ninih is released under the New BSD license (see LICENSE.txt). Go to the project\nhome page for more info:\n\nhttps://github.com/benhoyt/inih\n\n*/\n\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#include <stdio.h>\n#include <ctype.h>\n#include <string.h>\n\n#include \"ini.h\"\n\n#if !INI_USE_STACK\n#if INI_CUSTOM_ALLOCATOR\n#include <stddef.h>\nvoid* ini_malloc(size_t size);\nvoid ini_free(void* ptr);\nvoid* ini_realloc(void* ptr, size_t size);\n#else\n#include <stdlib.h>\n#define ini_malloc malloc\n#define ini_free free\n#define ini_realloc realloc\n#endif\n#endif\n\n#define MAX_SECTION 50\n#define MAX_NAME 50\n\n/* Used by ini_parse_string() to keep track of string parsing state. */\ntypedef struct {\n    const char* ptr;\n    size_t num_left;\n} ini_parse_string_ctx;\n\n/* Strip whitespace chars off end of given string, in place. Return s. */\nstatic char* rstrip(char* s)\n{\n    char* p = s + strlen(s);\n    while (p > s && isspace((unsigned char)(*--p)))\n        *p = '\\0';\n    return s;\n}\n\n/* Return pointer to first non-whitespace char in given string. */\nstatic char* lskip(const char* s)\n{\n    while (*s && isspace((unsigned char)(*s)))\n        s++;\n    return (char*)s;\n}\n\n/* Return pointer to first char (of chars) or inline comment in given string,\n   or pointer to NUL at end of string if neither found. Inline comment must\n   be prefixed by a whitespace character to register as a comment. */\nstatic char* find_chars_or_comment(const char* s, const char* chars)\n{\n#if INI_ALLOW_INLINE_COMMENTS\n    int was_space = 0;\n    while (*s && (!chars || !strchr(chars, *s)) &&\n           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {\n        was_space = isspace((unsigned char)(*s));\n        s++;\n    }\n#else\n    while (*s && (!chars || !strchr(chars, *s))) {\n        s++;\n    }\n#endif\n    return (char*)s;\n}\n\n/* Similar to strncpy, but ensures dest (size bytes) is\n   NUL-terminated, and doesn't pad with NULs. */\nstatic char* strncpy0(char* dest, const char* src, size_t size)\n{\n    /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */\n    size_t i;\n    for (i = 0; i < size - 1 && src[i]; i++)\n        dest[i] = src[i];\n    dest[i] = '\\0';\n    return dest;\n}\n\n/* See documentation in header file. */\nint ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,\n                     void* user)\n{\n    /* Uses a fair bit of stack (use heap instead if you need to) */\n#if INI_USE_STACK\n    char line[INI_MAX_LINE];\n    int max_line = INI_MAX_LINE;\n#else\n    char* line;\n    size_t max_line = INI_INITIAL_ALLOC;\n#endif\n#if INI_ALLOW_REALLOC && !INI_USE_STACK\n    char* new_line;\n    size_t offset;\n#endif\n    char section[MAX_SECTION] = \"\";\n    char prev_name[MAX_NAME] = \"\";\n\n    char* start;\n    char* end;\n    char* name;\n    char* value;\n    int lineno = 0;\n    int error = 0;\n\n#if !INI_USE_STACK\n    line = (char*)ini_malloc(INI_INITIAL_ALLOC);\n    if (!line) {\n        return -2;\n    }\n#endif\n\n#if INI_HANDLER_LINENO\n#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)\n#else\n#define HANDLER(u, s, n, v) handler(u, s, n, v)\n#endif\n\n    /* Scan through stream line by line */\n    while (reader(line, (int)max_line, stream) != NULL) {\n#if INI_ALLOW_REALLOC && !INI_USE_STACK\n        offset = strlen(line);\n        while (offset == max_line - 1 && line[offset - 1] != '\\n') {\n            max_line *= 2;\n            if (max_line > INI_MAX_LINE)\n                max_line = INI_MAX_LINE;\n            new_line = ini_realloc(line, max_line);\n            if (!new_line) {\n                ini_free(line);\n                return -2;\n            }\n            line = new_line;\n            if (reader(line + offset, (int)(max_line - offset), stream) == NULL)\n                break;\n            if (max_line >= INI_MAX_LINE)\n                break;\n            offset += strlen(line + offset);\n        }\n#endif\n\n        lineno++;\n\n        start = line;\n#if INI_ALLOW_BOM\n        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&\n                           (unsigned char)start[1] == 0xBB &&\n                           (unsigned char)start[2] == 0xBF) {\n            start += 3;\n        }\n#endif\n        start = lskip(rstrip(start));\n\n        if (strchr(INI_START_COMMENT_PREFIXES, *start)) {\n            /* Start-of-line comment */\n        }\n#if INI_ALLOW_MULTILINE\n        else if (*prev_name && *start && start > line) {\n            /* Non-blank line with leading whitespace, treat as continuation\n               of previous name's value (as per Python configparser). */\n            if (!HANDLER(user, section, prev_name, start) && !error)\n                error = lineno;\n        }\n#endif\n        else if (*start == '[') {\n            /* A \"[section]\" line */\n            end = find_chars_or_comment(start + 1, \"]\");\n            if (*end == ']') {\n                *end = '\\0';\n                strncpy0(section, start + 1, sizeof(section));\n                *prev_name = '\\0';\n#if INI_CALL_HANDLER_ON_NEW_SECTION\n                if (!HANDLER(user, section, NULL, NULL) && !error)\n                    error = lineno;\n#endif\n            }\n            else if (!error) {\n                /* No ']' found on section line */\n                error = lineno;\n            }\n        }\n        else if (*start) {\n            /* Not a comment, must be a name[=:]value pair */\n            end = find_chars_or_comment(start, \"=:\");\n            if (*end == '=' || *end == ':') {\n                *end = '\\0';\n                name = rstrip(start);\n                value = end + 1;\n#if INI_ALLOW_INLINE_COMMENTS\n                end = find_chars_or_comment(value, NULL);\n                if (*end)\n                    *end = '\\0';\n#endif\n                value = lskip(value);\n                rstrip(value);\n\n                /* Valid name[=:]value pair found, call handler */\n                strncpy0(prev_name, name, sizeof(prev_name));\n                if (!HANDLER(user, section, name, value) && !error)\n                    error = lineno;\n            }\n            else if (!error) {\n                /* No '=' or ':' found on name[=:]value line */\n#if INI_ALLOW_NO_VALUE\n                *end = '\\0';\n                name = rstrip(start);\n                if (!HANDLER(user, section, name, NULL) && !error)\n                    error = lineno;\n#else\n                error = lineno;\n#endif\n            }\n        }\n\n#if INI_STOP_ON_FIRST_ERROR\n        if (error)\n            break;\n#endif\n    }\n\n#if !INI_USE_STACK\n    ini_free(line);\n#endif\n\n    return error;\n}\n\n/* See documentation in header file. */\nint ini_parse_file(FILE* file, ini_handler handler, void* user)\n{\n    return ini_parse_stream((ini_reader)fgets, file, handler, user);\n}\n\n/* See documentation in header file. */\nint ini_parse(const char* filename, ini_handler handler, void* user)\n{\n    FILE* file;\n    int error;\n\n    file = fopen(filename, \"r\");\n    if (!file)\n        return -1;\n    error = ini_parse_file(file, handler, user);\n    fclose(file);\n    return error;\n}\n\n/* An ini_reader function to read the next line from a string buffer. This\n   is the fgets() equivalent used by ini_parse_string(). */\nstatic char* ini_reader_string(char* str, int num, void* stream) {\n    ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;\n    const char* ctx_ptr = ctx->ptr;\n    size_t ctx_num_left = ctx->num_left;\n    char* strp = str;\n    char c;\n\n    if (ctx_num_left == 0 || num < 2)\n        return NULL;\n\n    while (num > 1 && ctx_num_left != 0) {\n        c = *ctx_ptr++;\n        ctx_num_left--;\n        *strp++ = c;\n        if (c == '\\n')\n            break;\n        num--;\n    }\n\n    *strp = '\\0';\n    ctx->ptr = ctx_ptr;\n    ctx->num_left = ctx_num_left;\n    return str;\n}\n\n/* See documentation in header file. */\nint ini_parse_string(const char* string, ini_handler handler, void* user) {\n    ini_parse_string_ctx ctx;\n\n    ctx.ptr = string;\n    ctx.num_left = strlen(string);\n    return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,\n                            user);\n}\n"
  },
  {
    "path": "deps/inih/ini.h",
    "content": "/* inih -- simple .INI file parser\n\nSPDX-License-Identifier: BSD-3-Clause\n\nCopyright (C) 2009-2020, Ben Hoyt\n\ninih is released under the New BSD license (see LICENSE.txt). Go to the project\nhome page for more info:\n\nhttps://github.com/benhoyt/inih\n\n*/\n\n#ifndef INI_H\n#define INI_H\n\n/* Make this header file easier to include in C++ code */\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdio.h>\n\n/* Nonzero if ini_handler callback should accept lineno parameter. */\n#ifndef INI_HANDLER_LINENO\n#define INI_HANDLER_LINENO 0\n#endif\n\n/* Typedef for prototype of handler function. */\n#if INI_HANDLER_LINENO\ntypedef int (*ini_handler)(void* user, const char* section,\n                           const char* name, const char* value,\n                           int lineno);\n#else\ntypedef int (*ini_handler)(void* user, const char* section,\n                           const char* name, const char* value);\n#endif\n\n/* Typedef for prototype of fgets-style reader function. */\ntypedef char* (*ini_reader)(char* str, int num, void* stream);\n\n/* Parse given INI-style file. May have [section]s, name=value pairs\n   (whitespace stripped), and comments starting with ';' (semicolon). Section\n   is \"\" if name=value pair parsed before any section heading. name:value\n   pairs are also supported as a concession to Python's configparser.\n\n   For each name=value pair parsed, call handler function with given user\n   pointer as well as section, name, and value (data only valid for duration\n   of handler call). Handler should return nonzero on success, zero on error.\n\n   Returns 0 on success, line number of first error on parse error (doesn't\n   stop on first error), -1 on file open error, or -2 on memory allocation\n   error (only when INI_USE_STACK is zero).\n*/\nint ini_parse(const char* filename, ini_handler handler, void* user);\n\n/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't\n   close the file when it's finished -- the caller must do that. */\nint ini_parse_file(FILE* file, ini_handler handler, void* user);\n\n/* Same as ini_parse(), but takes an ini_reader function pointer instead of\n   filename. Used for implementing custom or string-based I/O (see also\n   ini_parse_string). */\nint ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,\n                     void* user);\n\n/* Same as ini_parse(), but takes a zero-terminated string with the INI data\ninstead of a file. Useful for parsing INI data from a network socket or\nalready in memory. */\nint ini_parse_string(const char* string, ini_handler handler, void* user);\n\n/* Nonzero to allow multi-line value parsing, in the style of Python's\n   configparser. If allowed, ini_parse() will call the handler with the same\n   name for each subsequent line parsed. */\n#ifndef INI_ALLOW_MULTILINE\n#define INI_ALLOW_MULTILINE 1\n#endif\n\n/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of\n   the file. See https://github.com/benhoyt/inih/issues/21 */\n#ifndef INI_ALLOW_BOM\n#define INI_ALLOW_BOM 1\n#endif\n\n/* Chars that begin a start-of-line comment. Per Python configparser, allow\n   both ; and # comments at the start of a line by default. */\n#ifndef INI_START_COMMENT_PREFIXES\n#define INI_START_COMMENT_PREFIXES \";#\"\n#endif\n\n/* Nonzero to allow inline comments (with valid inline comment characters\n   specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match\n   Python 3.2+ configparser behaviour. */\n#ifndef INI_ALLOW_INLINE_COMMENTS\n#define INI_ALLOW_INLINE_COMMENTS 1\n#endif\n#ifndef INI_INLINE_COMMENT_PREFIXES\n#define INI_INLINE_COMMENT_PREFIXES \";\"\n#endif\n\n/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */\n#ifndef INI_USE_STACK\n#define INI_USE_STACK 1\n#endif\n\n/* Maximum line length for any line in INI file (stack or heap). Note that\n   this must be 3 more than the longest line (due to '\\r', '\\n', and '\\0'). */\n#ifndef INI_MAX_LINE\n#define INI_MAX_LINE 200\n#endif\n\n/* Nonzero to allow heap line buffer to grow via realloc(), zero for a\n   fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is\n   zero. */\n#ifndef INI_ALLOW_REALLOC\n#define INI_ALLOW_REALLOC 0\n#endif\n\n/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK\n   is zero. */\n#ifndef INI_INITIAL_ALLOC\n#define INI_INITIAL_ALLOC 200\n#endif\n\n/* Stop parsing on first error (default is to keep parsing). */\n#ifndef INI_STOP_ON_FIRST_ERROR\n#define INI_STOP_ON_FIRST_ERROR 0\n#endif\n\n/* Nonzero to call the handler at the start of each new section (with\n   name and value NULL). Default is to only call the handler on\n   each name=value pair. */\n#ifndef INI_CALL_HANDLER_ON_NEW_SECTION\n#define INI_CALL_HANDLER_ON_NEW_SECTION 0\n#endif\n\n/* Nonzero to allow a name without a value (no '=' or ':' on the line) and\n   call the handler with value NULL in this case. Default is to treat\n   no-value lines as an error. */\n#ifndef INI_ALLOW_NO_VALUE\n#define INI_ALLOW_NO_VALUE 0\n#endif\n\n/* Nonzero to use custom ini_malloc, ini_free, and ini_realloc memory\n   allocation functions (INI_USE_STACK must also be 0). These functions must\n   have the same signatures as malloc/free/realloc and behave in a similar\n   way. ini_realloc is only needed if INI_ALLOW_REALLOC is set. */\n#ifndef INI_CUSTOM_ALLOCATOR\n#define INI_CUSTOM_ALLOCATOR 0\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INI_H */\n"
  },
  {
    "path": "deps/sol3/CMakeLists.txt",
    "content": "add_library(sol3 INTERFACE EXCLUDE_FROM_ALL)\ntarget_include_directories(sol3 INTERFACE include)\ntarget_link_libraries(sol3 INTERFACE lua::lua54)\n"
  },
  {
    "path": "deps/sol3/CONTRIBUTORS.md",
    "content": "# 🎉 Donators! ♥ 🎉\n\nThank you to all patrons, donators and contributors who help keep sol3 amazing.\n\n- Robert Salvet\n- Ορφέας Ζαφείρης - 2x Donations!\n- Michael Wallar\n- Johannes Schultz\n- Elias Daler\n- BECKMANN & EGLE Industrieelektronik GmbH [bue.de](https://www.bue.de/)\n\n\n# 🎉 Patrons! ♥ 🎉\n\nBeyond just a one-time donation, patrons make a continued commitment to help keep sol3 supported and bug-free. Thank you for your patronage! Here are the supporters that wanted to be featured as sol3 contributors.\n\n- Joel Falcou\n- Michael Caisse\n- Joshua Fisher\n- Ορφέας Ζαφείρης\n\n\n# Company Patrons / Supporters #\n\nCompanies who sign up for a long-term support contract or patronage are listed here! They really push forward what's possible with sol3 (and the newer v3)! Please reach out to phdofthehouse@gmail.com if you are interested in a custom solution or a long-term support contract that goes beyond the current release's needs!\n\n- Intrepid Control Systems [intrepidcs.com](https://www.intrepidcs.com/)\n"
  },
  {
    "path": "deps/sol3/LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013-2020 Rapptz, ThePhD, and contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "deps/sol3/README.md",
    "content": "## sol3 (sol2 v3.2.3)\n\n[![Linux & Max OSX Build Status](https://travis-ci.org/ThePhD/sol2.svg?branch=develop)](https://travis-ci.org/ThePhD/sol2)\n[![Windows Build status](https://ci.appveyor.com/api/projects/status/n38suofr21e9uk7h?svg=true)](https://ci.appveyor.com/project/ThePhD/sol2)\n[![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.io/en/latest/?badge=latest)\n\n[![Support via Github Sponsors](https://img.shields.io/badge/Github-Become%20a%20Sponsor-ff69b4.svg?style=flat&logo=GitHub)](https://github.com/users/ThePhD/sponsorship)\n[![Support via PayPal](https://cdn.rawgit.com/twolfson/paypal-github-button/1.0.0/dist/button.svg)](https://www.paypal.me/Soasis)\n[![Support via Ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Soasis) \n[![Support via Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.herokuapp.com%2FSoasis)](https://patreon.com/soasis)\n[![Support via Liberapay](https://img.shields.io/liberapay/patrons/ThePhD.svg)](https://liberapay.com/Soasis/)\n\nsol2 is a C++ library binding to Lua. It currently supports all Lua versions 5.1+ (LuaJIT 2.x included). sol2 aims to be easy to use and easy to add to a project.\nThe library is header-only for easy integration with projects.\n\n## Documentation\n\nFind it [here](http://sol2.rtfd.io/). A run-through kind of tutorial is [here](http://sol2.readthedocs.io/en/latest/tutorial/all-the-things.html)! The API documentation goes over most cases (particularly, the \"api/usertype\" and \"api/table_proxy\" and \"api/function\" sections) that should still get you off your feet and going, and there's an examples directory [here](https://github.com/ThePhD/sol2/tree/develop/examples) as well.\n\n## Sneak Peek\n\n```cpp\n#include <sol/sol.hpp>\n#include <cassert>\n\nint main() {\n    sol::state lua;\n    int x = 0;\n    lua.set_function(\"beep\", [&x]{ ++x; });\n    lua.script(\"beep()\");\n    assert(x == 1);\n}\n```\n\n```cpp\n#include <sol/sol.hpp>\n#include <cassert>\n\nstruct vars {\n    int boop = 0;\n};\n\nint main() {\n    sol::state lua;\n    lua.new_usertype<vars>(\"vars\", \"boop\", &vars::boop);\n    lua.script(\"beep = vars.new()\\n\"\n               \"beep.boop = 1\");\n    assert(lua.get<vars>(\"beep\").boop == 1);\n}\n```\n\nMore examples are given in the examples directory [here](https://github.com/ThePhD/sol2/tree/develop/examples). \n\n\n## Supporting\n\nPlease use the buttons above and help this project grow.\n\nYou can also help out the library by submitting pull requests to fix anything or add anything you think would be helpful! This includes making small, useful examples of something you haven't seen, or fixing typos and bad code in the documentation.\n\n\n## Presentations\n\n\"A Sun For the Moon - A Zero-Overhead Lua Abstraction using C++\"  \nThePhD\nLua Workshop 2016 - Mashape, San Francisco, CA  \n[Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/2016.10.14%20-%20ThePhD%20-%20No%20Overhead%20C%20Abstraction.pdf)\n\n\"Wrapping Lua C in C++ - Efficiently, Nicely, and with a Touch of Magic\"  \nThePhD\nBoston C++ Meetup November 2017 - CiC (Milk Street), Boston, MA  \n[Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/2017.11.08%20-%20ThePhD%20-%20Wrapping%20Lua%20C%20in%20C%2B%2B.pdf)\n\n\"Biting the CMake Bullet\"  \nThePhD\nBoston C++ Meetup February 2018 - CiC (Main Street), Cambridge, MA  \n[Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/2018.02.06%20-%20ThePhD%20-%20Biting%20the%20CMake%20Bullet.pdf)\n\n\"Compile Fast, Run Faster, Scale Forever: A look into the sol2 Library\"  \nThePhD\nC++Now 2018 - Hudson Commons, Aspen Physics Center, Aspen, Colorado  \n[Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/2018.05.10%20-%20ThePhD%20-%20Compile%20Fast%2C%20Run%20Faster%2C%20Scale%20Forever.pdf)\n\n\"Scripting at the Speed of Thought: Using Lua in C++ with sol3\"  \nThePhD\nCppCon 2018 - 404 Keystone, Meydenbauer Center, Aspen, Colorado  \n[Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/2018.09.28%20-%20ThePhD%20-%20Scripting%20at%20the%20Speed%20of%20Thought.pdf)\n\n\"The Plan for Tomorrow: Compile-Time Extension Points in C++\"\nThePhD\nC++Now 2019 - Flug Auditorium, Aspen Physics Center, Aspen, Colorado\n[Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/2019.05.10%20-%20ThePhD%20-%20The%20Plan%20for%20Tomorrow%20-%20Compile-Time%20Extension%20Points%20in%20C%2b%2b.pdf)\n\n\n## Features\n\n- [Fastest in the land](http://sol2.readthedocs.io/en/latest/benchmarks.html) (see: sol3 bar in graph).\n- Supports retrieval and setting of multiple types including: \n  * `std::string`, `std::wstring`, `std::u16string` and `std::u32string` support (and for views).\n  * understands and works with containers such as `std::map/unordered_map`, c-style arrays, vectors, non-standard custom containers and more.\n  * user-defined types, with or **without** registering that type \n  * `std::unique_ptr`, `std::shared_ptr`, and optional support of other pointer types like `boost::shared_ptr`.\n  * custom `optional<T>` that works with references, and support for the inferior `std::optional`.\n  * C++17 support for variants and similar new types.\n- Lambda, function, and member function bindings are supported.\n- Intermediate type for checking if a variable exists.\n- Simple API that completely abstracts away the C stack API, including `protected_function` with the ability to use an error-handling function.\n- `operator[]`-style manipulation of tables\n- C++ type representations in Lua userdata as `usertype`s with guaranteed cleanup.\n- Customization points to allow your C++ objects to be pushed and retrieved from Lua as multiple consecutive objects, or anything else you desire!\n- Overloaded function calls: `my_function(1); my_function(\"Hello\")` in the same Lua script route to different function calls based on parameters\n- Support for tables, nested tables, table iteration with `table.for_each` / `begin()` and `end()` iterators.\n- Zero string overhead for usertype function lookup.\n\n\n## Supported Compilers\n\nsol2 makes use of C++17 features. GCC 7.x.x and Clang 3.9.x (with `-std=c++1z` and appropriate standard library) \nor higher should be able to compile without problems. However, the officially supported and CI-tested compilers are:\n\n- GCC 7.x.x+ (MinGW 7.x.x+)\n- Clang 3.9.x+\n- Visual Studio 2017 Community (Visual C++ 15.0)+\n\nPlease make sure you use the `-std=c++2a`, `-std=c++1z`, `-std=c++17` or better standard flags \n(some of these flags are the defaults in later versions of GCC, such as 7+ and better).\n\nIf you would like support for an older compiler (at the cost of some features), use the latest tagged sol2 branch. If you would like support for an even older compiler, feel free to contact me for a Custom Solution.\n\nsol3 is checked by-hand for other platforms as well, including Android-based builds with GCC and iOS-based builds out of XCode with Apple-clang. It should work on both of these platforms, so long as you have the proper standards flags.\n\n\n## Creating a single header\n\nYou can grab a single header (and the single forward header) out of the library [here](https://github.com/ThePhD/sol2/tree/develop/single). For stable version, check the releases tab on GitHub for a provided single header file for maximum ease of use. A script called [`single.py`](https://github.com/ThePhD/sol2/blob/develop/single/single.py) is provided in the repository if there's some bleeding edge change that hasn't been published on the releases page. You can run this script to create a single file version of the library so you can only include that part of it. Check `single.py --help` for more info.\n\nIf you use CMake, you can also configure and generate a project that will generate the `sol2_single_header` for you. You can also include the project using CMake. Run CMake for more details. Thanks @Nava2, @alkino, @mrgreywater and others for help with making the CMake build a reality.\n\n\n## Running the Tests\n\nTesting on Travis-CI and Appveyor use CMake. You can generate the tests by running CMake and configuring `SOL2_TESTS`, `SOL2_TESTS_SINGLE`, `SOL2_TESTS_EXAMPLES`, and `SOL2_EXAMPLES` to be on. Make sure `SOL2_SINGLE` is also on.\n\nYou will need any flavor of python3 and an available compiler. The testing suite will build its own version of Lua and LuaJIT, so you do not have to provide one (you may provide one with the `LUA_LOCAL_DIR` variable).\n\n\n## License\n\nsol2 is distributed with an MIT License. You can see LICENSE.txt for more info.\n\nIf you need a custom solution, feel free to contact me.\n"
  },
  {
    "path": "deps/sol3/include/sol/config.hpp",
    "content": "// The MIT License (MIT)\n\n// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\n// this software and associated documentation files (the \"Software\"), to deal in\n// the Software without restriction, including without limitation the rights to\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n// the Software, and to permit persons to whom the Software is furnished to do so,\n// subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// This file was generated with a script.\n// Generated 2020-10-15 05:19:08.645208 UTC\n// This header was generated with sol v3.2.3 (revision e5e6466e)\n// https://github.com/ThePhD/sol2\n\n#ifndef SOL_SINGLE_CONFIG_HPP\n#define SOL_SINGLE_CONFIG_HPP\n\n// beginning of sol/config.hpp\n\n/* Base, empty configuration file!\n\n     To override, place a file in your include paths of the form:\n\n. (your include path here)\n| sol (directory, or equivalent)\n  | config.hpp (your config.hpp file)\n\n     So that when sol2 includes the file\n\n#include <sol/config.hpp>\n\n     it gives you the configuration values you desire. Configuration values can be\nseen in the safety.rst of the doc/src, or at\nhttps://sol2.readthedocs.io/en/latest/safety.html ! You can also pass them through\nthe build system, or the command line options of your compiler.\n\n*/\n\n// end of sol/config.hpp\n\n#endif // SOL_SINGLE_CONFIG_HPP\n"
  },
  {
    "path": "deps/sol3/include/sol/forward.hpp",
    "content": "// The MIT License (MIT)\n\n// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\n// this software and associated documentation files (the \"Software\"), to deal in\n// the Software without restriction, including without limitation the rights to\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n// the Software, and to permit persons to whom the Software is furnished to do so,\n// subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// This file was generated with a script.\n// Generated 2020-10-15 05:19:08.633139 UTC\n// This header was generated with sol v3.2.3 (revision e5e6466e)\n// https://github.com/ThePhD/sol2\n\n#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP\n#define SOL_SINGLE_INCLUDE_FORWARD_HPP\n\n// beginning of sol/forward.hpp\n\n#ifndef SOL_FORWARD_HPP\n#define SOL_FORWARD_HPP\n\n// beginning of sol/version.hpp\n\n#include <sol/config.hpp>\n\n#include <cstdint>\n\n#define SOL_VERSION_MAJOR 3\n#define SOL_VERSION_MINOR 2\n#define SOL_VERSION_PATCH 3\n#define SOL_VERSION_STRING \"3.2.3\"\n#define SOL_VERSION ((SOL_VERSION_MAJOR * 100000) + (SOL_VERSION_MINOR * 100) + (SOL_VERSION_PATCH))\n\n#define SOL_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0)\n#define SOL_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0)\n#define SOL_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3)\n#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0)\n\n#define SOL_ON          |\n#define SOL_OFF         ^\n#define SOL_DEFAULT_ON  +\n#define SOL_DEFAULT_OFF -\n\n#if defined(_MSC_VER)\n\t#define SOL_COMPILER_CLANG_I_ SOL_OFF\n\t#define SOL_COMPILER_GCC_I_   SOL_OFF\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_ON\n#elif defined(__clang__)\n\t#define SOL_COMPILER_CLANG_I_ SOL_ON\n\t#define SOL_COMPILER_GCC_I_   SOL_OFF\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_OFF\n#elif defined(__GNUC__)\n\t#define SOL_COMPILER_CLANG_I_ SOL_OFF\n\t#define SOL_COMPILER_GCC_I_   SOL_ON\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_OFF\n#else\n\t#define SOL_COMPILER_CLANG_I_ SOL_OFF\n\t#define SOL_COMPILER_GCC_I_   SOL_OFF\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_OFF\n#endif\n\n#if defined(__MINGW32__)\n\t#define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_ON\n#else\n\t#define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_OFF\n#endif\n\n#if SIZE_MAX <= 0xFFFFULL\n\t#define SOL_PLATFORM_X16_I_ SOL_ON\n\t#define SOL_PLATFORM_X86_I_ SOL_OFF\n\t#define SOL_PLATFORM_X64_I_ SOL_OFF\n#elif SIZE_MAX <= 0xFFFFFFFFULL\n\t#define SOL_PLATFORM_X16_I_ SOL_OFF\n\t#define SOL_PLATFORM_X86_I_ SOL_ON\n\t#define SOL_PLATFORM_X64_I_ SOL_OFF\n#else\n\t#define SOL_PLATFORM_X16_I_ SOL_OFF\n\t#define SOL_PLATFORM_X86_I_ SOL_OFF\n\t#define SOL_PLATFORM_X64_I_ SOL_ON\n#endif\n\n#define SOL_PLATFORM_ARM32_I_ SOL_OFF\n#define SOL_PLATFORM_ARM64_I_ SOL_OFF\n\n#if defined(_WIN32)\n\t#define SOL_PLATFORM_WINDOWS_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_WINDOWS_I_ SOL_OFF\n#endif\n#if defined(__APPLE__)\n\t#define SOL_PLATFORM_APPLE_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_APPLE_I_ SOL_OFF\n#endif\n#if defined(__unix__)\n\t#define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF\n#endif\n#if defined(__linux__)\n\t#define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF\n#endif\n\n#define SOL_PLATFORM_APPLE_IPHONE_I_ SOL_OFF\n#define SOL_PLATFORM_BSDLIKE_I_      SOL_OFF\n\n#if defined(SOL_IN_DEBUG_DETECTED)\n\t#if SOL_IN_DEBUG_DETECTED != 0\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_OFF\n\t#endif\n#elif !defined(NDEBUG)\n\t#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) && defined(_DEBUG)\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_ON\n\t#elif (SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)) && !defined(__OPTIMIZE__)\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_DEBUG_BUILD_I_ SOL_DEFAULT_OFF\n#endif // We are in a debug mode of some sort\n\n#if defined(SOL_NO_EXCEPTIONS)\n\t#if (SOL_NO_EXCEPTIONS != 0)\n\t\t#define SOL_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t#if !defined(_CPPUNWIND)\n\t\t#define SOL_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)\n\t#if !defined(__EXCEPTIONS)\n\t\t#define SOL_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_EXCEPTIONS_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_NO_RTTI)\n\t#if (SOL_NO_RTTI != 0)\n\t\t#define SOL_RTTI_I_ SOL_OFF\n\t#else\n\t\t#define SOL_RTTI_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t#if !defined(_CPPRTTI)\n\t\t#define SOL_RTTI_I_ SOL_OFF\n\t#else\n\t\t#define SOL_RTTI_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)\n\t#if !defined(__GXX_RTTI)\n\t\t#define SOL_RTTI_I_ SOL_OFF\n\t#else\n\t\t#define SOL_RTTI_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_RTTI_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_NO_THREAD_LOCAL)\n\t#if SOL_NO_THREAD_LOCAL != 0\n\t\t#define SOL_USE_THREAD_LOCAL_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_THREAD_LOCAL_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_USE_THREAD_LOCAL_I_ SOL_DEFAULT_ON\n#endif // thread_local keyword is bjorked on some platforms\n\n#if defined(SOL_ALL_SAFETIES_ON)\n\t#if SOL_ALL_SAFETIES_ON != 0\n\t\t#define SOL_ALL_SAFETIES_ON_I_ SOL_ON\n\t#else\n\t\t#define SOL_ALL_SAFETIES_ON_I_ SOL_FF\n\t#endif\n#else\n\t#define SOL_ALL_SAFETIES_ON_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_SAFE_GETTER)\n\t#if SOL_SAFE_GETTER != 0\n\t\t#define SOL_SAFE_GETTER_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_GETTER_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_GETTER_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_GETTER_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_GETTER_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_USERTYPE)\n\t#if SOL_SAFE_USERTYPE != 0\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_REFERENCES)\n\t#if SOL_SAFE_REFERENCES != 0\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_FUNCTIONS)\n\t#if SOL_SAFE_FUNCTIONS != 0\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF\n\t#endif\n#elif defined (SOL_SAFE_FUNCTION_OBJECTS)\n\t#if SOL_SAFE_FUNCTION_OBJECTS != 0\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_FUNCTION_CALLS)\n\t#if SOL_SAFE_FUNCTION_CALLS != 0\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_PROXIES)\n\t#if SOL_SAFE_PROXIES != 0\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_NUMERICS)\n\t#if SOL_SAFE_NUMERICS != 0\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_STACK_CHECK)\n\t#if SOL_SAFE_STACK_CHECK != 0\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_NO_CHECK_NUMBER_PRECISION)\n\t#if SOL_NO_CHECK_NUMBER_PRECISION != 0\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#endif\n#elif defined(SOL_NO_CHECKING_NUMBER_PRECISION)\n\t#if SOL_NO_CHECKING_NUMBER_PRECISION != 0\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_SAFE_NUMERICS_I_)\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_STRINGS_ARE_NUMBERS)\n\t#if (SOL_STRINGS_ARE_NUMBERS != 0)\n\t\t#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_ON\n\t#else\n\t\t#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_ENABLE_INTEROP)\n\t#if SOL_ENABLE_INTEROP != 0\n\t\t#define SOL_USE_INTEROP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_INTEROP_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_USE_INTEROP)\n\t#if SOL_USE_INTEROP != 0\n\t\t#define SOL_USE_INTEROP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_INTEROP_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_INTEROP_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_NO_NIL)\n\t#if (SOL_NO_NIL != 0)\n\t\t#define SOL_NIL_I_ SOL_OFF\n\t#else\n\t\t#define SOL_NIL_I_ SOL_ON\n\t#endif\n#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)\n\t#define SOL_NIL_I_ SOL_DEFAULT_OFF\n#else\n\t#define SOL_NIL_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_USERTYPE_TYPE_BINDING_INFO)\n\t#if (SOL_USERTYPE_TYPE_BINDING_INFO != 0)\n\t\t#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_ON\n\t#else\n\t\t#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_DEFAULT_ON\n#endif // We should generate a my_type.__type table with lots of class information for usertypes\n\n#if defined(SOL_AUTOMAGICAL_TYPES_BY_DEFAULT)\n\t#if (SOL_AUTOMAGICAL_TYPES_BY_DEFAULT != 0)\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_DEFAULT_AUTOMAGICAL_USERTYPES)\n\t#if (SOL_DEFAULT_AUTOMAGICAL_USERTYPES != 0)\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_DEFAULT_ON\n#endif // make is_automagical on/off by default\n\n#if defined(SOL_STD_VARIANT)\n\t#if (SOL_STD_VARIANT != 0)\n\t\t#define SOL_STD_VARIANT_I_ SOL_ON\n\t#else\n\t\t#define SOL_STD_VARIANT_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_COMPILER_CLANG_I_) && SOL_IS_ON(SOL_PLATFORM_APPLE_I_)\n\t\t#if defined(__has_include)\n\t\t\t#if __has_include(<variant>)\n\t\t\t\t#define SOL_STD_VARIANT_I_ SOL_ON\n\t\t\t#else\n\t\t\t\t#define SOL_STD_VARIANT_I_ SOL_OFF\n\t\t\t#endif\n\t\t#else\n\t\t\t#define SOL_STD_VARIANT_I_ SOL_OFF\n\t\t#endif\n\t#else\n\t\t#define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON\n\t#endif\n#endif // make is_automagical on/off by default\n\n#if defined(SOL_NOEXCEPT_FUNCTION_TYPE)\n\t#if (SOL_NOEXCEPT_FUNCTION_TYPE != 0)\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF\n\t#endif\n#else\n\t#if defined(__cpp_noexcept_function_type)\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L))\n\t\t// There is a bug in the VC++ compiler??\n\t\t// on /std:c++latest under x86 conditions (VS 15.5.2),\n\t\t// compiler errors are tossed for noexcept markings being on function types\n\t\t// that are identical in every other way to their non-noexcept marked types function types...\n\t\t// VS 2019: There is absolutely a bug.\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_DEFAULT_ON\n\t#endif\n#endif // noexcept is part of a function's type\n\n#if defined(SOL_STACK_STRING_OPTIMIZATION_SIZE) && SOL_STACK_STRING_OPTIMIZATION_SIZE > 0\n\t#define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ SOL_STACK_STRING_OPTIMIZATION_SIZE\n#else\n\t#define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ 1024\n#endif\n\n#if defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0\n\t#define SOL_ID_SIZE_I_ SOL_ID_SIZE\n#else\n\t#define SOL_ID_SIZE_I_ 512\n#endif\n\n#if defined(LUA_IDSIZE) && LUA_IDSIZE > 0\n\t#define SOL_FILE_ID_SIZE_I_ LUA_IDSIZE\n#elif defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0\n\t#define SOL_FILE_ID_SIZE_I_ SOL_FILE_ID_SIZE\n#else\n\t#define SOL_FILE_ID_SIZE_I_ 2048\n#endif\n\n#if defined(SOL_PRINT_ERRORS)\n\t#if (SOL_PRINT_ERRORS != 0)\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_ON\n\t#else\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_OFF\n\t#endif\n#endif\n\n#if defined(SOL_DEFAULT_PASS_ON_ERROR)\n\t#if (SOL_DEFAULT_PASS_ON_ERROR != 0)\n\t\t#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_USING_CXX_LUA)\n\t#if (SOL_USING_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_USE_CXX_LUA)\n\t#if (SOL_USE_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_CXX_LUA_I_ SOL_OFF\n#endif\n\n#if defined(SOL_USING_CXX_LUAJIT)\n\t#if (SOL_USING_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_USE_CXX_LUAJIT)\n\t#if (SOL_USE_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF\n#endif\n\n#if defined(SOL_NO_LUA_HPP)\n\t#if (SOL_NO_LUA_HPP != 0)\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_ON\n\t#endif\n#elif defined(SOL_USING_CXX_LUA)\n\t#define SOL_USE_LUA_HPP_I_ SOL_OFF\n#elif defined(__has_include)\n\t#if __has_include(<lua.hpp>)\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_LUA_HPP_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_CONTAINERS_START)\n\t#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START\n#elif defined(SOL_CONTAINERS_START_INDEX)\n\t#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START_INDEX\n#elif defined(SOL_CONTAINER_START_INDEX)\n\t#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINER_START_INDEX\n#else\n\t#define SOL_CONTAINER_START_INDEX_I_ 1\n#endif\n\n#if defined (SOL_NO_MEMORY_ALIGNMENT)\n\t#if (SOL_NO_MEMORY_ALIGNMENT != 0)\n\t\t#define SOL_ALIGN_MEMORY_I_ SOL_OFF\n\t#else\n\t\t#define SOL_ALIGN_MEMORY_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_ALIGN_MEMORY_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_USE_BOOST)\n\t#if (SOL_USE_BOOST != 0)\n\t\t#define SOL_USE_BOOST_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_BOOST_I_ SOL_OFF\n\t#endif\n#else\n\t\t#define SOL_USE_BOOST_I_ SOL_OFF\n#endif\n\n#if defined(SOL_USE_UNSAFE_BASE_LOOKUP)\n\t#if (SOL_USE_UNSAFE_BASE_LOOKUP != 0)\n\t\t#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF\n#endif\n\n#if defined(SOL_INSIDE_UNREAL)\n\t#if (SOL_INSIDE_UNREAL != 0)\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON\n\t#else\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_OFF\n\t#endif\n#else\n\t#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER)\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON\n\t#else\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_NO_COMPAT)\n\t#if (SOL_NO_COMPAT != 0)\n\t\t#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_GET_FUNCTION_POINTER_UNSAFE)\n\t#if (SOL_GET_FUNCTION_POINTER_UNSAFE != 0)\n\t\t#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_ON\n\t#else\n\t\t#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_DEFAULT_OFF\n#endif\n\n#if SOL_IS_ON(SOL_COMPILER_FRONTEND_MINGW_I_) && defined(__GNUC__) && (__GNUC__ < 6)\n\t// MinGW is off its rocker in some places...\n\t#define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON\n#else\n\t#define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_OFF\n#endif\n\n// end of sol/version.hpp\n\n#include <utility>\n#include <type_traits>\n#include <string_view>\n\n#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) || SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_)\nstruct lua_State;\n#else\nextern \"C\" {\nstruct lua_State;\n}\n#endif // C++ Mangling for Lua vs. Not\n\nnamespace sol {\n\n\tenum class type;\n\n\tclass stateless_reference;\n\ttemplate <bool b>\n\tclass basic_reference;\n\tusing reference = basic_reference<false>;\n\tusing main_reference = basic_reference<true>;\n\tclass stateless_stack_reference;\n\tclass stack_reference;\n\n\ttemplate <typename A>\n\tclass basic_bytecode;\n\n\tstruct lua_value;\n\n\tstruct proxy_base_tag;\n\ttemplate <typename>\n\tstruct proxy_base;\n\ttemplate <typename, typename>\n\tstruct table_proxy;\n\n\ttemplate <bool, typename>\n\tclass basic_table_core;\n\ttemplate <bool b>\n\tusing table_core = basic_table_core<b, reference>;\n\ttemplate <bool b>\n\tusing main_table_core = basic_table_core<b, main_reference>;\n\ttemplate <bool b>\n\tusing stack_table_core = basic_table_core<b, stack_reference>;\n\ttemplate <typename base_type>\n\tusing basic_table = basic_table_core<false, base_type>;\n\tusing table = table_core<false>;\n\tusing global_table = table_core<true>;\n\tusing main_table = main_table_core<false>;\n\tusing main_global_table = main_table_core<true>;\n\tusing stack_table = stack_table_core<false>;\n\tusing stack_global_table = stack_table_core<true>;\n\n\ttemplate <typename>\n\tstruct basic_lua_table;\n\tusing lua_table = basic_lua_table<reference>;\n\tusing stack_lua_table = basic_lua_table<stack_reference>;\n\n\ttemplate <typename T, typename base_type>\n\tclass basic_usertype;\n\ttemplate <typename T>\n\tusing usertype = basic_usertype<T, reference>;\n\ttemplate <typename T>\n\tusing stack_usertype = basic_usertype<T, stack_reference>;\n\n\ttemplate <typename base_type>\n\tclass basic_metatable;\n\tusing metatable = basic_metatable<reference>;\n\tusing stack_metatable = basic_metatable<stack_reference>;\n\n\ttemplate <typename base_t>\n\tstruct basic_environment;\n\tusing environment = basic_environment<reference>;\n\tusing main_environment = basic_environment<main_reference>;\n\tusing stack_environment = basic_environment<stack_reference>;\n\n\ttemplate <typename T, bool>\n\tclass basic_function;\n\ttemplate <typename T, bool, typename H>\n\tclass basic_protected_function;\n\tusing unsafe_function = basic_function<reference, false>;\n\tusing safe_function = basic_protected_function<reference, false, reference>;\n\tusing main_unsafe_function = basic_function<main_reference, false>;\n\tusing main_safe_function = basic_protected_function<main_reference, false, reference>;\n\tusing stack_unsafe_function = basic_function<stack_reference, false>;\n\tusing stack_safe_function = basic_protected_function<stack_reference, false, reference>;\n\tusing stack_aligned_unsafe_function = basic_function<stack_reference, true>;\n\tusing stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>;\n\tusing protected_function = safe_function;\n\tusing main_protected_function = main_safe_function;\n\tusing stack_protected_function = stack_safe_function;\n\tusing stack_aligned_protected_function = stack_aligned_safe_function;\n#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)\n\tusing function = protected_function;\n\tusing main_function = main_protected_function;\n\tusing stack_function = stack_protected_function;\n\tusing stack_aligned_function = stack_aligned_safe_function;\n#else\n\tusing function = unsafe_function;\n\tusing main_function = main_unsafe_function;\n\tusing stack_function = stack_unsafe_function;\n\tusing stack_aligned_function = stack_aligned_unsafe_function;\n#endif\n\tusing stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>;\n\n\tstruct unsafe_function_result;\n\tstruct protected_function_result;\n\tusing safe_function_result = protected_function_result;\n#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)\n\tusing function_result = safe_function_result;\n#else\n\tusing function_result = unsafe_function_result;\n#endif\n\n\ttemplate <typename base_t>\n\tclass basic_object_base;\n\ttemplate <typename base_t>\n\tclass basic_object;\n\ttemplate <typename base_t>\n\tclass basic_userdata;\n\ttemplate <typename base_t>\n\tclass basic_lightuserdata;\n\ttemplate <typename base_t>\n\tclass basic_coroutine;\n\ttemplate <typename base_t>\n\tclass basic_thread;\n\n\tusing object = basic_object<reference>;\n\tusing userdata = basic_userdata<reference>;\n\tusing lightuserdata = basic_lightuserdata<reference>;\n\tusing thread = basic_thread<reference>;\n\tusing coroutine = basic_coroutine<reference>;\n\tusing main_object = basic_object<main_reference>;\n\tusing main_userdata = basic_userdata<main_reference>;\n\tusing main_lightuserdata = basic_lightuserdata<main_reference>;\n\tusing main_coroutine = basic_coroutine<main_reference>;\n\tusing stack_object = basic_object<stack_reference>;\n\tusing stack_userdata = basic_userdata<stack_reference>;\n\tusing stack_lightuserdata = basic_lightuserdata<stack_reference>;\n\tusing stack_thread = basic_thread<stack_reference>;\n\tusing stack_coroutine = basic_coroutine<stack_reference>;\n\n\tstruct stack_proxy_base;\n\tstruct stack_proxy;\n\tstruct variadic_args;\n\tstruct variadic_results;\n\tstruct stack_count;\n\tstruct this_state;\n\tstruct this_main_state;\n\tstruct this_environment;\n\n\tclass state_view;\n\tclass state;\n\n\ttemplate <typename T>\n\tstruct as_table_t;\n\ttemplate <typename T>\n\tstruct as_container_t;\n\ttemplate <typename T>\n\tstruct nested;\n\ttemplate <typename T>\n\tstruct light;\n\ttemplate <typename T>\n\tstruct user;\n\ttemplate <typename T>\n\tstruct as_args_t;\n\ttemplate <typename T>\n\tstruct protect_t;\n\ttemplate <typename F, typename... Policies>\n\tstruct policy_wrapper;\n\n\ttemplate <typename T>\n\tstruct usertype_traits;\n\ttemplate <typename T>\n\tstruct unique_usertype_traits;\n\n\ttemplate <typename... Args>\n\tstruct types {\n\t\ttypedef std::make_index_sequence<sizeof...(Args)> indices;\n\t\tstatic constexpr std::size_t size() {\n\t\t\treturn sizeof...(Args);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct derive : std::false_type {\n\t\ttypedef types<> type;\n\t};\n\n\ttemplate <typename T>\n\tstruct base : std::false_type {\n\t\ttypedef types<> type;\n\t};\n\n\ttemplate <typename T>\n\tstruct weak_derive {\n\t\tstatic bool value;\n\t};\n\n\ttemplate <typename T>\n\tbool weak_derive<T>::value = false;\n\n\tnamespace stack {\n\t\tstruct record;\n\t}\n\n#if SOL_IS_OFF(SOL_USE_BOOST_I_)\n\ttemplate <class T>\n\tclass optional;\n\n\ttemplate <class T>\n\tclass optional<T&>;\n#endif\n\n\tusing check_handler_type = int(lua_State*, int, type, type, const char*);\n\n} // namespace sol\n\n#define SOL_BASE_CLASSES(T, ...)                       \\\n\tnamespace sol {                                   \\\n\t\ttemplate <>                                  \\\n\t\tstruct base<T> : std::true_type {            \\\n\t\t\ttypedef ::sol::types<__VA_ARGS__> type; \\\n\t\t};                                           \\\n\t}                                                 \\\n\tvoid a_sol3_detail_function_decl_please_no_collide()\n#define SOL_DERIVED_CLASSES(T, ...)                    \\\n\tnamespace sol {                                   \\\n\t\ttemplate <>                                  \\\n\t\tstruct derive<T> : std::true_type {          \\\n\t\t\ttypedef ::sol::types<__VA_ARGS__> type; \\\n\t\t};                                           \\\n\t}                                                 \\\n\tvoid a_sol3_detail_function_decl_please_no_collide()\n\n#endif // SOL_FORWARD_HPP\n// end of sol/forward.hpp\n\n#endif // SOL_SINGLE_INCLUDE_FORWARD_HPP\n"
  },
  {
    "path": "deps/sol3/include/sol/sol.hpp",
    "content": "// The MIT License (MIT)\n\n// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\n// this software and associated documentation files (the \"Software\"), to deal in\n// the Software without restriction, including without limitation the rights to\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n// the Software, and to permit persons to whom the Software is furnished to do so,\n// subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// This file was generated with a script.\n// Generated 2020-10-15 05:19:08.128139 UTC\n// This header was generated with sol v3.2.3 (revision e5e6466e)\n// https://github.com/ThePhD/sol2\n\n#ifndef SOL_SINGLE_INCLUDE_HPP\n#define SOL_SINGLE_INCLUDE_HPP\n\n// beginning of sol/sol.hpp\n\n#ifndef SOL_HPP\n#define SOL_HPP\n\n// beginning of sol/version.hpp\n\n#include <sol/config.hpp>\n\n#include <cstdint>\n\n#define SOL_VERSION_MAJOR 3\n#define SOL_VERSION_MINOR 2\n#define SOL_VERSION_PATCH 3\n#define SOL_VERSION_STRING \"3.2.3\"\n#define SOL_VERSION ((SOL_VERSION_MAJOR * 100000) + (SOL_VERSION_MINOR * 100) + (SOL_VERSION_PATCH))\n\n#define SOL_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0)\n#define SOL_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0)\n#define SOL_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3)\n#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0)\n\n#define SOL_ON          |\n#define SOL_OFF         ^\n#define SOL_DEFAULT_ON  +\n#define SOL_DEFAULT_OFF -\n\n#if defined(_MSC_VER)\n\t#define SOL_COMPILER_CLANG_I_ SOL_OFF\n\t#define SOL_COMPILER_GCC_I_   SOL_OFF\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_ON\n#elif defined(__clang__)\n\t#define SOL_COMPILER_CLANG_I_ SOL_ON\n\t#define SOL_COMPILER_GCC_I_   SOL_OFF\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_OFF\n#elif defined(__GNUC__)\n\t#define SOL_COMPILER_CLANG_I_ SOL_OFF\n\t#define SOL_COMPILER_GCC_I_   SOL_ON\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_OFF\n#else\n\t#define SOL_COMPILER_CLANG_I_ SOL_OFF\n\t#define SOL_COMPILER_GCC_I_   SOL_OFF\n\t#define SOL_COMPILER_EDG_I_   SOL_OFF\n\t#define SOL_COMPILER_VCXX_I_  SOL_OFF\n#endif\n\n#if defined(__MINGW32__)\n\t#define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_ON\n#else\n\t#define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_OFF\n#endif\n\n#if SIZE_MAX <= 0xFFFFULL\n\t#define SOL_PLATFORM_X16_I_ SOL_ON\n\t#define SOL_PLATFORM_X86_I_ SOL_OFF\n\t#define SOL_PLATFORM_X64_I_ SOL_OFF\n#elif SIZE_MAX <= 0xFFFFFFFFULL\n\t#define SOL_PLATFORM_X16_I_ SOL_OFF\n\t#define SOL_PLATFORM_X86_I_ SOL_ON\n\t#define SOL_PLATFORM_X64_I_ SOL_OFF\n#else\n\t#define SOL_PLATFORM_X16_I_ SOL_OFF\n\t#define SOL_PLATFORM_X86_I_ SOL_OFF\n\t#define SOL_PLATFORM_X64_I_ SOL_ON\n#endif\n\n#define SOL_PLATFORM_ARM32_I_ SOL_OFF\n#define SOL_PLATFORM_ARM64_I_ SOL_OFF\n\n#if defined(_WIN32)\n\t#define SOL_PLATFORM_WINDOWS_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_WINDOWS_I_ SOL_OFF\n#endif\n#if defined(__APPLE__)\n\t#define SOL_PLATFORM_APPLE_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_APPLE_I_ SOL_OFF\n#endif\n#if defined(__unix__)\n\t#define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF\n#endif\n#if defined(__linux__)\n\t#define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON\n#else\n\t#define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF\n#endif\n\n#define SOL_PLATFORM_APPLE_IPHONE_I_ SOL_OFF\n#define SOL_PLATFORM_BSDLIKE_I_      SOL_OFF\n\n#if defined(SOL_IN_DEBUG_DETECTED)\n\t#if SOL_IN_DEBUG_DETECTED != 0\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_OFF\n\t#endif\n#elif !defined(NDEBUG)\n\t#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) && defined(_DEBUG)\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_ON\n\t#elif (SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)) && !defined(__OPTIMIZE__)\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEBUG_BUILD_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_DEBUG_BUILD_I_ SOL_DEFAULT_OFF\n#endif // We are in a debug mode of some sort\n\n#if defined(SOL_NO_EXCEPTIONS)\n\t#if (SOL_NO_EXCEPTIONS != 0)\n\t\t#define SOL_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t#if !defined(_CPPUNWIND)\n\t\t#define SOL_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)\n\t#if !defined(__EXCEPTIONS)\n\t\t#define SOL_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_EXCEPTIONS_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_NO_RTTI)\n\t#if (SOL_NO_RTTI != 0)\n\t\t#define SOL_RTTI_I_ SOL_OFF\n\t#else\n\t\t#define SOL_RTTI_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t#if !defined(_CPPRTTI)\n\t\t#define SOL_RTTI_I_ SOL_OFF\n\t#else\n\t\t#define SOL_RTTI_I_ SOL_ON\n\t#endif\n#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)\n\t#if !defined(__GXX_RTTI)\n\t\t#define SOL_RTTI_I_ SOL_OFF\n\t#else\n\t\t#define SOL_RTTI_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_RTTI_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_NO_THREAD_LOCAL)\n\t#if SOL_NO_THREAD_LOCAL != 0\n\t\t#define SOL_USE_THREAD_LOCAL_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_THREAD_LOCAL_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_USE_THREAD_LOCAL_I_ SOL_DEFAULT_ON\n#endif // thread_local keyword is bjorked on some platforms\n\n#if defined(SOL_ALL_SAFETIES_ON)\n\t#if SOL_ALL_SAFETIES_ON != 0\n\t\t#define SOL_ALL_SAFETIES_ON_I_ SOL_ON\n\t#else\n\t\t#define SOL_ALL_SAFETIES_ON_I_ SOL_FF\n\t#endif\n#else\n\t#define SOL_ALL_SAFETIES_ON_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_SAFE_GETTER)\n\t#if SOL_SAFE_GETTER != 0\n\t\t#define SOL_SAFE_GETTER_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_GETTER_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_GETTER_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_GETTER_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_GETTER_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_USERTYPE)\n\t#if SOL_SAFE_USERTYPE != 0\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_REFERENCES)\n\t#if SOL_SAFE_REFERENCES != 0\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_FUNCTIONS)\n\t#if SOL_SAFE_FUNCTIONS != 0\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF\n\t#endif\n#elif defined (SOL_SAFE_FUNCTION_OBJECTS)\n\t#if SOL_SAFE_FUNCTION_OBJECTS != 0\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_FUNCTION_CALLS)\n\t#if SOL_SAFE_FUNCTION_CALLS != 0\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_PROXIES)\n\t#if SOL_SAFE_PROXIES != 0\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_NUMERICS)\n\t#if SOL_SAFE_NUMERICS != 0\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_SAFE_STACK_CHECK)\n\t#if SOL_SAFE_STACK_CHECK != 0\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_ON\n\t#else\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_NO_CHECK_NUMBER_PRECISION)\n\t#if SOL_NO_CHECK_NUMBER_PRECISION != 0\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#endif\n#elif defined(SOL_NO_CHECKING_NUMBER_PRECISION)\n\t#if SOL_NO_CHECKING_NUMBER_PRECISION != 0\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_SAFE_NUMERICS_I_)\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_STRINGS_ARE_NUMBERS)\n\t#if (SOL_STRINGS_ARE_NUMBERS != 0)\n\t\t#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_ON\n\t#else\n\t\t#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_ENABLE_INTEROP)\n\t#if SOL_ENABLE_INTEROP != 0\n\t\t#define SOL_USE_INTEROP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_INTEROP_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_USE_INTEROP)\n\t#if SOL_USE_INTEROP != 0\n\t\t#define SOL_USE_INTEROP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_INTEROP_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_INTEROP_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_NO_NIL)\n\t#if (SOL_NO_NIL != 0)\n\t\t#define SOL_NIL_I_ SOL_OFF\n\t#else\n\t\t#define SOL_NIL_I_ SOL_ON\n\t#endif\n#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)\n\t#define SOL_NIL_I_ SOL_DEFAULT_OFF\n#else\n\t#define SOL_NIL_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_USERTYPE_TYPE_BINDING_INFO)\n\t#if (SOL_USERTYPE_TYPE_BINDING_INFO != 0)\n\t\t#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_ON\n\t#else\n\t\t#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_DEFAULT_ON\n#endif // We should generate a my_type.__type table with lots of class information for usertypes\n\n#if defined(SOL_AUTOMAGICAL_TYPES_BY_DEFAULT)\n\t#if (SOL_AUTOMAGICAL_TYPES_BY_DEFAULT != 0)\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_DEFAULT_AUTOMAGICAL_USERTYPES)\n\t#if (SOL_DEFAULT_AUTOMAGICAL_USERTYPES != 0)\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_DEFAULT_ON\n#endif // make is_automagical on/off by default\n\n#if defined(SOL_STD_VARIANT)\n\t#if (SOL_STD_VARIANT != 0)\n\t\t#define SOL_STD_VARIANT_I_ SOL_ON\n\t#else\n\t\t#define SOL_STD_VARIANT_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_COMPILER_CLANG_I_) && SOL_IS_ON(SOL_PLATFORM_APPLE_I_)\n\t\t#if defined(__has_include)\n\t\t\t#if __has_include(<variant>)\n\t\t\t\t#define SOL_STD_VARIANT_I_ SOL_ON\n\t\t\t#else\n\t\t\t\t#define SOL_STD_VARIANT_I_ SOL_OFF\n\t\t\t#endif\n\t\t#else\n\t\t\t#define SOL_STD_VARIANT_I_ SOL_OFF\n\t\t#endif\n\t#else\n\t\t#define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON\n\t#endif\n#endif // make is_automagical on/off by default\n\n#if defined(SOL_NOEXCEPT_FUNCTION_TYPE)\n\t#if (SOL_NOEXCEPT_FUNCTION_TYPE != 0)\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF\n\t#endif\n#else\n\t#if defined(__cpp_noexcept_function_type)\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L))\n\t\t// There is a bug in the VC++ compiler??\n\t\t// on /std:c++latest under x86 conditions (VS 15.5.2),\n\t\t// compiler errors are tossed for noexcept markings being on function types\n\t\t// that are identical in every other way to their non-noexcept marked types function types...\n\t\t// VS 2019: There is absolutely a bug.\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_DEFAULT_ON\n\t#endif\n#endif // noexcept is part of a function's type\n\n#if defined(SOL_STACK_STRING_OPTIMIZATION_SIZE) && SOL_STACK_STRING_OPTIMIZATION_SIZE > 0\n\t#define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ SOL_STACK_STRING_OPTIMIZATION_SIZE\n#else\n\t#define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ 1024\n#endif\n\n#if defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0\n\t#define SOL_ID_SIZE_I_ SOL_ID_SIZE\n#else\n\t#define SOL_ID_SIZE_I_ 512\n#endif\n\n#if defined(LUA_IDSIZE) && LUA_IDSIZE > 0\n\t#define SOL_FILE_ID_SIZE_I_ LUA_IDSIZE\n#elif defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0\n\t#define SOL_FILE_ID_SIZE_I_ SOL_FILE_ID_SIZE\n#else\n\t#define SOL_FILE_ID_SIZE_I_ 2048\n#endif\n\n#if defined(SOL_PRINT_ERRORS)\n\t#if (SOL_PRINT_ERRORS != 0)\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_ON\n\t#else\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_ON\n\t#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_PRINT_ERRORS_I_ SOL_OFF\n\t#endif\n#endif\n\n#if defined(SOL_DEFAULT_PASS_ON_ERROR)\n\t#if (SOL_DEFAULT_PASS_ON_ERROR != 0)\n\t\t#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON\n\t#else\n\t\t#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_OFF\n#endif\n\n#if defined(SOL_USING_CXX_LUA)\n\t#if (SOL_USING_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_USE_CXX_LUA)\n\t#if (SOL_USE_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUA_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_CXX_LUA_I_ SOL_OFF\n#endif\n\n#if defined(SOL_USING_CXX_LUAJIT)\n\t#if (SOL_USING_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF\n\t#endif\n#elif defined(SOL_USE_CXX_LUAJIT)\n\t#if (SOL_USE_CXX_LUA != 0)\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF\n#endif\n\n#if defined(SOL_NO_LUA_HPP)\n\t#if (SOL_NO_LUA_HPP != 0)\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_ON\n\t#endif\n#elif defined(SOL_USING_CXX_LUA)\n\t#define SOL_USE_LUA_HPP_I_ SOL_OFF\n#elif defined(__has_include)\n\t#if __has_include(<lua.hpp>)\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_LUA_HPP_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_LUA_HPP_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_CONTAINERS_START)\n\t#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START\n#elif defined(SOL_CONTAINERS_START_INDEX)\n\t#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START_INDEX\n#elif defined(SOL_CONTAINER_START_INDEX)\n\t#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINER_START_INDEX\n#else\n\t#define SOL_CONTAINER_START_INDEX_I_ 1\n#endif\n\n#if defined (SOL_NO_MEMORY_ALIGNMENT)\n\t#if (SOL_NO_MEMORY_ALIGNMENT != 0)\n\t\t#define SOL_ALIGN_MEMORY_I_ SOL_OFF\n\t#else\n\t\t#define SOL_ALIGN_MEMORY_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_ALIGN_MEMORY_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_USE_BOOST)\n\t#if (SOL_USE_BOOST != 0)\n\t\t#define SOL_USE_BOOST_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_BOOST_I_ SOL_OFF\n\t#endif\n#else\n\t\t#define SOL_USE_BOOST_I_ SOL_OFF\n#endif\n\n#if defined(SOL_USE_UNSAFE_BASE_LOOKUP)\n\t#if (SOL_USE_UNSAFE_BASE_LOOKUP != 0)\n\t\t#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF\n#endif\n\n#if defined(SOL_INSIDE_UNREAL)\n\t#if (SOL_INSIDE_UNREAL != 0)\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON\n\t#else\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_OFF\n\t#endif\n#else\n\t#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER)\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON\n\t#else\n\t\t#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_NO_COMPAT)\n\t#if (SOL_NO_COMPAT != 0)\n\t\t#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_OFF\n\t#else\n\t\t#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_ON\n\t#endif\n#else\n\t#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_DEFAULT_ON\n#endif\n\n#if defined(SOL_GET_FUNCTION_POINTER_UNSAFE)\n\t#if (SOL_GET_FUNCTION_POINTER_UNSAFE != 0)\n\t\t#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_ON\n\t#else\n\t\t#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_OFF\n\t#endif\n#else\n\t#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_DEFAULT_OFF\n#endif\n\n#if SOL_IS_ON(SOL_COMPILER_FRONTEND_MINGW_I_) && defined(__GNUC__) && (__GNUC__ < 6)\n\t// MinGW is off its rocker in some places...\n\t#define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON\n#else\n\t#define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_OFF\n#endif\n\n// end of sol/version.hpp\n\n#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE_I_)\n#ifdef check\n#pragma push_macro(\"check\")\n#undef check\n#endif\n#endif // Unreal Engine 4 Bullshit\n\n#if SOL_IS_ON(SOL_COMPILER_GCC_I_)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wshadow\"\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#if __GNUC__ > 6\n#pragma GCC diagnostic ignored \"-Wnoexcept-type\"\n#endif\n#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_)\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n#pragma warning(push)\n#pragma warning(disable : 4505) // unreferenced local function has been removed GEE THANKS\n#endif                          // clang++ vs. g++ vs. VC++\n\n// beginning of sol/forward.hpp\n\n#ifndef SOL_FORWARD_HPP\n#define SOL_FORWARD_HPP\n\n#include <utility>\n#include <type_traits>\n#include <string_view>\n\n#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) || SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_)\nstruct lua_State;\n#else\nextern \"C\" {\nstruct lua_State;\n}\n#endif // C++ Mangling for Lua vs. Not\n\nnamespace sol {\n\n\tenum class type;\n\n\tclass stateless_reference;\n\ttemplate <bool b>\n\tclass basic_reference;\n\tusing reference = basic_reference<false>;\n\tusing main_reference = basic_reference<true>;\n\tclass stateless_stack_reference;\n\tclass stack_reference;\n\n\ttemplate <typename A>\n\tclass basic_bytecode;\n\n\tstruct lua_value;\n\n\tstruct proxy_base_tag;\n\ttemplate <typename>\n\tstruct proxy_base;\n\ttemplate <typename, typename>\n\tstruct table_proxy;\n\n\ttemplate <bool, typename>\n\tclass basic_table_core;\n\ttemplate <bool b>\n\tusing table_core = basic_table_core<b, reference>;\n\ttemplate <bool b>\n\tusing main_table_core = basic_table_core<b, main_reference>;\n\ttemplate <bool b>\n\tusing stack_table_core = basic_table_core<b, stack_reference>;\n\ttemplate <typename base_type>\n\tusing basic_table = basic_table_core<false, base_type>;\n\tusing table = table_core<false>;\n\tusing global_table = table_core<true>;\n\tusing main_table = main_table_core<false>;\n\tusing main_global_table = main_table_core<true>;\n\tusing stack_table = stack_table_core<false>;\n\tusing stack_global_table = stack_table_core<true>;\n\n\ttemplate <typename>\n\tstruct basic_lua_table;\n\tusing lua_table = basic_lua_table<reference>;\n\tusing stack_lua_table = basic_lua_table<stack_reference>;\n\n\ttemplate <typename T, typename base_type>\n\tclass basic_usertype;\n\ttemplate <typename T>\n\tusing usertype = basic_usertype<T, reference>;\n\ttemplate <typename T>\n\tusing stack_usertype = basic_usertype<T, stack_reference>;\n\n\ttemplate <typename base_type>\n\tclass basic_metatable;\n\tusing metatable = basic_metatable<reference>;\n\tusing stack_metatable = basic_metatable<stack_reference>;\n\n\ttemplate <typename base_t>\n\tstruct basic_environment;\n\tusing environment = basic_environment<reference>;\n\tusing main_environment = basic_environment<main_reference>;\n\tusing stack_environment = basic_environment<stack_reference>;\n\n\ttemplate <typename T, bool>\n\tclass basic_function;\n\ttemplate <typename T, bool, typename H>\n\tclass basic_protected_function;\n\tusing unsafe_function = basic_function<reference, false>;\n\tusing safe_function = basic_protected_function<reference, false, reference>;\n\tusing main_unsafe_function = basic_function<main_reference, false>;\n\tusing main_safe_function = basic_protected_function<main_reference, false, reference>;\n\tusing stack_unsafe_function = basic_function<stack_reference, false>;\n\tusing stack_safe_function = basic_protected_function<stack_reference, false, reference>;\n\tusing stack_aligned_unsafe_function = basic_function<stack_reference, true>;\n\tusing stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>;\n\tusing protected_function = safe_function;\n\tusing main_protected_function = main_safe_function;\n\tusing stack_protected_function = stack_safe_function;\n\tusing stack_aligned_protected_function = stack_aligned_safe_function;\n#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)\n\tusing function = protected_function;\n\tusing main_function = main_protected_function;\n\tusing stack_function = stack_protected_function;\n\tusing stack_aligned_function = stack_aligned_safe_function;\n#else\n\tusing function = unsafe_function;\n\tusing main_function = main_unsafe_function;\n\tusing stack_function = stack_unsafe_function;\n\tusing stack_aligned_function = stack_aligned_unsafe_function;\n#endif\n\tusing stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>;\n\n\tstruct unsafe_function_result;\n\tstruct protected_function_result;\n\tusing safe_function_result = protected_function_result;\n#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)\n\tusing function_result = safe_function_result;\n#else\n\tusing function_result = unsafe_function_result;\n#endif\n\n\ttemplate <typename base_t>\n\tclass basic_object_base;\n\ttemplate <typename base_t>\n\tclass basic_object;\n\ttemplate <typename base_t>\n\tclass basic_userdata;\n\ttemplate <typename base_t>\n\tclass basic_lightuserdata;\n\ttemplate <typename base_t>\n\tclass basic_coroutine;\n\ttemplate <typename base_t>\n\tclass basic_thread;\n\n\tusing object = basic_object<reference>;\n\tusing userdata = basic_userdata<reference>;\n\tusing lightuserdata = basic_lightuserdata<reference>;\n\tusing thread = basic_thread<reference>;\n\tusing coroutine = basic_coroutine<reference>;\n\tusing main_object = basic_object<main_reference>;\n\tusing main_userdata = basic_userdata<main_reference>;\n\tusing main_lightuserdata = basic_lightuserdata<main_reference>;\n\tusing main_coroutine = basic_coroutine<main_reference>;\n\tusing stack_object = basic_object<stack_reference>;\n\tusing stack_userdata = basic_userdata<stack_reference>;\n\tusing stack_lightuserdata = basic_lightuserdata<stack_reference>;\n\tusing stack_thread = basic_thread<stack_reference>;\n\tusing stack_coroutine = basic_coroutine<stack_reference>;\n\n\tstruct stack_proxy_base;\n\tstruct stack_proxy;\n\tstruct variadic_args;\n\tstruct variadic_results;\n\tstruct stack_count;\n\tstruct this_state;\n\tstruct this_main_state;\n\tstruct this_environment;\n\n\tclass state_view;\n\tclass state;\n\n\ttemplate <typename T>\n\tstruct as_table_t;\n\ttemplate <typename T>\n\tstruct as_container_t;\n\ttemplate <typename T>\n\tstruct nested;\n\ttemplate <typename T>\n\tstruct light;\n\ttemplate <typename T>\n\tstruct user;\n\ttemplate <typename T>\n\tstruct as_args_t;\n\ttemplate <typename T>\n\tstruct protect_t;\n\ttemplate <typename F, typename... Policies>\n\tstruct policy_wrapper;\n\n\ttemplate <typename T>\n\tstruct usertype_traits;\n\ttemplate <typename T>\n\tstruct unique_usertype_traits;\n\n\ttemplate <typename... Args>\n\tstruct types {\n\t\ttypedef std::make_index_sequence<sizeof...(Args)> indices;\n\t\tstatic constexpr std::size_t size() {\n\t\t\treturn sizeof...(Args);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct derive : std::false_type {\n\t\ttypedef types<> type;\n\t};\n\n\ttemplate <typename T>\n\tstruct base : std::false_type {\n\t\ttypedef types<> type;\n\t};\n\n\ttemplate <typename T>\n\tstruct weak_derive {\n\t\tstatic bool value;\n\t};\n\n\ttemplate <typename T>\n\tbool weak_derive<T>::value = false;\n\n\tnamespace stack {\n\t\tstruct record;\n\t}\n\n#if SOL_IS_OFF(SOL_USE_BOOST_I_)\n\ttemplate <class T>\n\tclass optional;\n\n\ttemplate <class T>\n\tclass optional<T&>;\n#endif\n\n\tusing check_handler_type = int(lua_State*, int, type, type, const char*);\n\n} // namespace sol\n\n#define SOL_BASE_CLASSES(T, ...)                       \\\n\tnamespace sol {                                   \\\n\t\ttemplate <>                                  \\\n\t\tstruct base<T> : std::true_type {            \\\n\t\t\ttypedef ::sol::types<__VA_ARGS__> type; \\\n\t\t};                                           \\\n\t}                                                 \\\n\tvoid a_sol3_detail_function_decl_please_no_collide()\n#define SOL_DERIVED_CLASSES(T, ...)                    \\\n\tnamespace sol {                                   \\\n\t\ttemplate <>                                  \\\n\t\tstruct derive<T> : std::true_type {          \\\n\t\t\ttypedef ::sol::types<__VA_ARGS__> type; \\\n\t\t};                                           \\\n\t}                                                 \\\n\tvoid a_sol3_detail_function_decl_please_no_collide()\n\n#endif // SOL_FORWARD_HPP\n// end of sol/forward.hpp\n\n// beginning of sol/forward_detail.hpp\n\n#ifndef SOL_FORWARD_DETAIL_HPP\n#define SOL_FORWARD_DETAIL_HPP\n\n// beginning of sol/traits.hpp\n\n// beginning of sol/tuple.hpp\n\n// beginning of sol/base_traits.hpp\n\n#include <type_traits>\n\nnamespace sol {\n\tnamespace detail {\n\t\tstruct unchecked_t {};\n\t\tconst unchecked_t unchecked = unchecked_t{};\n\t} // namespace detail\n\n\tnamespace meta {\n\t\tusing sfinae_yes_t = std::true_type;\n\t\tusing sfinae_no_t = std::false_type;\n\n\t\ttemplate <typename T>\n\t\tusing void_t = void;\n\n\t\ttemplate <typename T>\n\t\tusing unqualified = std::remove_cv<std::remove_reference_t<T>>;\n\n\t\ttemplate <typename T>\n\t\tusing unqualified_t = typename unqualified<T>::type;\n\n\t\tnamespace meta_detail {\n\t\t\ttemplate <typename T>\n\t\t\tstruct unqualified_non_alias : unqualified<T> {};\n\n\t\t\ttemplate <template <class...> class Test, class, class... Args>\n\t\t\tstruct is_detected : std::false_type {};\n\n\t\t\ttemplate <template <class...> class Test, class... Args>\n\t\t\tstruct is_detected<Test, void_t<Test<Args...>>, Args...> : std::true_type {};\n\t\t} // namespace meta_detail\n\n\t\ttemplate <template <class...> class Trait, class... Args>\n\t\tusing is_detected = typename meta_detail::is_detected<Trait, void, Args...>::type;\n\n\t\ttemplate <template <class...> class Trait, class... Args>\n\t\tconstexpr inline bool is_detected_v = is_detected<Trait, Args...>::value;\n\n\t\ttemplate <std::size_t I>\n\t\tusing index_value = std::integral_constant<std::size_t, I>;\n\n\t\ttemplate <bool>\n\t\tstruct conditional {\n\t\t\ttemplate <typename T, typename U>\n\t\t\tusing type = T;\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct conditional<false> {\n\t\t\ttemplate <typename T, typename U>\n\t\t\tusing type = U;\n\t\t};\n\n\t\ttemplate <bool B, typename T, typename U>\n\t\tusing conditional_t = typename conditional<B>::template type<T, U>;\n\n\t\tnamespace meta_detail {\n\t\t\ttemplate <typename T, template <typename...> class Templ>\n\t\t\tstruct is_specialization_of : std::false_type {};\n\t\t\ttemplate <typename... T, template <typename...> class Templ>\n\t\t\tstruct is_specialization_of<Templ<T...>, Templ> : std::true_type {};\n\t\t} // namespace meta_detail\n\n\t\ttemplate <typename T, template <typename...> class Templ>\n\t\tusing is_specialization_of = meta_detail::is_specialization_of<std::remove_cv_t<T>, Templ>;\n\n\t\ttemplate <typename T, template <typename...> class Templ>\n\t\tinline constexpr bool is_specialization_of_v = is_specialization_of<std::remove_cv_t<T>, Templ>::value;\n\n\t\ttemplate <typename T>\n\t\tstruct identity {\n\t\t\ttypedef T type;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tusing identity_t = typename identity<T>::type;\n\n\t\ttemplate <typename T>\n\t\tusing is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>;\n\n\t} // namespace meta\n} // namespace sol\n\n// end of sol/base_traits.hpp\n\n#include <tuple>\n#include <cstddef>\n\nnamespace sol {\n\tnamespace detail {\n\t\tusing swallow = std::initializer_list<int>;\n\t} // namespace detail\n\n\tnamespace meta {\n\t\ttemplate <typename T>\n\t\tusing is_tuple = is_specialization_of<T, std::tuple>;\n\n\t\ttemplate <typename T>\n\t\tconstexpr inline bool is_tuple_v = is_tuple<T>::value;\n\n\t\tnamespace detail {\n\t\t\ttemplate <typename... Args>\n\t\t\tstruct tuple_types_ { typedef types<Args...> type; };\n\n\t\t\ttemplate <typename... Args>\n\t\t\tstruct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; };\n\t\t} // namespace detail\n\n\t\ttemplate <typename... Args>\n\t\tusing tuple_types = typename detail::tuple_types_<Args...>::type;\n\n\t\ttemplate <typename Arg>\n\t\tstruct pop_front_type;\n\n\t\ttemplate <typename Arg>\n\t\tusing pop_front_type_t = typename pop_front_type<Arg>::type;\n\n\t\ttemplate <typename... Args>\n\t\tstruct pop_front_type<types<Args...>> {\n\t\t\ttypedef void front_type;\n\t\t\ttypedef types<Args...> type;\n\t\t};\n\n\t\ttemplate <typename Arg, typename... Args>\n\t\tstruct pop_front_type<types<Arg, Args...>> {\n\t\t\ttypedef Arg front_type;\n\t\t\ttypedef types<Args...> type;\n\t\t};\n\n\t\ttemplate <std::size_t N, typename Tuple>\n\t\tusing tuple_element = std::tuple_element<N, std::remove_reference_t<Tuple>>;\n\n\t\ttemplate <std::size_t N, typename Tuple>\n\t\tusing tuple_element_t = std::tuple_element_t<N, std::remove_reference_t<Tuple>>;\n\n\t\ttemplate <std::size_t N, typename Tuple>\n\t\tusing unqualified_tuple_element = unqualified<tuple_element_t<N, Tuple>>;\n\n\t\ttemplate <std::size_t N, typename Tuple>\n\t\tusing unqualified_tuple_element_t = unqualified_t<tuple_element_t<N, Tuple>>;\n\n\t} // namespace meta\n} // namespace sol\n\n// end of sol/tuple.hpp\n\n// beginning of sol/bind_traits.hpp\n\nnamespace sol { namespace meta {\n\tnamespace meta_detail {\n\n\t\ttemplate <class F>\n\t\tstruct check_deducible_signature {\n\t\t\tstruct nat {};\n\t\t\ttemplate <class G>\n\t\t\tstatic auto test(int) -> decltype(&G::operator(), void());\n\t\t\ttemplate <class>\n\t\t\tstatic auto test(...) -> nat;\n\n\t\t\tusing type = std::is_void<decltype(test<F>(0))>;\n\t\t};\n\t} // namespace meta_detail\n\n\ttemplate <class F>\n\tstruct has_deducible_signature : meta_detail::check_deducible_signature<F>::type {};\n\n\tnamespace meta_detail {\n\n\t\ttemplate <std::size_t I, typename T>\n\t\tstruct void_tuple_element : meta::tuple_element<I, T> {};\n\n\t\ttemplate <std::size_t I>\n\t\tstruct void_tuple_element<I, std::tuple<>> {\n\t\t\ttypedef void type;\n\t\t};\n\n\t\ttemplate <std::size_t I, typename T>\n\t\tusing void_tuple_element_t = typename void_tuple_element<I, T>::type;\n\n\t\ttemplate <bool it_is_noexcept, bool has_c_variadic, typename T, typename R, typename... Args>\n\t\tstruct basic_traits {\n\t\tprivate:\n\t\t\tusing first_type = meta::conditional_t<std::is_void<T>::value, int, T>&;\n\n\t\tpublic:\n\t\t\tinline static constexpr const bool is_noexcept = it_is_noexcept;\n\t\t\tinline static constexpr bool is_member_function = std::is_void<T>::value;\n\t\t\tinline static constexpr bool has_c_var_arg = has_c_variadic;\n\t\t\tinline static constexpr std::size_t arity = sizeof...(Args);\n\t\t\tinline static constexpr std::size_t free_arity = sizeof...(Args) + static_cast<std::size_t>(!std::is_void<T>::value);\n\t\t\ttypedef types<Args...> args_list;\n\t\t\ttypedef std::tuple<Args...> args_tuple;\n\t\t\ttypedef T object_type;\n\t\t\ttypedef R return_type;\n\t\t\ttypedef tuple_types<R> returns_list;\n\t\t\ttypedef R(function_type)(Args...);\n\t\t\ttypedef meta::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list;\n\t\t\ttypedef meta::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type;\n\t\t\ttypedef meta::conditional_t<std::is_void<T>::value, R (*)(Args...), R (*)(first_type, Args...)> free_function_pointer_type;\n\t\t\ttypedef std::remove_pointer_t<free_function_pointer_type> signature_type;\n\t\t\ttemplate <std::size_t i>\n\t\t\tusing arg_at = void_tuple_element_t<i, args_tuple>;\n\t\t};\n\n\t\ttemplate <typename Signature, bool b = has_deducible_signature<Signature>::value>\n\t\tstruct fx_traits : basic_traits<false, false, void, void> {};\n\n\t\t// Free Functions\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R(Args...), false> : basic_traits<false, false, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args...);\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R (*)(Args...), false> : basic_traits<false, false, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args...);\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R(Args..., ...), false> : basic_traits<false, true, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args..., ...);\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R (*)(Args..., ...), false> : basic_traits<false, true, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args..., ...);\n\t\t};\n\n\t\t// Member Functions\n\t\t/* C-Style Variadics */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...);\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...), false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...);\n\t\t};\n\n\t\t/* Const Volatile */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const volatile;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const volatile, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const volatile;\n\t\t};\n\n\t\t/* Member Function Qualifiers */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...)&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) &;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...)&, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) &;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const&, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const volatile&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const volatile&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const volatile&, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const volatile&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...)&&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) &&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...)&&, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) &&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const&&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const&&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const&&, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const&&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const volatile&&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const volatile&&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const volatile&&, false> : basic_traits<false, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const volatile&&;\n\t\t};\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args...) noexcept;\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R (*)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args...) noexcept;\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args..., ...) noexcept;\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R (*)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> {\n\t\t\ttypedef R (*function_pointer_type)(Args..., ...) noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) noexcept;\n\t\t};\n\n\t\t/* Const Volatile */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const volatile noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const volatile noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) & noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) & noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const volatile& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const volatile& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const volatile& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const volatile& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) && noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) && noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const&& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const&& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const&& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const&& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args...) const volatile&& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args...) const volatile&& noexcept;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (T::*)(Args..., ...) const volatile&& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (T::*function_pointer_type)(Args..., ...) const volatile&& noexcept;\n\t\t};\n\n#endif // noexcept is part of a function's type\n\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) && SOL_IS_ON(SOL_PLATFORM_X86_I_)\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R __stdcall(Args...), false> : basic_traits<false, false, void, R, Args...> {\n\t\t\ttypedef R(__stdcall* function_pointer_type)(Args...);\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R(__stdcall*)(Args...), false> : basic_traits<false, false, void, R, Args...> {\n\t\t\ttypedef R(__stdcall* function_pointer_type)(Args...);\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...);\n\t\t};\n\n\t\t/* Const Volatile */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const volatile;\n\t\t};\n\n\t\t/* Member Function Qualifiers */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...)&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) &;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const volatile&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...)&&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) &&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const&&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const&&;\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const volatile&&, false> : basic_traits<false, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&&;\n\t\t};\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R __stdcall(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> {\n\t\t\ttypedef R(__stdcall* function_pointer_type)(Args...) noexcept;\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R(__stdcall*)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> {\n\t\t\ttypedef R(__stdcall* function_pointer_type)(Args...) noexcept;\n\t\t};\n\n\t\t/* __stdcall cannot be applied to functions with varargs*/\n\t\t/*template <typename R, typename... Args>\n\t\tstruct fx_traits<__stdcall R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> {\n\t\t\ttypedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept;\n\t\t};\n\n\t\ttemplate <typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall *)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> {\n\t\t\ttypedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) noexcept;\n\t\t};*/\n\n\t\t/* Const Volatile */\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) const noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const volatile noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) & noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) & noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const& noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) const& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) const& noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const volatile& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const volatile& noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile& noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) && noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) && noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const&& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const&& noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) const&& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) const&& noexcept;\n\t\t};*/\n\n\t\ttemplate <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args...) const volatile&& noexcept, false> : basic_traits<true, false, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&& noexcept;\n\t\t};\n\n\t\t/* __stdcall does not work with varargs */\n\t\t/*template <typename T, typename R, typename... Args>\n\t\tstruct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile&& noexcept, false> : basic_traits<true, true, T, R, Args...> {\n\t\t\ttypedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile&& noexcept;\n\t\t};*/\n#endif // noexcept is part of a function's type\n#endif // __stdcall x86 VC++ bug\n\n\t\ttemplate <typename Signature>\n\t\tstruct fx_traits<Signature, true>\n\t\t: public fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};\n\n\t\ttemplate <typename Signature, bool b = std::is_member_object_pointer<Signature>::value>\n\t\tstruct callable_traits\n\t\t: public fx_traits<std::decay_t<Signature>> {};\n\n\t\ttemplate <typename R, typename T>\n\t\tstruct callable_traits<R(T::*), true> {\n\t\t\ttypedef meta::conditional_t<std::is_array_v<R>, std::add_lvalue_reference_t<R>, R> return_type;\n\t\t\ttypedef return_type Arg;\n\t\t\ttypedef T object_type;\n\t\t\tusing signature_type = R(T::*);\n\t\t\tinline static constexpr bool is_noexcept = false;\n\t\t\tinline static constexpr bool is_member_function = false;\n\t\t\tinline static constexpr std::size_t arity = 1;\n\t\t\tinline static constexpr std::size_t free_arity = 2;\n\t\t\ttypedef std::tuple<Arg> args_tuple;\n\t\t\ttypedef types<Arg> args_list;\n\t\t\ttypedef types<T, Arg> free_args_list;\n\t\t\ttypedef meta::tuple_types<return_type> returns_list;\n\t\t\ttypedef return_type(function_type)(T&, return_type);\n\t\t\ttypedef return_type (*function_pointer_type)(T&, Arg);\n\t\t\ttypedef return_type (*free_function_pointer_type)(T&, Arg);\n\t\t\ttemplate <std::size_t i>\n\t\t\tusing arg_at = void_tuple_element_t<i, args_tuple>;\n\t\t};\n\n\t} // namespace meta_detail\n\n\ttemplate <typename Signature>\n\tstruct bind_traits : meta_detail::callable_traits<Signature> {};\n\n\ttemplate <typename Signature>\n\tusing function_args_t = typename bind_traits<Signature>::args_list;\n\n\ttemplate <typename Signature>\n\tusing function_signature_t = typename bind_traits<Signature>::signature_type;\n\n\ttemplate <typename Signature>\n\tusing function_return_t = typename bind_traits<Signature>::return_type;\n}} // namespace sol::meta\n\n// end of sol/bind_traits.hpp\n\n// beginning of sol/pointer_like.hpp\n\n#include <utility>\n#include <type_traits>\n\nnamespace sol {\n\n\tnamespace meta {\n\t\tnamespace meta_detail {\n\t\t\ttemplate <typename T>\n\t\t\tusing is_dereferenceable_test = decltype(*std::declval<T>());\n\n\t\t\ttemplate <typename T>\n\t\t\tusing is_explicitly_dereferenceable_test = decltype(std::declval<T>().operator*());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusing is_pointer_like = std::integral_constant<bool, !std::is_array_v<T> && (std::is_pointer_v<T> || is_detected_v<meta_detail::is_explicitly_dereferenceable_test, T>)>;\n\n\t\ttemplate <typename T>\n\t\tconstexpr inline bool is_pointer_like_v = is_pointer_like<T>::value;\n\t} // namespace meta\n\n\tnamespace detail {\n\n\t\ttemplate <typename T>\n\t\tauto unwrap(T&& item) -> decltype(std::forward<T>(item)) {\n\t\t\treturn std::forward<T>(item);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tT& unwrap(std::reference_wrapper<T> arg) {\n\t\t\treturn arg.get();\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline decltype(auto) deref(T&& item) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::is_pointer_like_v<Tu>) {\n\t\t\t\treturn *std::forward<T>(item);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn std::forward<T>(item);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline decltype(auto) deref_move_only(T&& item) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu> && !std::is_copy_constructible_v<Tu>) {\n\t\t\t\treturn *std::forward<T>(item);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn std::forward<T>(item);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline T* ptr(T& val) {\n\t\t\treturn std::addressof(val);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline T* ptr(std::reference_wrapper<T> val) {\n\t\t\treturn std::addressof(val.get());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline T* ptr(T* val) {\n\t\t\treturn val;\n\t\t}\n\t} // namespace detail\n} // namespace sol\n\n// end of sol/pointer_like.hpp\n\n// beginning of sol/string_view.hpp\n\n#include <cstddef>\n#include <string>\n#include <string_view>\n#include <functional>\n\nnamespace sol {\n\ttemplate <typename C, typename T = std::char_traits<C>>\n\tusing basic_string_view = std::basic_string_view<C, T>;\n\n\ttypedef std::string_view string_view;\n\ttypedef std::wstring_view wstring_view;\n\ttypedef std::u16string_view u16string_view;\n\ttypedef std::u32string_view u32string_view;\n\ttypedef std::hash<std::string_view> string_view_hash;\n} // namespace sol\n\n// end of sol/string_view.hpp\n\n#include <type_traits>\n#include <cstdint>\n#include <memory>\n#include <functional>\n#include <array>\n#include <iterator>\n#include <iosfwd>\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n#include <variant>\n#endif // variant is weird on XCode, thanks XCode\n\nnamespace sol { namespace meta {\n\ttemplate <typename T>\n\tstruct unwrapped {\n\t\ttypedef T type;\n\t};\n\n\ttemplate <typename T>\n\tstruct unwrapped<std::reference_wrapper<T>> {\n\t\ttypedef T type;\n\t};\n\n\ttemplate <typename T>\n\tusing unwrapped_t = typename unwrapped<T>::type;\n\n\ttemplate <typename T>\n\tstruct unwrap_unqualified : unwrapped<unqualified_t<T>> {};\n\n\ttemplate <typename T>\n\tusing unwrap_unqualified_t = typename unwrap_unqualified<T>::type;\n\n\ttemplate <typename T>\n\tstruct remove_member_pointer;\n\n\ttemplate <typename R, typename T>\n\tstruct remove_member_pointer<R T::*> {\n\t\ttypedef R type;\n\t};\n\n\ttemplate <typename R, typename T>\n\tstruct remove_member_pointer<R T::*const> {\n\t\ttypedef R type;\n\t};\n\n\ttemplate <typename T>\n\tusing remove_member_pointer_t = remove_member_pointer<T>;\n\n\ttemplate <typename T, typename...>\n\tstruct all_same : std::true_type {};\n\n\ttemplate <typename T, typename U, typename... Args>\n\tstruct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> {};\n\n\ttemplate <typename T, typename...>\n\tstruct any_same : std::false_type {};\n\n\ttemplate <typename T, typename U, typename... Args>\n\tstruct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> {};\n\n\ttemplate <typename T, typename... Args>\n\tconstexpr inline bool any_same_v = any_same<T, Args...>::value;\n\n\ttemplate <bool B>\n\tusing boolean = std::integral_constant<bool, B>;\n\n\ttemplate <bool B>\n\tconstexpr inline bool boolean_v = boolean<B>::value;\n\n\ttemplate <typename T>\n\tusing neg = boolean<!T::value>;\n\n\ttemplate <typename T>\n\tconstexpr inline bool neg_v = neg<T>::value;\n\n\ttemplate <typename... Args>\n\tstruct all : boolean<true> {};\n\n\ttemplate <typename T, typename... Args>\n\tstruct all<T, Args...> : std::conditional_t<T::value, all<Args...>, boolean<false>> {};\n\n\ttemplate <typename... Args>\n\tstruct any : boolean<false> {};\n\n\ttemplate <typename T, typename... Args>\n\tstruct any<T, Args...> : std::conditional_t<T::value, boolean<true>, any<Args...>> {};\n\n\ttemplate <typename T, typename... Args>\n\tconstexpr inline bool all_v = all<T, Args...>::value;\n\n\ttemplate <typename T, typename... Args>\n\tconstexpr inline bool any_v = any<T, Args...>::value;\n\n\tenum class enable_t { _ };\n\n\tconstexpr const auto enabler = enable_t::_;\n\n\ttemplate <bool value, typename T = void>\n\tusing disable_if_t = std::enable_if_t<!value, T>;\n\n\ttemplate <typename... Args>\n\tusing enable = std::enable_if_t<all<Args...>::value, enable_t>;\n\n\ttemplate <typename... Args>\n\tusing disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>;\n\n\ttemplate <typename... Args>\n\tusing enable_any = std::enable_if_t<any<Args...>::value, enable_t>;\n\n\ttemplate <typename... Args>\n\tusing disable_any = std::enable_if_t<neg<any<Args...>>::value, enable_t>;\n\n\ttemplate <typename V, typename... Vs>\n\tstruct find_in_pack_v : boolean<false> {};\n\n\ttemplate <typename V, typename Vs1, typename... Vs>\n\tstruct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> {};\n\n\tnamespace meta_detail {\n\t\ttemplate <std::size_t I, typename T, typename... Args>\n\t\tstruct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> {};\n\n\t\ttemplate <std::size_t I, typename T, typename T1, typename... Args>\n\t\tstruct index_in_pack<I, T, T1, Args...>\n\t\t: conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> {};\n\t} // namespace meta_detail\n\n\ttemplate <typename T, typename... Args>\n\tstruct index_in_pack : meta_detail::index_in_pack<0, T, Args...> {};\n\n\ttemplate <typename T, typename List>\n\tstruct index_in : meta_detail::index_in_pack<0, T, List> {};\n\n\ttemplate <typename T, typename... Args>\n\tstruct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> {};\n\n\ttemplate <std::size_t I, typename... Args>\n\tstruct at_in_pack {};\n\n\ttemplate <std::size_t I, typename... Args>\n\tusing at_in_pack_t = typename at_in_pack<I, Args...>::type;\n\n\ttemplate <std::size_t I, typename Arg, typename... Args>\n\tstruct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> {};\n\n\ttemplate <typename Arg, typename... Args>\n\tstruct at_in_pack<0, Arg, Args...> {\n\t\ttypedef Arg type;\n\t};\n\n\tnamespace meta_detail {\n\t\ttemplate <typename, typename TI>\n\t\tusing on_even = meta::boolean<(TI::value % 2) == 0>;\n\n\t\ttemplate <typename, typename TI>\n\t\tusing on_odd = meta::boolean<(TI::value % 2) == 1>;\n\n\t\ttemplate <typename, typename>\n\t\tusing on_always = std::true_type;\n\n\t\ttemplate <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename... Ts>\n\t\tstruct count_when_for_pack : std::integral_constant<std::size_t, 0> {};\n\t\ttemplate <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename T, typename... Ts>\n\t\t\t          struct count_when_for_pack<When, Limit, I, Pred, T, Ts...> : conditional_t < sizeof...(Ts)\n\t\t\t     == 0\n\t\t\t|| Limit<2, std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>,\n\t\t\t     count_when_for_pack<When, Limit - static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value),\n\t\t\t          I + static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value&& Pred<T>::value), Pred, Ts...>> {};\n\t} // namespace meta_detail\n\n\ttemplate <template <typename...> class Pred, typename... Ts>\n\tstruct count_for_pack : meta_detail::count_when_for_pack<meta_detail::on_always, sizeof...(Ts), 0, Pred, Ts...> {};\n\n\ttemplate <template <typename...> class Pred, typename... Ts>\n\tinline constexpr std::size_t count_for_pack_v = count_for_pack<Pred, Ts...>::value;\n\n\ttemplate <template <typename...> class Pred, typename List>\n\tstruct count_for;\n\n\ttemplate <template <typename...> class Pred, typename... Args>\n\tstruct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> {};\n\n\ttemplate <std::size_t Limit, template <typename...> class Pred, typename... Ts>\n\tstruct count_for_to_pack : meta_detail::count_when_for_pack<meta_detail::on_always, Limit, 0, Pred, Ts...> {};\n\n\ttemplate <std::size_t Limit, template <typename...> class Pred, typename... Ts>\n\tinline constexpr std::size_t count_for_to_pack_v = count_for_to_pack<Limit, Pred, Ts...>::value;\n\n\ttemplate <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts>\n\tstruct count_when_for_to_pack : meta_detail::count_when_for_pack<When, Limit, 0, Pred, Ts...> {};\n\n\ttemplate <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts>\n\tinline constexpr std::size_t count_when_for_to_pack_v = count_when_for_to_pack<When, Limit, Pred, Ts...>::value;\n\n\ttemplate <template <typename...> class Pred, typename... Ts>\n\tusing count_even_for_pack = count_when_for_to_pack<meta_detail::on_even, sizeof...(Ts), Pred, Ts...>;\n\n\ttemplate <template <typename...> class Pred, typename... Ts>\n\tinline constexpr std::size_t count_even_for_pack_v = count_even_for_pack<Pred, Ts...>::value;\n\n\ttemplate <template <typename...> class Pred, typename... Ts>\n\tusing count_odd_for_pack = count_when_for_to_pack<meta_detail::on_odd, sizeof...(Ts), Pred, Ts...>;\n\n\ttemplate <template <typename...> class Pred, typename... Ts>\n\tinline constexpr std::size_t count_odd_for_pack_v = count_odd_for_pack<Pred, Ts...>::value;\n\n\ttemplate <typename... Args>\n\tstruct return_type {\n\t\ttypedef std::tuple<Args...> type;\n\t};\n\n\ttemplate <typename T>\n\tstruct return_type<T> {\n\t\ttypedef T type;\n\t};\n\n\ttemplate <>\n\tstruct return_type<> {\n\t\ttypedef void type;\n\t};\n\n\ttemplate <typename... Args>\n\tusing return_type_t = typename return_type<Args...>::type;\n\n\tnamespace meta_detail {\n\t\ttemplate <typename>\n\t\tstruct always_true : std::true_type {};\n\t\tstruct is_invokable_tester {\n\t\t\ttemplate <typename Fun, typename... Args>\n\t\t\tstatic always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int);\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\t} // namespace meta_detail\n\n\ttemplate <typename T>\n\tstruct is_invokable;\n\ttemplate <typename Fun, typename... Args>\n\tstruct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) {};\n\n\tnamespace meta_detail {\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct is_callable : std::is_function<std::remove_pointer_t<T>> {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_callable<T,\n\t\t\tstd::enable_if_t<std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value\n\t\t\t     && std::is_same<decltype(void(&T::operator())), void>::value>> {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_callable<T,\n\t\t\tstd::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value\n\t\t\t     && std::is_destructible<unqualified_t<T>>::value>> {\n\t\t\tstruct F {\n\t\t\t\tvoid operator()() {};\n\t\t\t};\n\t\t\tstruct Derived : T, F {};\n\t\t\ttemplate <typename U, U>\n\t\t\tstruct Check;\n\n\t\t\ttemplate <typename V>\n\t\t\tstatic sfinae_no_t test(Check<void (F::*)(), &V::operator()>*);\n\n\t\t\ttemplate <typename>\n\t\t\tstatic sfinae_yes_t test(...);\n\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<Derived>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct is_callable<T,\n\t\t\tstd::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value\n\t\t\t     && !std::is_destructible<unqualified_t<T>>::value>> {\n\t\t\tstruct F {\n\t\t\t\tvoid operator()() {};\n\t\t\t};\n\t\t\tstruct Derived : T, F {\n\t\t\t\t~Derived() = delete;\n\t\t\t};\n\t\t\ttemplate <typename U, U>\n\t\t\tstruct Check;\n\n\t\t\ttemplate <typename V>\n\t\t\tstatic sfinae_no_t test(Check<void (F::*)(), &V::operator()>*);\n\n\t\t\ttemplate <typename>\n\t\t\tstatic sfinae_yes_t test(...);\n\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<Derived>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\tstruct has_begin_end_impl {\n\t\t\ttemplate <typename T, typename U = unqualified_t<T>, typename B = decltype(std::declval<U&>().begin()),\n\t\t\t\ttypename E = decltype(std::declval<U&>().end())>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_key_type_impl {\n\t\t\ttemplate <typename T, typename U = unqualified_t<T>, typename V = typename U::key_type>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_key_comp_impl {\n\t\t\ttemplate <typename T, typename V = decltype(std::declval<unqualified_t<T>>().key_comp())>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_load_factor_impl {\n\t\t\ttemplate <typename T, typename V = decltype(std::declval<unqualified_t<T>>().load_factor())>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_mapped_type_impl {\n\t\t\ttemplate <typename T, typename V = typename unqualified_t<T>::mapped_type>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_value_type_impl {\n\t\t\ttemplate <typename T, typename V = typename unqualified_t<T>::value_type>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_iterator_impl {\n\t\t\ttemplate <typename T, typename V = typename unqualified_t<T>::iterator>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\tstruct has_key_value_pair_impl {\n\t\t\ttemplate <typename T, typename U = unqualified_t<T>, typename V = typename U::value_type, typename F = decltype(std::declval<V&>().first),\n\t\t\t\ttypename S = decltype(std::declval<V&>().second)>\n\t\t\tstatic std::true_type test(int);\n\n\t\t\ttemplate <typename...>\n\t\t\tstatic std::false_type test(...);\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_push_back_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_yes_t test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_insert_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(),\n\t\t\t\tstd::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_insert_after_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_yes_t test(decltype(std::declval<C>().insert_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(),\n\t\t\t\tstd::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_size_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_yes_t test(decltype(std::declval<C>().size())*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_max_size_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_yes_t test(decltype(std::declval<C>().max_size())*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_to_string_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_yes_t test(decltype(std::declval<C>().to_string())*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T, typename U, typename = void>\n\t\tclass supports_op_less_test : public std::false_type {};\n\t\ttemplate <typename T, typename U>\n\t\tclass supports_op_less_test<T, U, void_t<decltype(std::declval<T&>() < std::declval<U&>())>>\n\t\t: public std::integral_constant<bool,\n\t\t\t  !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant>> {};\n\n\t\ttemplate <typename T, typename U, typename = void>\n\t\tclass supports_op_equal_test : public std::false_type {};\n\t\ttemplate <typename T, typename U>\n\t\tclass supports_op_equal_test<T, U, void_t<decltype(std::declval<T&>() == std::declval<U&>())>>\n\t\t: public std::integral_constant<bool,\n\t\t\t  !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant>> {};\n\n\t\ttemplate <typename T, typename U, typename = void>\n\t\tclass supports_op_less_equal_test : public std::false_type {};\n\t\ttemplate <typename T, typename U>\n\t\tclass supports_op_less_equal_test<T, U, void_t<decltype(std::declval<T&>() <= std::declval<U&>())>>\n\t\t: public std::integral_constant<bool,\n\t\t\t  !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant>> {};\n\n\t\ttemplate <typename T, typename U, typename = void>\n\t\tclass supports_op_left_shift_test : public std::false_type {};\n\t\ttemplate <typename T, typename U>\n\t\tclass supports_op_left_shift_test<T, U, void_t<decltype(std::declval<T&>() << std::declval<U&>())>> : public std::true_type {};\n\n\t\ttemplate <typename T, typename = void>\n\t\tclass supports_adl_to_string_test : public std::false_type {};\n\t\ttemplate <typename T>\n\t\tclass supports_adl_to_string_test<T, void_t<decltype(to_string(std::declval<const T&>()))>> : public std::true_type {};\n\n\t\ttemplate <typename T, bool b>\n\t\tstruct is_matched_lookup_impl : std::false_type {};\n\t\ttemplate <typename T>\n\t\tstruct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> {};\n\n\t\ttemplate <typename T>\n\t\tusing non_void_t = meta::conditional_t<std::is_void_v<T>, ::sol::detail::unchecked_t, T>;\n\t} // namespace meta_detail\n\n\ttemplate <typename T, typename U = T>\n\tclass supports_op_less : public meta_detail::supports_op_less_test<T, U> {};\n\n\ttemplate <typename T, typename U = T>\n\tclass supports_op_equal : public meta_detail::supports_op_equal_test<T, U> {};\n\n\ttemplate <typename T, typename U = T>\n\tclass supports_op_less_equal : public meta_detail::supports_op_less_equal_test<T, U> {};\n\n\ttemplate <typename T, typename U = T>\n\tclass supports_op_left_shift : public meta_detail::supports_op_left_shift_test<T, U> {};\n\n\ttemplate <typename T>\n\tclass supports_adl_to_string : public meta_detail::supports_adl_to_string_test<T> {};\n\n\ttemplate <typename T>\n\tclass supports_to_string_member : public meta::boolean<meta_detail::has_to_string_test<meta_detail::non_void_t<T>>::value> {};\n\n\ttemplate <typename T>\n\tusing is_callable = boolean<meta_detail::is_callable<T>::value>;\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_callable_v = is_callable<T>::value;\n\n\ttemplate <typename T>\n\tstruct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tconstexpr inline bool has_begin_end_v = has_begin_end<T>::value;\n\n\ttemplate <typename T>\n\tstruct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tstruct has_key_type : decltype(meta_detail::has_key_type_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tstruct has_key_comp : decltype(meta_detail::has_key_comp_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tstruct has_load_factor : decltype(meta_detail::has_load_factor_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tstruct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tstruct has_iterator : decltype(meta_detail::has_iterator_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tstruct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) {};\n\n\ttemplate <typename T>\n\tusing has_push_back = meta::boolean<meta_detail::has_push_back_test<T>::value>;\n\n\ttemplate <typename T>\n\tusing has_max_size = meta::boolean<meta_detail::has_max_size_test<T>::value>;\n\n\ttemplate <typename T>\n\tusing has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>;\n\n\ttemplate <typename T>\n\tusing has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>;\n\n\ttemplate <typename T>\n\tusing has_size = meta::boolean<meta_detail::has_size_test<T>::value>;\n\n\ttemplate <typename T>\n\tusing is_associative = meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>>;\n\n\ttemplate <typename T>\n\tusing is_lookup = meta::all<has_key_type<T>, has_value_type<T>>;\n\n\ttemplate <typename T>\n\tusing is_ordered = meta::all<has_key_comp<T>, meta::neg<has_load_factor<T>>>;\n\n\ttemplate <typename T>\n\tusing is_matched_lookup = meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value>;\n\n\ttemplate <typename T>\n\tusing is_initializer_list = meta::is_specialization_of<T, std::initializer_list>;\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_initializer_list_v = is_initializer_list<T>::value;\n\n\ttemplate <typename T, typename CharT = char>\n\tusing is_string_literal_array_of = boolean<std::is_array_v<T> && std::is_same_v<std::remove_all_extents_t<T>, CharT>>;\n\n\ttemplate <typename T, typename CharT = char>\n\tconstexpr inline bool is_string_literal_array_of_v = is_string_literal_array_of<T, CharT>::value;\n\n\ttemplate <typename T>\n\tusing is_string_literal_array = boolean<std::is_array_v<T> && any_same_v<std::remove_all_extents_t<T>, char, char16_t, char32_t, wchar_t>>;\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_string_literal_array_v = is_string_literal_array<T>::value;\n\n\ttemplate <typename T, typename CharT>\n\tstruct is_string_of : std::false_type {};\n\n\ttemplate <typename CharT, typename CharTargetT, typename TraitsT, typename AllocT>\n\tstruct is_string_of<std::basic_string<CharT, TraitsT, AllocT>, CharTargetT> : std::is_same<CharT, CharTargetT> {};\n\n\ttemplate <typename T, typename CharT>\n\tconstexpr inline bool is_string_of_v = is_string_of<T, CharT>::value;\n\n\ttemplate <typename T, typename CharT>\n\tstruct is_string_view_of : std::false_type {};\n\n\ttemplate <typename CharT, typename CharTargetT, typename TraitsT>\n\tstruct is_string_view_of<std::basic_string_view<CharT, TraitsT>, CharTargetT> : std::is_same<CharT, CharTargetT> {};\n\n\ttemplate <typename T, typename CharT>\n\tconstexpr inline bool is_string_view_of_v = is_string_view_of<T, CharT>::value;\n\n\ttemplate <typename T>\n\tusing is_string_like\n\t\t= meta::boolean<is_specialization_of_v<T, std::basic_string> || is_specialization_of_v<T, std::basic_string_view> || is_string_literal_array_v<T>>;\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_string_like_v = is_string_like<T>::value;\n\n\ttemplate <typename T, typename CharT = char>\n\tusing is_string_constructible = meta::boolean<\n\t\tis_string_literal_array_of_v<T,\n\t\t     CharT> || std::is_same_v<T, const CharT*> || std::is_same_v<T, CharT> || is_string_of_v<T, CharT> || std::is_same_v<T, std::initializer_list<CharT>> || is_string_view_of_v<T, CharT>>;\n\n\ttemplate <typename T, typename CharT = char>\n\tconstexpr inline bool is_string_constructible_v = is_string_constructible<T, CharT>::value;\n\n\ttemplate <typename T>\n\tusing is_string_like_or_constructible = meta::boolean<is_string_like_v<T> || is_string_constructible_v<T>>;\n\n\ttemplate <typename T>\n\tstruct is_pair : std::false_type {};\n\n\ttemplate <typename T1, typename T2>\n\tstruct is_pair<std::pair<T1, T2>> : std::true_type {};\n\n\ttemplate <typename T, typename Char>\n\tusing is_c_str_of = any<std::is_same<T, const Char*>, std::is_same<T, Char const* const>, std::is_same<T, Char*>, is_string_of<T, Char>,\n\t\tis_string_literal_array_of<T, Char>>;\n\n\ttemplate <typename T, typename Char>\n\tconstexpr inline bool is_c_str_of_v = is_c_str_of<T, Char>::value;\n\n\ttemplate <typename T>\n\tusing is_c_str = is_c_str_of<T, char>;\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_c_str_v = is_c_str<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_move_only : all<neg<std::is_reference<T>>, neg<std::is_copy_constructible<unqualified_t<T>>>, std::is_move_constructible<unqualified_t<T>>> {};\n\n\ttemplate <typename T>\n\tusing is_not_move_only = neg<is_move_only<T>>;\n\n\tnamespace meta_detail {\n\t\ttemplate <typename T>\n\t\tdecltype(auto) force_tuple(T&& x) {\n\t\t\tif constexpr (meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>) {\n\t\t\t\treturn std::forward<T>(x);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn std::tuple<T>(std::forward<T>(x));\n\t\t\t}\n\t\t}\n\t} // namespace meta_detail\n\n\ttemplate <typename... X>\n\tdecltype(auto) tuplefy(X&&... x) {\n\t\treturn std::tuple_cat(meta_detail::force_tuple(std::forward<X>(x))...);\n\t}\n\n\ttemplate <typename T, typename = void>\n\tstruct iterator_tag {\n\t\tusing type = std::input_iterator_tag;\n\t};\n\n\ttemplate <typename T>\n\tstruct iterator_tag<T, conditional_t<false, typename std::iterator_traits<T>::iterator_category, void>> {\n\t\tusing type = typename std::iterator_traits<T>::iterator_category;\n\t};\n\n}} // namespace sol::meta\n\n// end of sol/traits.hpp\n\nnamespace sol {\n\tnamespace detail {\n\t\tconst bool default_safe_function_calls =\n#if SOL_IS_ON(SOL_SAFE_FUNCTION_CALLS_I_)\n\t\t     true;\n#else\n\t\t     false;\n#endif\n\t} // namespace detail\n\n\tnamespace meta { namespace meta_detail {\n\t}} // namespace meta::meta_detail\n\n\tnamespace stack { namespace stack_detail {\n\t\tusing undefined_method_func = void (*)(stack_reference);\n\n\t\ttemplate <typename T>\n\t\tvoid set_undefined_methods_on(stack_reference);\n\n\t\tstruct undefined_metatable;\n\t}} // namespace stack::stack_detail\n} // namespace sol\n\n#endif // SOL_FORWARD_DETAIL_HPP\n// end of sol/forward_detail.hpp\n\n// beginning of sol/bytecode.hpp\n\n// beginning of sol/compatibility.hpp\n\n// beginning of sol/compatibility/lua_version.hpp\n\n#if SOL_IS_ON(SOL_USE_CXX_LUA_I_)\n\t#include <lua.h>\n\t#include <lualib.h>\n\t#include <lauxlib.h>\n#elif SOL_IS_ON(SOL_USE_LUA_HPP_I_)\n\t#include <lua.hpp>\n#else\n\textern \"C\" {\n\t\t#include <lua.h>\n\t\t#include <lauxlib.h>\n\t\t#include <lualib.h>\n\t}\n#endif // C++ Mangling for Lua vs. Not\n\n#if defined(SOL_LUAJIT)\n\t#if (SOL_LUAJIT != 0)\n\t\t#define SOL_USE_LUAJIT_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_LUAJIT_I_ SOL_OFF\n\t#endif\n#elif defined(LUAJIT_VERSION)\n\t#define SOL_USE_LUAJIT_I_ SOL_OFF\n#else\n\t#define SOL_USE_LUAJIT_I_ SOL_DEFAULT_OFF\n#endif // luajit\n\n#if SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_)\n\t#include <luajit.h>\n#elif SOL_IS_ON(SOL_USE_LUAJIT_I_)\n\textern \"C\" {\n\t\t#include <luajit.h>\n\t}\n#endif // C++ LuaJIT ... whatever that means\n\n#if defined(SOL_LUAJIT_VERSION)\n\t#define SOL_LUAJIT_VERSION_I_ SOL_LUAJIT_VERSION\n#elif SOL_IS_ON(SOL_USE_LUAJIT_I_)\n\t#define SOL_LUAJIT_VERSION_I_ LUAJIT_VERSION_NUM\n#else\n\t#define SOL_LUAJIT_VERSION_I_ 0\n#endif\n\n#if defined(MOONJIT_VERSION)\n\t#define SOL_USE_MOONJIT_I_ SOL_ON\n#else\n\t#define SOL_USE_MOONJIT_I_ SOL_OFF\n#endif\n\n#if !defined(SOL_LUA_VERSION)\n\t#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502\n\t\t#define SOL_LUA_VERSION LUA_VERSION_NUM\n\t#elif defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501\n\t\t#define SOL_LUA_VERSION LUA_VERSION_NUM\n\t#elif !defined(LUA_VERSION_NUM) || !(LUA_VERSION_NUM)\n\t\t// Definitely 5.0\n\t\t#define SOL_LUA_VERSION 500\n\t#else\n\t\t// ??? Not sure, assume latest?\n\t\t#define SOL_LUA_VERSION 504\n\t#endif // Lua Version 503, 502, 501 || luajit, 500\n#endif // SOL_LUA_VERSION\n\n#if defined(SOL_LUA_VERSION)\n\t#define SOL_LUA_VESION_I_ SOL_LUA_VERSION\n#else\n\t#define SOL_LUA_VESION_I_ 504\n#endif\n\n#if defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE)\n\t#if (SOL_EXCEPTIONS_ALWAYS_UNSAFE != 0)\n\t\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF\n\t#else\n\t\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_ON\n\t#endif\n#elif defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)\n\t#if (SOL_EXCEPTIONS_SAFE_PROPAGATION != 0)\n\t\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_ON\n\t#else\n\t\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF\n\t#endif\n#elif SOL_LUAJIT_VERSION_I_ >= 20100\n\t// LuaJIT 2.1.0-beta3 and better have exception support locked in for all platforms (mostly)\n\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON\n#elif SOL_LUAJIT_VERSION_I_ >= 20000\n\t// LuaJIT 2.0.x have exception support only on x64 builds\n\t#if SOL_IS_ON(SOL_PLATFORM_X64_I_)\n\t\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON\n\t#else\n\t\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF\n\t#endif\n#else\n\t// otherwise, there is no exception safety for\n\t// shoving exceptions through Lua and errors should\n\t// always be serialized\n\t#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_OFF\n#endif // LuaJIT beta 02.01.00 have better exception handling on all platforms since beta3\n\n#if defined(SOL_LUAJIT_USE_EXCEPTION_TRAMPOLINE)\n\t#if (SOL_LUAJIT_USE_EXCEPTION_TRAMPOLINE != 0)\n\t\t#define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS_I_) && SOL_IS_ON(SOL_USE_LUAJIT_I_)\n\t\t#define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_ON\n\t#else\n\t\t#define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n#if defined(SOL_LUAL_STREAM_HAS_CLOSE_FUNCTION)\n\t#if (SOL_LUAL_STREAM_HAS_CLOSE_FUNCTION != 0)\n\t\t#define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_ON\n\t#else\n\t\t#define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_OFF\n\t#endif\n#else\n\t#if SOL_IS_OFF(SOL_USE_LUAJIT_I_) && (SOL_LUA_VERSION > 501)\n\t\t#define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_ON\n\t#else\n\t\t#define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_DEFAULT_OFF\n\t#endif\n#endif\n\n// end of sol/compatibility/lua_version.hpp\n\n#if SOL_IS_ON(SOL_USE_COMPATIBILITY_LAYER_I_)\n\n#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) || SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_)\n#ifndef COMPAT53_LUA_CPP\n#define COMPAT53_LUA_CPP 1\n#endif // Build Lua Compat layer as C++\n#endif\n#ifndef COMPAT53_INCLUDE_SOURCE\n#define COMPAT53_INCLUDE_SOURCE 1\n#endif // Build Compat Layer Inline\n\n// beginning of sol/compatibility/compat-5.3.h\n\n#ifndef KEPLER_PROJECT_COMPAT53_H_\n#define KEPLER_PROJECT_COMPAT53_H_\n\n#include <stddef.h>\n#include <limits.h>\n#include <string.h>\n#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)\nextern \"C\" {\n#endif\n#include <lua.h>\n#include <lauxlib.h>\n#include <lualib.h>\n#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)\n}\n#endif\n\n#ifndef COMPAT53_PREFIX\n/* we chose this name because many other lua bindings / libs have\n* their own compatibility layer, and that use the compat53 declaration\n* frequently, causing all kinds of linker / compiler issues\n*/\n#  define COMPAT53_PREFIX kp_compat53\n#endif // COMPAT53_PREFIX\n\n#ifndef COMPAT53_API\n#  if defined(COMPAT53_INCLUDE_SOURCE) && COMPAT53_INCLUDE_SOURCE\n#    if defined(__GNUC__) || defined(__clang__)\n#      define COMPAT53_API __attribute__((__unused__)) static inline \n#    else\n#      define COMPAT53_API static inline \n#    endif /* Clang/GCC */\n#  else /* COMPAT53_INCLUDE_SOURCE */\n/* we are not including source, so everything is extern */\n#      define COMPAT53_API extern\n#  endif /* COMPAT53_INCLUDE_SOURCE */\n#endif /* COMPAT53_PREFIX */\n\n#define COMPAT53_CONCAT_HELPER(a, b) a##b\n#define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b)\n\n/* declarations for Lua 5.1 */\n#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501\n\n/* XXX not implemented:\n* lua_arith (new operators)\n* lua_upvalueid\n* lua_upvaluejoin\n* lua_version\n* lua_yieldk\n*/\n\n#ifndef LUA_OK\n#  define LUA_OK 0\n#endif\n#ifndef LUA_OPADD\n#  define LUA_OPADD 0\n#endif\n#ifndef LUA_OPSUB\n#  define LUA_OPSUB 1\n#endif\n#ifndef LUA_OPMUL\n#  define LUA_OPMUL 2\n#endif\n#ifndef LUA_OPDIV\n#  define LUA_OPDIV 3\n#endif\n#ifndef LUA_OPMOD\n#  define LUA_OPMOD 4\n#endif\n#ifndef LUA_OPPOW\n#  define LUA_OPPOW 5\n#endif\n#ifndef LUA_OPUNM\n#  define LUA_OPUNM 6\n#endif\n#ifndef LUA_OPEQ\n#  define LUA_OPEQ 0\n#endif\n#ifndef LUA_OPLT\n#  define LUA_OPLT 1\n#endif\n#ifndef LUA_OPLE\n#  define LUA_OPLE 2\n#endif\n\n/* LuaJIT/Lua 5.1 does not have the updated\n* error codes for thread status/function returns (but some patched versions do)\n* define it only if it's not found\n*/\n#if !defined(LUA_ERRGCMM)\n/* Use + 2 because in some versions of Lua (Lua 5.1)\n* LUA_ERRFILE is defined as (LUA_ERRERR+1)\n* so we need to avoid it (LuaJIT might have something at this\n* integer value too)\n*/\n#  define LUA_ERRGCMM (LUA_ERRERR + 2)\n#endif /* LUA_ERRGCMM define */\n\n#if !defined(MOONJIT_VERSION)\ntypedef size_t lua_Unsigned;\n#endif\n\ntypedef struct luaL_Buffer_53 {\n\tluaL_Buffer b; /* make incorrect code crash! */\n\tchar *ptr;\n\tsize_t nelems;\n\tsize_t capacity;\n\tlua_State *L2;\n} luaL_Buffer_53;\n#define luaL_Buffer luaL_Buffer_53\n\n/* In PUC-Rio 5.1, userdata is a simple FILE*\n* In LuaJIT, it's a struct where the first member is a FILE*\n* We can't support the `closef` member\n*/\ntypedef struct luaL_Stream {\n\tFILE *f;\n} luaL_Stream;\n\n#define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex)\nCOMPAT53_API int lua_absindex(lua_State *L, int i);\n\n#define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith)\nCOMPAT53_API void lua_arith(lua_State *L, int op);\n\n#define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare)\nCOMPAT53_API int lua_compare(lua_State *L, int idx1, int idx2, int op);\n\n#define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy)\nCOMPAT53_API void lua_copy(lua_State *L, int from, int to);\n\n#define lua_getuservalue(L, i) \\\n  (lua_getfenv((L), (i)), lua_type((L), -1))\n#define lua_setuservalue(L, i) \\\n  (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i)))\n\n#define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len)\nCOMPAT53_API void lua_len(lua_State *L, int i);\n\n#define lua_pushstring(L, s) \\\n  (lua_pushstring((L), (s)), lua_tostring((L), -1))\n\n#define lua_pushlstring(L, s, len) \\\n  ((((len) == 0) ? lua_pushlstring((L), \"\", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1))\n\n#ifndef luaL_newlibtable\n#  define luaL_newlibtable(L, l) \\\n  (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1))\n#endif\n#ifndef luaL_newlib\n#  define luaL_newlib(L, l) \\\n  (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l)))\n#endif\n\n#ifndef lua_pushglobaltable\n#  define lua_pushglobaltable(L) \\\n  lua_pushvalue((L), LUA_GLOBALSINDEX)\n#endif\n#define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp)\nCOMPAT53_API int lua_rawgetp(lua_State *L, int i, const void *p);\n\n#define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp)\nCOMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p);\n\n#define lua_rawlen(L, i) lua_objlen((L), (i))\n\n#define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL)\n\n#define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx)\nCOMPAT53_API lua_Number lua_tonumberx(lua_State *L, int i, int *isnum);\n\n#define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion)\nCOMPAT53_API void luaL_checkversion(lua_State *L);\n\n#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53)\nCOMPAT53_API int lua_load(lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode);\n\n#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex)\nCOMPAT53_API int luaL_loadfilex(lua_State *L, const char *filename, const char *mode);\n\n#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx)\nCOMPAT53_API int luaL_loadbufferx(lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);\n\n#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53)\nCOMPAT53_API void luaL_checkstack(lua_State *L, int sp, const char *msg);\n\n#define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable)\nCOMPAT53_API int luaL_getsubtable(lua_State* L, int i, const char *name);\n\n#define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len)\nCOMPAT53_API lua_Integer luaL_len(lua_State *L, int i);\n\n#define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs)\nCOMPAT53_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup);\n\n#define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable)\nCOMPAT53_API void luaL_setmetatable(lua_State *L, const char *tname);\n\n#define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata)\nCOMPAT53_API void *luaL_testudata(lua_State *L, int i, const char *tname);\n\n#define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback)\nCOMPAT53_API void luaL_traceback(lua_State *L, lua_State *L1, const char *msg, int level);\n\n#define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult)\nCOMPAT53_API int luaL_fileresult(lua_State *L, int stat, const char *fname);\n\n#define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult)\nCOMPAT53_API int luaL_execresult(lua_State *L, int stat);\n\n#define lua_callk(L, na, nr, ctx, cont) \\\n  ((void)(ctx), (void)(cont), lua_call((L), (na), (nr)))\n#define lua_pcallk(L, na, nr, err, ctx, cont) \\\n  ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err)))\n\n#define lua_resume(L, from, nargs) \\\n  ((void)(from), lua_resume((L), (nargs)))\n\n#define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53)\nCOMPAT53_API void luaL_buffinit(lua_State *L, luaL_Buffer_53 *B);\n\n#define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53)\nCOMPAT53_API char *luaL_prepbuffsize(luaL_Buffer_53 *B, size_t s);\n\n#define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53)\nCOMPAT53_API void luaL_addlstring(luaL_Buffer_53 *B, const char *s, size_t l);\n\n#define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53)\nCOMPAT53_API void luaL_addvalue(luaL_Buffer_53 *B);\n\n#define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53)\nCOMPAT53_API void luaL_pushresult(luaL_Buffer_53 *B);\n\n#undef luaL_buffinitsize\n#define luaL_buffinitsize(L, B, s) \\\n  (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s)))\n\n#undef luaL_prepbuffer\n#define luaL_prepbuffer(B) \\\n  luaL_prepbuffsize((B), LUAL_BUFFERSIZE)\n\n#undef luaL_addchar\n#define luaL_addchar(B, c) \\\n  ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \\\n   ((B)->ptr[(B)->nelems++] = (c)))\n\n#undef luaL_addsize\n#define luaL_addsize(B, s) \\\n  ((B)->nelems += (s))\n\n#undef luaL_addstring\n#define luaL_addstring(B, s) \\\n  luaL_addlstring((B), (s), strlen((s)))\n\n#undef luaL_pushresultsize\n#define luaL_pushresultsize(B, s) \\\n  (luaL_addsize((B), (s)), luaL_pushresult((B)))\n\n#if defined(LUA_COMPAT_APIINTCASTS)\n#define lua_pushunsigned(L, n) \\\n  lua_pushinteger((L), (lua_Integer)(n))\n#define lua_tounsignedx(L, i, is) \\\n  ((lua_Unsigned)lua_tointegerx((L), (i), (is)))\n#define lua_tounsigned(L, i) \\\n  lua_tounsignedx((L), (i), NULL)\n#define luaL_checkunsigned(L, a) \\\n  ((lua_Unsigned)luaL_checkinteger((L), (a)))\n#define luaL_optunsigned(L, a, d) \\\n  ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d)))\n#endif\n\n#endif /* Lua 5.1 only */\n\n/* declarations for Lua 5.1 and 5.2 */\n#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502\n\ntypedef int lua_KContext;\n\ntypedef int(*lua_KFunction)(lua_State *L, int status, lua_KContext ctx);\n\n#define lua_dump(L, w, d, s) \\\n  ((void)(s), lua_dump((L), (w), (d)))\n\n#define lua_getfield(L, i, k) \\\n  (lua_getfield((L), (i), (k)), lua_type((L), -1))\n\n#define lua_gettable(L, i) \\\n  (lua_gettable((L), (i)), lua_type((L), -1))\n\n#define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti)\nCOMPAT53_API int lua_geti(lua_State *L, int index, lua_Integer i);\n\n#define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger)\nCOMPAT53_API int lua_isinteger(lua_State *L, int index);\n\n#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53)\nCOMPAT53_API lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum);\n\n#define lua_numbertointeger(n, p) \\\n  ((*(p) = (lua_Integer)(n)), 1)\n\n#define lua_rawget(L, i) \\\n  (lua_rawget((L), (i)), lua_type((L), -1))\n\n#define lua_rawgeti(L, i, n) \\\n  (lua_rawgeti((L), (i), (n)), lua_type((L), -1))\n\n#define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate)\nCOMPAT53_API void lua_rotate(lua_State *L, int idx, int n);\n\n#define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti)\nCOMPAT53_API void lua_seti(lua_State *L, int index, lua_Integer i);\n\n#define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber)\nCOMPAT53_API size_t lua_stringtonumber(lua_State *L, const char *s);\n\n#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring)\nCOMPAT53_API const char *luaL_tolstring(lua_State *L, int idx, size_t *len);\n\n#define luaL_getmetafield(L, o, e) \\\n  (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL)\n\n#define luaL_newmetatable(L, tn) \\\n  (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, \"__name\"), 1) : 0)\n\n#define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53)\nCOMPAT53_API void luaL_requiref(lua_State *L, const char *modname,\n\tlua_CFunction openf, int glb);\n\n#endif /* Lua 5.1 and Lua 5.2 */\n\n/* declarations for Lua 5.2 */\n#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502\n\n/* XXX not implemented:\n* lua_isyieldable\n* lua_getextraspace\n* lua_arith (new operators)\n* lua_pushfstring (new formats)\n*/\n\n#define lua_getglobal(L, n) \\\n  (lua_getglobal((L), (n)), lua_type((L), -1))\n\n#define lua_getuservalue(L, i) \\\n  (lua_getuservalue((L), (i)), lua_type((L), -1))\n\n#define lua_pushlstring(L, s, len) \\\n  (((len) == 0) ? lua_pushlstring((L), \"\", 0) : lua_pushlstring((L), (s), (len)))\n\n#define lua_rawgetp(L, i, p) \\\n  (lua_rawgetp((L), (i), (p)), lua_type((L), -1))\n\n#define LUA_KFUNCTION(_name) \\\n  static int (_name)(lua_State *L, int status, lua_KContext ctx); \\\n  static int (_name ## _52)(lua_State *L) { \\\n    lua_KContext ctx; \\\n    int status = lua_getctx(L, &ctx); \\\n    return (_name)(L, status, ctx); \\\n  } \\\n  static int (_name)(lua_State *L, int status, lua_KContext ctx)\n\n#define lua_pcallk(L, na, nr, err, ctx, cont) \\\n  lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52)\n\n#define lua_callk(L, na, nr, ctx, cont) \\\n  lua_callk((L), (na), (nr), (ctx), cont ## _52)\n\n#define lua_yieldk(L, nr, ctx, cont) \\\n  lua_yieldk((L), (nr), (ctx), cont ## _52)\n\n#ifdef lua_call\n#  undef lua_call\n#  define lua_call(L, na, nr) \\\n  (lua_callk)((L), (na), (nr), 0, NULL)\n#endif\n\n#ifdef lua_pcall\n#  undef lua_pcall\n#  define lua_pcall(L, na, nr, err) \\\n  (lua_pcallk)((L), (na), (nr), (err), 0, NULL)\n#endif\n\n#ifdef lua_yield\n#  undef lua_yield\n#  define lua_yield(L, nr) \\\n  (lua_yieldk)((L), (nr), 0, NULL)\n#endif\n\n#endif /* Lua 5.2 only */\n\n/* other Lua versions */\n#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 504\n\n#  error \"unsupported Lua version (i.e. not Lua 5.1, 5.2, 5.3, or 5.4)\"\n\n#endif /* other Lua versions except 5.1, 5.2, 5.3, and 5.4 */\n\n/* helper macro for defining continuation functions (for every version\n* *except* Lua 5.2) */\n#ifndef LUA_KFUNCTION\n#define LUA_KFUNCTION(_name) \\\n  static int (_name)(lua_State *L, int status, lua_KContext ctx)\n#endif\n\n#if defined(COMPAT53_INCLUDE_SOURCE) && COMPAT53_INCLUDE_SOURCE == 1\n// beginning of sol/compatibility/compat-5.3.c.h\n\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <errno.h>\n#include <stdio.h>\n\n/* don't compile it again if it already is included via compat53.h */\n#ifndef KEPLER_PROJECT_COMPAT53_C_\n#define KEPLER_PROJECT_COMPAT53_C_\n\n/* definitions for Lua 5.1 only */\n#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501\n\n#ifndef COMPAT53_FOPEN_NO_LOCK\n#if defined(_MSC_VER)\n#define COMPAT53_FOPEN_NO_LOCK 1\n#else /* otherwise */\n#define COMPAT53_FOPEN_NO_LOCK 0\n#endif /* VC++ only so far */\n#endif /* No-lock fopen_s usage if possible */\n\n#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK\n#include <share.h>\n#endif /* VC++ _fsopen for share-allowed file read */\n\n#ifndef COMPAT53_HAVE_STRERROR_R\n#if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || (!defined(__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6))\n#define COMPAT53_HAVE_STRERROR_R 1\n#else /* none of the defines matched: define to 0 */\n#define COMPAT53_HAVE_STRERROR_R 0\n#endif /* have strerror_r of some form */\n#endif /* strerror_r */\n\n#ifndef COMPAT53_HAVE_STRERROR_S\n#if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || (defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__)\n#define COMPAT53_HAVE_STRERROR_S 1\n#else /* not VC++ or C11 */\n#define COMPAT53_HAVE_STRERROR_S 0\n#endif /* strerror_s from VC++ or C11 */\n#endif /* strerror_s */\n\n#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE\n#define COMPAT53_LUA_FILE_BUFFER_SIZE 4096\n#endif /* Lua File Buffer Size */\n\nstatic char* compat53_strerror(int en, char* buff, size_t sz) {\n#if COMPAT53_HAVE_STRERROR_R\n\t/* use strerror_r here, because it's available on these specific platforms */\n\tif (sz > 0) {\n\t\tbuff[0] = '\\0';\n\t\t/* we don't care whether the GNU version or the XSI version is used: */\n\t\tif (strerror_r(en, buff, sz)) {\n\t\t\t/* Yes, we really DO want to ignore the return value!\n\t\t\t * GCC makes that extra hard, not even a (void) cast will do. */\n\t\t}\n\t\tif (buff[0] == '\\0') {\n\t\t\t/* Buffer is unchanged, so we probably have called GNU strerror_r which\n\t\t\t * returned a static constant string. Chances are that strerror will\n\t\t\t * return the same static constant string and therefore be thread-safe. */\n\t\t\treturn strerror(en);\n\t\t}\n\t}\n\treturn buff; /* sz is 0 *or* strerror_r wrote into the buffer */\n#elif COMPAT53_HAVE_STRERROR_S\n\t/* for MSVC and other C11 implementations, use strerror_s since it's\n\t * provided by default by the libraries */\n\tstrerror_s(buff, sz, en);\n\treturn buff;\n#else\n\t/* fallback, but strerror is not guaranteed to be threadsafe due to modifying\n\t * errno itself and some impls not locking a static buffer for it ... but most\n\t * known systems have threadsafe errno: this might only change if the locale\n\t * is changed out from under someone while this function is being called */\n\t(void)buff;\n\t(void)sz;\n\treturn strerror(en);\n#endif\n}\n\nCOMPAT53_API int lua_absindex(lua_State* L, int i) {\n\tif (i < 0 && i > LUA_REGISTRYINDEX)\n\t\ti += lua_gettop(L) + 1;\n\treturn i;\n}\n\nstatic void compat53_call_lua(lua_State* L, char const code[], size_t len, int nargs, int nret) {\n\tlua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code);\n\tif (lua_type(L, -1) != LUA_TFUNCTION) {\n\t\tlua_pop(L, 1);\n\t\tif (luaL_loadbuffer(L, code, len, \"=none\"))\n\t\t\tlua_error(L);\n\t\tlua_pushvalue(L, -1);\n\t\tlua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code);\n\t}\n\tlua_insert(L, -nargs - 1);\n\tlua_call(L, nargs, nret);\n}\n\nstatic const char compat53_arith_code[]\n     = \"local op,a,b=...\\n\"\n       \"if op==0 then return a+b\\n\"\n       \"elseif op==1 then return a-b\\n\"\n       \"elseif op==2 then return a*b\\n\"\n       \"elseif op==3 then return a/b\\n\"\n       \"elseif op==4 then return a%b\\n\"\n       \"elseif op==5 then return a^b\\n\"\n       \"elseif op==6 then return -a\\n\"\n       \"end\\n\";\n\nCOMPAT53_API void lua_arith(lua_State* L, int op) {\n\tif (op < LUA_OPADD || op > LUA_OPUNM)\n\t\tluaL_error(L, \"invalid 'op' argument for lua_arith\");\n\tluaL_checkstack(L, 5, \"not enough stack slots\");\n\tif (op == LUA_OPUNM)\n\t\tlua_pushvalue(L, -1);\n\tlua_pushnumber(L, op);\n\tlua_insert(L, -3);\n\tcompat53_call_lua(L, compat53_arith_code, sizeof(compat53_arith_code) - 1, 3, 1);\n}\n\nstatic const char compat53_compare_code[]\n     = \"local a,b=...\\n\"\n       \"return a<=b\\n\";\n\nCOMPAT53_API int lua_compare(lua_State* L, int idx1, int idx2, int op) {\n\tint result = 0;\n\tswitch (op) {\n\tcase LUA_OPEQ:\n\t\treturn lua_equal(L, idx1, idx2);\n\tcase LUA_OPLT:\n\t\treturn lua_lessthan(L, idx1, idx2);\n\tcase LUA_OPLE:\n\t\tluaL_checkstack(L, 5, \"not enough stack slots\");\n\t\tidx1 = lua_absindex(L, idx1);\n\t\tidx2 = lua_absindex(L, idx2);\n\t\tlua_pushvalue(L, idx1);\n\t\tlua_pushvalue(L, idx2);\n\t\tcompat53_call_lua(L, compat53_compare_code, sizeof(compat53_compare_code) - 1, 2, 1);\n\t\tresult = lua_toboolean(L, -1);\n\t\tlua_pop(L, 1);\n\t\treturn result;\n\tdefault:\n\t\tluaL_error(L, \"invalid 'op' argument for lua_compare\");\n\t}\n\treturn 0;\n}\n\nCOMPAT53_API void lua_copy(lua_State* L, int from, int to) {\n\tint abs_to = lua_absindex(L, to);\n\tluaL_checkstack(L, 1, \"not enough stack slots\");\n\tlua_pushvalue(L, from);\n\tlua_replace(L, abs_to);\n}\n\nCOMPAT53_API void lua_len(lua_State* L, int i) {\n\tswitch (lua_type(L, i)) {\n\tcase LUA_TSTRING:\n\t\tlua_pushnumber(L, (lua_Number)lua_objlen(L, i));\n\t\tbreak;\n\tcase LUA_TTABLE:\n\t\tif (!luaL_callmeta(L, i, \"__len\"))\n\t\t\tlua_pushnumber(L, (lua_Number)lua_objlen(L, i));\n\t\tbreak;\n\tcase LUA_TUSERDATA:\n\t\tif (luaL_callmeta(L, i, \"__len\"))\n\t\t\tbreak;\n\t\t/* FALLTHROUGH */\n\tdefault:\n\t\tluaL_error(L, \"attempt to get length of a %s value\", lua_typename(L, lua_type(L, i)));\n\t}\n}\n\nCOMPAT53_API int lua_rawgetp(lua_State* L, int i, const void* p) {\n\tint abs_i = lua_absindex(L, i);\n\tlua_pushlightuserdata(L, (void*)p);\n\tlua_rawget(L, abs_i);\n\treturn lua_type(L, -1);\n}\n\nCOMPAT53_API void lua_rawsetp(lua_State* L, int i, const void* p) {\n\tint abs_i = lua_absindex(L, i);\n\tluaL_checkstack(L, 1, \"not enough stack slots\");\n\tlua_pushlightuserdata(L, (void*)p);\n\tlua_insert(L, -2);\n\tlua_rawset(L, abs_i);\n}\n\nCOMPAT53_API lua_Number lua_tonumberx(lua_State* L, int i, int* isnum) {\n\tlua_Number n = lua_tonumber(L, i);\n\tif (isnum != NULL) {\n\t\t*isnum = (n != 0 || lua_isnumber(L, i));\n\t}\n\treturn n;\n}\n\nCOMPAT53_API void luaL_checkversion(lua_State* L) {\n\t(void)L;\n}\n\nCOMPAT53_API void luaL_checkstack(lua_State* L, int sp, const char* msg) {\n\tif (!lua_checkstack(L, sp + LUA_MINSTACK)) {\n\t\tif (msg != NULL)\n\t\t\tluaL_error(L, \"stack overflow (%s)\", msg);\n\t\telse {\n\t\t\tlua_pushliteral(L, \"stack overflow\");\n\t\t\tlua_error(L);\n\t\t}\n\t}\n}\n\nCOMPAT53_API int luaL_getsubtable(lua_State* L, int i, const char* name) {\n\tint abs_i = lua_absindex(L, i);\n\tluaL_checkstack(L, 3, \"not enough stack slots\");\n\tlua_pushstring(L, name);\n\tlua_gettable(L, abs_i);\n\tif (lua_istable(L, -1))\n\t\treturn 1;\n\tlua_pop(L, 1);\n\tlua_newtable(L);\n\tlua_pushstring(L, name);\n\tlua_pushvalue(L, -2);\n\tlua_settable(L, abs_i);\n\treturn 0;\n}\n\nCOMPAT53_API lua_Integer luaL_len(lua_State* L, int i) {\n\tlua_Integer res = 0;\n\tint isnum = 0;\n\tluaL_checkstack(L, 1, \"not enough stack slots\");\n\tlua_len(L, i);\n\tres = lua_tointegerx(L, -1, &isnum);\n\tlua_pop(L, 1);\n\tif (!isnum)\n\t\tluaL_error(L, \"object length is not an integer\");\n\treturn res;\n}\n\nCOMPAT53_API void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) {\n\tluaL_checkstack(L, nup + 1, \"too many upvalues\");\n\tfor (; l->name != NULL; l++) { /* fill the table with given functions */\n\t\tint i;\n\t\tlua_pushstring(L, l->name);\n\t\tfor (i = 0; i < nup; i++) /* copy upvalues to the top */\n\t\t\tlua_pushvalue(L, -(nup + 1));\n\t\tlua_pushcclosure(L, l->func, nup); /* closure with those upvalues */\n\t\tlua_settable(L, -(nup + 3));       /* table must be below the upvalues, the name and the closure */\n\t}\n\tlua_pop(L, nup); /* remove upvalues */\n}\n\nCOMPAT53_API void luaL_setmetatable(lua_State* L, const char* tname) {\n\tluaL_checkstack(L, 1, \"not enough stack slots\");\n\tluaL_getmetatable(L, tname);\n\tlua_setmetatable(L, -2);\n}\n\nCOMPAT53_API void* luaL_testudata(lua_State* L, int i, const char* tname) {\n\tvoid* p = lua_touserdata(L, i);\n\tluaL_checkstack(L, 2, \"not enough stack slots\");\n\tif (p == NULL || !lua_getmetatable(L, i))\n\t\treturn NULL;\n\telse {\n\t\tint res = 0;\n\t\tluaL_getmetatable(L, tname);\n\t\tres = lua_rawequal(L, -1, -2);\n\t\tlua_pop(L, 2);\n\t\tif (!res)\n\t\t\tp = NULL;\n\t}\n\treturn p;\n}\n\nstatic int compat53_countlevels(lua_State* L) {\n\tlua_Debug ar;\n\tint li = 1, le = 1;\n\t/* find an upper bound */\n\twhile (lua_getstack(L, le, &ar)) {\n\t\tli = le;\n\t\tle *= 2;\n\t}\n\t/* do a binary search */\n\twhile (li < le) {\n\t\tint m = (li + le) / 2;\n\t\tif (lua_getstack(L, m, &ar))\n\t\t\tli = m + 1;\n\t\telse\n\t\t\tle = m;\n\t}\n\treturn le - 1;\n}\n\nstatic int compat53_findfield(lua_State* L, int objidx, int level) {\n\tif (level == 0 || !lua_istable(L, -1))\n\t\treturn 0;                               /* not found */\n\tlua_pushnil(L);                              /* start 'next' loop */\n\twhile (lua_next(L, -2)) {                    /* for each pair in table */\n\t\tif (lua_type(L, -2) == LUA_TSTRING) {   /* ignore non-string keys */\n\t\t\tif (lua_rawequal(L, objidx, -1)) { /* found object? */\n\t\t\t\tlua_pop(L, 1);                /* remove value (but keep name) */\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */\n\t\t\t\tlua_remove(L, -2);                              /* remove table (but keep name) */\n\t\t\t\tlua_pushliteral(L, \".\");\n\t\t\t\tlua_insert(L, -2); /* place '.' between the two names */\n\t\t\t\tlua_concat(L, 3);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tlua_pop(L, 1); /* remove value */\n\t}\n\treturn 0; /* not found */\n}\n\nstatic int compat53_pushglobalfuncname(lua_State* L, lua_Debug* ar) {\n\tint top = lua_gettop(L);\n\tlua_getinfo(L, \"f\", ar); /* push function */\n\tlua_pushvalue(L, LUA_GLOBALSINDEX);\n\tif (compat53_findfield(L, top + 1, 2)) {\n\t\tlua_copy(L, -1, top + 1); /* move name to proper place */\n\t\tlua_pop(L, 2);            /* remove pushed values */\n\t\treturn 1;\n\t}\n\telse {\n\t\tlua_settop(L, top); /* remove function and global table */\n\t\treturn 0;\n\t}\n}\n\nstatic void compat53_pushfuncname(lua_State* L, lua_Debug* ar) {\n\tif (*ar->namewhat != '\\0') /* is there a name? */\n\t\tlua_pushfstring(L, \"function \" LUA_QS, ar->name);\n\telse if (*ar->what == 'm') /* main? */\n\t\tlua_pushliteral(L, \"main chunk\");\n\telse if (*ar->what == 'C') {\n\t\tif (compat53_pushglobalfuncname(L, ar)) {\n\t\t\tlua_pushfstring(L, \"function \" LUA_QS, lua_tostring(L, -1));\n\t\t\tlua_remove(L, -2); /* remove name */\n\t\t}\n\t\telse\n\t\t\tlua_pushliteral(L, \"?\");\n\t}\n\telse\n\t\tlua_pushfstring(L, \"function <%s:%d>\", ar->short_src, ar->linedefined);\n}\n\n#define COMPAT53_LEVELS1 12 /* size of the first part of the stack */\n#define COMPAT53_LEVELS2 10 /* size of the second part of the stack */\n\nCOMPAT53_API void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level) {\n\tlua_Debug ar;\n\tint top = lua_gettop(L);\n\tint numlevels = compat53_countlevels(L1);\n\tint mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0;\n\tif (msg)\n\t\tlua_pushfstring(L, \"%s\\n\", msg);\n\tlua_pushliteral(L, \"stack traceback:\");\n\twhile (lua_getstack(L1, level++, &ar)) {\n\t\tif (level == mark) {                       /* too many levels? */\n\t\t\tlua_pushliteral(L, \"\\n\\t...\");        /* add a '...' */\n\t\t\tlevel = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */\n\t\t}\n\t\telse {\n\t\t\tlua_getinfo(L1, \"Slnt\", &ar);\n\t\t\tlua_pushfstring(L, \"\\n\\t%s:\", ar.short_src);\n\t\t\tif (ar.currentline > 0)\n\t\t\t\tlua_pushfstring(L, \"%d:\", ar.currentline);\n\t\t\tlua_pushliteral(L, \" in \");\n\t\t\tcompat53_pushfuncname(L, &ar);\n\t\t\tlua_concat(L, lua_gettop(L) - top);\n\t\t}\n\t}\n\tlua_concat(L, lua_gettop(L) - top);\n}\n\nCOMPAT53_API int luaL_fileresult(lua_State* L, int stat, const char* fname) {\n\tconst char* serr = NULL;\n\tint en = errno; /* calls to Lua API may change this value */\n\tchar buf[512] = { 0 };\n\tif (stat) {\n\t\tlua_pushboolean(L, 1);\n\t\treturn 1;\n\t}\n\telse {\n\t\tlua_pushnil(L);\n\t\tserr = compat53_strerror(en, buf, sizeof(buf));\n\t\tif (fname)\n\t\t\tlua_pushfstring(L, \"%s: %s\", fname, serr);\n\t\telse\n\t\t\tlua_pushstring(L, serr);\n\t\tlua_pushnumber(L, (lua_Number)en);\n\t\treturn 3;\n\t}\n}\n\nstatic int compat53_checkmode(lua_State* L, const char* mode, const char* modename, int err) {\n\tif (mode && strchr(mode, modename[0]) == NULL) {\n\t\tlua_pushfstring(L, \"attempt to load a %s chunk (mode is '%s')\", modename, mode);\n\t\treturn err;\n\t}\n\treturn LUA_OK;\n}\n\ntypedef struct {\n\tlua_Reader reader;\n\tvoid* ud;\n\tint has_peeked_data;\n\tconst char* peeked_data;\n\tsize_t peeked_data_size;\n} compat53_reader_data;\n\nstatic const char* compat53_reader(lua_State* L, void* ud, size_t* size) {\n\tcompat53_reader_data* data = (compat53_reader_data*)ud;\n\tif (data->has_peeked_data) {\n\t\tdata->has_peeked_data = 0;\n\t\t*size = data->peeked_data_size;\n\t\treturn data->peeked_data;\n\t}\n\telse\n\t\treturn data->reader(L, data->ud, size);\n}\n\nCOMPAT53_API int lua_load(lua_State* L, lua_Reader reader, void* data, const char* source, const char* mode) {\n\tint status = LUA_OK;\n\tcompat53_reader_data compat53_data = { reader, data, 1, 0, 0 };\n\tcompat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size));\n\tif (compat53_data.peeked_data && compat53_data.peeked_data_size && compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */\n\t\tstatus = compat53_checkmode(L, mode, \"binary\", LUA_ERRSYNTAX);\n\telse\n\t\tstatus = compat53_checkmode(L, mode, \"text\", LUA_ERRSYNTAX);\n\tif (status != LUA_OK)\n\t\treturn status;\n\t\t/* we need to call the original 5.1 version of lua_load! */\n#undef lua_load\n\treturn lua_load(L, compat53_reader, &compat53_data, source);\n#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53)\n}\n\ntypedef struct {\n\tint n;                                    /* number of pre-read characters */\n\tFILE* f;                                  /* file being read */\n\tchar buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */\n} compat53_LoadF;\n\nstatic const char* compat53_getF(lua_State* L, void* ud, size_t* size) {\n\tcompat53_LoadF* lf = (compat53_LoadF*)ud;\n\t(void)L;            /* not used */\n\tif (lf->n > 0) {    /* are there pre-read characters to be read? */\n\t\t*size = lf->n; /* return them (chars already in buffer) */\n\t\tlf->n = 0;     /* no more pre-read characters */\n\t}\n\telse { /* read a block from file */\n\t\t  /* 'fread' can return > 0 *and* set the EOF flag. If next call to\n\t\t  'compat53_getF' called 'fread', it might still wait for user input.\n\t\t  The next check avoids this problem. */\n\t\tif (feof(lf->f))\n\t\t\treturn NULL;\n\t\t*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */\n\t}\n\treturn lf->buff;\n}\n\nstatic int compat53_errfile(lua_State* L, const char* what, int fnameindex) {\n\tchar buf[512] = { 0 };\n\tconst char* serr = compat53_strerror(errno, buf, sizeof(buf));\n\tconst char* filename = lua_tostring(L, fnameindex) + 1;\n\tlua_pushfstring(L, \"cannot %s %s: %s\", what, filename, serr);\n\tlua_remove(L, fnameindex);\n\treturn LUA_ERRFILE;\n}\n\nstatic int compat53_skipBOM(compat53_LoadF* lf) {\n\tconst char* p = \"\\xEF\\xBB\\xBF\"; /* UTF-8 BOM mark */\n\tint c;\n\tlf->n = 0;\n\tdo {\n\t\tc = getc(lf->f);\n\t\tif (c == EOF || c != *(const unsigned char*)p++)\n\t\t\treturn c;\n\t\tlf->buff[lf->n++] = (char)c; /* to be read by the parser */\n\t} while (*p != '\\0');\n\tlf->n = 0;          /* prefix matched; discard it */\n\treturn getc(lf->f); /* return next character */\n}\n\n/*\n** reads the first character of file 'f' and skips an optional BOM mark\n** in its beginning plus its first line if it starts with '#'. Returns\n** true if it skipped the first line.  In any case, '*cp' has the\n** first \"valid\" character of the file (after the optional BOM and\n** a first-line comment).\n*/\nstatic int compat53_skipcomment(compat53_LoadF* lf, int* cp) {\n\tint c = *cp = compat53_skipBOM(lf);\n\tif (c == '#') { /* first line is a comment (Unix exec. file)? */\n\t\tdo {       /* skip first line */\n\t\t\tc = getc(lf->f);\n\t\t} while (c != EOF && c != '\\n');\n\t\t*cp = getc(lf->f); /* skip end-of-line, if present */\n\t\treturn 1;          /* there was a comment */\n\t}\n\telse\n\t\treturn 0; /* no comment */\n}\n\nCOMPAT53_API int luaL_loadfilex(lua_State* L, const char* filename, const char* mode) {\n\tcompat53_LoadF lf;\n\tint status, readstatus;\n\tint c;\n\tint fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */\n\tif (filename == NULL) {\n\t\tlua_pushliteral(L, \"=stdin\");\n\t\tlf.f = stdin;\n\t}\n\telse {\n\t\tlua_pushfstring(L, \"@%s\", filename);\n#if defined(_MSC_VER)\n\t\t/* This code is here to stop a deprecation error that stops builds\n\t\t * if a certain macro is defined. While normally not caring would\n\t\t * be best, some header-only libraries and builds can't afford to\n\t\t * dictate this to the user. A quick check shows that fopen_s this\n\t\t * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET,\n\t\t * possibly even before that so we don't need to do any version\n\t\t * number checks, since this has been there since forever.  */\n\n\t\t/* TO USER: if you want the behavior of typical fopen_s/fopen,\n\t\t * which does lock the file on VC++, define the macro used below to 0 */\n#if COMPAT53_FOPEN_NO_LOCK\n\t\tlf.f = _fsopen(filename, \"r\", _SH_DENYNO); /* do not lock the file in any way */\n\t\tif (lf.f == NULL)\n\t\t\treturn compat53_errfile(L, \"open\", fnameindex);\n#else  /* use default locking version */\n\t\tif (fopen_s(&lf.f, filename, \"r\") != 0)\n\t\t\treturn compat53_errfile(L, \"open\", fnameindex);\n#endif /* Locking vs. No-locking fopen variants */\n#else\n\t\tlf.f = fopen(filename, \"r\"); /* default stdlib doesn't forcefully lock files here */\n\t\tif (lf.f == NULL)\n\t\t\treturn compat53_errfile(L, \"open\", fnameindex);\n#endif\n\t}\n\tif (compat53_skipcomment(&lf, &c))       /* read initial portion */\n\t\tlf.buff[lf.n++] = '\\n';             /* add line to correct line numbers */\n\tif (c == LUA_SIGNATURE[0] && filename) { /* binary file? */\n#if defined(_MSC_VER)\n\t\tif (freopen_s(&lf.f, filename, \"rb\", lf.f) != 0)\n\t\t\treturn compat53_errfile(L, \"reopen\", fnameindex);\n#else\n\t\tlf.f = freopen(filename, \"rb\", lf.f); /* reopen in binary mode */\n\t\tif (lf.f == NULL)\n\t\t\treturn compat53_errfile(L, \"reopen\", fnameindex);\n#endif\n\t\tcompat53_skipcomment(&lf, &c); /* re-read initial portion */\n\t}\n\tif (c != EOF)\n\t\tlf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */\n\tstatus = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode);\n\treadstatus = ferror(lf.f);\n\tif (filename)\n\t\tfclose(lf.f); /* close file (even in case of errors) */\n\tif (readstatus) {\n\t\tlua_settop(L, fnameindex); /* ignore results from 'lua_load' */\n\t\treturn compat53_errfile(L, \"read\", fnameindex);\n\t}\n\tlua_remove(L, fnameindex);\n\treturn status;\n}\n\nCOMPAT53_API int luaL_loadbufferx(lua_State* L, const char* buff, size_t sz, const char* name, const char* mode) {\n\tint status = LUA_OK;\n\tif (sz > 0 && buff[0] == LUA_SIGNATURE[0]) {\n\t\tstatus = compat53_checkmode(L, mode, \"binary\", LUA_ERRSYNTAX);\n\t}\n\telse {\n\t\tstatus = compat53_checkmode(L, mode, \"text\", LUA_ERRSYNTAX);\n\t}\n\tif (status != LUA_OK)\n\t\treturn status;\n\treturn luaL_loadbuffer(L, buff, sz, name);\n}\n\n#if !defined(l_inspectstat) \\\n     && (defined(unix) || defined(__unix) || defined(__unix__) || defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || (defined(__APPLE__) && defined(__MACH__)))\n/* some form of unix; check feature macros in unistd.h for details */\n#include <unistd.h>\n/* check posix version; the relevant include files and macros probably\n * were available before 2001, but I'm not sure */\n#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L\n#include <sys/wait.h>\n#define l_inspectstat(stat, what)   \\\n\tif (WIFEXITED(stat)) {         \\\n\t\tstat = WEXITSTATUS(stat); \\\n\t}                              \\\n\telse if (WIFSIGNALED(stat)) {  \\\n\t\tstat = WTERMSIG(stat);    \\\n\t\twhat = \"signal\";          \\\n\t}\n#endif\n#endif\n\n/* provide default (no-op) version */\n#if !defined(l_inspectstat)\n#define l_inspectstat(stat, what) ((void)0)\n#endif\n\nCOMPAT53_API int luaL_execresult(lua_State* L, int stat) {\n\tconst char* what = \"exit\";\n\tif (stat == -1)\n\t\treturn luaL_fileresult(L, 0, NULL);\n\telse {\n\t\tl_inspectstat(stat, what);\n\t\tif (*what == 'e' && stat == 0)\n\t\t\tlua_pushboolean(L, 1);\n\t\telse\n\t\t\tlua_pushnil(L);\n\t\tlua_pushstring(L, what);\n\t\tlua_pushinteger(L, stat);\n\t\treturn 3;\n\t}\n}\n\nCOMPAT53_API void luaL_buffinit(lua_State* L, luaL_Buffer_53* B) {\n\t/* make it crash if used via pointer to a 5.1-style luaL_Buffer */\n\tB->b.p = NULL;\n\tB->b.L = NULL;\n\tB->b.lvl = 0;\n\t/* reuse the buffer from the 5.1-style luaL_Buffer though! */\n\tB->ptr = B->b.buffer;\n\tB->capacity = LUAL_BUFFERSIZE;\n\tB->nelems = 0;\n\tB->L2 = L;\n}\n\nCOMPAT53_API char* luaL_prepbuffsize(luaL_Buffer_53* B, size_t s) {\n\tif (B->capacity - B->nelems < s) { /* needs to grow */\n\t\tchar* newptr = NULL;\n\t\tsize_t newcap = B->capacity * 2;\n\t\tif (newcap - B->nelems < s)\n\t\t\tnewcap = B->nelems + s;\n\t\tif (newcap < B->capacity) /* overflow */\n\t\t\tluaL_error(B->L2, \"buffer too large\");\n\t\tnewptr = (char*)lua_newuserdata(B->L2, newcap);\n\t\tmemcpy(newptr, B->ptr, B->nelems);\n\t\tif (B->ptr != B->b.buffer)\n\t\t\tlua_replace(B->L2, -2); /* remove old buffer */\n\t\tB->ptr = newptr;\n\t\tB->capacity = newcap;\n\t}\n\treturn B->ptr + B->nelems;\n}\n\nCOMPAT53_API void luaL_addlstring(luaL_Buffer_53* B, const char* s, size_t l) {\n\tmemcpy(luaL_prepbuffsize(B, l), s, l);\n\tluaL_addsize(B, l);\n}\n\nCOMPAT53_API void luaL_addvalue(luaL_Buffer_53* B) {\n\tsize_t len = 0;\n\tconst char* s = lua_tolstring(B->L2, -1, &len);\n\tif (!s)\n\t\tluaL_error(B->L2, \"cannot convert value to string\");\n\tif (B->ptr != B->b.buffer)\n\t\tlua_insert(B->L2, -2); /* userdata buffer must be at stack top */\n\tluaL_addlstring(B, s, len);\n\tlua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1);\n}\n\nvoid luaL_pushresult(luaL_Buffer_53* B) {\n\tlua_pushlstring(B->L2, B->ptr, B->nelems);\n\tif (B->ptr != B->b.buffer)\n\t\tlua_replace(B->L2, -2); /* remove userdata buffer */\n}\n\n#endif /* Lua 5.1 */\n\n/* definitions for Lua 5.1 and Lua 5.2 */\n#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502\n\nCOMPAT53_API int lua_geti(lua_State* L, int index, lua_Integer i) {\n\tindex = lua_absindex(L, index);\n\tlua_pushinteger(L, i);\n\tlua_gettable(L, index);\n\treturn lua_type(L, -1);\n}\n\nCOMPAT53_API int lua_isinteger(lua_State* L, int index) {\n\tif (lua_type(L, index) == LUA_TNUMBER) {\n\t\tlua_Number n = lua_tonumber(L, index);\n\t\tlua_Integer i = lua_tointeger(L, index);\n\t\tif (i == n)\n\t\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nCOMPAT53_API lua_Integer lua_tointegerx(lua_State* L, int i, int* isnum) {\n\tint ok = 0;\n\tlua_Number n = lua_tonumberx(L, i, &ok);\n\tif (ok) {\n\t\tif (n == (lua_Integer)n) {\n\t\t\tif (isnum)\n\t\t\t\t*isnum = 1;\n\t\t\treturn (lua_Integer)n;\n\t\t}\n\t}\n\tif (isnum)\n\t\t*isnum = 0;\n\treturn 0;\n}\n\nstatic void compat53_reverse(lua_State* L, int a, int b) {\n\tfor (; a < b; ++a, --b) {\n\t\tlua_pushvalue(L, a);\n\t\tlua_pushvalue(L, b);\n\t\tlua_replace(L, a);\n\t\tlua_replace(L, b);\n\t}\n}\n\nCOMPAT53_API void lua_rotate(lua_State* L, int idx, int n) {\n\tint n_elems = 0;\n\tidx = lua_absindex(L, idx);\n\tn_elems = lua_gettop(L) - idx + 1;\n\tif (n < 0)\n\t\tn += n_elems;\n\tif (n > 0 && n < n_elems) {\n\t\tluaL_checkstack(L, 2, \"not enough stack slots available\");\n\t\tn = n_elems - n;\n\t\tcompat53_reverse(L, idx, idx + n - 1);\n\t\tcompat53_reverse(L, idx + n, idx + n_elems - 1);\n\t\tcompat53_reverse(L, idx, idx + n_elems - 1);\n\t}\n}\n\nCOMPAT53_API void lua_seti(lua_State* L, int index, lua_Integer i) {\n\tluaL_checkstack(L, 1, \"not enough stack slots available\");\n\tindex = lua_absindex(L, index);\n\tlua_pushinteger(L, i);\n\tlua_insert(L, -2);\n\tlua_settable(L, index);\n}\n\n#if !defined(lua_str2number)\n#define lua_str2number(s, p) strtod((s), (p))\n#endif\n\nCOMPAT53_API size_t lua_stringtonumber(lua_State* L, const char* s) {\n\tchar* endptr;\n\tlua_Number n = lua_str2number(s, &endptr);\n\tif (endptr != s) {\n\t\twhile (*endptr != '\\0' && isspace((unsigned char)*endptr))\n\t\t\t++endptr;\n\t\tif (*endptr == '\\0') {\n\t\t\tlua_pushnumber(L, n);\n\t\t\treturn endptr - s + 1;\n\t\t}\n\t}\n\treturn 0;\n}\n\nCOMPAT53_API const char* luaL_tolstring(lua_State* L, int idx, size_t* len) {\n\tif (!luaL_callmeta(L, idx, \"__tostring\")) {\n\t\tint t = lua_type(L, idx), tt = 0;\n\t\tchar const* name = NULL;\n\t\tswitch (t) {\n\t\tcase LUA_TNIL:\n\t\t\tlua_pushliteral(L, \"nil\");\n\t\t\tbreak;\n\t\tcase LUA_TSTRING:\n\t\tcase LUA_TNUMBER:\n\t\t\tlua_pushvalue(L, idx);\n\t\t\tbreak;\n\t\tcase LUA_TBOOLEAN:\n\t\t\tif (lua_toboolean(L, idx))\n\t\t\t\tlua_pushliteral(L, \"true\");\n\t\t\telse\n\t\t\t\tlua_pushliteral(L, \"false\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttt = luaL_getmetafield(L, idx, \"__name\");\n\t\t\tname = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t);\n\t\t\tlua_pushfstring(L, \"%s: %p\", name, lua_topointer(L, idx));\n\t\t\tif (tt != LUA_TNIL)\n\t\t\t\tlua_replace(L, -2);\n\t\t\tbreak;\n\t\t}\n\t}\n\telse {\n\t\tif (!lua_isstring(L, -1))\n\t\t\tluaL_error(L, \"'__tostring' must return a string\");\n\t}\n\treturn lua_tolstring(L, -1, len);\n}\n\nCOMPAT53_API void luaL_requiref(lua_State* L, const char* modname, lua_CFunction openf, int glb) {\n\tluaL_checkstack(L, 3, \"not enough stack slots available\");\n\tluaL_getsubtable(L, LUA_REGISTRYINDEX, \"_LOADED\");\n\tif (lua_getfield(L, -1, modname) == LUA_TNIL) {\n\t\tlua_pop(L, 1);\n\t\tlua_pushcfunction(L, openf);\n\t\tlua_pushstring(L, modname);\n\t\tlua_call(L, 1, 1);\n\t\tlua_pushvalue(L, -1);\n\t\tlua_setfield(L, -3, modname);\n\t}\n\tif (glb) {\n\t\tlua_pushvalue(L, -1);\n\t\tlua_setglobal(L, modname);\n\t}\n\tlua_replace(L, -2);\n}\n\n#endif /* Lua 5.1 and 5.2 */\n\n#endif /* KEPLER_PROJECT_COMPAT53_C_ */\n\n/*********************************************************************\n * This file contains parts of Lua 5.2's and Lua 5.3's source code:\n *\n * Copyright (C) 1994-2014 Lua.org, PUC-Rio.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *********************************************************************/\n// end of sol/compatibility/compat-5.3.c.h\n\n#endif\n\n#endif /* KEPLER_PROJECT_COMPAT53_H_ */\n\n// end of sol/compatibility/compat-5.3.h\n\n// beginning of sol/compatibility/compat-5.4.h\n\n#ifndef NOT_KEPLER_PROJECT_COMPAT54_H_\n#define NOT_KEPLER_PROJECT_COMPAT54_H_\n\n#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)\nextern \"C\" {\n#endif\n#include <lua.h>\n#include <lauxlib.h>\n#include <lualib.h>\n#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)\n}\n#endif\n\n#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 504\n\n#if !defined(LUA_ERRGCMM)\n/* So Lua 5.4 actually removes this, which breaks sol2...\n man, this API is quite unstable...!\n*/\n#  define LUA_ERRGCMM (LUA_ERRERR + 2)\n#endif /* LUA_ERRGCMM define */\n\n#endif // Lua 5.4 only\n\n#endif // NOT_KEPLER_PROJECT_COMPAT54_H_// end of sol/compatibility/compat-5.4.h\n\n#endif\n\n// end of sol/compatibility.hpp\n\n#include <vector>\n#include <cstdint>\n#include <cstddef>\n\nnamespace sol {\n\n\ttemplate <typename Allocator = std::allocator<std::byte>>\n\tclass basic_bytecode : private std::vector<std::byte, Allocator> {\n\tprivate:\n\t\tusing base_t = std::vector<std::byte, Allocator>;\n\n\tpublic:\n\t\tusing typename base_t::allocator_type;\n\t\tusing typename base_t::const_iterator;\n\t\tusing typename base_t::const_pointer;\n\t\tusing typename base_t::const_reference;\n\t\tusing typename base_t::const_reverse_iterator;\n\t\tusing typename base_t::difference_type;\n\t\tusing typename base_t::iterator;\n\t\tusing typename base_t::pointer;\n\t\tusing typename base_t::reference;\n\t\tusing typename base_t::reverse_iterator;\n\t\tusing typename base_t::size_type;\n\t\tusing typename base_t::value_type;\n\n\t\tusing base_t::base_t;\n\t\tusing base_t::operator=;\n\n\t\tusing base_t::data;\n\t\tusing base_t::empty;\n\t\tusing base_t::max_size;\n\t\tusing base_t::size;\n\n\t\tusing base_t::at;\n\t\tusing base_t::operator[];\n\t\tusing base_t::back;\n\t\tusing base_t::front;\n\n\t\tusing base_t::begin;\n\t\tusing base_t::cbegin;\n\t\tusing base_t::cend;\n\t\tusing base_t::end;\n\n\t\tusing base_t::crbegin;\n\t\tusing base_t::crend;\n\t\tusing base_t::rbegin;\n\t\tusing base_t::rend;\n\n\t\tusing base_t::get_allocator;\n\t\tusing base_t::swap;\n\n\t\tusing base_t::clear;\n\t\tusing base_t::emplace;\n\t\tusing base_t::emplace_back;\n\t\tusing base_t::erase;\n\t\tusing base_t::insert;\n\t\tusing base_t::pop_back;\n\t\tusing base_t::push_back;\n\t\tusing base_t::reserve;\n\t\tusing base_t::resize;\n\t\tusing base_t::shrink_to_fit;\n\n\t\tstring_view as_string_view() const {\n\t\t\treturn string_view(reinterpret_cast<const char*>(this->data()), this->size());\n\t\t}\n\t};\n\n\ttemplate <typename Container>\n\tinline int basic_insert_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata) {\n\t\tusing storage_t = Container;\n\t\tconst std::byte* p_code = static_cast<const std::byte*>(memory);\n\t\tstorage_t& bc = *static_cast<storage_t*>(userdata);\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\tbc.insert(bc.cend(), p_code, p_code + memory_size);\n#else\n\t\ttry {\n\t\t\tbc.insert(bc.cend(), p_code, p_code + memory_size);\n\t\t}\n\t\tcatch (...) {\n\t\t\treturn -1;\n\t\t}\n#endif\n\t\treturn 0;\n\t}\n\n\tusing bytecode = basic_bytecode<>;\n\n\tconstexpr inline auto bytecode_dump_writer = &basic_insert_dump_writer<bytecode>;\n\n} // namespace sol\n\n// end of sol/bytecode.hpp\n\n// beginning of sol/stack.hpp\n\n// beginning of sol/trampoline.hpp\n\n// beginning of sol/types.hpp\n\n// beginning of sol/error.hpp\n\n#include <stdexcept>\n#include <string>\n#include <array>\n\nnamespace sol {\n\tnamespace detail {\n\t\tstruct direct_error_tag {};\n\t\tconst auto direct_error = direct_error_tag{};\n\n\t\tstruct error_result {\n\t\t\tint results;\n\t\t\tconst char* format_string;\n\t\t\tstd::array<const char*, 4> args_strings;\n\n\t\t\terror_result() : results(0), format_string(nullptr) {\n\t\t\t}\n\n\t\t\terror_result(int results) : results(results), format_string(nullptr) {\n\t\t\t}\n\n\t\t\terror_result(const char* fmt, const char* msg) : results(0), format_string(fmt) {\n\t\t\t\targs_strings[0] = msg;\n\t\t\t}\n\t\t};\n\n\t\tinline int handle_errors(lua_State* L, const error_result& er) {\n\t\t\tif (er.format_string == nullptr) {\n\t\t\t\treturn er.results;\n\t\t\t}\n\t\t\treturn luaL_error(L, er.format_string, er.args_strings[0], er.args_strings[1], er.args_strings[2], er.args_strings[3]);\n\t\t}\n\t} // namespace detail\n\n\tclass error : public std::runtime_error {\n\tprivate:\n\t\t// Because VC++ is upsetting, most of the time!\n\t\tstd::string what_reason;\n\n\tpublic:\n\t\terror(const std::string& str) : error(detail::direct_error, \"lua: error: \" + str) {\n\t\t}\n\t\terror(std::string&& str) : error(detail::direct_error, \"lua: error: \" + std::move(str)) {\n\t\t}\n\t\terror(detail::direct_error_tag, const std::string& str) : std::runtime_error(\"\"), what_reason(str) {\n\t\t}\n\t\terror(detail::direct_error_tag, std::string&& str) : std::runtime_error(\"\"), what_reason(std::move(str)) {\n\t\t}\n\n\t\terror(const error& e) = default;\n\t\terror(error&& e) = default;\n\t\terror& operator=(const error& e) = default;\n\t\terror& operator=(error&& e) = default;\n\n\t\tvirtual const char* what() const noexcept override {\n\t\t\treturn what_reason.c_str();\n\t\t}\n\t};\n\n} // namespace sol\n\n// end of sol/error.hpp\n\n// beginning of sol/optional.hpp\n\n// beginning of sol/in_place.hpp\n\n#include <cstddef>\n#include <utility>\n\nnamespace sol {\n\n\tusing in_place_t = std::in_place_t;\n\tconstexpr std::in_place_t in_place {};\n\tconstexpr std::in_place_t in_place_of {};\n\n\ttemplate <typename T>\n\tusing in_place_type_t = std::in_place_type_t<T>;\n\ttemplate <typename T>\n\tconstexpr std::in_place_type_t<T> in_place_type {};\n\n\ttemplate <size_t I>\n\tusing in_place_index_t = std::in_place_index_t<I>;\n\ttemplate <size_t I>\n\tconstexpr in_place_index_t<I> in_place_index {};\n\n} // namespace sol\n\n// end of sol/in_place.hpp\n\n#if SOL_IS_ON(SOL_USE_BOOST_I_)\n#include <boost/optional.hpp>\n#else\n// beginning of sol/optional_implementation.hpp\n\n#define SOL_TL_OPTIONAL_VERSION_MAJOR 0\n#define SOL_TL_OPTIONAL_VERSION_MINOR 5\n\n#include <exception>\n#include <functional>\n#include <new>\n#include <type_traits>\n#include <utility>\n#include <cstdlib>\n#include <optional>\n\n#if (defined(_MSC_VER) && _MSC_VER == 1900)\n#define SOL_TL_OPTIONAL_MSVC2015\n#endif\n\n#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))\n#define SOL_TL_OPTIONAL_GCC49\n#endif\n\n#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__))\n#define SOL_TL_OPTIONAL_GCC54\n#endif\n\n#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && !defined(__clang__))\n#define SOL_TL_OPTIONAL_GCC55\n#endif\n\n#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))\n#define SOL_TL_OPTIONAL_NO_CONSTRR\n\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::has_trivial_copy_constructor<T>::value\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value\n\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value\n\n#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))\n#ifndef SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX\n#define SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX\nnamespace sol { namespace detail {\n\ttemplate <class T>\n\tstruct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {};\n#ifdef _GLIBCXX_VECTOR\n\ttemplate <class T, class A>\n\tstruct is_trivially_copy_constructible<std::vector<T, A>> : std::is_trivially_copy_constructible<T> {};\n#endif\n}} // namespace sol::detail\n#endif\n\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) sol::detail::is_trivially_copy_constructible<T>::value\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value\n#else\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::is_trivially_copy_constructible<T>::value\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value\n#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value\n#endif\n\n#if __cplusplus > 201103L\n#define SOL_TL_OPTIONAL_CXX14\n#endif\n\n#if (__cplusplus == 201103L || defined(SOL_TL_OPTIONAL_MSVC2015) || defined(SOL_TL_OPTIONAL_GCC49))\n#define SOL_TL_OPTIONAL_11_CONSTEXPR\n#else\n   /// \\exclude\n#define SOL_TL_OPTIONAL_11_CONSTEXPR constexpr\n#endif\n\nnamespace sol {\n#ifndef SOL_TL_MONOSTATE_INPLACE_MUTEX\n#define SOL_TL_MONOSTATE_INPLACE_MUTEX\n\t/// \\brief Used to represent an optional with no data; essentially a bool\n\tclass monostate {};\n#endif\n\n\ttemplate <class T>\n\tclass optional;\n\n\t/// \\exclude\n\tnamespace detail {\n#ifndef SOL_TL_TRAITS_MUTEX\n#define SOL_TL_TRAITS_MUTEX\n\t\t// C++14-style aliases for brevity\n\t\ttemplate <class T>\n\t\tusing remove_const_t = typename std::remove_const<T>::type;\n\t\ttemplate <class T>\n\t\tusing remove_reference_t = typename std::remove_reference<T>::type;\n\t\ttemplate <class T>\n\t\tusing decay_t = typename std::decay<T>::type;\n\t\ttemplate <bool E, class T = void>\n\t\tusing enable_if_t = typename std::enable_if<E, T>::type;\n\t\ttemplate <bool B, class T, class F>\n\t\tusing conditional_t = typename std::conditional<B, T, F>::type;\n\n\t\t// std::conjunction from C++17\n\t\ttemplate <class...>\n\t\tstruct conjunction : std::true_type {};\n\t\ttemplate <class B>\n\t\tstruct conjunction<B> : B {};\n\t\ttemplate <class B, class... Bs>\n\t\tstruct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};\n\n#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L\n#define SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND\n#endif\n\n#ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND\n\t\ttemplate <class T>\n\t\tstruct is_pointer_to_non_const_member_func : std::false_type {};\n\t\ttemplate <class T, class Ret, class... Args>\n\t\tstruct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type {};\n\t\ttemplate <class T, class Ret, class... Args>\n\t\tstruct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&> : std::true_type {};\n\t\ttemplate <class T, class Ret, class... Args>\n\t\tstruct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type {};\n\t\ttemplate <class T, class Ret, class... Args>\n\t\tstruct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type {};\n\t\ttemplate <class T, class Ret, class... Args>\n\t\tstruct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&> : std::true_type {};\n\t\ttemplate <class T, class Ret, class... Args>\n\t\tstruct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&> : std::true_type {};\n\n\t\ttemplate <class T>\n\t\tstruct is_const_or_const_ref : std::false_type {};\n\t\ttemplate <class T>\n\t\tstruct is_const_or_const_ref<T const&> : std::true_type {};\n\t\ttemplate <class T>\n\t\tstruct is_const_or_const_ref<T const> : std::true_type {};\n#endif\n\n\t\t// std::invoke from C++17\n\t\t// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround\n\t\ttemplate <typename Fn, typename... Args,\n#ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND\n\t\t     typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value && is_const_or_const_ref<Args...>::value)>,\n#endif\n\t\t     typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>\n\t\tconstexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))\n\t\t     -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {\n\t\t\treturn std::mem_fn(f)(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename Fn, typename... Args, typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>\n\t\tconstexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))\n\t\t     -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {\n\t\t\treturn std::forward<Fn>(f)(std::forward<Args>(args)...);\n\t\t}\n\n\t\t// std::invoke_result from C++17\n\t\ttemplate <class F, class, class... Us>\n\t\tstruct invoke_result_impl;\n\n\t\ttemplate <class F, class... Us>\n\t\tstruct invoke_result_impl<F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), Us...> {\n\t\t\tusing type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));\n\t\t};\n\n\t\ttemplate <class F, class... Us>\n\t\tusing invoke_result = invoke_result_impl<F, void, Us...>;\n\n\t\ttemplate <class F, class... Us>\n\t\tusing invoke_result_t = typename invoke_result<F, Us...>::type;\n#endif\n\n\t\t// std::void_t from C++17\n\t\ttemplate <class...>\n\t\tstruct voider {\n\t\t\tusing type = void;\n\t\t};\n\t\ttemplate <class... Ts>\n\t\tusing void_t = typename voider<Ts...>::type;\n\n\t\t// Trait for checking if a type is a sol::optional\n\t\ttemplate <class T>\n\t\tstruct is_optional_impl : std::false_type {};\n\t\ttemplate <class T>\n\t\tstruct is_optional_impl<optional<T>> : std::true_type {};\n\t\ttemplate <class T>\n\t\tusing is_optional = is_optional_impl<decay_t<T>>;\n\n\t\t// Change void to sol::monostate\n\t\ttemplate <class U>\n\t\tusing fixup_void = conditional_t<std::is_void<U>::value, monostate, U>;\n\n\t\ttemplate <class F, class U, class = invoke_result_t<F, U>>\n\t\tusing get_map_return = optional<fixup_void<invoke_result_t<F, U>>>;\n\n\t\t// Check if invoking F for some Us returns void\n\t\ttemplate <class F, class = void, class... U>\n\t\tstruct returns_void_impl;\n\t\ttemplate <class F, class... U>\n\t\tstruct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> : std::is_void<invoke_result_t<F, U...>> {};\n\t\ttemplate <class F, class... U>\n\t\tusing returns_void = returns_void_impl<F, void, U...>;\n\n\t\ttemplate <class T, class... U>\n\t\tusing enable_if_ret_void = enable_if_t<returns_void<T&&, U...>::value>;\n\n\t\ttemplate <class T, class... U>\n\t\tusing disable_if_ret_void = enable_if_t<!returns_void<T&&, U...>::value>;\n\n\t\ttemplate <class T, class U>\n\t\tusing enable_forward_value = detail::enable_if_t<std::is_constructible<T, U&&>::value && !std::is_same<detail::decay_t<U>, in_place_t>::value\n\t\t     && !std::is_same<optional<T>, detail::decay_t<U>>::value>;\n\n\t\ttemplate <class T, class U, class Other>\n\t\tusing enable_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && !std::is_constructible<T, optional<U>&>::value\n\t\t     && !std::is_constructible<T, optional<U>&&>::value && !std::is_constructible<T, const optional<U>&>::value\n\t\t     && !std::is_constructible<T, const optional<U>&&>::value && !std::is_convertible<optional<U>&, T>::value\n\t\t     && !std::is_convertible<optional<U>&&, T>::value && !std::is_convertible<const optional<U>&, T>::value\n\t\t     && !std::is_convertible<const optional<U>&&, T>::value>;\n\n\t\ttemplate <class T, class U>\n\t\tusing enable_assign_forward = detail::enable_if_t<!std::is_same<optional<T>, detail::decay_t<U>>::value\n\t\t     && !detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value && std::is_constructible<T, U>::value\n\t\t     && std::is_assignable<T&, U>::value>;\n\n\t\ttemplate <class T, class U, class Other>\n\t\tusing enable_assign_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && std::is_assignable<T&, Other>::value\n\t\t     && !std::is_constructible<T, optional<U>&>::value && !std::is_constructible<T, optional<U>&&>::value\n\t\t     && !std::is_constructible<T, const optional<U>&>::value && !std::is_constructible<T, const optional<U>&&>::value\n\t\t     && !std::is_convertible<optional<U>&, T>::value && !std::is_convertible<optional<U>&&, T>::value\n\t\t     && !std::is_convertible<const optional<U>&, T>::value && !std::is_convertible<const optional<U>&&, T>::value\n\t\t     && !std::is_assignable<T&, optional<U>&>::value && !std::is_assignable<T&, optional<U>&&>::value\n\t\t     && !std::is_assignable<T&, const optional<U>&>::value && !std::is_assignable<T&, const optional<U>&&>::value>;\n\n#ifdef _MSC_VER\n\t\t// TODO make a version which works with MSVC\n\t\ttemplate <class T, class U = T>\n\t\tstruct is_swappable : std::true_type {};\n\n\t\ttemplate <class T, class U = T>\n\t\tstruct is_nothrow_swappable : std::true_type {};\n#else\n\t\t// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept\n\t\tnamespace swap_adl_tests {\n\t\t\t// if swap ADL finds this then it would call std::swap otherwise (same\n\t\t\t// signature)\n\t\t\tstruct tag {};\n\n\t\t\ttemplate <class T>\n\t\t\ttag swap(T&, T&);\n\t\t\ttemplate <class T, std::size_t N>\n\t\t\ttag swap(T (&a)[N], T (&b)[N]);\n\n\t\t\t// helper functions to test if an unqualified swap is possible, and if it\n\t\t\t// becomes std::swap\n\t\t\ttemplate <class, class>\n\t\t\tstd::false_type can_swap(...) noexcept(false);\n\t\t\ttemplate <class T, class U, class = decltype(swap(std::declval<T&>(), std::declval<U&>()))>\n\t\t\tstd::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T&>(), std::declval<U&>())));\n\n\t\t\ttemplate <class, class>\n\t\t\tstd::false_type uses_std(...);\n\t\t\ttemplate <class T, class U>\n\t\t\tstd::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag> uses_std(int);\n\n\t\t\ttemplate <class T>\n\t\t\tstruct is_std_swap_noexcept\n\t\t\t: std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value> {};\n\n\t\t\ttemplate <class T, std::size_t N>\n\t\t\tstruct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};\n\n\t\t\ttemplate <class T, class U>\n\t\t\tstruct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};\n\t\t} // namespace swap_adl_tests\n\n\t\ttemplate <class T, class U = T>\n\t\tstruct is_swappable : std::integral_constant<bool,\n\t\t                           decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value\n\t\t                                && (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value\n\t\t                                     || (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> {};\n\n\t\ttemplate <class T, std::size_t N>\n\t\tstruct is_swappable<T[N], T[N]> : std::integral_constant<bool,\n\t\t                                       decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value\n\t\t                                            && (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || is_swappable<T, T>::value)> {};\n\n\t\ttemplate <class T, class U = T>\n\t\tstruct is_nothrow_swappable\n\t\t: std::integral_constant<bool,\n\t\t       is_swappable<T, U>::value\n\t\t            && ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value)\n\t\t                 || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};\n#endif\n\n\t\t// The storage base manages the actual storage, and correctly propagates\n\t\t// trivial destruction from T. This case is for when T is not trivially\n\t\t// destructible.\n\t\ttemplate <class T, bool = ::std::is_trivially_destructible<T>::value>\n\t\tstruct optional_storage_base {\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {\n\t\t\t}\n\n\t\t\ttemplate <class... U>\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) {\n\t\t\t}\n\n\t\t\t~optional_storage_base() {\n\t\t\t\tif (m_has_value) {\n\t\t\t\t\tm_value.~T();\n\t\t\t\t\tm_has_value = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstruct dummy {};\n\t\t\tunion {\n\t\t\t\tdummy m_dummy;\n\t\t\t\tT m_value;\n\t\t\t};\n\n\t\t\tbool m_has_value;\n\t\t};\n\n\t\t// This case is for when T is trivially destructible.\n\t\ttemplate <class T>\n\t\tstruct optional_storage_base<T, true> {\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {\n\t\t\t}\n\n\t\t\ttemplate <class... U>\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) {\n\t\t\t}\n\n\t\t\t// No destructor, so this class is trivially destructible\n\n\t\t\tstruct dummy {};\n\t\t\tunion {\n\t\t\t\tdummy m_dummy;\n\t\t\t\tT m_value;\n\t\t\t};\n\n\t\t\tbool m_has_value = false;\n\t\t};\n\n\t\t// This base class provides some handy member functions which can be used in\n\t\t// further derived classes\n\t\ttemplate <class T>\n\t\tstruct optional_operations_base : optional_storage_base<T> {\n\t\t\tusing optional_storage_base<T>::optional_storage_base;\n\n\t\t\tvoid hard_reset() noexcept {\n\t\t\t\tget().~T();\n\t\t\t\tthis->m_has_value = false;\n\t\t\t}\n\n\t\t\ttemplate <class... Args>\n\t\t\tvoid construct(Args&&... args) noexcept {\n\t\t\t\tnew (std::addressof(this->m_value)) T(std::forward<Args>(args)...);\n\t\t\t\tthis->m_has_value = true;\n\t\t\t}\n\n\t\t\ttemplate <class Opt>\n\t\t\tvoid assign(Opt&& rhs) {\n\t\t\t\tif (this->has_value()) {\n\t\t\t\t\tif (rhs.has_value()) {\n\t\t\t\t\t\tthis->m_value = std::forward<Opt>(rhs).get();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis->m_value.~T();\n\t\t\t\t\t\tthis->m_has_value = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telse if (rhs.has_value()) {\n\t\t\t\t\tconstruct(std::forward<Opt>(rhs).get());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool has_value() const {\n\t\t\t\treturn this->m_has_value;\n\t\t\t}\n\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T& get() & {\n\t\t\t\treturn this->m_value;\n\t\t\t}\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR const T& get() const& {\n\t\t\t\treturn this->m_value;\n\t\t\t}\n\t\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T&& get() && {\n\t\t\t\treturn std::move(this->m_value);\n\t\t\t}\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t\tconstexpr const T&& get() const&& {\n\t\t\t\treturn std::move(this->m_value);\n\t\t\t}\n#endif\n\t\t};\n\n\t\t// This class manages conditionally having a trivial copy constructor\n\t\t// This specialization is for when T is trivially copy constructible\n\t\ttemplate <class T, bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>\n\t\tstruct optional_copy_base : optional_operations_base<T> {\n\t\t\tusing optional_operations_base<T>::optional_operations_base;\n\t\t};\n\n\t\t// This specialization is for when T is not trivially copy constructible\n\t\ttemplate <class T>\n\t\tstruct optional_copy_base<T, false> : optional_operations_base<T> {\n\t\t\tusing base_t = optional_operations_base<T>;\n\n\t\t\tusing base_t::base_t;\n\n\t\t\toptional_copy_base() = default;\n\t\t\toptional_copy_base(const optional_copy_base& rhs) : base_t() {\n\t\t\t\tif (rhs.has_value()) {\n\t\t\t\t\tthis->construct(rhs.get());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis->m_has_value = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toptional_copy_base(optional_copy_base&& rhs) = default;\n\t\t\toptional_copy_base& operator=(const optional_copy_base& rhs) = default;\n\t\t\toptional_copy_base& operator=(optional_copy_base&& rhs) = default;\n\t\t};\n\n#ifndef SOL_TL_OPTIONAL_GCC49\n\t\ttemplate <class T, bool = std::is_trivially_move_constructible<T>::value>\n\t\tstruct optional_move_base : optional_copy_base<T> {\n\t\t\tusing optional_copy_base<T>::optional_copy_base;\n\t\t};\n#else\n\t\ttemplate <class T, bool = false>\n\t\tstruct optional_move_base;\n#endif\n\t\ttemplate <class T>\n\t\tstruct optional_move_base<T, false> : optional_copy_base<T> {\n\t\t\tusing optional_copy_base<T>::optional_copy_base;\n\n\t\t\toptional_move_base() = default;\n\t\t\toptional_move_base(const optional_move_base& rhs) = default;\n\n\t\t\toptional_move_base(optional_move_base&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) {\n\t\t\t\tif (rhs.has_value()) {\n\t\t\t\t\tthis->construct(std::move(rhs.get()));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis->m_has_value = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\toptional_move_base& operator=(const optional_move_base& rhs) = default;\n\t\t\toptional_move_base& operator=(optional_move_base&& rhs) = default;\n\t\t};\n\n\t\t// This class manages conditionally having a trivial copy assignment operator\n\t\ttemplate <class T,\n\t\t     bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) && SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)\n\t\t          && SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T)>\n\t\tstruct optional_copy_assign_base : optional_move_base<T> {\n\t\t\tusing optional_move_base<T>::optional_move_base;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_copy_assign_base<T, false> : optional_move_base<T> {\n\t\t\tusing optional_move_base<T>::optional_move_base;\n\n\t\t\toptional_copy_assign_base() = default;\n\t\t\toptional_copy_assign_base(const optional_copy_assign_base& rhs) = default;\n\n\t\t\toptional_copy_assign_base(optional_copy_assign_base&& rhs) = default;\n\t\t\toptional_copy_assign_base& operator=(const optional_copy_assign_base& rhs) {\n\t\t\t\tthis->assign(rhs);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\toptional_copy_assign_base& operator=(optional_copy_assign_base&& rhs) = default;\n\t\t};\n\n#ifndef SOL_TL_OPTIONAL_GCC49\n\t\ttemplate <class T,\n\t\t     bool = std::is_trivially_destructible<T>::value&& std::is_trivially_move_constructible<T>::value&& std::is_trivially_move_assignable<T>::value>\n\t\tstruct optional_move_assign_base : optional_copy_assign_base<T> {\n\t\t\tusing optional_copy_assign_base<T>::optional_copy_assign_base;\n\t\t};\n#else\n\t\ttemplate <class T, bool = false>\n\t\tstruct optional_move_assign_base;\n#endif\n\n\t\ttemplate <class T>\n\t\tstruct optional_move_assign_base<T, false> : optional_copy_assign_base<T> {\n\t\t\tusing optional_copy_assign_base<T>::optional_copy_assign_base;\n\n\t\t\toptional_move_assign_base() = default;\n\t\t\toptional_move_assign_base(const optional_move_assign_base& rhs) = default;\n\n\t\t\toptional_move_assign_base(optional_move_assign_base&& rhs) = default;\n\n\t\t\toptional_move_assign_base& operator=(const optional_move_assign_base& rhs) = default;\n\n\t\t\toptional_move_assign_base& operator=(optional_move_assign_base&& rhs) noexcept(\n\t\t\t     std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_assignable<T>::value) {\n\t\t\t\tthis->assign(std::move(rhs));\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t};\n\n\t\t// optional_delete_ctor_base will conditionally delete copy and move\n\t\t// constructors depending on whether T is copy/move constructible\n\t\ttemplate <class T, bool EnableCopy = std::is_copy_constructible<T>::value, bool EnableMove = std::is_move_constructible<T>::value>\n\t\tstruct optional_delete_ctor_base {\n\t\t\toptional_delete_ctor_base() = default;\n\t\t\toptional_delete_ctor_base(const optional_delete_ctor_base&) = default;\n\t\t\toptional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;\n\t\t\toptional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;\n\t\t\toptional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_delete_ctor_base<T, true, false> {\n\t\t\toptional_delete_ctor_base() = default;\n\t\t\toptional_delete_ctor_base(const optional_delete_ctor_base&) = default;\n\t\t\toptional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;\n\t\t\toptional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;\n\t\t\toptional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_delete_ctor_base<T, false, true> {\n\t\t\toptional_delete_ctor_base() = default;\n\t\t\toptional_delete_ctor_base(const optional_delete_ctor_base&) = delete;\n\t\t\toptional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;\n\t\t\toptional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;\n\t\t\toptional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_delete_ctor_base<T, false, false> {\n\t\t\toptional_delete_ctor_base() = default;\n\t\t\toptional_delete_ctor_base(const optional_delete_ctor_base&) = delete;\n\t\t\toptional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;\n\t\t\toptional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;\n\t\t\toptional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;\n\t\t};\n\n\t\t// optional_delete_assign_base will conditionally delete copy and move\n\t\t// constructors depending on whether T is copy/move constructible + assignable\n\t\ttemplate <class T, bool EnableCopy = (std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value),\n\t\t     bool EnableMove = (std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)>\n\t\tstruct optional_delete_assign_base {\n\t\t\toptional_delete_assign_base() = default;\n\t\t\toptional_delete_assign_base(const optional_delete_assign_base&) = default;\n\t\t\toptional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;\n\t\t\toptional_delete_assign_base& operator=(const optional_delete_assign_base&) = default;\n\t\t\toptional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_delete_assign_base<T, true, false> {\n\t\t\toptional_delete_assign_base() = default;\n\t\t\toptional_delete_assign_base(const optional_delete_assign_base&) = default;\n\t\t\toptional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;\n\t\t\toptional_delete_assign_base& operator=(const optional_delete_assign_base&) = default;\n\t\t\toptional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_delete_assign_base<T, false, true> {\n\t\t\toptional_delete_assign_base() = default;\n\t\t\toptional_delete_assign_base(const optional_delete_assign_base&) = default;\n\t\t\toptional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;\n\t\t\toptional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete;\n\t\t\toptional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default;\n\t\t};\n\n\t\ttemplate <class T>\n\t\tstruct optional_delete_assign_base<T, false, false> {\n\t\t\toptional_delete_assign_base() = default;\n\t\t\toptional_delete_assign_base(const optional_delete_assign_base&) = default;\n\t\t\toptional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;\n\t\t\toptional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete;\n\t\t\toptional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete;\n\t\t};\n\n\t} // namespace detail\n\n\t/// \\brief A tag type to represent an empty optional\n\tusing nullopt_t = std::nullopt_t;\n\n\t/// \\brief Represents an empty optional\n\t/// \\synopsis static constexpr nullopt_t nullopt;\n\t///\n\t/// *Examples*:\n\t/// ```\n\t/// sol::optional<int> a = sol::nullopt;\n\t/// void foo (sol::optional<int>);\n\t/// foo(sol::nullopt); //pass an empty optional\n\t/// ```\n\tusing std::nullopt;\n\n\tclass bad_optional_access : public std::exception {\n\tpublic:\n\t\tbad_optional_access() = default;\n\t\tconst char* what() const noexcept {\n\t\t\treturn \"Optional has no value\";\n\t\t}\n\t};\n\n\t/// An optional object is an object that contains the storage for another\n\t/// object and manages the lifetime of this contained object, if any. The\n\t/// contained object may be initialized after the optional object has been\n\t/// initialized, and may be destroyed before the optional object has been\n\t/// destroyed. The initialization state of the contained object is tracked by\n\t/// the optional object.\n\ttemplate <class T>\n\tclass optional : private detail::optional_move_assign_base<T>,\n\t                 private detail::optional_delete_ctor_base<T>,\n\t                 private detail::optional_delete_assign_base<T> {\n\t\tusing base = detail::optional_move_assign_base<T>;\n\n\t\tstatic_assert(!std::is_same<T, in_place_t>::value, \"instantiation of optional with in_place_t is ill-formed\");\n\t\tstatic_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value, \"instantiation of optional with nullopt_t is ill-formed\");\n\n\tpublic:\n#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)\n\t\t/// \\group and_then\n\t\t/// Carries out some operation which returns an optional on the stored\n\t\t/// object if there is one. \\requires `std::invoke(std::forward<F>(f),\n\t\t/// value())` returns a `std::optional<U>` for some `U`. \\returns Let `U` be\n\t\t/// the result of `std::invoke(std::forward<F>(f), value())`. Returns a\n\t\t/// `std::optional<U>`. The return value is empty if `*this` is empty,\n\t\t/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`\n\t\t/// is returned.\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & {\n\t\t\tusing result = detail::invoke_result_t<F, T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && {\n\t\t\tusing result = detail::invoke_result_t<F, T&&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &;\n\t\ttemplate <class F>\n\t\tconstexpr auto and_then(F&& f) const& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &&;\n\t\ttemplate <class F>\n\t\tconstexpr auto and_then(F&& f) const&& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);\n\t\t}\n#endif\n#else\n\t\t/// \\group and_then\n\t\t/// Carries out some operation which returns an optional on the stored\n\t\t/// object if there is one. \\requires `std::invoke(std::forward<F>(f),\n\t\t/// value())` returns a `std::optional<U>` for some `U`.\n\t\t/// \\returns Let `U` be the result of `std::invoke(std::forward<F>(f),\n\t\t/// value())`. Returns a `std::optional<U>`. The return value is empty if\n\t\t/// `*this` is empty, otherwise the return value of\n\t\t/// `std::invoke(std::forward<F>(f), value())` is returned.\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & {\n\t\t\tusing result = detail::invoke_result_t<F, T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&&> and_then(F&& f) && {\n\t\t\tusing result = detail::invoke_result_t<F, T&&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &;\n\t\ttemplate <class F>\n\t\tconstexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &&;\n\t\ttemplate <class F>\n\t\tconstexpr detail::invoke_result_t<F, const T&&> and_then(F&& f) const&& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);\n\t\t}\n#endif\n#endif\n\n#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)\n\t\t/// \\brief Carries out some operation on the stored object if there is one.\n\t\t/// \\returns Let `U` be the result of `std::invoke(std::forward<F>(f),\n\t\t/// value())`. Returns a `std::optional<U>`. The return value is empty if\n\t\t/// `*this` is empty, otherwise an `optional<U>` is constructed from the\n\t\t/// return value of `std::invoke(std::forward<F>(f), value())` and is\n\t\t/// returned.\n\t\t///\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & {\n\t\t\treturn optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && {\n\t\t\treturn optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) const&;\n\t\ttemplate <class F>\n\t\tconstexpr auto map(F&& f) const& {\n\t\t\treturn optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) const&&;\n\t\ttemplate <class F>\n\t\tconstexpr auto map(F&& f) const&& {\n\t\t\treturn optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n#else\n\t\t/// \\brief Carries out some operation on the stored object if there is one.\n\t\t/// \\returns Let `U` be the result of `std::invoke(std::forward<F>(f),\n\t\t/// value())`. Returns a `std::optional<U>`. The return value is empty if\n\t\t/// `*this` is empty, otherwise an `optional<U>` is constructed from the\n\t\t/// return value of `std::invoke(std::forward<F>(f), value())` and is\n\t\t/// returned.\n\t\t///\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & {\n\t\t\treturn optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && {\n\t\t\treturn optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) const&;\n\t\ttemplate <class F>\n\t\tconstexpr decltype(optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& {\n\t\t\treturn optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) const&&;\n\t\ttemplate <class F>\n\t\tconstexpr decltype(optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& {\n\t\t\treturn optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n#endif\n#endif\n\n\t\t/// \\brief Calls `f` if the optional is empty\n\t\t/// \\requires `std::invoke_result_t<F>` must be void or convertible to\n\t\t/// `optional<T>`.\n\t\t/// \\effects If `*this` has a value, returns `*this`.\n\t\t/// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns\n\t\t/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.\n\t\t///\n\t\t/// \\group or_else\n\t\t/// \\synopsis template <class F> optional<T> or_else (F &&f) &;\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {\n\t\t\tif (has_value())\n\t\t\t\treturn *this;\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {\n\t\t\treturn has_value() ? *this : std::forward<F>(f)();\n\t\t}\n\n\t\t/// \\group or_else\n\t\t/// \\synopsis template <class F> optional<T> or_else (F &&f) &&;\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) && {\n\t\t\tif (has_value())\n\t\t\t\treturn std::move(*this);\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && {\n\t\t\treturn has_value() ? std::move(*this) : std::forward<F>(f)();\n\t\t}\n\n\t\t/// \\group or_else\n\t\t/// \\synopsis template <class F> optional<T> or_else (F &&f) const &;\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) const& {\n\t\t\tif (has_value())\n\t\t\t\treturn *this;\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& {\n\t\t\treturn has_value() ? *this : std::forward<F>(f)();\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) const&& {\n\t\t\tif (has_value())\n\t\t\t\treturn std::move(*this);\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) const&& {\n\t\t\treturn has_value() ? std::move(*this) : std::forward<F>(f)();\n\t\t}\n#endif\n\n\t\t/// \\brief Maps the stored value with `f` if there is one, otherwise returns\n\t\t/// `u`.\n\t\t///\n\t\t/// \\details If there is a value stored, then `f` is called with `**this`\n\t\t/// and the value is returned. Otherwise `u` is returned.\n\t\t///\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) & {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);\n\t\t}\n\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) && {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);\n\t\t}\n\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) const& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) const&& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);\n\t\t}\n#endif\n\n\t\t/// \\brief Maps the stored value with `f` if there is one, otherwise calls\n\t\t/// `u` and returns the result.\n\t\t///\n\t\t/// \\details If there is a value stored, then `f` is\n\t\t/// called with `**this` and the value is returned. Otherwise\n\t\t/// `std::forward<U>(u)()` is returned.\n\t\t///\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u) &;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) & {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();\n\t\t}\n\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u)\n\t\t/// &&;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) && {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();\n\t\t}\n\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u)\n\t\t/// const &;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u)\n\t\t/// const &&;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();\n\t\t}\n#endif\n\n\t\t/// \\returns `u` if `*this` has a value, otherwise an empty optional.\n\t\ttemplate <class U>\n\t\tconstexpr optional<typename std::decay<U>::type> conjunction(U&& u) const {\n\t\t\tusing result = optional<detail::decay_t<U>>;\n\t\t\treturn has_value() ? result { u } : result { nullopt };\n\t\t}\n\n\t\t/// \\returns `rhs` if `*this` is empty, otherwise the current value.\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & {\n\t\t\treturn has_value() ? *this : rhs;\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(const optional& rhs) const& {\n\t\t\treturn has_value() ? *this : rhs;\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && {\n\t\t\treturn has_value() ? std::move(*this) : rhs;\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(const optional& rhs) const&& {\n\t\t\treturn has_value() ? std::move(*this) : rhs;\n\t\t}\n#endif\n\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & {\n\t\t\treturn has_value() ? *this : std::move(rhs);\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(optional&& rhs) const& {\n\t\t\treturn has_value() ? *this : std::move(rhs);\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && {\n\t\t\treturn has_value() ? std::move(*this) : std::move(rhs);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(optional&& rhs) const&& {\n\t\t\treturn has_value() ? std::move(*this) : std::move(rhs);\n\t\t}\n#endif\n\n\t\t/// Takes the value out of the optional, leaving it empty\n\t\t/// \\group take\n\t\toptional take() & {\n\t\t\toptional ret = *this;\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n\n\t\t/// \\group take\n\t\toptional take() const& {\n\t\t\toptional ret = *this;\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n\n\t\t/// \\group take\n\t\toptional take() && {\n\t\t\toptional ret = std::move(*this);\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group take\n\t\toptional take() const&& {\n\t\t\toptional ret = std::move(*this);\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n#endif\n\n\t\tusing value_type = T;\n\n\t\t/// Constructs an optional that does not contain a value.\n\t\t/// \\group ctor_empty\n\t\tconstexpr optional() noexcept = default;\n\n\t\t/// \\group ctor_empty\n\t\tconstexpr optional(nullopt_t) noexcept {\n\t\t}\n\n\t\t/// Copy constructor\n\t\t///\n\t\t/// If `rhs` contains a value, the stored value is direct-initialized with\n\t\t/// it. Otherwise, the constructed optional is empty.\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) = default;\n\n\t\t/// Move constructor\n\t\t///\n\t\t/// If `rhs` contains a value, the stored value is direct-initialized with\n\t\t/// it. Otherwise, the constructed optional is empty.\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default;\n\n\t\t/// Constructs the stored value in-place using the given arguments.\n\t\t/// \\group in_place\n\t\t/// \\synopsis template <class... Args> constexpr explicit optional(in_place_t, Args&&... args);\n\t\ttemplate <class... Args>\n\t\tconstexpr explicit optional(detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>, Args&&... args)\n\t\t: base(in_place, std::forward<Args>(args)...) {\n\t\t}\n\n\t\t/// \\group in_place\n\t\t/// \\synopsis template <class U, class... Args>\\nconstexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args);\n\t\ttemplate <class U, class... Args>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR explicit optional(detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>,\n\t\t     std::initializer_list<U> il, Args&&... args) {\n\t\t\tthis->construct(il, std::forward<Args>(args)...);\n\t\t}\n\n#if 0 // SOL_MODIFICATION\n      /// Constructs the stored value with `u`.\n      /// \\synopsis template <class U=T> constexpr optional(U &&u);\n\t\ttemplate <class U = T, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr>\n\t\tconstexpr optional(U&& u) : base(in_place, std::forward<U>(u)) {\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class U = T, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr>\n\t\tconstexpr explicit optional(U&& u) : base(in_place, std::forward<U>(u)) {\n\t\t}\n#else\n\t\t/// Constructs the stored value with `u`.\n\t\t/// \\synopsis template <class U=T> constexpr optional(U &&u);\n\t\tconstexpr optional(T&& u) : base(in_place, std::move(u)) {\n\t\t}\n\n\t\t/// \\exclude\n\t\tconstexpr optional(const T& u) : base(in_place, u) {\n\t\t}\n#endif // sol3 modification\n\n\t\t/// Converting copy constructor.\n\t\t/// \\synopsis template <class U> optional(const optional<U> &rhs);\n\t\ttemplate <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<std::is_convertible<const U&, T>::value>* = nullptr>\n\t\toptional(const optional<U>& rhs) {\n\t\t\tif (rhs.has_value()) {\n\t\t\t\tthis->construct(*rhs);\n\t\t\t}\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr>\n\t\texplicit optional(const optional<U>& rhs) {\n\t\t\tif (rhs.has_value()) {\n\t\t\t\tthis->construct(*rhs);\n\t\t\t}\n\t\t}\n\n\t\t/// Converting move constructor.\n\t\t/// \\synopsis template <class U> optional(optional<U> &&rhs);\n\t\ttemplate <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr>\n\t\toptional(optional<U>&& rhs) {\n\t\t\tif (rhs.has_value()) {\n\t\t\t\tthis->construct(std::move(*rhs));\n\t\t\t}\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr>\n\t\texplicit optional(optional<U>&& rhs) {\n\t\t\tthis->construct(std::move(*rhs));\n\t\t}\n\n\t\t/// Destroys the stored value if there is one.\n\t\t~optional() = default;\n\n\t\t/// Assignment to empty.\n\t\t///\n\t\t/// Destroys the current value if there is one.\n\t\toptional& operator=(nullopt_t) noexcept {\n\t\t\tif (has_value()) {\n\t\t\t\tthis->m_value.~T();\n\t\t\t\tthis->m_has_value = false;\n\t\t\t}\n\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Copy assignment.\n\t\t///\n\t\t/// Copies the value from `rhs` if there is one. Otherwise resets the stored\n\t\t/// value in `*this`.\n\t\toptional& operator=(const optional& rhs) = default;\n\n\t\t/// Move assignment.\n\t\t///\n\t\t/// Moves the value from `rhs` if there is one. Otherwise resets the stored\n\t\t/// value in `*this`.\n\t\toptional& operator=(optional&& rhs) = default;\n\n\t\t/// Assigns the stored value from `u`, destroying the old value if there was\n\t\t/// one.\n\t\t/// \\synopsis optional &operator=(U &&u);\n\t\ttemplate <class U = T, detail::enable_assign_forward<T, U>* = nullptr>\n\t\toptional& operator=(U&& u) {\n\t\t\tif (has_value()) {\n\t\t\t\tthis->m_value = std::forward<U>(u);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis->construct(std::forward<U>(u));\n\t\t\t}\n\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Converting copy assignment operator.\n\t\t///\n\t\t/// Copies the value from `rhs` if there is one. Otherwise resets the stored\n\t\t/// value in `*this`.\n\t\t/// \\synopsis optional &operator=(const optional<U> & rhs);\n\t\ttemplate <class U, detail::enable_assign_from_other<T, U, const U&>* = nullptr>\n\t\toptional& operator=(const optional<U>& rhs) {\n\t\t\tif (has_value()) {\n\t\t\t\tif (rhs.has_value()) {\n\t\t\t\t\tthis->m_value = *rhs;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis->hard_reset();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (rhs.has_value()) {\n\t\t\t\tthis->construct(*rhs);\n\t\t\t}\n\n\t\t\treturn *this;\n\t\t}\n\n\t\t// TODO check exception guarantee\n\t\t/// Converting move assignment operator.\n\t\t///\n\t\t/// Moves the value from `rhs` if there is one. Otherwise resets the stored\n\t\t/// value in `*this`.\n\t\t/// \\synopsis optional &operator=(optional<U> && rhs);\n\t\ttemplate <class U, detail::enable_assign_from_other<T, U, U>* = nullptr>\n\t\toptional& operator=(optional<U>&& rhs) {\n\t\t\tif (has_value()) {\n\t\t\t\tif (rhs.has_value()) {\n\t\t\t\t\tthis->m_value = std::move(*rhs);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis->hard_reset();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (rhs.has_value()) {\n\t\t\t\tthis->construct(std::move(*rhs));\n\t\t\t}\n\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Constructs the value in-place, destroying the current one if there is\n\t\t/// one.\n\t\t/// \\group emplace\n\t\ttemplate <class... Args>\n\t\tT& emplace(Args&&... args) {\n\t\t\tstatic_assert(std::is_constructible<T, Args&&...>::value, \"T must be constructible with Args\");\n\n\t\t\t*this = nullopt;\n\t\t\tthis->construct(std::forward<Args>(args)...);\n\t\t\treturn value();\n\t\t}\n\n\t\t/// \\group emplace\n\t\t/// \\synopsis template <class U, class... Args>\\nT& emplace(std::initializer_list<U> il, Args &&... args);\n\t\ttemplate <class U, class... Args>\n\t\tdetail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&> emplace(std::initializer_list<U> il, Args&&... args) {\n\t\t\t*this = nullopt;\n\t\t\tthis->construct(il, std::forward<Args>(args)...);\n\t\t\treturn value();\n\t\t}\n\n\t\t/// Swaps this optional with the other.\n\t\t///\n\t\t/// If neither optionals have a value, nothing happens.\n\t\t/// If both have a value, the values are swapped.\n\t\t/// If one has a value, it is moved to the other and the movee is left\n\t\t/// valueless.\n\t\tvoid swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&& detail::is_nothrow_swappable<T>::value) {\n\t\t\tif (has_value()) {\n\t\t\t\tif (rhs.has_value()) {\n\t\t\t\t\tusing std::swap;\n\t\t\t\t\tswap(**this, *rhs);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnew (std::addressof(rhs.m_value)) T(std::move(this->m_value));\n\t\t\t\t\tthis->m_value.T::~T();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (rhs.has_value()) {\n\t\t\t\tnew (std::addressof(this->m_value)) T(std::move(rhs.m_value));\n\t\t\t\trhs.m_value.T::~T();\n\t\t\t}\n\t\t}\n\n\t\t/// \\returns a pointer to the stored value\n\t\t/// \\requires a value is stored\n\t\t/// \\group pointer\n\t\t/// \\synopsis constexpr const T *operator->() const;\n\t\tconstexpr const T* operator->() const {\n\t\t\treturn std::addressof(this->m_value);\n\t\t}\n\n\t\t/// \\group pointer\n\t\t/// \\synopsis constexpr T *operator->();\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() {\n\t\t\treturn std::addressof(this->m_value);\n\t\t}\n\n\t\t/// \\returns the stored value\n\t\t/// \\requires a value is stored\n\t\t/// \\group deref\n\t\t/// \\synopsis constexpr T &operator*();\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() & {\n\t\t\treturn this->m_value;\n\t\t}\n\n\t\t/// \\group deref\n\t\t/// \\synopsis constexpr const T &operator*() const;\n\t\tconstexpr const T& operator*() const& {\n\t\t\treturn this->m_value;\n\t\t}\n\n\t\t/// \\exclude\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T&& operator*() && {\n\t\t\treturn std::move(this->m_value);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\exclude\n\t\tconstexpr const T&& operator*() const&& {\n\t\t\treturn std::move(this->m_value);\n\t\t}\n#endif\n\n\t\t/// \\returns whether or not the optional has a value\n\t\t/// \\group has_value\n\t\tconstexpr bool has_value() const noexcept {\n\t\t\treturn this->m_has_value;\n\t\t}\n\n\t\t/// \\group has_value\n\t\tconstexpr explicit operator bool() const noexcept {\n\t\t\treturn this->m_has_value;\n\t\t}\n\n\t\t/// \\returns the contained value if there is one, otherwise throws\n\t\t/// [bad_optional_access]\n\t\t/// \\group value\n\t\t/// \\synopsis constexpr T &value();\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T& value() & {\n\t\t\tif (has_value())\n\t\t\t\treturn this->m_value;\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\tstd::abort();\n#else\n\t\t\tthrow bad_optional_access();\n#endif // No exceptions allowed\n\t\t}\n\t\t/// \\group value\n\t\t/// \\synopsis constexpr const T &value() const;\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const& {\n\t\t\tif (has_value())\n\t\t\t\treturn this->m_value;\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\tstd::abort();\n#else\n\t\t\tthrow bad_optional_access();\n#endif // No exceptions allowed\n\t\t}\n\t\t/// \\exclude\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T&& value() && {\n\t\t\tif (has_value())\n\t\t\t\treturn std::move(this->m_value);\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\tstd::abort();\n#else\n\t\t\tthrow bad_optional_access();\n#endif // No exceptions allowed\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\exclude\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR const T&& value() const&& {\n\t\t\tif (has_value())\n\t\t\t\treturn std::move(this->m_value);\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\tstd::abort();\n#else\n\t\t\tthrow bad_optional_access();\n#endif // No exceptions allowed\n\t\t}\n#endif\n\n\t\t/// \\returns the stored value if there is one, otherwise returns `u`\n\t\t/// \\group value_or\n\t\ttemplate <class U>\n\t\tconstexpr T value_or(U&& u) const& {\n\t\t\tstatic_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value, \"T must be copy constructible and convertible from U\");\n\t\t\treturn has_value() ? **this : static_cast<T>(std::forward<U>(u));\n\t\t}\n\n\t\t/// \\group value_or\n\t\ttemplate <class U>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T value_or(U&& u) && {\n\t\t\tstatic_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value, \"T must be move constructible and convertible from U\");\n\t\t\treturn has_value() ? **this : static_cast<T>(std::forward<U>(u));\n\t\t}\n\n\t\t/// Destroys the stored value if one exists, making the optional empty\n\t\tvoid reset() noexcept {\n\t\t\tif (has_value()) {\n\t\t\t\tthis->m_value.~T();\n\t\t\t\tthis->m_has_value = false;\n\t\t\t}\n\t\t}\n\t}; // namespace sol\n\n\t/// \\group relop\n\t/// \\brief Compares two optional objects\n\t/// \\details If both optionals contain a value, they are compared with `T`s\n\t/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are\n\t/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs`\n\t/// is not.\n\ttemplate <class T, class U>\n\tinline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {\n\t\treturn lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs);\n\t}\n\t/// \\group relop\n\ttemplate <class T, class U>\n\tinline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {\n\t\treturn lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs);\n\t}\n\t/// \\group relop\n\ttemplate <class T, class U>\n\tinline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) {\n\t\treturn rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);\n\t}\n\t/// \\group relop\n\ttemplate <class T, class U>\n\tinline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) {\n\t\treturn lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);\n\t}\n\t/// \\group relop\n\ttemplate <class T, class U>\n\tinline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {\n\t\treturn !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);\n\t}\n\t/// \\group relop\n\ttemplate <class T, class U>\n\tinline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {\n\t\treturn !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);\n\t}\n\n\t/// \\group relop_nullopt\n\t/// \\brief Compares an optional to a `nullopt`\n\t/// \\details Equivalent to comparing the optional to an empty optional\n\ttemplate <class T>\n\tinline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept {\n\t\treturn !lhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept {\n\t\treturn !rhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept {\n\t\treturn lhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept {\n\t\treturn rhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {\n\t\treturn false;\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept {\n\t\treturn rhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept {\n\t\treturn !lhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {\n\t\treturn true;\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept {\n\t\treturn lhs.has_value();\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {\n\t\treturn false;\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {\n\t\treturn true;\n\t}\n\t/// \\group relop_nullopt\n\ttemplate <class T>\n\tinline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept {\n\t\treturn !rhs.has_value();\n\t}\n\n\t/// \\group relop_t\n\t/// \\brief Compares the optional with a value.\n\t/// \\details If the optional has a value, it is compared with the other value\n\t/// using `T`s relational operators. Otherwise, the optional is considered\n\t/// less than the value.\n\ttemplate <class T, class U>\n\tinline constexpr bool operator==(const optional<T>& lhs, const U& rhs) {\n\t\treturn lhs.has_value() ? *lhs == rhs : false;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator==(const U& lhs, const optional<T>& rhs) {\n\t\treturn rhs.has_value() ? lhs == *rhs : false;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) {\n\t\treturn lhs.has_value() ? *lhs != rhs : true;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) {\n\t\treturn rhs.has_value() ? lhs != *rhs : true;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator<(const optional<T>& lhs, const U& rhs) {\n\t\treturn lhs.has_value() ? *lhs < rhs : true;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator<(const U& lhs, const optional<T>& rhs) {\n\t\treturn rhs.has_value() ? lhs < *rhs : false;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) {\n\t\treturn lhs.has_value() ? *lhs <= rhs : true;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) {\n\t\treturn rhs.has_value() ? lhs <= *rhs : false;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator>(const optional<T>& lhs, const U& rhs) {\n\t\treturn lhs.has_value() ? *lhs > rhs : false;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator>(const U& lhs, const optional<T>& rhs) {\n\t\treturn rhs.has_value() ? lhs > *rhs : true;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) {\n\t\treturn lhs.has_value() ? *lhs >= rhs : false;\n\t}\n\t/// \\group relop_t\n\ttemplate <class T, class U>\n\tinline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) {\n\t\treturn rhs.has_value() ? lhs >= *rhs : true;\n\t}\n\n\t/// \\synopsis template <class T>\\nvoid swap(optional<T> &lhs, optional<T> &rhs);\n\ttemplate <class T, detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr, detail::enable_if_t<detail::is_swappable<T>::value>* = nullptr>\n\tvoid swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) {\n\t\treturn lhs.swap(rhs);\n\t}\n\n\tnamespace detail {\n\t\tstruct i_am_secret {};\n\t} // namespace detail\n\n\ttemplate <class T = detail::i_am_secret, class U, class Ret = detail::conditional_t<std::is_same<T, detail::i_am_secret>::value, detail::decay_t<U>, T>>\n\tinline constexpr optional<Ret> make_optional(U&& v) {\n\t\treturn optional<Ret>(std::forward<U>(v));\n\t}\n\n\ttemplate <class T, class... Args>\n\tinline constexpr optional<T> make_optional(Args&&... args) {\n\t\treturn optional<T>(in_place, std::forward<Args>(args)...);\n\t}\n\ttemplate <class T, class U, class... Args>\n\tinline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) {\n\t\treturn optional<T>(in_place, il, std::forward<Args>(args)...);\n\t}\n\n#if __cplusplus >= 201703L\n\ttemplate <class T>\n\toptional(T)->optional<T>;\n#endif\n\n\t/// \\exclude\n\tnamespace detail {\n#ifdef SOL_TL_OPTIONAL_CXX14\n\t\ttemplate <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),\n\t\t     detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr>\n\t\tconstexpr auto optional_map_impl(Opt&& opt, F&& f) {\n\t\t\treturn opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt);\n\t\t}\n\n\t\ttemplate <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),\n\t\t     detail::enable_if_t<std::is_void<Ret>::value>* = nullptr>\n\t\tauto optional_map_impl(Opt&& opt, F&& f) {\n\t\t\tif (opt.has_value()) {\n\t\t\t\tdetail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));\n\t\t\t\treturn make_optional(monostate {});\n\t\t\t}\n\n\t\t\treturn optional<monostate>(nullopt);\n\t\t}\n#else\n\t\ttemplate <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),\n\t\t     detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr>\n\n\t\tconstexpr auto optional_map_impl(Opt&& opt, F&& f) -> optional<Ret> {\n\t\t\treturn opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt);\n\t\t}\n\n\t\ttemplate <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),\n\t\t     detail::enable_if_t<std::is_void<Ret>::value>* = nullptr>\n\n\t\tauto optional_map_impl(Opt&& opt, F&& f) -> optional<monostate> {\n\t\t\tif (opt.has_value()) {\n\t\t\t\tdetail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));\n\t\t\t\treturn monostate {};\n\t\t\t}\n\n\t\t\treturn nullopt;\n\t\t}\n#endif\n\t} // namespace detail\n\n\t/// Specialization for when `T` is a reference. `optional<T&>` acts similarly\n\t/// to a `T*`, but provides more operations and shows intent more clearly.\n\t///\n\t/// *Examples*:\n\t///\n\t/// ```\n\t/// int i = 42;\n\t/// sol::optional<int&> o = i;\n\t/// *o == 42; //true\n\t/// i = 12;\n\t/// *o = 12; //true\n\t/// &*o == &i; //true\n\t/// ```\n\t///\n\t/// Assignment has rebind semantics rather than assign-through semantics:\n\t///\n\t/// ```\n\t/// int j = 8;\n\t/// o = j;\n\t///\n\t/// &*o == &j; //true\n\t/// ```\n\ttemplate <class T>\n\tclass optional<T&> {\n\tpublic:\n#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)\n\t\t/// \\group and_then\n\t\t/// Carries out some operation which returns an optional on the stored\n\t\t/// object if there is one. \\requires `std::invoke(std::forward<F>(f),\n\t\t/// value())` returns a `std::optional<U>` for some `U`. \\returns Let `U` be\n\t\t/// the result of `std::invoke(std::forward<F>(f), value())`. Returns a\n\t\t/// `std::optional<U>`. The return value is empty if `*this` is empty,\n\t\t/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`\n\t\t/// is returned.\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & {\n\t\t\tusing result = detail::invoke_result_t<F, T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && {\n\t\t\tusing result = detail::invoke_result_t<F, T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &;\n\t\ttemplate <class F>\n\t\tconstexpr auto and_then(F&& f) const& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &&;\n\t\ttemplate <class F>\n\t\tconstexpr auto and_then(F&& f) const&& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n#endif\n#else\n\t\t/// \\group and_then\n\t\t/// Carries out some operation which returns an optional on the stored\n\t\t/// object if there is one. \\requires `std::invoke(std::forward<F>(f),\n\t\t/// value())` returns a `std::optional<U>` for some `U`. \\returns Let `U` be\n\t\t/// the result of `std::invoke(std::forward<F>(f), value())`. Returns a\n\t\t/// `std::optional<U>`. The return value is empty if `*this` is empty,\n\t\t/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`\n\t\t/// is returned.\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & {\n\t\t\tusing result = detail::invoke_result_t<F, T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) && {\n\t\t\tusing result = detail::invoke_result_t<F, T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &;\n\t\ttemplate <class F>\n\t\tconstexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group and_then\n\t\t/// \\synopsis template <class F>\\nconstexpr auto and_then(F &&f) const &&;\n\t\ttemplate <class F>\n\t\tconstexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const&& {\n\t\t\tusing result = detail::invoke_result_t<F, const T&>;\n\t\t\tstatic_assert(detail::is_optional<result>::value, \"F must return an optional\");\n\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);\n\t\t}\n#endif\n#endif\n\n#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)\n\t\t/// \\brief Carries out some operation on the stored object if there is one.\n\t\t/// \\returns Let `U` be the result of `std::invoke(std::forward<F>(f),\n\t\t/// value())`. Returns a `std::optional<U>`. The return value is empty if\n\t\t/// `*this` is empty, otherwise an `optional<U>` is constructed from the\n\t\t/// return value of `std::invoke(std::forward<F>(f), value())` and is\n\t\t/// returned.\n\t\t///\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & {\n\t\t\treturn detail::optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && {\n\t\t\treturn detail::optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) const&;\n\t\ttemplate <class F>\n\t\tconstexpr auto map(F&& f) const& {\n\t\t\treturn detail::optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> constexpr auto map(F &&f) const&&;\n\t\ttemplate <class F>\n\t\tconstexpr auto map(F&& f) const&& {\n\t\t\treturn detail::optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n#else\n\t\t/// \\brief Carries out some operation on the stored object if there is one.\n\t\t/// \\returns Let `U` be the result of `std::invoke(std::forward<F>(f),\n\t\t/// value())`. Returns a `std::optional<U>`. The return value is empty if\n\t\t/// `*this` is empty, otherwise an `optional<U>` is constructed from the\n\t\t/// return value of `std::invoke(std::forward<F>(f), value())` and is\n\t\t/// returned.\n\t\t///\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) &;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & {\n\t\t\treturn detail::optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) &&;\n\t\ttemplate <class F>\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && {\n\t\t\treturn detail::optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) const&;\n\t\ttemplate <class F>\n\t\tconstexpr decltype(detail::optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& {\n\t\t\treturn detail::optional_map_impl(*this, std::forward<F>(f));\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group map\n\t\t/// \\synopsis template <class F> auto map(F &&f) const&&;\n\t\ttemplate <class F>\n\t\tconstexpr decltype(detail::optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& {\n\t\t\treturn detail::optional_map_impl(std::move(*this), std::forward<F>(f));\n\t\t}\n#endif\n#endif\n\n\t\t/// \\brief Calls `f` if the optional is empty\n\t\t/// \\requires `std::invoke_result_t<F>` must be void or convertible to\n\t\t/// `optional<T>`. \\effects If `*this` has a value, returns `*this`.\n\t\t/// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns\n\t\t/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.\n\t\t///\n\t\t/// \\group or_else\n\t\t/// \\synopsis template <class F> optional<T> or_else (F &&f) &;\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {\n\t\t\tif (has_value())\n\t\t\t\treturn *this;\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {\n\t\t\treturn has_value() ? *this : std::forward<F>(f)();\n\t\t}\n\n\t\t/// \\group or_else\n\t\t/// \\synopsis template <class F> optional<T> or_else (F &&f) &&;\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) && {\n\t\t\tif (has_value())\n\t\t\t\treturn std::move(*this);\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && {\n\t\t\treturn has_value() ? std::move(*this) : std::forward<F>(f)();\n\t\t}\n\n\t\t/// \\group or_else\n\t\t/// \\synopsis template <class F> optional<T> or_else (F &&f) const &;\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) const& {\n\t\t\tif (has_value())\n\t\t\t\treturn *this;\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& {\n\t\t\treturn has_value() ? *this : std::forward<F>(f)();\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::enable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) const&& {\n\t\t\tif (has_value())\n\t\t\t\treturn std::move(*this);\n\n\t\t\tstd::forward<F>(f)();\n\t\t\treturn nullopt;\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class F, detail::disable_if_ret_void<F>* = nullptr>\n\t\toptional<T> or_else(F&& f) const&& {\n\t\t\treturn has_value() ? std::move(*this) : std::forward<F>(f)();\n\t\t}\n#endif\n\n\t\t/// \\brief Maps the stored value with `f` if there is one, otherwise returns\n\t\t/// `u`.\n\t\t///\n\t\t/// \\details If there is a value stored, then `f` is called with `**this`\n\t\t/// and the value is returned. Otherwise `u` is returned.\n\t\t///\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) & {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);\n\t\t}\n\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) && {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);\n\t\t}\n\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) const& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group map_or\n\t\ttemplate <class F, class U>\n\t\tU map_or(F&& f, U&& u) const&& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);\n\t\t}\n#endif\n\n\t\t/// \\brief Maps the stored value with `f` if there is one, otherwise calls\n\t\t/// `u` and returns the result.\n\t\t///\n\t\t/// \\details If there is a value stored, then `f` is\n\t\t/// called with `**this` and the value is returned. Otherwise\n\t\t/// `std::forward<U>(u)()` is returned.\n\t\t///\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u) &;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) & {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();\n\t\t}\n\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u)\n\t\t/// &&;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) && {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();\n\t\t}\n\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u)\n\t\t/// const &;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group map_or_else\n\t\t/// \\synopsis template <class F, class U>\\nauto map_or_else(F &&f, U &&u)\n\t\t/// const &&;\n\t\ttemplate <class F, class U>\n\t\tdetail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& {\n\t\t\treturn has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();\n\t\t}\n#endif\n\n\t\t/// \\returns `u` if `*this` has a value, otherwise an empty optional.\n\t\ttemplate <class U>\n\t\tconstexpr optional<typename std::decay<U>::type> conjunction(U&& u) const {\n\t\t\tusing result = optional<detail::decay_t<U>>;\n\t\t\treturn has_value() ? result { u } : result { nullopt };\n\t\t}\n\n\t\t/// \\returns `rhs` if `*this` is empty, otherwise the current value.\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & {\n\t\t\treturn has_value() ? *this : rhs;\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(const optional& rhs) const& {\n\t\t\treturn has_value() ? *this : rhs;\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && {\n\t\t\treturn has_value() ? std::move(*this) : rhs;\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(const optional& rhs) const&& {\n\t\t\treturn has_value() ? std::move(*this) : rhs;\n\t\t}\n#endif\n\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & {\n\t\t\treturn has_value() ? *this : std::move(rhs);\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(optional&& rhs) const& {\n\t\t\treturn has_value() ? *this : std::move(rhs);\n\t\t}\n\n\t\t/// \\group disjunction\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && {\n\t\t\treturn has_value() ? std::move(*this) : std::move(rhs);\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group disjunction\n\t\tconstexpr optional disjunction(optional&& rhs) const&& {\n\t\t\treturn has_value() ? std::move(*this) : std::move(rhs);\n\t\t}\n#endif\n\n\t\t/// Takes the value out of the optional, leaving it empty\n\t\t/// \\group take\n\t\toptional take() & {\n\t\t\toptional ret = *this;\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n\n\t\t/// \\group take\n\t\toptional take() const& {\n\t\t\toptional ret = *this;\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n\n\t\t/// \\group take\n\t\toptional take() && {\n\t\t\toptional ret = std::move(*this);\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n\n#ifndef SOL_TL_OPTIONAL_NO_CONSTRR\n\t\t/// \\group take\n\t\toptional take() const&& {\n\t\t\toptional ret = std::move(*this);\n\t\t\treset();\n\t\t\treturn ret;\n\t\t}\n#endif\n\n\t\tusing value_type = T&;\n\n\t\t/// Constructs an optional that does not contain a value.\n\t\t/// \\group ctor_empty\n\t\tconstexpr optional() noexcept : m_value(nullptr) {\n\t\t}\n\n\t\t/// \\group ctor_empty\n\t\tconstexpr optional(nullopt_t) noexcept : m_value(nullptr) {\n\t\t}\n\n\t\t/// Copy constructor\n\t\t///\n\t\t/// If `rhs` contains a value, the stored value is direct-initialized with\n\t\t/// it. Otherwise, the constructed optional is empty.\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) noexcept = default;\n\n\t\t/// Move constructor\n\t\t///\n\t\t/// If `rhs` contains a value, the stored value is direct-initialized with\n\t\t/// it. Otherwise, the constructed optional is empty.\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default;\n\n\t\t/// Constructs the stored value with `u`.\n\t\t/// \\synopsis template <class U=T> constexpr optional(U &&u);\n\t\ttemplate <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr>\n\t\tconstexpr optional(U&& u) : m_value(std::addressof(u)) {\n\t\t\tstatic_assert(std::is_lvalue_reference<U>::value, \"U must be an lvalue\");\n\t\t}\n\n\t\t/// \\exclude\n\t\ttemplate <class U>\n\t\tconstexpr explicit optional(const optional<U>& rhs) : optional(*rhs) {\n\t\t}\n\n\t\t/// No-op\n\t\t~optional() = default;\n\n\t\t/// Assignment to empty.\n\t\t///\n\t\t/// Destroys the current value if there is one.\n\t\toptional& operator=(nullopt_t) noexcept {\n\t\t\tm_value = nullptr;\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Copy assignment.\n\t\t///\n\t\t/// Rebinds this optional to the referee of `rhs` if there is one. Otherwise\n\t\t/// resets the stored value in `*this`.\n\t\toptional& operator=(const optional& rhs) = default;\n\n\t\t/// Rebinds this optional to `u`.\n\t\t///\n\t\t/// \\requires `U` must be an lvalue reference.\n\t\t/// \\synopsis optional &operator=(U &&u);\n\t\ttemplate <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr>\n\t\toptional& operator=(U&& u) {\n\t\t\tstatic_assert(std::is_lvalue_reference<U>::value, \"U must be an lvalue\");\n\t\t\tm_value = std::addressof(u);\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Converting copy assignment operator.\n\t\t///\n\t\t/// Rebinds this optional to the referee of `rhs` if there is one. Otherwise\n\t\t/// resets the stored value in `*this`.\n\t\ttemplate <class U>\n\t\toptional& operator=(const optional<U>& rhs) {\n\t\t\tm_value = std::addressof(rhs.value());\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Constructs the value in-place, destroying the current one if there is\n\t\t/// one.\n\t\t///\n\t\t/// \\group emplace\n\t\ttemplate <class... Args>\n\t\tT& emplace(Args&&... args) noexcept {\n\t\t\tstatic_assert(std::is_constructible<T, Args&&...>::value, \"T must be constructible with Args\");\n\n\t\t\t*this = nullopt;\n\t\t\tthis->construct(std::forward<Args>(args)...);\n\t\t}\n\n\t\t/// Swaps this optional with the other.\n\t\t///\n\t\t/// If neither optionals have a value, nothing happens.\n\t\t/// If both have a value, the values are swapped.\n\t\t/// If one has a value, it is moved to the other and the movee is left\n\t\t/// valueless.\n\t\tvoid swap(optional& rhs) noexcept {\n\t\t\tstd::swap(m_value, rhs.m_value);\n\t\t}\n\n\t\t/// \\returns a pointer to the stored value\n\t\t/// \\requires a value is stored\n\t\t/// \\group pointer\n\t\t/// \\synopsis constexpr const T *operator->() const;\n\t\tconstexpr const T* operator->() const {\n\t\t\treturn m_value;\n\t\t}\n\n\t\t/// \\group pointer\n\t\t/// \\synopsis constexpr T *operator->();\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() {\n\t\t\treturn m_value;\n\t\t}\n\n\t\t/// \\returns the stored value\n\t\t/// \\requires a value is stored\n\t\t/// \\group deref\n\t\t/// \\synopsis constexpr T &operator*();\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() {\n\t\t\treturn *m_value;\n\t\t}\n\n\t\t/// \\group deref\n\t\t/// \\synopsis constexpr const T &operator*() const;\n\t\tconstexpr const T& operator*() const {\n\t\t\treturn *m_value;\n\t\t}\n\n\t\t/// \\returns whether or not the optional has a value\n\t\t/// \\group has_value\n\t\tconstexpr bool has_value() const noexcept {\n\t\t\treturn m_value != nullptr;\n\t\t}\n\n\t\t/// \\group has_value\n\t\tconstexpr explicit operator bool() const noexcept {\n\t\t\treturn m_value != nullptr;\n\t\t}\n\n\t\t/// \\returns the contained value if there is one, otherwise throws\n\t\t/// [bad_optional_access]\n\t\t/// \\group value\n\t\t/// synopsis constexpr T &value();\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR T& value() {\n\t\t\tif (has_value())\n\t\t\t\treturn *m_value;\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\tstd::abort();\n#else\n\t\t\tthrow bad_optional_access();\n#endif // No exceptions allowed\n\t\t}\n\t\t/// \\group value\n\t\t/// \\synopsis constexpr const T &value() const;\n\t\tSOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const {\n\t\t\tif (has_value())\n\t\t\t\treturn *m_value;\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\tstd::abort();\n#else\n\t\t\tthrow bad_optional_access();\n#endif // No exceptions allowed\n\t\t}\n\n\t\t/// \\returns the stored value if there is one, otherwise returns `u`\n\t\t/// \\group value_or\n\t\ttemplate <class U>\n\t\tconstexpr T& value_or(U&& u) const {\n\t\t\tstatic_assert(std::is_convertible<U&&, T&>::value, \"T must be convertible from U\");\n\t\t\treturn has_value() ? const_cast<T&>(**this) : static_cast<T&>(std::forward<U>(u));\n\t\t}\n\n\t\t/// Destroys the stored value if one exists, making the optional empty\n\t\tvoid reset() noexcept {\n\t\t\tm_value = nullptr;\n\t\t}\n\n\tprivate:\n\t\tT* m_value;\n\t};\n\n} // namespace sol\n\nnamespace std {\n\t// TODO SFINAE\n\ttemplate <class T>\n\tstruct hash<::sol::optional<T>> {\n\t\t::std::size_t operator()(const ::sol::optional<T>& o) const {\n\t\t\tif (!o.has_value())\n\t\t\t\treturn 0;\n\n\t\t\treturn ::std::hash<::sol::detail::remove_const_t<T>>()(*o);\n\t\t}\n\t};\n} // namespace std\n\n// end of sol/optional_implementation.hpp\n\n#endif // Boost vs. Better optional\n\n#include <optional>\n\nnamespace sol {\n\n#if SOL_IS_ON(SOL_USE_BOOST_I_)\n\ttemplate <typename T>\n\tusing optional = boost::optional<T>;\n\tusing nullopt_t = boost::none_t;\n\tconst nullopt_t nullopt = boost::none;\n#endif // Boost vs. Better optional\n\n\tnamespace meta {\n\t\ttemplate <typename T>\n\t\tusing is_optional = any<is_specialization_of<T, optional>, is_specialization_of<T, std::optional>>;\n\n\t\ttemplate <typename T>\n\t\tconstexpr inline bool is_optional_v = is_optional<T>::value;\n\t} // namespace meta\n\n\tnamespace detail {\n\t\ttemplate <typename T>\n\t\tstruct associated_nullopt {\n\t\t\tinline static constexpr std::nullopt_t value = std::nullopt;\n\t\t};\n\n#if SOL_IS_ON(SOL_USE_BOOST_I_)\n\t\ttemplate <typename T>\n\t\tstruct associated_nullopt<boost::optional<T>> {\n\t\t\tinline static constexpr std::nullopt_t value = boost::nullopt;\n\t\t};\n#endif // Boost nullopt\n\n\t\ttemplate <typename T>\n\t\tinline constexpr auto associated_nullopt_v = associated_nullopt<T>::value;\n\t} // namespace detail\n} // namespace sol\n\n// end of sol/optional.hpp\n\n// beginning of sol/raii.hpp\n\n#include <memory>\n\nnamespace sol {\n\tnamespace detail {\n\t\tstruct default_construct {\n\t\t\ttemplate <typename T, typename... Args>\n\t\t\tstatic void construct(T&& obj, Args&&... args) {\n\t\t\t\ttypedef meta::unqualified_t<T> Tu;\n\t\t\t\tstd::allocator<Tu> alloc{};\n\t\t\t\tstd::allocator_traits<std::allocator<Tu>>::construct(alloc, std::forward<T>(obj), std::forward<Args>(args)...);\n\t\t\t}\n\n\t\t\ttemplate <typename T, typename... Args>\n\t\t\tvoid operator()(T&& obj, Args&&... args) const {\n\t\t\t\tconstruct(std::forward<T>(obj), std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\tstruct default_destruct {\n\t\t\ttemplate <typename T>\n\t\t\tstatic void destroy(T&& obj) {\n\t\t\t\tstd::allocator<meta::unqualified_t<T>> alloc{};\n\t\t\t\talloc.destroy(obj);\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tvoid operator()(T&& obj) const {\n\t\t\t\tdestroy(std::forward<T>(obj));\n\t\t\t}\n\t\t};\n\n\t\tstruct deleter {\n\t\t\ttemplate <typename T>\n\t\t\tvoid operator()(T* p) const {\n\t\t\t\tdelete p;\n\t\t\t}\n\t\t};\n\n\t\tstruct state_deleter {\n\t\t\tvoid operator()(lua_State* L) const {\n\t\t\t\tlua_close(L);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename Dx, typename... Args>\n\t\tinline std::unique_ptr<T, Dx> make_unique_deleter(Args&&... args) {\n\t\t\treturn std::unique_ptr<T, Dx>(new T(std::forward<Args>(args)...));\n\t\t}\n\n\t\ttemplate <typename Tag, typename T>\n\t\tstruct tagged {\n\t\tprivate:\n\t\t\tT value_;\n\t\t\n\t\tpublic:\n\t\t\ttemplate <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, tagged>> = meta::enabler>\n\t\t\ttagged(Arg&& arg, Args&&... args)\n\t\t\t: value_(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t\t}\n\n\t\t\tT& value() & {\n\t\t\t\treturn value_;\n\t\t\t}\n\n\t\t\tT const& value() const& {\n\t\t\t\treturn value_;\n\t\t\t}\n\n\t\t\tT&& value() && {\n\t\t\t\treturn std::move(value_);\n\t\t\t}\n\t\t};\n\t} // namespace detail\n\n\ttemplate <typename... Args>\n\tstruct constructor_list {};\n\n\ttemplate <typename... Args>\n\tusing constructors = constructor_list<Args...>;\n\n\tconst auto default_constructor = constructors<types<>>{};\n\n\tstruct no_construction {};\n\tconst auto no_constructor = no_construction{};\n\n\tstruct call_construction {};\n\tconst auto call_constructor = call_construction{};\n\n\ttemplate <typename... Functions>\n\tstruct constructor_wrapper {\n\t\tstd::tuple<Functions...> functions;\n\t\ttemplate <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, constructor_wrapper>> = meta::enabler>\n\t\tconstructor_wrapper(Arg&& arg, Args&&... args)\n\t\t: functions(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t}\n\t};\n\n\ttemplate <typename... Functions>\n\tinline auto initializers(Functions&&... functions) {\n\t\treturn constructor_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...);\n\t}\n\n\ttemplate <typename... Functions>\n\tstruct factory_wrapper {\n\t\tstd::tuple<Functions...> functions;\n\t\ttemplate <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, factory_wrapper>> = meta::enabler>\n\t\tfactory_wrapper(Arg&& arg, Args&&... args)\n\t\t: functions(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t}\n\t};\n\n\ttemplate <typename... Functions>\n\tinline auto factories(Functions&&... functions) {\n\t\treturn factory_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...);\n\t}\n\n\ttemplate <typename Function>\n\tstruct destructor_wrapper {\n\t\tFunction fx;\n\t\tdestructor_wrapper(Function f)\n\t\t: fx(std::move(f)) {\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct destructor_wrapper<void> {};\n\n\tconst destructor_wrapper<void> default_destructor{};\n\n\ttemplate <typename Fx>\n\tinline auto destructor(Fx&& fx) {\n\t\treturn destructor_wrapper<std::decay_t<Fx>>(std::forward<Fx>(fx));\n\t}\n\n} // namespace sol\n\n// end of sol/raii.hpp\n\n// beginning of sol/policies.hpp\n\n#include <array>\n\nnamespace sol {\n\tnamespace detail {\n\t\tstruct policy_base_tag {};\n\t} // namespace detail\n\n\ttemplate <int Target, int... In>\n\tstruct static_stack_dependencies : detail::policy_base_tag {};\n\ttypedef static_stack_dependencies<-1, 1> self_dependency;\n\ttemplate <int... In>\n\tstruct returns_self_with : detail::policy_base_tag {};\n\ttypedef returns_self_with<> returns_self;\n\n\tstruct stack_dependencies : detail::policy_base_tag {\n\t\tint target;\n\t\tstd::array<int, 64> stack_indices;\n\t\tstd::size_t len;\n\n\t\ttemplate <typename... Args>\n\t\tstack_dependencies(int stack_target, Args&&... args) : target(stack_target), stack_indices(), len(sizeof...(Args)) {\n\t\t\tstd::size_t i = 0;\n\t\t\t(void)detail::swallow{ int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int())... };\n\t\t}\n\n\t\tint& operator[](std::size_t i) {\n\t\t\treturn stack_indices[i];\n\t\t}\n\n\t\tconst int& operator[](std::size_t i) const {\n\t\t\treturn stack_indices[i];\n\t\t}\n\n\t\tstd::size_t size() const {\n\t\t\treturn len;\n\t\t}\n\t};\n\n\ttemplate <typename F, typename... Policies>\n\tstruct policy_wrapper {\n\t\ttypedef std::index_sequence_for<Policies...> indices;\n\n\t\tF value;\n\t\tstd::tuple<Policies...> policies;\n\n\t\ttemplate <typename Fx, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Fx>, policy_wrapper>>> = meta::enabler>\n\t\tpolicy_wrapper(Fx&& fx, Args&&... args) : value(std::forward<Fx>(fx)), policies(std::forward<Args>(args)...) {\n\t\t}\n\n\t\tpolicy_wrapper(const policy_wrapper&) = default;\n\t\tpolicy_wrapper& operator=(const policy_wrapper&) = default;\n\t\tpolicy_wrapper(policy_wrapper&&) = default;\n\t\tpolicy_wrapper& operator=(policy_wrapper&&) = default;\n\t};\n\n\ttemplate <typename F, typename... Args>\n\tauto policies(F&& f, Args&&... args) {\n\t\treturn policy_wrapper<std::decay_t<F>, std::decay_t<Args>...>(std::forward<F>(f), std::forward<Args>(args)...);\n\t}\n\n\tnamespace detail {\n\t\ttemplate <typename T>\n\t\tusing is_policy = meta::is_specialization_of<T, policy_wrapper>;\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_policy_v = is_policy<T>::value;\n\t} // namespace detail\n} // namespace sol\n\n// end of sol/policies.hpp\n\n// beginning of sol/ebco.hpp\n\n#include <type_traits>\n#include <utility>\n\nnamespace sol { namespace detail {\n\n\ttemplate <typename T, std::size_t tag = 0, typename = void>\n\tstruct ebco {\n\t\tT value_;\n\n\t\tebco() = default;\n\t\tebco(const ebco&) = default;\n\t\tebco(ebco&&) = default;\n\t\tebco& operator=(const ebco&) = default;\n\t\tebco& operator=(ebco&&) = default;\n\t\tebco(const T& v) : value_(v){};\n\t\tebco(T&& v) : value_(std::move(v)){};\n\t\tebco& operator=(const T& v) {\n\t\t\tvalue_ = v;\n\t\t\treturn *this;\n\t\t}\n\t\tebco& operator=(T&& v) {\n\t\t\tvalue_ = std::move(v);\n\t\t\treturn *this;\n\t\t};\n\t\ttemplate <typename Arg, typename... Args,\n\t\t     typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,\n\t\t                                      ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>\n\t\tebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...){}\n\n\t\tT& value() & {\n\t\t\treturn value_;\n\t\t}\n\n\t\tT const& value() const & {\n\t\t\treturn value_;\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(value_);\n\t\t}\n\t};\n\n\ttemplate <typename T, std::size_t tag>\n\tstruct ebco<T, tag, std::enable_if_t<!std::is_reference_v<T> && std::is_class_v<T> && !std::is_final_v<T>>> : T {\n\t\tebco() = default;\n\t\tebco(const ebco&) = default;\n\t\tebco(ebco&&) = default;\n\t\tebco(const T& v) : T(v){};\n\t\tebco(T&& v) : T(std::move(v)){};\n\t\ttemplate <typename Arg, typename... Args,\n\t\t\ttypename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,\n\t\t\t                                 ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>\n\t\tebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tebco& operator=(const ebco&) = default;\n\t\tebco& operator=(ebco&&) = default;\n\t\tebco& operator=(const T& v) {\n\t\t\tstatic_cast<T&>(*this) = v;\n\t\t\treturn *this;\n\t\t}\n\t\tebco& operator=(T&& v) {\n\t\t\tstatic_cast<T&>(*this) = std::move(v);\n\t\t\treturn *this;\n\t\t};\n\n\t\tT& value() & {\n\t\t\treturn static_cast<T&>(*this);\n\t\t}\n\n\t\tT const& value() const & {\n\t\t\treturn static_cast<T const&>(*this);\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(static_cast<T&>(*this));\n\t\t}\n\t};\n\n\ttemplate <typename T, std::size_t tag>\n\tstruct ebco<T&, tag> {\n\t\tT& ref;\n\n\t\tebco() = default;\n\t\tebco(const ebco&) = default;\n\t\tebco(ebco&&) = default;\n\t\tebco(T& v) : ref(v){};\n\n\t\tebco& operator=(const ebco&) = default;\n\t\tebco& operator=(ebco&&) = default;\n\t\tebco& operator=(T& v) {\n\t\t\tref = v;\n\t\t\treturn *this;\n\t\t}\n\n\t\tT& value() const {\n\t\t\treturn const_cast<ebco<T&, tag>&>(*this).ref;\n\t\t}\n\t};\n\n\ttemplate <typename T, std::size_t tag>\n\tstruct ebco<T&&, tag> {\n\t\tT&& ref;\n\n\t\tebco() = default;\n\t\tebco(const ebco&) = default;\n\t\tebco(ebco&&) = default;\n\t\tebco(T&& v) : ref(v){};\n\n\t\tebco& operator=(const ebco&) = default;\n\t\tebco& operator=(ebco&&) = default;\n\t\tebco& operator=(T&& v) {\n\t\t\tref = std::move(v);\n\t\t\treturn *this;\n\t\t}\n\n\t\tT& value() & {\n\t\t\treturn ref;\n\t\t}\n\n\t\tconst T& value() const & {\n\t\t\treturn ref;\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(ref);\n\t\t}\n\t};\n\n}} // namespace sol::detail\n\n// end of sol/ebco.hpp\n\n#include <array>\n#include <initializer_list>\n#include <string>\n#include <string_view>\n#include <optional>\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n#include <variant>\n#endif // variant shenanigans (thanks, Mac OSX)\n\nnamespace sol {\n\tnamespace detail {\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\ttypedef int (*lua_CFunction_noexcept)(lua_State* L) noexcept;\n#else\n\t\ttypedef int (*lua_CFunction_noexcept)(lua_State* L);\n#endif // noexcept function type for lua_CFunction\n\n\t\ttemplate <typename T>\n\t\tstruct unique_usertype { };\n\n\t\ttemplate <typename T>\n\t\tstruct implicit_wrapper {\n\t\t\tT& item;\n\t\t\timplicit_wrapper(T* item) : item(*item) {\n\t\t\t}\n\t\t\timplicit_wrapper(T& item) : item(item) {\n\t\t\t}\n\t\t\toperator T&() {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t\toperator T*() {\n\t\t\t\treturn std::addressof(item);\n\t\t\t}\n\t\t};\n\n\t\tstruct yield_tag_t { };\n\t\tconst yield_tag_t yield_tag = yield_tag_t {};\n\t} // namespace detail\n\n\tstruct lua_nil_t { };\n\tinline constexpr lua_nil_t lua_nil {};\n\tinline bool operator==(lua_nil_t, lua_nil_t) {\n\t\treturn true;\n\t}\n\tinline bool operator!=(lua_nil_t, lua_nil_t) {\n\t\treturn false;\n\t}\n#if SOL_IS_ON(SOL_NIL_I_)\n\tusing nil_t = lua_nil_t;\n\tinline constexpr const nil_t& nil = lua_nil;\n#endif\n\n\tnamespace detail {\n\t\tstruct non_lua_nil_t { };\n\t} // namespace detail\n\n\tstruct metatable_key_t { };\n\tconst metatable_key_t metatable_key = {};\n\n\tstruct env_key_t { };\n\tconst env_key_t env_key = {};\n\n\tstruct no_metatable_t { };\n\tconst no_metatable_t no_metatable = {};\n\n\ttemplate <typename T>\n\tstruct yielding_t {\n\t\tT func;\n\n\t\tyielding_t() = default;\n\t\tyielding_t(const yielding_t&) = default;\n\t\tyielding_t(yielding_t&&) = default;\n\t\tyielding_t& operator=(const yielding_t&) = default;\n\t\tyielding_t& operator=(yielding_t&&) = default;\n\t\ttemplate <typename Arg,\n\t\t     meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, yielding_t>>,\n\t\t          meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>\n\t\tyielding_t(Arg&& arg) : func(std::forward<Arg>(arg)) {\n\t\t}\n\t\ttemplate <typename Arg0, typename Arg1, typename... Args>\n\t\tyielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : func(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {\n\t\t}\n\t};\n\n\ttemplate <typename F>\n\tinline yielding_t<std::decay_t<F>> yielding(F&& f) {\n\t\treturn yielding_t<std::decay_t<F>>(std::forward<F>(f));\n\t}\n\n\ttypedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref;\n\n\ttemplate <typename T>\n\tstruct non_null { };\n\n\ttemplate <typename... Args>\n\tstruct function_sig { };\n\n\tstruct upvalue_index {\n\t\tint index;\n\t\tupvalue_index(int idx) : index(lua_upvalueindex(idx)) {\n\t\t}\n\n\t\toperator int() const {\n\t\t\treturn index;\n\t\t}\n\t};\n\n\tstruct raw_index {\n\t\tint index;\n\t\traw_index(int i) : index(i) {\n\t\t}\n\n\t\toperator int() const {\n\t\t\treturn index;\n\t\t}\n\t};\n\n\tstruct absolute_index {\n\t\tint index;\n\t\tabsolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {\n\t\t}\n\n\t\toperator int() const {\n\t\t\treturn index;\n\t\t}\n\t};\n\n\tstruct ref_index {\n\t\tint index;\n\t\tref_index(int idx) : index(idx) {\n\t\t}\n\n\t\toperator int() const {\n\t\t\treturn index;\n\t\t}\n\t};\n\n\tstruct stack_count {\n\t\tint count;\n\n\t\tstack_count(int cnt) : count(cnt) {\n\t\t}\n\t};\n\n\tstruct lightuserdata_value {\n\t\tvoid* value;\n\t\tlightuserdata_value(void* data) : value(data) {\n\t\t}\n\t\toperator void*() const {\n\t\t\treturn value;\n\t\t}\n\t};\n\n\tstruct userdata_value {\n\t\tvoid* value;\n\t\tuserdata_value(void* data) : value(data) {\n\t\t}\n\t\toperator void*() const {\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate <typename L>\n\tstruct light {\n\t\tL* value;\n\n\t\tlight(L& x) : value(std::addressof(x)) {\n\t\t}\n\t\tlight(L* x) : value(x) {\n\t\t}\n\t\tlight(void* x) : value(static_cast<L*>(x)) {\n\t\t}\n\t\toperator L*() const {\n\t\t\treturn value;\n\t\t}\n\t\toperator L&() const {\n\t\t\treturn *value;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tauto make_light(T& l) {\n\t\ttypedef meta::unwrapped_t<std::remove_pointer_t<std::remove_pointer_t<T>>> L;\n\t\treturn light<L>(l);\n\t}\n\n\ttemplate <typename U>\n\tstruct user {\n\t\tU value;\n\n\t\tuser(U&& x) : value(std::forward<U>(x)) {\n\t\t}\n\t\toperator std::add_pointer_t<std::remove_reference_t<U>>() {\n\t\t\treturn std::addressof(value);\n\t\t}\n\t\toperator std::add_lvalue_reference_t<U>() {\n\t\t\treturn value;\n\t\t}\n\t\toperator std::add_const_t<std::add_lvalue_reference_t<U>> &() const {\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tauto make_user(T&& u) {\n\t\ttypedef meta::unwrapped_t<meta::unqualified_t<T>> U;\n\t\treturn user<U>(std::forward<T>(u));\n\t}\n\n\ttemplate <typename T>\n\tstruct metatable_registry_key {\n\t\tT key;\n\n\t\tmetatable_registry_key(T key) : key(std::forward<T>(key)) {\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tauto meta_registry_key(T&& key) {\n\t\ttypedef meta::unqualified_t<T> K;\n\t\treturn metatable_registry_key<K>(std::forward<T>(key));\n\t}\n\n\ttemplate <typename... Upvalues>\n\tstruct closure {\n\t\tlua_CFunction c_function;\n\t\tstd::tuple<Upvalues...> upvalues;\n\t\tclosure(lua_CFunction f, Upvalues... targetupvalues) : c_function(f), upvalues(std::forward<Upvalues>(targetupvalues)...) {\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct closure<> {\n\t\tlua_CFunction c_function;\n\t\tint upvalues;\n\t\tclosure(lua_CFunction f, int upvalue_count = 0) : c_function(f), upvalues(upvalue_count) {\n\t\t}\n\t};\n\n\ttypedef closure<> c_closure;\n\n\ttemplate <typename... Args>\n\tclosure<Args...> make_closure(lua_CFunction f, Args&&... args) {\n\t\treturn closure<Args...>(f, std::forward<Args>(args)...);\n\t}\n\n\ttemplate <typename Sig, typename... Ps>\n\tstruct function_arguments {\n\t\tstd::tuple<Ps...> arguments;\n\t\ttemplate <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler>\n\t\tfunction_arguments(Arg&& arg, Args&&... args) : arguments(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t}\n\t};\n\n\ttemplate <typename Sig = function_sig<>, typename... Args>\n\tauto as_function(Args&&... args) {\n\t\treturn function_arguments<Sig, std::decay_t<Args>...>(std::forward<Args>(args)...);\n\t}\n\n\ttemplate <typename Sig = function_sig<>, typename... Args>\n\tauto as_function_reference(Args&&... args) {\n\t\treturn function_arguments<Sig, Args...>(std::forward<Args>(args)...);\n\t}\n\n\ttemplate <typename T>\n\tstruct as_table_t {\n\tprivate:\n\t\tT value_;\n\n\tpublic:\n\t\tas_table_t() = default;\n\t\tas_table_t(const as_table_t&) = default;\n\t\tas_table_t(as_table_t&&) = default;\n\t\tas_table_t& operator=(const as_table_t&) = default;\n\t\tas_table_t& operator=(as_table_t&&) = default;\n\t\ttemplate <typename Arg,\n\t\t     meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>,\n\t\t          meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>\n\t\tas_table_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {\n\t\t}\n\t\ttemplate <typename Arg0, typename Arg1, typename... Args>\n\t\tas_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tT& value() & {\n\t\t\treturn value_;\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(value_);\n\t\t}\n\n\t\tconst T& value() const& {\n\t\t\treturn value_;\n\t\t}\n\n\t\toperator std::add_lvalue_reference_t<T>() {\n\t\t\treturn value_;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct nested {\n\tprivate:\n\t\tT value_;\n\n\tpublic:\n\t\tusing nested_type = T;\n\n\t\tnested() = default;\n\t\tnested(const nested&) = default;\n\t\tnested(nested&&) = default;\n\t\tnested& operator=(const nested&) = default;\n\t\tnested& operator=(nested&&) = default;\n\t\ttemplate <typename Arg,\n\t\t     meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>,\n\t\t          meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>\n\t\tnested(Arg&& arg) : value_(std::forward<Arg>(arg)) {\n\t\t}\n\t\ttemplate <typename Arg0, typename Arg1, typename... Args>\n\t\tnested(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tT& value() & {\n\t\t\treturn value_;\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(value_);\n\t\t}\n\n\t\tconst T& value() const& {\n\t\t\treturn value_;\n\t\t}\n\n\t\toperator std::add_lvalue_reference_t<T>() {\n\t\t\treturn value_;\n\t\t}\n\t};\n\n\tstruct nested_tag_t { };\n\tconstexpr inline nested_tag_t nested_tag {};\n\n\ttemplate <typename T>\n\tas_table_t<T> as_table_ref(T&& container) {\n\t\treturn as_table_t<T>(std::forward<T>(container));\n\t}\n\n\ttemplate <typename T>\n\tas_table_t<meta::unqualified_t<T>> as_table(T&& container) {\n\t\treturn as_table_t<meta::unqualified_t<T>>(std::forward<T>(container));\n\t}\n\n\ttemplate <typename T>\n\tnested<T> as_nested_ref(T&& container) {\n\t\treturn nested<T>(std::forward<T>(container));\n\t}\n\n\ttemplate <typename T>\n\tnested<meta::unqualified_t<T>> as_nested(T&& container) {\n\t\treturn nested<meta::unqualified_t<T>>(std::forward<T>(container));\n\t}\n\n\ttemplate <typename T>\n\tstruct as_container_t {\n\tprivate:\n\t\tT value_;\n\n\tpublic:\n\t\tusing type = T;\n\n\t\tas_container_t() = default;\n\t\tas_container_t(const as_container_t&) = default;\n\t\tas_container_t(as_container_t&&) = default;\n\t\tas_container_t& operator=(const as_container_t&) = default;\n\t\tas_container_t& operator=(as_container_t&&) = default;\n\t\ttemplate <typename Arg,\n\t\t     meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_container_t>>,\n\t\t          meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>\n\t\tas_container_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {\n\t\t}\n\t\ttemplate <typename Arg0, typename Arg1, typename... Args>\n\t\tas_container_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tT& value() & {\n\t\t\treturn value_;\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(value_);\n\t\t}\n\n\t\tconst T& value() const& {\n\t\t\treturn value_;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct as_container_t<T&> {\n\tprivate:\n\t\tstd::reference_wrapper<T> value_;\n\n\tpublic:\n\t\tas_container_t(T& value) : value_(value) {\n\t\t}\n\n\t\tT& value() {\n\t\t\treturn value_;\n\t\t}\n\n\t\toperator T&() {\n\t\t\treturn value();\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tauto as_container(T&& value) {\n\t\treturn as_container_t<T>(std::forward<T>(value));\n\t}\n\n\ttemplate <typename T>\n\tstruct push_invoke_t {\n\tprivate:\n\t\tT value_;\n\n\tpublic:\n\t\tpush_invoke_t() = default;\n\t\tpush_invoke_t(const push_invoke_t&) = default;\n\t\tpush_invoke_t(push_invoke_t&&) = default;\n\t\tpush_invoke_t& operator=(const push_invoke_t&) = default;\n\t\tpush_invoke_t& operator=(push_invoke_t&&) = default;\n\t\ttemplate <typename Arg,\n\t\t     meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, push_invoke_t>>,\n\t\t          meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>\n\t\tpush_invoke_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {\n\t\t}\n\t\ttemplate <typename Arg0, typename Arg1, typename... Args>\n\t\tpush_invoke_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tT& value() & {\n\t\t\treturn value_;\n\t\t}\n\n\t\tT&& value() && {\n\t\t\treturn std::move(value_);\n\t\t}\n\n\t\tconst T& value() const& {\n\t\t\treturn value_;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct push_invoke_t<T&> {\n\t\tstd::reference_wrapper<T> value_;\n\n\t\tpush_invoke_t(T& value) : value_(value) {\n\t\t}\n\n\t\tT& value() {\n\t\t\treturn value_;\n\t\t}\n\t};\n\n\ttemplate <typename Fx>\n\tauto push_invoke(Fx&& fx) {\n\t\treturn push_invoke_t<Fx>(std::forward<Fx>(fx));\n\t}\n\n\tstruct override_value_t { };\n\tconstexpr inline override_value_t override_value = override_value_t();\n\tstruct update_if_empty_t { };\n\tconstexpr inline update_if_empty_t update_if_empty = update_if_empty_t();\n\tstruct create_if_nil_t { };\n\tconstexpr inline create_if_nil_t create_if_nil = create_if_nil_t();\n\n\tnamespace detail {\n\t\tenum insert_mode { none = 0x0, update_if_empty = 0x01, override_value = 0x02, create_if_nil = 0x04 };\n\n\t\ttemplate <typename T, typename...>\n\t\tusing is_insert_mode = std::integral_constant<bool,\n\t\t     std::is_same_v<T, override_value_t> || std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, create_if_nil_t>>;\n\n\t\ttemplate <typename T, typename...>\n\t\tusing is_not_insert_mode = meta::neg<is_insert_mode<T>>;\n\t} // namespace detail\n\n\tstruct this_state {\n\t\tlua_State* L;\n\n\t\tthis_state(lua_State* Ls) : L(Ls) {\n\t\t}\n\n\t\toperator lua_State*() const noexcept {\n\t\t\treturn lua_state();\n\t\t}\n\n\t\tlua_State* operator->() const noexcept {\n\t\t\treturn lua_state();\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn L;\n\t\t}\n\t};\n\n\tstruct this_main_state {\n\t\tlua_State* L;\n\n\t\tthis_main_state(lua_State* Ls) : L(Ls) {\n\t\t}\n\n\t\toperator lua_State*() const noexcept {\n\t\t\treturn lua_state();\n\t\t}\n\n\t\tlua_State* operator->() const noexcept {\n\t\t\treturn lua_state();\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn L;\n\t\t}\n\t};\n\n\tstruct new_table {\n\t\tint sequence_hint = 0;\n\t\tint map_hint = 0;\n\n\t\tnew_table() = default;\n\t\tnew_table(const new_table&) = default;\n\t\tnew_table(new_table&&) = default;\n\t\tnew_table& operator=(const new_table&) = default;\n\t\tnew_table& operator=(new_table&&) = default;\n\n\t\tnew_table(int sequence_hint, int map_hint = 0) : sequence_hint(sequence_hint), map_hint(map_hint) {\n\t\t}\n\t};\n\n\tconst new_table create = {};\n\n\tenum class lib : char {\n\t\t// print, assert, and other base functions\n\t\tbase,\n\t\t// require and other package functions\n\t\tpackage,\n\t\t// coroutine functions and utilities\n\t\tcoroutine,\n\t\t// string library\n\t\tstring,\n\t\t// functionality from the OS\n\t\tos,\n\t\t// all things math\n\t\tmath,\n\t\t// the table manipulator and observer functions\n\t\ttable,\n\t\t// the debug library\n\t\tdebug,\n\t\t// the bit library: different based on which you're using\n\t\tbit32,\n\t\t// input/output library\n\t\tio,\n\t\t// LuaJIT only\n\t\tffi,\n\t\t// LuaJIT only\n\t\tjit,\n\t\t// library for handling utf8: new to Lua\n\t\tutf8,\n\t\t// do not use\n\t\tcount\n\t};\n\n\tenum class call_syntax { dot = 0, colon = 1 };\n\n\tenum class load_mode {\n\t\tany = 0,\n\t\ttext = 1,\n\t\tbinary = 2,\n\t};\n\n\tenum class call_status : int {\n\t\tok = LUA_OK,\n\t\tyielded = LUA_YIELD,\n\t\truntime = LUA_ERRRUN,\n\t\tmemory = LUA_ERRMEM,\n\t\thandler = LUA_ERRERR,\n\t\tgc = LUA_ERRGCMM,\n\t\tsyntax = LUA_ERRSYNTAX,\n\t\tfile = LUA_ERRFILE,\n\t};\n\n\tenum class thread_status : int {\n\t\tok = LUA_OK,\n\t\tyielded = LUA_YIELD,\n\t\truntime = LUA_ERRRUN,\n\t\tmemory = LUA_ERRMEM,\n\t\tgc = LUA_ERRGCMM,\n\t\thandler = LUA_ERRERR,\n\t\tdead = -1,\n\t};\n\n\tenum class load_status : int {\n\t\tok = LUA_OK,\n\t\tsyntax = LUA_ERRSYNTAX,\n\t\tmemory = LUA_ERRMEM,\n\t\tgc = LUA_ERRGCMM,\n\t\tfile = LUA_ERRFILE,\n\t};\n\n\tenum class gc_mode : int {\n\t\tincremental = 0,\n\t\tgenerational = 1,\n\t\tdefault_value = incremental,\n\t};\n\n\tenum class type : int {\n\t\tnone = LUA_TNONE,\n\t\tlua_nil = LUA_TNIL,\n#if SOL_IS_ON(SOL_NIL_I_)\n\t\tnil = lua_nil,\n#endif // Objective C/C++ Keyword that's found in OSX SDK and OBJC -- check for all forms to protect\n\t\tstring = LUA_TSTRING,\n\t\tnumber = LUA_TNUMBER,\n\t\tthread = LUA_TTHREAD,\n\t\tboolean = LUA_TBOOLEAN,\n\t\tfunction = LUA_TFUNCTION,\n\t\tuserdata = LUA_TUSERDATA,\n\t\tlightuserdata = LUA_TLIGHTUSERDATA,\n\t\ttable = LUA_TTABLE,\n\t\tpoly = -0xFFFF\n\t};\n\n\tinline const std::string& to_string(call_status c) {\n\t\tstatic const std::array<std::string, 10> names { { \"ok\",\n\t\t\t\"yielded\",\n\t\t\t\"runtime\",\n\t\t\t\"memory\",\n\t\t\t\"handler\",\n\t\t\t\"gc\",\n\t\t\t\"syntax\",\n\t\t\t\"file\",\n\t\t\t\"CRITICAL_EXCEPTION_FAILURE\",\n\t\t\t\"CRITICAL_INDETERMINATE_STATE_FAILURE\" } };\n\t\tswitch (c) {\n\t\tcase call_status::ok:\n\t\t\treturn names[0];\n\t\tcase call_status::yielded:\n\t\t\treturn names[1];\n\t\tcase call_status::runtime:\n\t\t\treturn names[2];\n\t\tcase call_status::memory:\n\t\t\treturn names[3];\n\t\tcase call_status::handler:\n\t\t\treturn names[4];\n\t\tcase call_status::gc:\n\t\t\treturn names[5];\n\t\tcase call_status::syntax:\n\t\t\treturn names[6];\n\t\tcase call_status::file:\n\t\t\treturn names[7];\n\t\t}\n\t\tif (static_cast<std::ptrdiff_t>(c) == -1) {\n\t\t\t// One of the many cases where a critical exception error has occurred\n\t\t\treturn names[8];\n\t\t}\n\t\treturn names[9];\n\t}\n\n\tinline bool is_indeterminate_call_failure(call_status c) {\n\t\tswitch (c) {\n\t\tcase call_status::ok:\n\t\tcase call_status::yielded:\n\t\tcase call_status::runtime:\n\t\tcase call_status::memory:\n\t\tcase call_status::handler:\n\t\tcase call_status::gc:\n\t\tcase call_status::syntax:\n\t\tcase call_status::file:\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tinline const std::string& to_string(load_status c) {\n\t\tstatic const std::array<std::string, 7> names {\n\t\t\t{ \"ok\", \"memory\", \"gc\", \"syntax\", \"file\", \"CRITICAL_EXCEPTION_FAILURE\", \"CRITICAL_INDETERMINATE_STATE_FAILURE\" }\n\t\t};\n\t\tswitch (c) {\n\t\tcase load_status::ok:\n\t\t\treturn names[0];\n\t\tcase load_status::memory:\n\t\t\treturn names[1];\n\t\tcase load_status::gc:\n\t\t\treturn names[2];\n\t\tcase load_status::syntax:\n\t\t\treturn names[3];\n\t\tcase load_status::file:\n\t\t\treturn names[4];\n\t\t}\n\t\tif (static_cast<int>(c) == -1) {\n\t\t\t// One of the many cases where a critical exception error has occurred\n\t\t\treturn names[5];\n\t\t}\n\t\treturn names[6];\n\t}\n\n\tinline const std::string& to_string(load_mode c) {\n\t\tstatic const std::array<std::string, 3> names { {\n\t\t\t\"bt\",\n\t\t\t\"t\",\n\t\t\t\"b\",\n\t\t} };\n\t\treturn names[static_cast<std::size_t>(c)];\n\t}\n\n\tenum class meta_function {\n\t\tconstruct,\n\t\tindex,\n\t\tnew_index,\n\t\tmode,\n\t\tcall,\n\t\tcall_function = call,\n\t\tmetatable,\n\t\tto_string,\n\t\tlength,\n\t\tunary_minus,\n\t\taddition,\n\t\tsubtraction,\n\t\tmultiplication,\n\t\tdivision,\n\t\tmodulus,\n\t\tpower_of,\n\t\tinvolution = power_of,\n\t\tconcatenation,\n\t\tequal_to,\n\t\tless_than,\n\t\tless_than_or_equal_to,\n\t\tgarbage_collect,\n\t\tfloor_division,\n\t\tbitwise_left_shift,\n\t\tbitwise_right_shift,\n\t\tbitwise_not,\n\t\tbitwise_and,\n\t\tbitwise_or,\n\t\tbitwise_xor,\n\t\tpairs,\n\t\tipairs,\n\t\tnext,\n\t\ttype,\n\t\ttype_info,\n\t\tcall_construct,\n\t\tstorage,\n\t\tgc_names,\n\t\tstatic_index,\n\t\tstatic_new_index,\n\t};\n\n\ttypedef meta_function meta_method;\n\n\tinline const std::array<std::string, 37>& meta_function_names() {\n\t\tstatic const std::array<std::string, 37> names = { { \"new\",\n\t\t\t\"__index\",\n\t\t\t\"__newindex\",\n\t\t\t\"__mode\",\n\t\t\t\"__call\",\n\t\t\t\"__metatable\",\n\t\t\t\"__tostring\",\n\t\t\t\"__len\",\n\t\t\t\"__unm\",\n\t\t\t\"__add\",\n\t\t\t\"__sub\",\n\t\t\t\"__mul\",\n\t\t\t\"__div\",\n\t\t\t\"__mod\",\n\t\t\t\"__pow\",\n\t\t\t\"__concat\",\n\t\t\t\"__eq\",\n\t\t\t\"__lt\",\n\t\t\t\"__le\",\n\t\t\t\"__gc\",\n\n\t\t\t\"__idiv\",\n\t\t\t\"__shl\",\n\t\t\t\"__shr\",\n\t\t\t\"__bnot\",\n\t\t\t\"__band\",\n\t\t\t\"__bor\",\n\t\t\t\"__bxor\",\n\n\t\t\t\"__pairs\",\n\t\t\t\"__ipairs\",\n\t\t\t\"next\",\n\n\t\t\t\"__type\",\n\t\t\t\"__typeinfo\",\n\t\t\t\"__sol.call_new\",\n\t\t\t\"__sol.storage\",\n\t\t\t\"__sol.gc_names\",\n\t\t\t\"__sol.static_index\",\n\t\t\t\"__sol.static_new_index\" } };\n\t\treturn names;\n\t}\n\n\tinline const std::string& to_string(meta_function mf) {\n\t\treturn meta_function_names()[static_cast<int>(mf)];\n\t}\n\n\tinline type type_of(lua_State* L, int index) {\n\t\treturn static_cast<type>(lua_type(L, index));\n\t}\n\n\tinline std::string type_name(lua_State* L, type t) {\n\t\treturn lua_typename(L, static_cast<int>(t));\n\t}\n\n\ttemplate <typename T>\n\tstruct is_lua_reference\n\t: std::integral_constant<bool, std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T> || std::is_base_of_v<stack_reference, T>> { };\n\n\ttemplate <typename T>\n\tinline constexpr bool is_lua_reference_v = is_lua_reference<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_lua_reference_or_proxy : std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, table_proxy>> { };\n\n\ttemplate <typename T>\n\tinline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_transparent_argument : std::false_type { };\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_transparent_argument_v = is_transparent_argument<T>::value;\n\n\ttemplate <>\n\tstruct is_transparent_argument<this_state> : std::true_type { };\n\ttemplate <>\n\tstruct is_transparent_argument<this_main_state> : std::true_type { };\n\ttemplate <>\n\tstruct is_transparent_argument<this_environment> : std::true_type { };\n\ttemplate <>\n\tstruct is_transparent_argument<variadic_args> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_variadic_arguments : std::is_same<T, variadic_args> { };\n\n\ttemplate <typename T>\n\tstruct is_container\n\t: std::integral_constant<bool,\n\t       !std::is_same_v<state_view,\n\t            T> && !std::is_same_v<state, T> && !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> {\n\t};\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_container_v = is_container<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>,\n\t                               meta::supports_op_left_shift<std::ostream, meta::unqualified_t<T>>> { };\n\n\tnamespace detail {\n\t\ttemplate <typename T, typename = void>\n\t\tstruct lua_type_of : std::integral_constant<type, type::userdata> { };\n\n\t\ttemplate <typename C, typename T, typename A>\n\t\tstruct lua_type_of<std::basic_string<C, T, A>> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <typename C, typename T>\n\t\tstruct lua_type_of<basic_string_view<C, T>> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <std::size_t N>\n\t\tstruct lua_type_of<char[N]> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <std::size_t N>\n\t\tstruct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <std::size_t N>\n\t\tstruct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <std::size_t N>\n\t\tstruct lua_type_of<char32_t[N]> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<char> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<wchar_t> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<char16_t> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<char32_t> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<const char*> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<bool> : std::integral_constant<type, type::boolean> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<lua_nil_t> : std::integral_constant<type, type::lua_nil> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<lua_value> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<detail::non_lua_nil_t> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<std::nullptr_t> : std::integral_constant<type, type::lua_nil> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<error> : std::integral_constant<type, type::string> { };\n\n\t\ttemplate <bool b, typename Base>\n\t\tstruct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_lua_table<Base>> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_metatable<Base>> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <typename T, typename Base>\n\t\tstruct lua_type_of<basic_usertype<T, Base>> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<metatable_key_t> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <typename B>\n\t\tstruct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<env_key_t> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<new_table> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<std::initializer_list<T>> : std::integral_constant<type, type::table> { };\n\n\t\ttemplate <bool b>\n\t\tstruct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<stack_reference> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_object<Base>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <typename... Args>\n\t\tstruct lua_type_of<std::tuple<Args...>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <typename A, typename B>\n\t\tstruct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<void*> : std::integral_constant<type, type::lightuserdata> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<const void*> : std::integral_constant<type, type::lightuserdata> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<light<T>> : std::integral_constant<type, type::lightuserdata> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<user<T>> : std::integral_constant<type, type::userdata> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_lightuserdata<Base>> : std::integral_constant<type, type::lightuserdata> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_userdata<Base>> : std::integral_constant<type, type::userdata> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<lua_CFunction> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<std::remove_pointer_t<lua_CFunction>> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <typename Base, bool aligned>\n\t\tstruct lua_type_of<basic_function<Base, aligned>> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <typename Base, bool aligned, typename Handler>\n\t\tstruct lua_type_of<basic_protected_function<Base, aligned, Handler>> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_coroutine<Base>> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <typename Base>\n\t\tstruct lua_type_of<basic_thread<Base>> : std::integral_constant<type, type::thread> { };\n\n\t\ttemplate <typename Signature>\n\t\tstruct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<optional<T>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<std::optional<T>> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<variadic_results> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<stack_count> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<this_state> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<this_main_state> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<this_environment> : std::integral_constant<type, type::poly> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<type> : std::integral_constant<type, type::poly> { };\n\n#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<T*> : std::integral_constant<type, std::is_function_v<T> ? type::function : type::userdata> { };\n#else\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<T*> : std::integral_constant<type, type::userdata> { };\n#endif\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_same_v<T, lua_Number> || std::is_same_v<T, lua_Integer>>>\n\t\t: std::integral_constant<type, type::number> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<T, std::enable_if_t<std::is_function_v<T>>> : std::integral_constant<type, type::function> { };\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<T, std::enable_if_t<std::is_enum_v<T>>> : std::integral_constant<type, type::number> { };\n\n\t\ttemplate <>\n\t\tstruct lua_type_of<meta_function> : std::integral_constant<type, type::string> { };\n\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n\t\ttemplate <typename... Tn>\n\t\tstruct lua_type_of<std::variant<Tn...>> : std::integral_constant<type, type::poly> { };\n#endif // std::variant deployment sucks on Clang\n\n\t\ttemplate <typename T>\n\t\tstruct lua_type_of<nested<T>> : meta::conditional_t<::sol::is_container_v<T>, std::integral_constant<type, type::table>, lua_type_of<T>> { };\n\n\t\ttemplate <typename C, C v, template <typename...> class V, typename... Args>\n\t\tstruct accumulate : std::integral_constant<C, v> { };\n\n\t\ttemplate <typename C, C v, template <typename...> class V, typename T, typename... Args>\n\t\tstruct accumulate<C, v, V, T, Args...> : accumulate<C, v + V<T>::value, V, Args...> { };\n\n\t\ttemplate <typename C, C v, template <typename...> class V, typename List>\n\t\tstruct accumulate_list;\n\n\t\ttemplate <typename C, C v, template <typename...> class V, typename... Args>\n\t\tstruct accumulate_list<C, v, V, types<Args...>> : accumulate<C, v, V, Args...> { };\n\t} // namespace detail\n\n\ttemplate <typename T>\n\tstruct lua_type_of : detail::lua_type_of<T> {\n\t\ttypedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;\n\t};\n\n\ttemplate <typename T>\n\tinline constexpr type lua_type_of_v = lua_type_of<T>::value;\n\n\ttemplate <typename T>\n\tstruct lua_size : std::integral_constant<int, 1> {\n\t\ttypedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;\n\t};\n\n\ttemplate <typename A, typename B>\n\tstruct lua_size<std::pair<A, B>> : std::integral_constant<int, lua_size<A>::value + lua_size<B>::value> { };\n\n\ttemplate <typename... Args>\n\tstruct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> { };\n\n\ttemplate <typename T>\n\tinline constexpr int lua_size_v = lua_size<T>::value;\n\n\tnamespace detail {\n\t\ttemplate <typename...>\n\t\tstruct void_ {\n\t\t\ttypedef void type;\n\t\t};\n\t\ttemplate <typename T, typename = void>\n\t\tstruct has_internal_marker_impl : std::false_type { };\n\t\ttemplate <typename T>\n\t\tstruct has_internal_marker_impl<T, typename void_<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>::type> : std::true_type { };\n\n\t\ttemplate <typename T>\n\t\tusing has_internal_marker = has_internal_marker_impl<T>;\n\n\t\ttemplate <typename T>\n\t\tconstexpr inline bool has_internal_marker_v = has_internal_marker<T>::value;\n\t} // namespace detail\n\n\ttemplate <typename T>\n\tstruct is_lua_primitive\n\t: std::integral_constant<bool,\n\t       type::userdata\n\t                 != lua_type_of_v<\n\t                      T> || ((type::userdata == lua_type_of_v<T>)&&detail::has_internal_marker_v<lua_type_of<T>> && !detail::has_internal_marker_v<lua_size<T>>)\n\t            || is_lua_reference_or_proxy_v<T> || meta::is_specialization_of_v<T, std::tuple> || meta::is_specialization_of_v<T, std::pair>> { };\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_lua_primitive_v = is_lua_primitive<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_main_threaded : std::is_base_of<main_reference, T> { };\n\n\ttemplate <typename T>\n\tstruct is_stack_based : std::is_base_of<stack_reference, T> { };\n\ttemplate <>\n\tstruct is_stack_based<variadic_args> : std::true_type { };\n\ttemplate <>\n\tstruct is_stack_based<unsafe_function_result> : std::true_type { };\n\ttemplate <>\n\tstruct is_stack_based<protected_function_result> : std::true_type { };\n\ttemplate <>\n\tstruct is_stack_based<stack_proxy> : std::true_type { };\n\ttemplate <>\n\tstruct is_stack_based<stack_proxy_base> : std::true_type { };\n\ttemplate <>\n\tstruct is_stack_based<stack_count> : std::true_type { };\n\n\ttemplate <typename T>\n\tconstexpr inline bool is_stack_based_v = is_stack_based<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_lua_primitive<T*> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_primitive<unsafe_function_result> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_primitive<protected_function_result> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<std::reference_wrapper<T>> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<user<T>> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<light<T>> : is_lua_primitive<T*> { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<optional<T>> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<std::optional<T>> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<as_table_t<T>> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<nested<T>> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_primitive<userdata_value> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_primitive<lightuserdata_value> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_primitive<stack_proxy> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_primitive<stack_proxy_base> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> { };\n\n\ttemplate <typename T>\n\tstruct is_lua_index : std::is_integral<T> { };\n\ttemplate <>\n\tstruct is_lua_index<raw_index> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_index<absolute_index> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_index<ref_index> : std::true_type { };\n\ttemplate <>\n\tstruct is_lua_index<upvalue_index> : std::true_type { };\n\n\ttemplate <typename Signature>\n\tstruct lua_bind_traits : meta::bind_traits<Signature> {\n\tprivate:\n\t\ttypedef meta::bind_traits<Signature> base_t;\n\n\tpublic:\n\t\ttypedef std::integral_constant<bool, meta::count_for<is_variadic_arguments, typename base_t::args_list>::value != 0> runtime_variadics_t;\n\t\tstatic const std::size_t true_arity = base_t::arity;\n\t\tstatic const std::size_t arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::args_list>::value\n\t\t     - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;\n\t\tstatic const std::size_t true_free_arity = base_t::free_arity;\n\t\tstatic const std::size_t free_arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::free_args_list>::value\n\t\t     - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;\n\t};\n\n\ttemplate <typename T>\n\tstruct is_table : std::false_type { };\n\ttemplate <bool x, typename T>\n\tstruct is_table<basic_table_core<x, T>> : std::true_type { };\n\ttemplate <typename T>\n\tstruct is_table<basic_lua_table<T>> : std::true_type { };\n\n\ttemplate <typename T>\n\tinline constexpr bool is_table_v = is_table<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_stack_table : std::false_type { };\n\ttemplate <bool x, typename T>\n\tstruct is_stack_table<basic_table_core<x, T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> { };\n\ttemplate <typename T>\n\tstruct is_stack_table<basic_lua_table<T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> { };\n\n\ttemplate <typename T>\n\tinline constexpr bool is_stack_table_v = is_stack_table<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_function : std::false_type { };\n\ttemplate <typename T, bool aligned>\n\tstruct is_function<basic_function<T, aligned>> : std::true_type { };\n\ttemplate <typename T, bool aligned, typename Handler>\n\tstruct is_function<basic_protected_function<T, aligned, Handler>> : std::true_type { };\n\n\ttemplate <typename T>\n\tusing is_lightuserdata = meta::is_specialization_of<T, basic_lightuserdata>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_lightuserdata_v = is_lightuserdata<T>::value;\n\n\ttemplate <typename T>\n\tusing is_userdata = meta::is_specialization_of<T, basic_userdata>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_userdata_v = is_userdata<T>::value;\n\n\ttemplate <typename T>\n\tusing is_environment = std::integral_constant<bool, is_userdata_v<T> || is_table_v<T> || meta::is_specialization_of_v<T, basic_environment>>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_environment_v = is_environment<T>::value;\n\n\ttemplate <typename T>\n\tusing is_table_like = std::integral_constant<bool, is_table_v<T> || is_environment_v<T> || is_userdata_v<T>>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_table_like_v = is_table_like<T>::value;\n\n\ttemplate <typename T>\n\tstruct is_automagical\n\t: std::integral_constant<bool,\n\t       (SOL_IS_ON(SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_))\n\t            || (std::is_array_v<\n\t                     meta::unqualified_t<T>> || (!std::is_same_v<meta::unqualified_t<T>, state> && !std::is_same_v<meta::unqualified_t<T>, state_view>))> {\n\t};\n\n\ttemplate <typename T>\n\tinline type type_of() {\n\t\treturn lua_type_of<meta::unqualified_t<T>>::value;\n\t}\n\n\tnamespace detail {\n\t\ttemplate <typename T>\n\t\tstruct is_non_factory_constructor : std::false_type { };\n\n\t\ttemplate <typename... Args>\n\t\tstruct is_non_factory_constructor<constructors<Args...>> : std::true_type { };\n\n\t\ttemplate <typename... Args>\n\t\tstruct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type { };\n\n\t\ttemplate <>\n\t\tstruct is_non_factory_constructor<no_construction> : std::true_type { };\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_non_factory_constructor_v = is_non_factory_constructor<T>::value;\n\n\t\ttemplate <typename T>\n\t\tstruct is_constructor : is_non_factory_constructor<T> { };\n\n\t\ttemplate <typename... Args>\n\t\tstruct is_constructor<factory_wrapper<Args...>> : std::true_type { };\n\n\t\ttemplate <typename T>\n\t\tstruct is_constructor<protect_t<T>> : is_constructor<meta::unqualified_t<T>> { };\n\n\t\ttemplate <typename F, typename... Policies>\n\t\tstruct is_constructor<policy_wrapper<F, Policies...>> : is_constructor<meta::unqualified_t<F>> { };\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_constructor_v = is_constructor<T>::value;\n\n\t\ttemplate <typename... Args>\n\t\tusing any_is_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;\n\n\t\ttemplate <typename... Args>\n\t\tinline constexpr bool any_is_constructor_v = any_is_constructor<Args...>::value;\n\n\t\ttemplate <typename T>\n\t\tstruct is_destructor : std::false_type { };\n\n\t\ttemplate <typename Fx>\n\t\tstruct is_destructor<destructor_wrapper<Fx>> : std::true_type { };\n\n\t\ttemplate <typename... Args>\n\t\tusing any_is_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;\n\n\t\ttemplate <typename... Args>\n\t\tinline constexpr bool any_is_destructor_v = any_is_destructor<Args...>::value;\n\t} // namespace detail\n\n\ttemplate <typename T>\n\tusing is_lua_c_function = meta::any<std::is_same<lua_CFunction, T>, std::is_same<detail::lua_CFunction_noexcept, T>, std::is_same<lua_CFunction_ref, T>>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_lua_c_function_v = is_lua_c_function<T>::value;\n\n\tstruct automagic_enrollments {\n\t\tbool default_constructor = true;\n\t\tbool destructor = true;\n\t\tbool pairs_operator = true;\n\t\tbool to_string_operator = true;\n\t\tbool call_operator = true;\n\t\tbool less_than_operator = true;\n\t\tbool less_than_or_equal_to_operator = true;\n\t\tbool length_operator = true;\n\t\tbool equal_to_operator = true;\n\t};\n\n} // namespace sol\n\n// end of sol/types.hpp\n\n#include <exception>\n#include <cstring>\n\n#if SOL_IS_ON(SOL_PRINT_ERRORS_I_)\n#include <iostream>\n#endif\n\nnamespace sol {\n\t// must push a single object to be the error object\n\t// NOTE: the VAST MAJORITY of all Lua libraries -- C or otherwise -- expect a string for the type of error\n\t// break this convention at your own risk\n\tusing exception_handler_function = int (*)(lua_State*, optional<const std::exception&>, string_view);\n\n\tnamespace detail {\n\t\tinline const char (&default_exception_handler_name())[11] {\n\t\t\tstatic const char name[11] = \"sol.\\xE2\\x98\\xA2\\xE2\\x98\\xA2\";\n\t\t\treturn name;\n\t\t}\n\n\t\t// must push at least 1 object on the stack\n\t\tinline int default_exception_handler(lua_State* L, optional<const std::exception&>, string_view what) {\n#if SOL_IS_ON(SOL_PRINT_ERRORS_I_)\n\t\t\tstd::cerr << \"[sol3] An exception occurred: \";\n\t\t\tstd::cerr.write(what.data(), what.size());\n\t\t\tstd::cerr << std::endl;\n#endif\n\t\t\tlua_pushlstring(L, what.data(), what.size());\n\t\t\treturn 1;\n\t\t}\n\n\t\tinline int call_exception_handler(lua_State* L, optional<const std::exception&> maybe_ex, string_view what) {\n\t\t\tlua_getglobal(L, default_exception_handler_name());\n\t\t\ttype t = static_cast<type>(lua_type(L, -1));\n\t\t\tif (t != type::lightuserdata) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn default_exception_handler(L, std::move(maybe_ex), std::move(what));\n\t\t\t}\n\t\t\tvoid* vfunc = lua_touserdata(L, -1);\n\t\t\tlua_pop(L, 1);\n\t\t\tif (vfunc == nullptr) {\n\t\t\t\treturn default_exception_handler(L, std::move(maybe_ex), std::move(what));\n\t\t\t}\n\t\t\texception_handler_function exfunc = reinterpret_cast<exception_handler_function>(vfunc);\n\t\t\treturn exfunc(L, std::move(maybe_ex), std::move(what));\n\t\t}\n\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\ttemplate <lua_CFunction f>\n\t\tint static_trampoline(lua_State* L) noexcept {\n\t\t\treturn f(L);\n\t\t}\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\ttemplate <lua_CFunction_noexcept f>\n\t\tint static_trampoline_noexcept(lua_State* L) noexcept {\n\t\t\treturn f(L);\n\t\t}\n#else\n\t\ttemplate <lua_CFunction f>\n\t\tint static_trampoline_noexcept(lua_State* L) noexcept {\n\t\t\treturn f(L);\n\t\t}\n#endif\n\n\t\ttemplate <typename Fx, typename... Args>\n\t\tint trampoline(lua_State* L, Fx&& f, Args&&... args) noexcept {\n\t\t\treturn f(L, std::forward<Args>(args)...);\n\t\t}\n\n\t\tinline int c_trampoline(lua_State* L, lua_CFunction f) noexcept {\n\t\t\treturn trampoline(L, f);\n\t\t}\n#else\n\n\t\tinline int lua_cfunction_trampoline(lua_State* L, lua_CFunction f) {\n#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS_I_)\n\t\t\treturn f(L);\n\n#else\n\t\t\ttry {\n\t\t\t\treturn f(L);\n\t\t\t}\n\t\t\tcatch (const char* cs) {\n\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs));\n\t\t\t}\n\t\t\tcatch (const std::string& s) {\n\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size()));\n\t\t\t}\n\t\t\tcatch (const std::exception& e) {\n\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(e), e.what());\n\t\t\t}\n#if SOL_IS_OFF(SOL_USE_LUAJIT_I_)\n\t\t\t// LuaJIT cannot have the catchall when the safe propagation is on\n\t\t\t// but LuaJIT will swallow all C++ errors\n\t\t\t// if we don't at least catch std::exception ones\n\t\t\tcatch (...) {\n\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(nullopt), \"caught (...) exception\");\n\t\t\t}\n#endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it\n\t\t\treturn lua_error(L);\n#endif // Safe exceptions\n\t\t}\n\n\t\ttemplate <lua_CFunction f>\n\t\tint static_trampoline(lua_State* L) {\n\t\t\treturn lua_cfunction_trampoline(L, f);\n\t\t}\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\ttemplate <lua_CFunction_noexcept f>\n\t\tint static_trampoline_noexcept(lua_State* L) noexcept {\n\t\t\treturn f(L);\n\t\t}\n#else\n\t\ttemplate <lua_CFunction f>\n\t\tint static_trampoline_noexcept(lua_State* L) noexcept {\n\t\t\treturn f(L);\n\t\t}\n#endif\n\n\t\ttemplate <typename Fx, typename... Args>\n\t\tint trampoline(lua_State* L, Fx&& f, Args&&... args) {\n\t\t\tif constexpr (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) {\n\t\t\t\treturn f(L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS_I_)\n\t\t\t\treturn f(L, std::forward<Args>(args)...);\n#else\n\t\t\t\ttry {\n\t\t\t\t\treturn f(L, std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\tcatch (const char* cs) {\n\t\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs));\n\t\t\t\t}\n\t\t\t\tcatch (const std::string& s) {\n\t\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size()));\n\t\t\t\t}\n\t\t\t\tcatch (const std::exception& e) {\n\t\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(e), e.what());\n\t\t\t\t}\n#if SOL_IS_OFF(SOL_USE_LUAJIT_I_)\n\t\t\t\t// LuaJIT cannot have the catchall when the safe propagation is on\n\t\t\t\t// but LuaJIT will swallow all C++ errors\n\t\t\t\t// if we don't at least catch std::exception ones\n\t\t\t\tcatch (...) {\n\t\t\t\t\tcall_exception_handler(L, optional<const std::exception&>(nullopt), \"caught (...) exception\");\n\t\t\t\t}\n#endif\n\t\t\t\treturn lua_error(L);\n#endif\n\t\t\t}\n\t\t}\n\n\t\tinline int c_trampoline(lua_State* L, lua_CFunction f) {\n\t\t\treturn trampoline(L, f);\n\t\t}\n#endif // Exceptions vs. No Exceptions\n\n\t\ttemplate <typename F, F fx>\n\t\tinline int typed_static_trampoline(lua_State* L) {\n\t\t\tif constexpr (meta::bind_traits<F>::is_noexcept) {\n\t\t\t\treturn static_trampoline_noexcept<fx>(L);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn static_trampoline<fx>(L);\n\t\t\t}\n\t\t}\n\t} // namespace detail\n\n\tinline void set_default_exception_handler(lua_State* L, exception_handler_function exf = &detail::default_exception_handler) {\n\t\tstatic_assert(sizeof(void*) >= sizeof(exception_handler_function),\n\t\t     \"void* storage is too small to transport the exception handler: please file a bug on the sol2 issue tracker to get this looked at!\");\n\t\tvoid* storage;\n\t\tstd::memcpy(&storage, &exf, sizeof(exception_handler_function));\n\t\tlua_pushlightuserdata(L, storage);\n\t\tlua_setglobal(L, detail::default_exception_handler_name());\n\t}\n} // namespace sol\n\n// end of sol/trampoline.hpp\n\n// beginning of sol/stack_core.hpp\n\n// beginning of sol/inheritance.hpp\n\n// beginning of sol/usertype_traits.hpp\n\n// beginning of sol/demangle.hpp\n\n#include <string>\n#include <array>\n#include <cctype>\n#if SOL_IS_ON(SOL_MINGW_CCTYPE_IS_POISONED_I_)\nextern \"C\" {\n#include <ctype.h>\n}\n#endif // MinGW is on some stuff\n#include <locale>\n\nnamespace sol { namespace detail {\n\tinline constexpr std::array<string_view, 9> removals { { \"{anonymous}\",\n\t\t\"(anonymous namespace)\",\n\t\t\"public:\",\n\t\t\"private:\",\n\t\t\"protected:\",\n\t\t\"struct \",\n\t\t\"class \",\n\t\t\"`anonymous-namespace'\",\n\t\t\"`anonymous namespace'\" } };\n\n#if SOL_IS_ON(SOL_COMPILER_GCC_I_) || SOL_IS_ON(SOL_COMPILER_CLANG_I_)\n\tinline std::string ctti_get_type_name_from_sig(std::string name) {\n\t\t// cardinal sins from MINGW\n\t\tusing namespace std;\n\t\tstd::size_t start = name.find_first_of('[');\n\t\tstart = name.find_first_of('=', start);\n\t\tstd::size_t end = name.find_last_of(']');\n\t\tif (end == std::string::npos)\n\t\t\tend = name.size();\n\t\tif (start == std::string::npos)\n\t\t\tstart = 0;\n\t\tif (start < name.size() - 1)\n\t\t\tstart += 1;\n\t\tname = name.substr(start, end - start);\n\t\tstart = name.rfind(\"seperator_mark\");\n\t\tif (start != std::string::npos) {\n\t\t\tname.erase(start - 2, name.length());\n\t\t}\n\t\twhile (!name.empty() && isblank(name.front()))\n\t\t\tname.erase(name.begin());\n\t\twhile (!name.empty() && isblank(name.back()))\n\t\t\tname.pop_back();\n\n\t\tfor (std::size_t r = 0; r < removals.size(); ++r) {\n\t\t\tauto found = name.find(removals[r]);\n\t\t\twhile (found != std::string::npos) {\n\t\t\t\tname.erase(found, removals[r].size());\n\t\t\t\tfound = name.find(removals[r]);\n\t\t\t}\n\t\t}\n\n\t\treturn name;\n\t}\n\n\ttemplate <typename T, class seperator_mark = int>\n\tinline std::string ctti_get_type_name() {\n\t\treturn ctti_get_type_name_from_sig(__PRETTY_FUNCTION__);\n\t}\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\tinline std::string ctti_get_type_name_from_sig(std::string name) {\n\t\tstd::size_t start = name.find(\"get_type_name\");\n\t\tif (start == std::string::npos)\n\t\t\tstart = 0;\n\t\telse\n\t\t\tstart += 13;\n\t\tif (start < name.size() - 1)\n\t\t\tstart += 1;\n\t\tstd::size_t end = name.find_last_of('>');\n\t\tif (end == std::string::npos)\n\t\t\tend = name.size();\n\t\tname = name.substr(start, end - start);\n\t\tif (name.find(\"struct\", 0) == 0)\n\t\t\tname.replace(0, 6, \"\", 0);\n\t\tif (name.find(\"class\", 0) == 0)\n\t\t\tname.replace(0, 5, \"\", 0);\n\t\twhile (!name.empty() && isblank(name.front()))\n\t\t\tname.erase(name.begin());\n\t\twhile (!name.empty() && isblank(name.back()))\n\t\t\tname.pop_back();\n\n\t\tfor (std::size_t r = 0; r < removals.size(); ++r) {\n\t\t\tauto found = name.find(removals[r]);\n\t\t\twhile (found != std::string::npos) {\n\t\t\t\tname.erase(found, removals[r].size());\n\t\t\t\tfound = name.find(removals[r]);\n\t\t\t}\n\t\t}\n\n\t\treturn name;\n\t}\n\n\ttemplate <typename T>\n\tstd::string ctti_get_type_name() {\n\t\treturn ctti_get_type_name_from_sig(__FUNCSIG__);\n\t}\n#else\n#error Compiler not supported for demangling\n#endif // compilers\n\n\ttemplate <typename T>\n\tstd::string demangle_once() {\n\t\tstd::string realname = ctti_get_type_name<T>();\n\t\treturn realname;\n\t}\n\n\tinline std::string short_demangle_from_type_name(std::string realname) {\n\t\t// This isn't the most complete but it'll do for now...?\n\t\tstatic const std::array<std::string, 10> ops = {\n\t\t\t{ \"operator<\", \"operator<<\", \"operator<<=\", \"operator<=\", \"operator>\", \"operator>>\", \"operator>>=\", \"operator>=\", \"operator->\", \"operator->*\" }\n\t\t};\n\t\tint level = 0;\n\t\tstd::ptrdiff_t idx = 0;\n\t\tfor (idx = static_cast<std::ptrdiff_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) {\n\t\t\tif (level == 0 && realname[idx] == ':') {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbool isleft = realname[idx] == '<';\n\t\t\tbool isright = realname[idx] == '>';\n\t\t\tif (!isleft && !isright)\n\t\t\t\tcontinue;\n\t\t\tbool earlybreak = false;\n\t\t\tfor (const auto& op : ops) {\n\t\t\t\tstd::size_t nisop = realname.rfind(op, idx);\n\t\t\t\tif (nisop == std::string::npos)\n\t\t\t\t\tcontinue;\n\t\t\t\tstd::size_t nisopidx = idx - op.size() + 1;\n\t\t\t\tif (nisop == nisopidx) {\n\t\t\t\t\tidx = static_cast<std::ptrdiff_t>(nisopidx);\n\t\t\t\t\tearlybreak = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (earlybreak) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlevel += isleft ? -1 : 1;\n\t\t}\n\t\tif (idx > 0) {\n\t\t\trealname.erase(0, realname.length() < static_cast<std::size_t>(idx) ? realname.length() : idx + 1);\n\t\t}\n\t\treturn realname;\n\t}\n\n\ttemplate <typename T>\n\tstd::string short_demangle_once() {\n\t\tstd::string realname = ctti_get_type_name<T>();\n\t\treturn short_demangle_from_type_name(realname);\n\t}\n\n\ttemplate <typename T>\n\tconst std::string& demangle() {\n\t\tstatic const std::string d = demangle_once<T>();\n\t\treturn d;\n\t}\n\n\ttemplate <typename T>\n\tconst std::string& short_demangle() {\n\t\tstatic const std::string d = short_demangle_once<T>();\n\t\treturn d;\n\t}\n}} // namespace sol::detail\n\n// end of sol/demangle.hpp\n\nnamespace sol {\n\n\ttemplate <typename T>\n\tstruct usertype_traits {\n\t\tstatic const std::string& name() {\n\t\t\tstatic const std::string& n = detail::short_demangle<T>();\n\t\t\treturn n;\n\t\t}\n\t\tstatic const std::string& qualified_name() {\n\t\t\tstatic const std::string& q_n = detail::demangle<T>();\n\t\t\treturn q_n;\n\t\t}\n\t\tstatic const std::string& metatable() {\n\t\t\tstatic const std::string m = std::string(\"sol.\").append(detail::demangle<T>());\n\t\t\treturn m;\n\t\t}\n\t\tstatic const std::string& user_metatable() {\n\t\t\tstatic const std::string u_m = std::string(\"sol.\").append(detail::demangle<T>()).append(\".user\");\n\t\t\treturn u_m;\n\t\t}\n\t\tstatic const std::string& user_gc_metatable() {\n\t\t\tstatic const std::string u_g_m = std::string(\"sol.\").append(detail::demangle<T>()).append(\".user\\xE2\\x99\\xBB\");\n\t\t\treturn u_g_m;\n\t\t}\n\t\tstatic const std::string& gc_table() {\n\t\t\tstatic const std::string g_t = std::string(\"sol.\").append(detail::demangle<T>()).append(\".\\xE2\\x99\\xBB\");\n\t\t\treturn g_t;\n\t\t}\n\t};\n\n} // namespace sol\n\n// end of sol/usertype_traits.hpp\n\n// beginning of sol/unique_usertype_traits.hpp\n\n#include <memory>\n\nnamespace sol {\n\n\ttemplate <typename T>\n\tstruct unique_usertype_traits {\n\t\ttypedef T type;\n\t\ttypedef T actual_type;\n\t\ttemplate <typename X>\n\t\tusing rebind_base = void;\n\n\t\tstatic const bool value = false;\n\n\t\ttemplate <typename U>\n\t\tstatic bool is_null(U&&) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttemplate <typename U>\n\t\tstatic auto get(U&& value) {\n\t\t\treturn std::addressof(detail::deref(value));\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unique_usertype_traits<std::shared_ptr<T>> {\n\t\ttypedef T type;\n\t\ttypedef std::shared_ptr<T> actual_type;\n\t\t// rebind is non-void\n\t\t// if and only if unique usertype\n\t\t// is cast-capable\n\t\ttemplate <typename X>\n\t\tusing rebind_base = std::shared_ptr<X>;\n\n\t\tstatic const bool value = true;\n\n\t\tstatic bool is_null(const actual_type& p) {\n\t\t\treturn p == nullptr;\n\t\t}\n\n\t\tstatic type* get(const actual_type& p) {\n\t\t\treturn p.get();\n\t\t}\n\t};\n\n\ttemplate <typename T, typename D>\n\tstruct unique_usertype_traits<std::unique_ptr<T, D>> {\n\t\tusing type = T;\n\t\tusing actual_type = std::unique_ptr<T, D>;\n\n\t\tstatic const bool value = true;\n\n\t\tstatic bool is_null(const actual_type& p) {\n\t\t\treturn p == nullptr;\n\t\t}\n\n\t\tstatic type* get(const actual_type& p) {\n\t\t\treturn p.get();\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};\n\n\ttemplate <typename T>\n\tinline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value;\n\n\tnamespace detail {\n\t\ttemplate <typename T, typename Rebind = void>\n\t\tusing is_base_rebindable_test = typename T::template rebind_base<Rebind>;\n\t}\n\n\ttemplate <typename T>\n\tusing is_base_rebindable = meta::is_detected<detail::is_base_rebindable_test, T>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_base_rebindable_v = is_base_rebindable<T>::value;\n\n\tnamespace detail {\n\t\ttemplate <typename T, typename = void>\n\t\tstruct is_base_rebindable_non_void_sfinae : std::false_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_base_rebindable_non_void_sfinae<T, std::enable_if_t<is_base_rebindable_v<T>>>\n\t\t: std::integral_constant<bool, !std::is_void_v<typename T::template rebind_base<void>>> {};\n\t} // namespace detail\n\n\ttemplate <typename T>\n\tusing is_base_rebindable_non_void = meta::is_detected<detail::is_base_rebindable_test, T>;\n\n\ttemplate <typename T>\n\tinline constexpr bool is_base_rebindable_non_void_v = is_base_rebindable_non_void<T>::value;\n\n} // namespace sol\n\n// end of sol/unique_usertype_traits.hpp\n\nnamespace sol {\n\ttemplate <typename... Args>\n\tstruct base_list {};\n\ttemplate <typename... Args>\n\tusing bases = base_list<Args...>;\n\n\ttypedef bases<> base_classes_tag;\n\tconst auto base_classes = base_classes_tag();\n\n\ttemplate <typename... Args>\n\tstruct is_to_stringable<base_list<Args...>> : std::false_type {};\n\n\tnamespace detail {\n\n\t\tinline decltype(auto) base_class_check_key() {\n\t\t\tstatic const auto& key = \"class_check\";\n\t\t\treturn key;\n\t\t}\n\n\t\tinline decltype(auto) base_class_cast_key() {\n\t\t\tstatic const auto& key = \"class_cast\";\n\t\t\treturn key;\n\t\t}\n\n\t\tinline decltype(auto) base_class_index_propogation_key() {\n\t\t\tstatic const auto& key = u8\"\\xF0\\x9F\\x8C\\xB2.index\";\n\t\t\treturn key;\n\t\t}\n\n\t\tinline decltype(auto) base_class_new_index_propogation_key() {\n\t\t\tstatic const auto& key = u8\"\\xF0\\x9F\\x8C\\xB2.new_index\";\n\t\t\treturn key;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tstruct inheritance {\n\t\t\ttypedef typename base<T>::type bases_t;\n\n\t\t\tstatic bool type_check_bases(types<>, const string_view&) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttemplate <typename Base, typename... Args>\n\t\t\tstatic bool type_check_bases(types<Base, Args...>, const string_view& ti) {\n\t\t\t\treturn ti == usertype_traits<Base>::qualified_name() || type_check_bases(types<Args...>(), ti);\n\t\t\t}\n\n\t\t\tstatic bool type_check(const string_view& ti) {\n\t\t\t\treturn ti == usertype_traits<T>::qualified_name() || type_check_bases(bases_t(), ti);\n\t\t\t}\n\n\t\t\ttemplate <typename ...Bases>\n\t\t\tstatic bool type_check_with(const string_view& ti) {\n\t\t\t\treturn ti == usertype_traits<T>::qualified_name() || type_check_bases(types<Bases...>(), ti);\n\t\t\t}\n\n\t\t\tstatic void* type_cast_bases(types<>, T*, const string_view&) {\n\t\t\t\treturn nullptr;\n\t\t\t}\n\n\t\t\ttemplate <typename Base, typename... Args>\n\t\t\tstatic void* type_cast_bases(types<Base, Args...>, T* data, const string_view& ti) {\n\t\t\t\t// Make sure to convert to T first, and then dynamic cast to the proper type\n\t\t\t\treturn ti != usertype_traits<Base>::qualified_name() ? type_cast_bases(types<Args...>(), data, ti) : static_cast<void*>(static_cast<Base*>(data));\n\t\t\t}\n\n\t\t\tstatic void* type_cast(void* voiddata, const string_view& ti) {\n\t\t\t\tT* data = static_cast<T*>(voiddata);\n\t\t\t\treturn static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(bases_t(), data, ti) : data);\n\t\t\t}\n\n\t\t\ttemplate <typename... Bases>\n\t\t\tstatic void* type_cast_with(void* voiddata, const string_view& ti) {\n\t\t\t\tT* data = static_cast<T*>(voiddata);\n\t\t\t\treturn static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(types<Bases...>(), data, ti) : data);\n\t\t\t}\n\n\t\t\ttemplate <typename U>\n\t\t\tstatic bool type_unique_cast_bases(types<>, void*, void*, const string_view&) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\ttemplate <typename U, typename Base, typename... Args>\n\t\t\tstatic int type_unique_cast_bases(types<Base, Args...>, void* source_data, void* target_data, const string_view& ti) {\n\t\t\t\tusing uu_traits = unique_usertype_traits<U>;\n\t\t\t\tusing base_ptr = typename uu_traits::template rebind_base<Base>;\n\t\t\t\tstring_view base_ti = usertype_traits<Base>::qualified_name();\n\t\t\t\tif (base_ti == ti) {\n\t\t\t\t\tif (target_data != nullptr) {\n\t\t\t\t\t\tU* source = static_cast<U*>(source_data);\n\t\t\t\t\t\tbase_ptr* target = static_cast<base_ptr*>(target_data);\n\t\t\t\t\t\t// perform proper derived -> base conversion\n\t\t\t\t\t\t*target = *source;\n\t\t\t\t\t}\n\t\t\t\t\treturn 2;\n\t\t\t\t}\n\t\t\t\treturn type_unique_cast_bases<U>(types<Args...>(), source_data, target_data, ti);\n\t\t\t}\n\n\t\t\ttemplate <typename U>\n\t\t\tstatic int type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) {\n\t\t\t\ttypedef unique_usertype_traits<U> uu_traits;\n\t\t\t\tif constexpr (is_base_rebindable_v<uu_traits>) {\n\t\t\t\t\ttypedef typename uu_traits::template rebind_base<void> rebind_t;\n\t\t\t\t\ttypedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, bases_t> cond_bases_t;\n\t\t\t\t\tstring_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();\n\t\t\t\t\tif (rebind_ti != this_rebind_ti) {\n\t\t\t\t\t\t// this is not even of the same unique type\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t\tstring_view this_ti = usertype_traits<T>::qualified_name();\n\t\t\t\t\tif (ti == this_ti) {\n\t\t\t\t\t\t// direct match, return 1\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)rebind_ti;\n\t\t\t\t\tstring_view this_ti = usertype_traits<T>::qualified_name();\n\t\t\t\t\tif (ti == this_ti) {\n\t\t\t\t\t\t// direct match, return 1\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn type_unique_cast_bases<U>(types<>(), source_data, target_data, ti);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename U, typename... Bases>\n\t\t\tstatic int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) {\n\t\t\t\tusing uc_bases_t = types<Bases...>;\n\t\t\t\ttypedef unique_usertype_traits<U> uu_traits;\n\t\t\t\tif constexpr (is_base_rebindable_v<uu_traits>) {\n\t\t\t\t\tusing rebind_t = typename uu_traits::template rebind_base<void>;\n\t\t\t\t\tusing cond_bases_t = meta::conditional_t<std::is_void<rebind_t>::value, types<>, uc_bases_t>;\n\t\t\t\t\tstring_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();\n\t\t\t\t\tif (rebind_ti != this_rebind_ti) {\n\t\t\t\t\t\t// this is not even of the same unique type\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t\tstring_view this_ti = usertype_traits<T>::qualified_name();\n\t\t\t\t\tif (ti == this_ti) {\n\t\t\t\t\t\t// direct match, return 1\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)rebind_ti;\n\t\t\t\t\tstring_view this_ti = usertype_traits<T>::qualified_name();\n\t\t\t\t\tif (ti == this_ti) {\n\t\t\t\t\t\t// direct match, return 1\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn type_unique_cast_bases<U>(types<>(), source_data, target_data, ti);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tusing inheritance_check_function = decltype(&inheritance<void>::type_check);\n\t\tusing inheritance_cast_function = decltype(&inheritance<void>::type_cast);\n\t\tusing inheritance_unique_cast_function = decltype(&inheritance<void>::type_unique_cast<void>);\n\t} // namespace detail\n} // namespace sol\n\n// end of sol/inheritance.hpp\n\n// beginning of sol/error_handler.hpp\n\n#include <cstdio>\n\nnamespace sol {\n\n\tnamespace detail {\n\t\tconstexpr const char* not_a_number = \"not a numeric type\";\n\t\tconstexpr const char* not_a_number_or_number_string = \"not a numeric type or numeric string\";\n\t\tconstexpr const char* not_a_number_integral = \"not a numeric type that fits exactly an integer (number maybe has significant decimals)\";\n\t\tconstexpr const char* not_a_number_or_number_string_integral\n\t\t     = \"not a numeric type or a numeric string that fits exactly an integer (e.g. number maybe has significant decimals)\";\n\n\t\tconstexpr const char* not_enough_stack_space = \"not enough space left on Lua stack\";\n\t\tconstexpr const char* not_enough_stack_space_floating = \"not enough space left on Lua stack for a floating point number\";\n\t\tconstexpr const char* not_enough_stack_space_integral = \"not enough space left on Lua stack for an integral number\";\n\t\tconstexpr const char* not_enough_stack_space_string = \"not enough space left on Lua stack for a string\";\n\t\tconstexpr const char* not_enough_stack_space_meta_function_name = \"not enough space left on Lua stack for the name of a meta_function\";\n\t\tconstexpr const char* not_enough_stack_space_userdata = \"not enough space left on Lua stack to create a sol3 userdata\";\n\t\tconstexpr const char* not_enough_stack_space_generic = \"not enough space left on Lua stack to push valuees\";\n\t\tconstexpr const char* not_enough_stack_space_environment = \"not enough space left on Lua stack to retrieve environment\";\n\t\tconstexpr const char* protected_function_error = \"caught (...) unknown error during protected_function call\";\n\n\t\tinline void accumulate_and_mark(const std::string& n, std::string& aux_message, int& marker) {\n\t\t\tif (marker > 0) {\n\t\t\t\taux_message += \", \";\n\t\t\t}\n\t\t\taux_message += n;\n\t\t\t++marker;\n\t\t}\n\t} // namespace detail\n\n\tinline std::string associated_type_name(lua_State* L, int index, type t) {\n\t\tswitch (t) {\n\t\tcase type::poly:\n\t\t\treturn \"anything\";\n\t\tcase type::userdata: {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 2, \"not enough space to push get the type name\");\n#endif // make sure stack doesn't overflow\n\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlua_pushlstring(L, \"__name\", 6);\n\t\t\tlua_rawget(L, -2);\n\t\t\tsize_t sz;\n\t\t\tconst char* name = lua_tolstring(L, -1, &sz);\n\t\t\tstd::string tn(name, static_cast<std::string::size_type>(sz));\n\t\t\tlua_pop(L, 2);\n\t\t\treturn tn;\n\t\t}\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn lua_typename(L, static_cast<int>(t));\n\t}\n\n\tinline int push_type_panic_string(lua_State* L, int index, type expected, type actual, string_view message, string_view aux_message) noexcept {\n\t\tconst char* err = message.size() == 0\n\t\t     ? (aux_message.size() == 0 ? \"stack index %d, expected %s, received %s\" : \"stack index %d, expected %s, received %s: %s\")\n\t\t     : \"stack index %d, expected %s, received %s: %s %s\";\n\t\tconst char* type_name = expected == type::poly ? \"anything\" : lua_typename(L, static_cast<int>(expected));\n\t\t{\n\t\t\tstd::string actual_name = associated_type_name(L, index, actual);\n\t\t\tlua_pushfstring(L, err, index, type_name, actual_name.c_str(), message.data(), aux_message.data());\n\t\t}\n\t\treturn 1;\n\t}\n\n\tinline int type_panic_string(lua_State* L, int index, type expected, type actual, string_view message = \"\") noexcept(false) {\n\t\tpush_type_panic_string(L, index, expected, actual, message, \"\");\n\t\treturn lua_error(L);\n\t}\n\n\tinline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {\n\t\tpush_type_panic_string(L, index, expected, actual, message == nullptr ? \"\" : message, \"\");\n\t\treturn lua_error(L);\n\t}\n\n\tstruct type_panic_t {\n\t\tint operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) {\n\t\t\treturn type_panic_c_str(L, index, expected, actual, nullptr);\n\t\t}\n\t\tint operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {\n\t\t\treturn type_panic_c_str(L, index, expected, actual, message.data());\n\t\t}\n\t};\n\n\tconst type_panic_t type_panic = {};\n\n\tstruct constructor_handler {\n\t\tint operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {\n\t\t\tpush_type_panic_string(L, index, expected, actual, message, \"(type check failed in constructor)\");\n\t\t\treturn lua_error(L);\n\t\t}\n\t};\n\n\ttemplate <typename F = void>\n\tstruct argument_handler {\n\t\tint operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {\n\t\t\tpush_type_panic_string(L, index, expected, actual, message, \"(bad argument to variable or function call)\");\n\t\t\treturn lua_error(L);\n\t\t}\n\t};\n\n\ttemplate <typename R, typename... Args>\n\tstruct argument_handler<types<R, Args...>> {\n\t\tint operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {\n\t\t\t{\n\t\t\t\tstd::string aux_message = \"(bad argument into '\";\n\t\t\t\taux_message += detail::demangle<R>();\n\t\t\t\taux_message += \"(\";\n\t\t\t\tint marker = 0;\n\t\t\t\t(void)detail::swallow { int(), (detail::accumulate_and_mark(detail::demangle<Args>(), aux_message, marker), int())... };\n\t\t\t\taux_message += \")')\";\n\t\t\t\tpush_type_panic_string(L, index, expected, actual, message, aux_message);\n\t\t\t}\n\t\t\treturn lua_error(L);\n\t\t}\n\t};\n\n\t// Specify this function as the handler for lua::check if you know there's nothing wrong\n\tinline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept {\n\t\treturn 0;\n\t}\n\n\tinline void type_error(lua_State* L, int expected, int actual) noexcept(false) {\n\t\tluaL_error(L, \"expected %s, received %s\", lua_typename(L, expected), lua_typename(L, actual));\n\t}\n\n\tinline void type_error(lua_State* L, type expected, type actual) noexcept(false) {\n\t\ttype_error(L, static_cast<int>(expected), static_cast<int>(actual));\n\t}\n\n\tinline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) {\n\t\tif (expected != type::poly && expected != actual) {\n\t\t\ttype_panic_c_str(L, index, expected, actual, nullptr);\n\t\t}\n\t}\n\n\tinline void type_assert(lua_State* L, int index, type expected) {\n\t\ttype actual = type_of(L, index);\n\t\ttype_assert(L, index, expected, actual);\n\t}\n\n} // namespace sol\n\n// end of sol/error_handler.hpp\n\n// beginning of sol/reference.hpp\n\n// beginning of sol/stack_reference.hpp\n\nnamespace sol {\n\tnamespace detail {\n\t\tinline bool xmovable(lua_State* leftL, lua_State* rightL) {\n\t\t\tif (rightL == nullptr || leftL == nullptr || leftL == rightL) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst void* leftregistry = lua_topointer(leftL, LUA_REGISTRYINDEX);\n\t\t\tconst void* rightregistry = lua_topointer(rightL, LUA_REGISTRYINDEX);\n\t\t\treturn leftregistry == rightregistry;\n\t\t}\n\t} // namespace detail\n\n\tclass stateless_stack_reference {\n\tprivate:\n\t\tfriend class stack_reference;\n\t\t\n\t\tint index = 0;\n\n\t\tint registry_index() const noexcept {\n\t\t\treturn LUA_NOREF;\n\t\t}\n\n\tpublic:\n\t\tstateless_stack_reference() noexcept = default;\n\t\tstateless_stack_reference(lua_nil_t) noexcept : stateless_stack_reference(){};\n\t\tstateless_stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(absolute_index(L, i)) {\n\t\t}\n\t\tstateless_stack_reference(lua_State*, absolute_index i) noexcept : stateless_stack_reference(i) {\n\t\t}\n\t\tstateless_stack_reference(lua_State*, raw_index i) noexcept : stateless_stack_reference(i) {\n\t\t}\n\t\tstateless_stack_reference(absolute_index i) noexcept : index(i) {\n\t\t}\n\t\tstateless_stack_reference(raw_index i) noexcept : index(i) {\n\t\t}\n\t\tstateless_stack_reference(lua_State*, ref_index) noexcept = delete;\n\t\tstateless_stack_reference(ref_index) noexcept = delete;\n\t\tstateless_stack_reference(const reference&) noexcept = delete;\n\t\tstateless_stack_reference(const stateless_stack_reference&) noexcept = default;\n\t\tstateless_stack_reference(stateless_stack_reference&& o) noexcept = default;\n\t\tstateless_stack_reference& operator=(stateless_stack_reference&&) noexcept = default;\n\t\tstateless_stack_reference& operator=(const stateless_stack_reference&) noexcept = default;\n\n\t\tint push(lua_State* L) const noexcept {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push a single reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushvalue(L, index);\n\t\t\treturn 1;\n\t\t}\n\n\t\tvoid pop(lua_State* L, int n = 1) const noexcept {\n\t\t\tlua_pop(L, n);\n\t\t}\n\n\t\tint stack_index() const noexcept {\n\t\t\treturn index;\n\t\t}\n\n\t\tconst void* pointer(lua_State* L) const noexcept {\n\t\t\tconst void* vp = lua_topointer(L, stack_index());\n\t\t\treturn vp;\n\t\t}\n\n\t\ttype get_type(lua_State* L) const noexcept {\n\t\t\tint result = lua_type(L, index);\n\t\t\treturn static_cast<type>(result);\n\t\t}\n\n\t\tbool valid(lua_State* L) const noexcept {\n\t\t\ttype t = get_type(L);\n\t\t\treturn t != type::lua_nil && t != type::none;\n\t\t}\n\n\t\tvoid abandon(lua_State* = nullptr) {\n\t\t\tindex = 0;\n\t\t}\n\t};\n\n\tclass stack_reference : public stateless_stack_reference {\n\tprivate:\n\t\tlua_State* luastate = nullptr;\n\n\tpublic:\n\t\tstack_reference() noexcept = default;\n\t\tstack_reference(lua_nil_t) noexcept\n\t\t: stack_reference() {};\n\t\tstack_reference(lua_State* L, lua_nil_t) noexcept : stateless_stack_reference(L, 0), luastate(L) {\n\t\t}\n\t\tstack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(L, i), luastate(L) {\n\t\t}\n\t\tstack_reference(lua_State* L, absolute_index i) noexcept : stateless_stack_reference(L, i), luastate(L) {\n\t\t}\n\t\tstack_reference(lua_State* L, raw_index i) noexcept : stateless_stack_reference(L, i), luastate(L) {\n\t\t}\n\t\tstack_reference(lua_State* L, ref_index i) noexcept = delete;\n\t\tstack_reference(lua_State* L, const reference& r) noexcept = delete;\n\t\tstack_reference(lua_State* L, const stack_reference& r) noexcept\n\t\t: luastate(L) {\n\t\t\tif (!r.valid()) {\n\t\t\t\tindex = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tint i = r.stack_index();\n\t\t\tif (detail::xmovable(lua_state(), r.lua_state())) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push a single reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushvalue(r.lua_state(), r.index);\n\t\t\t\tlua_xmove(r.lua_state(), luastate, 1);\n\t\t\t\ti = absolute_index(luastate, -1);\n\t\t\t}\n\t\t\tindex = i;\n\t\t}\n\t\tstack_reference(stack_reference&& o) noexcept = default;\n\t\tstack_reference& operator=(stack_reference&&) noexcept = default;\n\t\tstack_reference(const stack_reference&) noexcept = default;\n\t\tstack_reference& operator=(const stack_reference&) noexcept = default;\n\n\t\tint push() const noexcept {\n\t\t\treturn push(lua_state());\n\t\t}\n\n\t\tint push(lua_State* Ls) const noexcept {\n\t\t\treturn stateless_stack_reference::push(Ls);\n\t\t}\n\n\t\tvoid pop() const noexcept {\n\t\t\tpop(lua_state());\n\t\t}\n\n\t\tvoid pop(lua_State* Ls, int n = 1) const noexcept {\n\t\t\tstateless_stack_reference::pop(Ls, n);\n\t\t}\n\n\t\tconst void* pointer() const noexcept {\n\t\t\treturn stateless_stack_reference::pointer(lua_state());\n\t\t}\n\n\t\ttype get_type() const noexcept {\n\t\t\treturn stateless_stack_reference::get_type(lua_state());\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn luastate;\n\t\t}\n\n\t\tbool valid() const noexcept {\n\t\t\treturn stateless_stack_reference::valid(lua_state());\n\t\t}\n\n\t\tvoid abandon () {\n\t\t\tstateless_stack_reference::abandon(lua_state());\n\t\t}\n\t};\n\n\tinline bool operator==(const stack_reference& l, const stack_reference& r) {\n\t\treturn lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 0;\n\t}\n\n\tinline bool operator!=(const stack_reference& l, const stack_reference& r) {\n\t\treturn !operator==(l, r);\n\t}\n\n\tinline bool operator==(const stack_reference& lhs, const lua_nil_t&) {\n\t\treturn !lhs.valid();\n\t}\n\n\tinline bool operator==(const lua_nil_t&, const stack_reference& rhs) {\n\t\treturn !rhs.valid();\n\t}\n\n\tinline bool operator!=(const stack_reference& lhs, const lua_nil_t&) {\n\t\treturn lhs.valid();\n\t}\n\n\tinline bool operator!=(const lua_nil_t&, const stack_reference& rhs) {\n\t\treturn rhs.valid();\n\t}\n\n\tstruct stack_reference_equals {\n\t\tbool operator()(const lua_nil_t& lhs, const stack_reference& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\n\t\tbool operator()(const stack_reference& lhs, const lua_nil_t& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\n\t\tbool operator()(const stack_reference& lhs, const stack_reference& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\t};\n\n\tstruct stack_reference_hash {\n\t\ttypedef stack_reference argument_type;\n\t\ttypedef std::size_t result_type;\n\n\t\tresult_type operator()(const argument_type& lhs) const {\n\t\t\tstd::hash<const void*> h;\n\t\t\treturn h(lhs.pointer());\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/stack_reference.hpp\n\n#include <functional>\n\nnamespace sol {\n\tnamespace detail {\n\t\tinline const char (&default_main_thread_name())[9] {\n\t\t\tstatic const char name[9] = \"sol.\\xF0\\x9F\\x93\\x8C\";\n\t\t\treturn name;\n\t\t}\n\t} // namespace detail\n\n\tnamespace stack {\n\t\tinline void remove(lua_State* L, int rawindex, int count) {\n\t\t\tif (count < 1)\n\t\t\t\treturn;\n\t\t\tint top = lua_gettop(L);\n\t\t\tif (top < 1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (rawindex == -count || top == rawindex) {\n\t\t\t\t// Slice them right off the top\n\t\t\t\tlua_pop(L, static_cast<int>(count));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Remove each item one at a time using stack operations\n\t\t\t// Probably slower, maybe, haven't benchmarked,\n\t\t\t// but necessary\n\t\t\tint index = lua_absindex(L, rawindex);\n\t\t\tif (index < 0) {\n\t\t\t\tindex = lua_gettop(L) + (index + 1);\n\t\t\t}\n\t\t\tint last = index + count;\n\t\t\tfor (int i = index; i < last; ++i) {\n\t\t\t\tlua_remove(L, index);\n\t\t\t}\n\t\t}\n\n\t\tstruct push_popper_at {\n\t\t\tlua_State* L;\n\t\t\tint index;\n\t\t\tint count;\n\t\t\tpush_popper_at(lua_State* luastate, int index = -1, int count = 1) : L(luastate), index(index), count(count) {\n\t\t\t}\n\t\t\t~push_popper_at() {\n\t\t\t\tremove(L, index, count);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <bool top_level>\n\t\tstruct push_popper_n {\n\t\t\tlua_State* L;\n\t\t\tint t;\n\t\t\tpush_popper_n(lua_State* luastate, int x) : L(luastate), t(x) {\n\t\t\t}\n\t\t\tpush_popper_n(const push_popper_n&) = delete;\n\t\t\tpush_popper_n(push_popper_n&&) = default;\n\t\t\tpush_popper_n& operator=(const push_popper_n&) = delete;\n\t\t\tpush_popper_n& operator=(push_popper_n&&) = default;\n\t\t\t~push_popper_n() {\n\t\t\t\tlua_pop(L, t);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct push_popper_n<true> {\n\t\t\tpush_popper_n(lua_State*, int) {\n\t\t\t}\n\t\t};\n\n\t\ttemplate <bool, typename T, typename = void>\n\t\tstruct push_popper {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tT t;\n\t\t\tint idx;\n\n\t\t\tpush_popper(T x) : t(x), idx(lua_absindex(t.lua_state(), -t.push())) {\n\t\t\t}\n\n\t\t\tint index_of(const Tu&) {\n\t\t\t\treturn idx;\n\t\t\t}\n\n\t\t\t~push_popper() {\n\t\t\t\tt.pop();\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename C>\n\t\tstruct push_popper<true, T, C> {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\n\t\t\tpush_popper(T) {\n\t\t\t}\n\n\t\t\tint index_of(const Tu&) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t~push_popper() {\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\n\t\t\tpush_popper(T) {\n\t\t\t}\n\n\t\t\tint index_of(const Tu& r) {\n\t\t\t\treturn r.stack_index();\n\t\t\t}\n\n\t\t\t~push_popper() {\n\t\t\t}\n\t\t};\n\n\t\ttemplate <bool top_level = false, typename T>\n\t\tpush_popper<top_level, T> push_pop(T&& x) {\n\t\t\treturn push_popper<top_level, T>(std::forward<T>(x));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tpush_popper_at push_pop_at(T&& x) {\n\t\t\tint c = x.push();\n\t\t\tlua_State* L = x.lua_state();\n\t\t\treturn push_popper_at(L, lua_absindex(L, -c), c);\n\t\t}\n\n\t\ttemplate <bool top_level = false>\n\t\tpush_popper_n<top_level> pop_n(lua_State* L, int x) {\n\t\t\treturn push_popper_n<top_level>(L, x);\n\t\t}\n\t} // namespace stack\n\n\tinline lua_State* main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) {\n#if SOL_LUA_VESION_I_ < 502\n\t\tif (L == nullptr)\n\t\t\treturn backup_if_unsupported;\n\t\tlua_getglobal(L, detail::default_main_thread_name());\n\t\tauto pp = stack::pop_n(L, 1);\n\t\tif (type_of(L, -1) == type::thread) {\n\t\t\treturn lua_tothread(L, -1);\n\t\t}\n\t\treturn backup_if_unsupported;\n#else\n\t\tif (L == nullptr)\n\t\t\treturn backup_if_unsupported;\n\t\tlua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);\n\t\tlua_State* Lmain = lua_tothread(L, -1);\n\t\tlua_pop(L, 1);\n\t\treturn Lmain;\n#endif // Lua 5.2+ has the main thread unqualified_getter\n\t}\n\n\tnamespace detail {\n\t\tstruct global_tag {\n\t\t} const global_ {};\n\t\tstruct no_safety_tag {\n\t\t} const no_safety {};\n\n\t\ttemplate <bool b>\n\t\tinline lua_State* pick_main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) {\n\t\t\t(void)L;\n\t\t\t(void)backup_if_unsupported;\n\t\t\tif (b) {\n\t\t\t\treturn main_thread(L, backup_if_unsupported);\n\t\t\t}\n\t\t\treturn L;\n\t\t}\n\t} // namespace detail\n\n\tclass stateless_reference {\n\tprivate:\n\t\ttemplate <bool o_main_only>\n\t\tfriend class basic_reference;\n\n\t\tint ref = LUA_NOREF;\n\n\t\tint copy(lua_State* L) const noexcept {\n\t\t\tif (ref == LUA_NOREF)\n\t\t\t\treturn LUA_NOREF;\n\t\t\tpush(L);\n\t\t\treturn luaL_ref(L, LUA_REGISTRYINDEX);\n\t\t}\n\n\t\tlua_State* copy_assign(lua_State* L, lua_State* rL, const stateless_reference& r) {\n\t\t\tif (valid(L)) {\n\t\t\t\tderef(L);\n\t\t\t}\n\t\t\tref = r.copy(L);\n\t\t\treturn rL;\n\t\t}\n\n\t\tlua_State* move_assign(lua_State* L, lua_State* rL, stateless_reference&& r) {\n\t\t\tif (valid(L)) {\n\t\t\t\tderef(L);\n\t\t\t}\n\t\t\tref = r.ref;\n\t\t\tr.ref = LUA_NOREF;\n\t\t\treturn rL;\n\t\t}\n\n\tprotected:\n\t\tint stack_index() const noexcept {\n\t\t\treturn -1;\n\t\t}\n\n\t\tstateless_reference(lua_State* L, detail::global_tag) noexcept {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push this reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushglobaltable(L);\n\t\t\tref = luaL_ref(L, LUA_REGISTRYINDEX);\n\t\t}\n\n\t\tstateless_reference(int raw_ref_index) noexcept : ref(raw_ref_index) {\n\t\t}\n\n\tpublic:\n\t\tstateless_reference() noexcept = default;\n\t\tstateless_reference(lua_nil_t) noexcept : stateless_reference() {\n\t\t}\n\t\tstateless_reference(const stack_reference& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tstateless_reference(stack_reference&& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tstateless_reference(lua_State* L, const stateless_reference& r) noexcept {\n\t\t\tif (r.ref == LUA_REFNIL) {\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.ref == LUA_NOREF || L == nullptr) {\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tref = r.copy(L);\n\t\t}\n\n\t\tstateless_reference(lua_State* L, stateless_reference&& r) noexcept {\n\t\t\tif (r.ref == LUA_REFNIL) {\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.ref == LUA_NOREF || L == nullptr) {\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tref = r.ref;\n\t\t\tr.ref = LUA_NOREF;\n\t\t}\n\n\t\tstateless_reference(lua_State* L, const stack_reference& r) noexcept {\n\t\t\tif (L == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) {\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.get_type() == type::lua_nil) {\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (L != r.lua_state() && !detail::xmovable(L, r.lua_state())) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tr.push(L);\n\t\t\tref = luaL_ref(L, LUA_REGISTRYINDEX);\n\t\t}\n\n\t\tstateless_reference(lua_State* L, int index = -1) noexcept {\n\t\t\t// use L to stick with that state's execution stack\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push this reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushvalue(L, index);\n\t\t\tref = luaL_ref(L, LUA_REGISTRYINDEX);\n\t\t}\n\t\tstateless_reference(lua_State* L, ref_index index) noexcept {\n\t\t\tlua_rawgeti(L, LUA_REGISTRYINDEX, index.index);\n\t\t\tref = luaL_ref(L, LUA_REGISTRYINDEX);\n\t\t}\n\t\tstateless_reference(lua_State*, lua_nil_t) noexcept {\n\t\t}\n\n\t\t~stateless_reference() noexcept = default;\n\n\t\tstateless_reference(const stateless_reference& o) noexcept = delete;\n\t\tstateless_reference& operator=(const stateless_reference& r) noexcept = delete;\n\n\t\tstateless_reference(stateless_reference&& o) noexcept : ref(o.ref) {\n\t\t\to.ref = LUA_NOREF;\n\t\t}\n\n\t\tstateless_reference& operator=(stateless_reference&& o) noexcept {\n\t\t\tref = o.ref;\n\t\t\to.ref = LUA_NOREF;\n\t\t\treturn *this;\n\t\t}\n\n\t\tint push(lua_State* L) const noexcept {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push this reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\tlua_rawgeti(L, LUA_REGISTRYINDEX, ref);\n\t\t\treturn 1;\n\t\t}\n\n\t\tvoid pop(lua_State* L, int n = 1) const noexcept {\n\t\t\tlua_pop(L, n);\n\t\t}\n\n\t\tint registry_index() const noexcept {\n\t\t\treturn ref;\n\t\t}\n\n\t\tbool valid(lua_State*) const noexcept {\n\t\t\treturn !(ref == LUA_NOREF || ref == LUA_REFNIL);\n\t\t}\n\n\t\tconst void* pointer(lua_State* L) const noexcept {\n\t\t\tint si = push(L);\n\t\t\tconst void* vp = lua_topointer(L, -si);\n\t\t\tlua_pop(L, si);\n\t\t\treturn vp;\n\t\t}\n\n\t\ttype get_type(lua_State* L) const noexcept {\n\t\t\tint p = push(L);\n\t\t\tint result = lua_type(L, -1);\n\t\t\tpop(L, p);\n\t\t\treturn static_cast<type>(result);\n\t\t}\n\n\t\tvoid abandon(lua_State* = nullptr) {\n\t\t\tref = LUA_NOREF;\n\t\t}\n\n\t\tvoid deref(lua_State* L) const noexcept {\n\t\t\tluaL_unref(L, LUA_REGISTRYINDEX, ref);\n\t\t}\n\t};\n\n\ttemplate <bool main_only = false>\n\tclass basic_reference : public stateless_reference {\n\tprivate:\n\t\ttemplate <bool o_main_only>\n\t\tfriend class basic_reference;\n\t\tlua_State* luastate = nullptr; // non-owning\n\n\t\ttemplate <bool r_main_only>\n\t\tvoid copy_assign(const basic_reference<r_main_only>& r) {\n\t\t\tif (valid()) {\n\t\t\t\tderef();\n\t\t\t}\n\t\t\tif (r.ref == LUA_REFNIL) {\n\t\t\t\tluastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state());\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.ref == LUA_NOREF) {\n\t\t\t\tluastate = r.luastate;\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (detail::xmovable(lua_state(), r.lua_state())) {\n\t\t\t\tr.push(lua_state());\n\t\t\t\tref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tluastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state());\n\t\t\tref = r.copy();\n\t\t}\n\n\t\ttemplate <bool r_main_only>\n\t\tvoid move_assign(basic_reference<r_main_only>&& r) {\n\t\t\tif (valid()) {\n\t\t\t\tderef();\n\t\t\t}\n\t\t\tif (r.ref == LUA_REFNIL) {\n\t\t\t\tluastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state());\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.ref == LUA_NOREF) {\n\t\t\t\tluastate = r.luastate;\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (detail::xmovable(lua_state(), r.lua_state())) {\n\t\t\t\tr.push(lua_state());\n\t\t\t\tref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tluastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state());\n\t\t\tref = r.ref;\n\t\t\tr.ref = LUA_NOREF;\n\t\t\tr.luastate = nullptr;\n\t\t}\n\n\tprotected:\n\t\tbasic_reference(lua_State* L, detail::global_tag) noexcept\n\t\t: basic_reference(detail::pick_main_thread<main_only>(L, L), detail::global_, detail::global_) {\n\t\t}\n\n\t\tbasic_reference(lua_State* L, detail::global_tag, detail::global_tag) noexcept : stateless_reference(L, detail::global_), luastate(L) {\n\t\t}\n\n\t\tbasic_reference(lua_State* oL, const basic_reference<!main_only>& o) noexcept : stateless_reference(oL, o), luastate(oL) {\n\t\t}\n\n\t\tvoid deref() const noexcept {\n\t\t\treturn stateless_reference::deref(lua_state());\n\t\t}\n\n\t\tint copy() const noexcept {\n\t\t\treturn copy(lua_state());\n\t\t}\n\n\t\tint copy(lua_State* L) const noexcept {\n\t\t\treturn stateless_reference::copy(L);\n\t\t}\n\n\tpublic:\n\t\tbasic_reference() noexcept = default;\n\t\tbasic_reference(lua_nil_t) noexcept : basic_reference() {\n\t\t}\n\t\tbasic_reference(const stack_reference& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_reference(stack_reference&& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <bool r_main_only>\n\t\tbasic_reference(lua_State* L, const basic_reference<r_main_only>& r) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) {\n\t\t\tif (r.ref == LUA_REFNIL) {\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.ref == LUA_NOREF || lua_state() == nullptr) {\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (detail::xmovable(lua_state(), r.lua_state())) {\n\t\t\t\tr.push(lua_state());\n\t\t\t\tref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tref = r.copy();\n\t\t}\n\n\t\ttemplate <bool r_main_only>\n\t\tbasic_reference(lua_State* L, basic_reference<r_main_only>&& r) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) {\n\t\t\tif (r.ref == LUA_REFNIL) {\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.ref == LUA_NOREF || lua_state() == nullptr) {\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (detail::xmovable(lua_state(), r.lua_state())) {\n\t\t\t\tr.push(lua_state());\n\t\t\t\tref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tref = r.ref;\n\t\t\tr.ref = LUA_NOREF;\n\t\t\tr.luastate = nullptr;\n\t\t}\n\n\t\tbasic_reference(lua_State* L, const stack_reference& r) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) {\n\t\t\tif (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) {\n\t\t\t\tref = LUA_NOREF;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (r.get_type() == type::lua_nil) {\n\t\t\t\tref = LUA_REFNIL;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (lua_state() != r.lua_state() && !detail::xmovable(lua_state(), r.lua_state())) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tr.push(lua_state());\n\t\t\tref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);\n\t\t}\n\t\tbasic_reference(lua_State* L, int index = -1) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) {\n\t\t\t// use L to stick with that state's execution stack\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push this reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushvalue(L, index);\n\t\t\tref = luaL_ref(L, LUA_REGISTRYINDEX);\n\t\t}\n\t\tbasic_reference(lua_State* L, ref_index index) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) {\n\t\t\tlua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index);\n\t\t\tref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);\n\t\t}\n\t\tbasic_reference(lua_State* L, lua_nil_t) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) {\n\t\t}\n\n\t\t~basic_reference() noexcept {\n\t\t\tif (lua_state() == nullptr || ref == LUA_NOREF)\n\t\t\t\treturn;\n\t\t\tderef();\n\t\t}\n\n\t\tbasic_reference(const basic_reference& o) noexcept : stateless_reference(o.copy()), luastate(o.lua_state()) {\n\t\t}\n\n\t\tbasic_reference(basic_reference&& o) noexcept : stateless_reference(std::move(o)), luastate(o.lua_state()) {\n\t\t\to.luastate = nullptr;\n\t\t}\n\n\t\tbasic_reference(const basic_reference<!main_only>& o) noexcept\n\t\t: basic_reference(detail::pick_main_thread<main_only>(o.lua_state(), o.lua_state()), o) {\n\t\t}\n\n\t\tbasic_reference(basic_reference<!main_only>&& o) noexcept\n\t\t: stateless_reference(std::move(o)), luastate(detail::pick_main_thread<main_only>(o.lua_state(), o.lua_state())) {\n\t\t\to.luastate = nullptr;\n\t\t\to.ref = LUA_NOREF;\n\t\t}\n\n\t\tbasic_reference& operator=(basic_reference&& r) noexcept {\n\t\t\tmove_assign(std::move(r));\n\t\t\treturn *this;\n\t\t}\n\n\t\tbasic_reference& operator=(const basic_reference& r) noexcept {\n\t\t\tcopy_assign(r);\n\t\t\treturn *this;\n\t\t}\n\n\t\tbasic_reference& operator=(basic_reference<!main_only>&& r) noexcept {\n\t\t\tmove_assign(std::move(r));\n\t\t\treturn *this;\n\t\t}\n\n\t\tbasic_reference& operator=(const basic_reference<!main_only>& r) noexcept {\n\t\t\tcopy_assign(r);\n\t\t\treturn *this;\n\t\t}\n\n\t\tbasic_reference& operator=(const lua_nil_t&) noexcept {\n\t\t\tif (valid()) {\n\t\t\t\tderef();\n\t\t\t}\n\t\t\tluastate = nullptr;\n\t\t\tref = LUA_NOREF;\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename Super>\n\t\tbasic_reference& operator=(proxy_base<Super>&& r);\n\n\t\ttemplate <typename Super>\n\t\tbasic_reference& operator=(const proxy_base<Super>& r);\n\n\t\tint push() const noexcept {\n\t\t\treturn push(lua_state());\n\t\t}\n\n\t\tint push(lua_State* L) const noexcept {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, \"not enough Lua stack space to push this reference value\");\n#endif // make sure stack doesn't overflow\n\t\t\tif (lua_state() == nullptr) {\n\t\t\t\tlua_pushnil(L);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tlua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref);\n\t\t\tif (L != lua_state()) {\n\t\t\t\tlua_xmove(lua_state(), L, 1);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tvoid pop() const noexcept {\n\t\t\tpop(lua_state());\n\t\t}\n\n\t\tvoid pop(lua_State* L, int n = 1) const noexcept {\n\t\t\tstateless_reference::pop(L, n);\n\t\t}\n\n\t\tint registry_index() const noexcept {\n\t\t\treturn stateless_reference::registry_index();\n\t\t}\n\n\t\tbool valid() const noexcept {\n\t\t\treturn stateless_reference::valid(lua_state());\n\t\t}\n\n\t\tconst void* pointer() const noexcept {\n\t\t\treturn stateless_reference::pointer(lua_state());\n\t\t}\n\n\t\texplicit operator bool() const noexcept {\n\t\t\treturn valid();\n\t\t}\n\n\t\ttype get_type() const noexcept {\n\t\t\treturn stateless_reference::get_type(lua_state());\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn luastate;\n\t\t}\n\t};\n\n\ttemplate <bool lb, bool rb>\n\tinline bool operator==(const basic_reference<lb>& l, const basic_reference<rb>& r) {\n\t\tauto ppl = stack::push_pop(l);\n\t\tauto ppr = stack::push_pop(r);\n\t\treturn lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1;\n\t}\n\n\ttemplate <bool lb, bool rb>\n\tinline bool operator!=(const basic_reference<lb>& l, const basic_reference<rb>& r) {\n\t\treturn !operator==(l, r);\n\t}\n\n\ttemplate <bool lb>\n\tinline bool operator==(const basic_reference<lb>& l, const stack_reference& r) {\n\t\tauto ppl = stack::push_pop(l);\n\t\treturn lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1;\n\t}\n\n\ttemplate <bool lb>\n\tinline bool operator!=(const basic_reference<lb>& l, const stack_reference& r) {\n\t\treturn !operator==(l, r);\n\t}\n\n\ttemplate <bool rb>\n\tinline bool operator==(const stack_reference& l, const basic_reference<rb>& r) {\n\t\tauto ppr = stack::push_pop(r);\n\t\treturn lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1;\n\t}\n\n\ttemplate <bool rb>\n\tinline bool operator!=(const stack_reference& l, const basic_reference<rb>& r) {\n\t\treturn !operator==(l, r);\n\t}\n\n\ttemplate <bool lb>\n\tinline bool operator==(const basic_reference<lb>& lhs, const lua_nil_t&) {\n\t\treturn !lhs.valid();\n\t}\n\n\ttemplate <bool rb>\n\tinline bool operator==(const lua_nil_t&, const basic_reference<rb>& rhs) {\n\t\treturn !rhs.valid();\n\t}\n\n\ttemplate <bool lb>\n\tinline bool operator!=(const basic_reference<lb>& lhs, const lua_nil_t&) {\n\t\treturn lhs.valid();\n\t}\n\n\ttemplate <bool rb>\n\tinline bool operator!=(const lua_nil_t&, const basic_reference<rb>& rhs) {\n\t\treturn rhs.valid();\n\t}\n\n\tstruct reference_equals : public stack_reference_equals {\n\t\ttemplate <bool rb>\n\t\tbool operator()(const lua_nil_t& lhs, const basic_reference<rb>& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\n\t\ttemplate <bool lb>\n\t\tbool operator()(const basic_reference<lb>& lhs, const lua_nil_t& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\n\t\ttemplate <bool lb, bool rb>\n\t\tbool operator()(const basic_reference<lb>& lhs, const basic_reference<rb>& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\n\t\ttemplate <bool lb>\n\t\tbool operator()(const basic_reference<lb>& lhs, const stack_reference& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\n\t\ttemplate <bool rb>\n\t\tbool operator()(const stack_reference& lhs, const basic_reference<rb>& rhs) const {\n\t\t\treturn lhs == rhs;\n\t\t}\n\t};\n\n\tstruct reference_hash : public stack_reference_hash {\n\t\ttypedef reference argument_type;\n\t\ttypedef std::size_t result_type;\n\n\t\ttemplate <bool lb>\n\t\tresult_type operator()(const basic_reference<lb>& lhs) const {\n\t\t\tstd::hash<const void*> h;\n\t\t\treturn h(lhs.pointer());\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/reference.hpp\n\n// beginning of sol/tie.hpp\n\nnamespace sol {\n\n\tnamespace detail {\n\t\ttemplate <typename T>\n\t\tstruct is_speshul : std::false_type {};\n\t} // namespace detail\n\n\ttemplate <typename T>\n\tstruct tie_size : std::tuple_size<T> {};\n\n\ttemplate <typename T>\n\tstruct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> {};\n\n\ttemplate <typename... Tn>\n\tstruct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> {\n\tprivate:\n\t\ttypedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t;\n\n\t\ttemplate <typename T>\n\t\tvoid set(std::false_type, T&& target) {\n\t\t\tstd::get<0>(*this) = std::forward<T>(target);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tvoid set(std::true_type, T&& target) {\n\t\t\ttypedef tie_size<meta::unqualified_t<T>> value_size;\n\t\t\ttypedef tie_size<std::tuple<Tn...>> tie_size;\n\t\t\ttypedef meta::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;\n\t\t\ttypedef std::make_index_sequence<indices_size::value> indices;\n\t\t\tset_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target));\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename T>\n\t\tvoid set_extra(std::true_type, std::index_sequence<I...>, T&& target) {\n\t\t\tusing std::get;\n\t\t\t(void)detail::swallow{0,\n\t\t\t\t(get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)..., 0};\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename T>\n\t\tvoid set_extra(std::false_type, std::index_sequence<I...>, T&& target) {\n\t\t\tusing std::get;\n\t\t\t(void)detail::swallow{0,\n\t\t\t\t(get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)..., 0};\n\t\t}\n\n\tpublic:\n\t\tusing base_t::base_t;\n\n\t\ttemplate <typename T>\n\t\ttie_t& operator=(T&& value) {\n\t\t\ttypedef is_tieable<meta::unqualified_t<T>> tieable;\n\t\t\tset(tieable(), std::forward<T>(value));\n\t\t\treturn *this;\n\t\t}\n\t};\n\n\ttemplate <typename... Tn>\n\tstruct tie_size<tie_t<Tn...>> : std::tuple_size<std::tuple<Tn...>> {};\n\n\tnamespace adl_barrier_detail {\n\t\ttemplate <typename... Tn>\n\t\tinline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) {\n\t\t\treturn tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...);\n\t\t}\n\t} // namespace adl_barrier_detail\n\n\tusing namespace adl_barrier_detail;\n\n} // namespace sol\n\n// end of sol/tie.hpp\n\n// beginning of sol/stack_guard.hpp\n\n#include <functional>\n\nnamespace sol {\n\tnamespace detail {\n\t\tinline void stack_fail(int, int) {\n#if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS)\n\t\t\tthrow error(detail::direct_error, \"imbalanced stack after operation finish\");\n#else\n\t\t\t// Lol, what do you want, an error printout? :3c\n\t\t\t// There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so\n\t\t\t// hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard.\n#endif // No Exceptions\n\t\t}\n\t} // namespace detail\n\n\tstruct stack_guard {\n\t\tlua_State* L;\n\t\tint top;\n\t\tstd::function<void(int, int)> on_mismatch;\n\n\t\tstack_guard(lua_State* L) : stack_guard(L, lua_gettop(L)) {\n\t\t}\n\t\tstack_guard(lua_State* L, int top, std::function<void(int, int)> fx = detail::stack_fail) : L(L), top(top), on_mismatch(std::move(fx)) {\n\t\t}\n\t\tbool check_stack(int modification = 0) const {\n\t\t\tint bottom = lua_gettop(L) + modification;\n\t\t\tif (top == bottom) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\ton_mismatch(top, bottom);\n\t\t\treturn false;\n\t\t}\n\t\t~stack_guard() {\n\t\t\tcheck_stack();\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/stack_guard.hpp\n\n#include <vector>\n#include <bitset>\n#include <forward_list>\n#include <string>\n#include <limits>\n#include <algorithm>\n#include <sstream>\n#include <optional>\n#include <type_traits>\n\nnamespace sol {\n\tnamespace detail {\n\t\tstruct with_function_tag { };\n\t\tstruct as_reference_tag { };\n\t\ttemplate <typename T>\n\t\tstruct as_pointer_tag { };\n\t\ttemplate <typename T>\n\t\tstruct as_value_tag { };\n\t\ttemplate <typename T>\n\t\tstruct as_unique_tag { };\n\t\ttemplate <typename T>\n\t\tstruct as_table_tag { };\n\n\t\tusing lua_reg_table = luaL_Reg[64];\n\n\t\tusing unique_destructor = void (*)(void*);\n\t\tusing unique_tag = detail::inheritance_unique_cast_function;\n\n\t\tinline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space, std::size_t& required_space) {\n\t\t\t// this handels arbitrary alignments...\n\t\t\t// make this into a power-of-2-only?\n\t\t\t// actually can't: this is a C++14-compatible framework,\n\t\t\t// power of 2 alignment is C++17\n\t\t\tstd::uintptr_t initial = reinterpret_cast<std::uintptr_t>(ptr);\n\t\t\tstd::uintptr_t offby = static_cast<std::uintptr_t>(initial % alignment);\n\t\t\tstd::uintptr_t padding = (alignment - offby) % alignment;\n\t\t\trequired_space += size + padding;\n\t\t\tif (space < required_space) {\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tptr = static_cast<void*>(static_cast<char*>(ptr) + padding);\n\t\t\tspace -= padding;\n\t\t\treturn ptr;\n\t\t}\n\n\t\tinline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space) {\n\t\t\tstd::size_t required_space = 0;\n\t\t\treturn align(alignment, size, ptr, space, required_space);\n\t\t}\n\n\t\tinline void align_one(std::size_t a, std::size_t s, void*& target_alignment) {\n\t\t\tstd::size_t space = (std::numeric_limits<std::size_t>::max)();\n\t\t\ttarget_alignment = align(a, s, target_alignment, space);\n\t\t\ttarget_alignment = static_cast<void*>(static_cast<char*>(target_alignment) + s);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tstd::size_t aligned_space_for(void* alignment = nullptr) {\n\t\t\t// use temporary storage to prevent strict UB shenanigans\n\t\t\tchar alignment_shim[(std::max)({ sizeof(Args)... }) + (std::max)({ alignof(Args)... })] {};\n\t\t\tchar* start = alignment == nullptr ? static_cast<char*>(alignment) : alignment_shim;\n\t\t\t(void)detail::swallow { int {}, (align_one(std::alignment_of_v<Args>, sizeof(Args), alignment), int {})... };\n\t\t\treturn static_cast<char*>(alignment) - start;\n\t\t}\n\n\t\tinline void* align_usertype_pointer(void* ptr) {\n\t\t\tusing use_align = std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of<void*>::value > 1)\n#endif\n\t\t\t     >;\n\t\t\tif (!use_align::value) {\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t\tstd::size_t space = (std::numeric_limits<std::size_t>::max)();\n\t\t\treturn align(std::alignment_of<void*>::value, sizeof(void*), ptr, space);\n\t\t}\n\n\t\ttemplate <bool pre_aligned = false, bool pre_shifted = false>\n\t\tvoid* align_usertype_unique_destructor(void* ptr) {\n\t\t\tusing use_align = std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of<unique_destructor>::value > 1)\n#endif\n\t\t\t     >;\n\t\t\tif (!pre_aligned) {\n\t\t\t\tptr = align_usertype_pointer(ptr);\n\t\t\t}\n\t\t\tif (!pre_shifted) {\n\t\t\t\tptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*));\n\t\t\t}\n\t\t\tif (!use_align::value) {\n\t\t\t\treturn static_cast<void*>(static_cast<void**>(ptr) + 1);\n\t\t\t}\n\t\t\tstd::size_t space = (std::numeric_limits<std::size_t>::max)();\n\t\t\treturn align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), ptr, space);\n\t\t}\n\n\t\ttemplate <bool pre_aligned = false, bool pre_shifted = false>\n\t\tvoid* align_usertype_unique_tag(void* ptr) {\n\t\t\tusing use_align = std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of<unique_tag>::value > 1)\n#endif\n\t\t\t     >;\n\t\t\tif (!pre_aligned) {\n\t\t\t\tptr = align_usertype_unique_destructor(ptr);\n\t\t\t}\n\t\t\tif (!pre_shifted) {\n\t\t\t\tptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor));\n\t\t\t}\n\t\t\tif (!use_align::value) {\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t\tstd::size_t space = (std::numeric_limits<std::size_t>::max)();\n\t\t\treturn align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), ptr, space);\n\t\t}\n\n\t\ttemplate <typename T, bool pre_aligned = false, bool pre_shifted = false>\n\t\tvoid* align_usertype_unique(void* ptr) {\n\t\t\ttypedef std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of_v<T> > 1)\n#endif\n\t\t\t     >\n\t\t\t     use_align;\n\t\t\tif (!pre_aligned) {\n\t\t\t\tptr = align_usertype_unique_tag(ptr);\n\t\t\t}\n\t\t\tif (!pre_shifted) {\n\t\t\t\tptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_tag));\n\t\t\t}\n\t\t\tif (!use_align::value) {\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t\tstd::size_t space = (std::numeric_limits<std::size_t>::max)();\n\t\t\treturn align(std::alignment_of_v<T>, sizeof(T), ptr, space);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tvoid* align_user(void* ptr) {\n\t\t\ttypedef std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of_v<T> > 1)\n#endif\n\t\t\t     >\n\t\t\t     use_align;\n\t\t\tif (!use_align::value) {\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t\tstd::size_t space = (std::numeric_limits<std::size_t>::max)();\n\t\t\treturn align(std::alignment_of_v<T>, sizeof(T), ptr, space);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tT** usertype_allocate_pointer(lua_State* L) {\n\t\t\ttypedef std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of<T*>::value > 1)\n#endif\n\t\t\t     >\n\t\t\t     use_align;\n\t\t\tif (!use_align::value) {\n\t\t\t\tT** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));\n\t\t\t\treturn pointerpointer;\n\t\t\t}\n\t\t\tstatic const std::size_t initial_size = aligned_space_for<T*>(nullptr);\n\t\t\tstatic const std::size_t misaligned_size = aligned_space_for<T*>(reinterpret_cast<void*>(0x1));\n\n\t\t\tstd::size_t allocated_size = initial_size;\n\t\t\tvoid* unadjusted = lua_newuserdata(L, initial_size);\n\t\t\tvoid* adjusted = align(std::alignment_of<T*>::value, sizeof(T*), unadjusted, allocated_size);\n\t\t\tif (adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\t// what kind of absolute garbage trash allocator are we dealing with?\n\t\t\t\t// whatever, add some padding in the case of MAXIMAL alignment waste...\n\t\t\t\tallocated_size = misaligned_size;\n\t\t\t\tunadjusted = lua_newuserdata(L, allocated_size);\n\t\t\t\tadjusted = align(std::alignment_of<T*>::value, sizeof(T*), unadjusted, allocated_size);\n\t\t\t\tif (adjusted == nullptr) {\n\t\t\t\t\t// trash allocator can burn in hell\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t// luaL_error(L, \"if you are the one that wrote this allocator you should feel bad for doing a\n\t\t\t\t\t// worse job than malloc/realloc and should go read some books, yeah?\");\n\t\t\t\t\tluaL_error(L, \"cannot properly align memory for '%s'\", detail::demangle<T*>().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn static_cast<T**>(adjusted);\n\t\t}\n\n\t\tinline bool attempt_alloc(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t value_align, std::size_t value_size,\n\t\t     std::size_t allocated_size, void*& pointer_adjusted, void*& data_adjusted) {\n\t\t\tvoid* adjusted = lua_newuserdata(L, allocated_size);\n\t\t\tpointer_adjusted = align(ptr_align, ptr_size, adjusted, allocated_size);\n\t\t\tif (pointer_adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// subtract size of what we're going to allocate there\n\t\t\tallocated_size -= ptr_size;\n\t\t\tadjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size);\n\t\t\tdata_adjusted = align(value_align, value_size, adjusted, allocated_size);\n\t\t\tif (data_adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tinline bool attempt_alloc_unique(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t real_align, std::size_t real_size,\n\t\t     std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& id_adjusted, void*& data_adjusted) {\n\t\t\tvoid* adjusted = lua_newuserdata(L, allocated_size);\n\t\t\tpointer_adjusted = align(ptr_align, ptr_size, adjusted, allocated_size);\n\t\t\tif (pointer_adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tallocated_size -= ptr_size;\n\n\t\t\tadjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size);\n\t\t\tdx_adjusted = align(std::alignment_of_v<unique_destructor>, sizeof(unique_destructor), adjusted, allocated_size);\n\t\t\tif (dx_adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tallocated_size -= sizeof(unique_destructor);\n\n\t\t\tadjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor));\n\n\t\t\tid_adjusted = align(std::alignment_of_v<unique_tag>, sizeof(unique_tag), adjusted, allocated_size);\n\t\t\tif (id_adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tallocated_size -= sizeof(unique_tag);\n\n\t\t\tadjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag));\n\t\t\tdata_adjusted = align(real_align, real_size, adjusted, allocated_size);\n\t\t\tif (data_adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tT* usertype_allocate(lua_State* L) {\n\t\t\ttypedef std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of<T*>::value > 1 || std::alignment_of_v<T> > 1)\n#endif\n\t\t\t     >\n\t\t\t     use_align;\n\t\t\tif (!use_align::value) {\n\t\t\t\tT** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));\n\t\t\t\tT*& pointerreference = *pointerpointer;\n\t\t\t\tT* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);\n\t\t\t\tpointerreference = allocationtarget;\n\t\t\t\treturn allocationtarget;\n\t\t\t}\n\n\t\t\t/* the assumption is that `lua_newuserdata` -- unless someone\n\t\t\tpasses a specific lua_Alloc that gives us bogus, un-aligned pointers\n\t\t\t-- uses malloc, which tends to hand out more or less aligned pointers to memory\n\t\t\t(most of the time, anyhow)\n\n\t\t\tbut it's not guaranteed, so we have to do a post-adjustment check and increase padding\n\n\t\t\twe do this preliminarily with compile-time stuff, to see\n\t\t\tif we strike lucky with the allocator and alignment values\n\n\t\t\totherwise, we have to re-allocate the userdata and\n\t\t\tover-allocate some space for additional padding because\n\t\t\tcompilers are optimized for aligned reads/writes\n\t\t\t(and clang will barf UBsan errors on us for not being aligned)\n\t\t\t*/\n\t\t\tstatic const std::size_t initial_size = aligned_space_for<T*, T>(nullptr);\n\t\t\tstatic const std::size_t misaligned_size = aligned_space_for<T*, T>(reinterpret_cast<void*>(0x1));\n\n\t\t\tvoid* pointer_adjusted;\n\t\t\tvoid* data_adjusted;\n\t\t\tbool result\n\t\t\t     = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), initial_size, pointer_adjusted, data_adjusted);\n\t\t\tif (!result) {\n\t\t\t\t// we're likely to get something that fails to perform the proper allocation a second time,\n\t\t\t\t// so we use the suggested_new_size bump to help us out here\n\t\t\t\tpointer_adjusted = nullptr;\n\t\t\t\tdata_adjusted = nullptr;\n\t\t\t\tresult = attempt_alloc(\n\t\t\t\t     L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), misaligned_size, pointer_adjusted, data_adjusted);\n\t\t\t\tif (!result) {\n\t\t\t\t\tif (pointer_adjusted == nullptr) {\n\t\t\t\t\t\tluaL_error(L, \"aligned allocation of userdata block (pointer section) for '%s' failed\", detail::demangle<T>().c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tluaL_error(L, \"aligned allocation of userdata block (data section) for '%s' failed\", detail::demangle<T>().c_str());\n\t\t\t\t\t}\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tT** pointerpointer = reinterpret_cast<T**>(pointer_adjusted);\n\t\t\tT*& pointerreference = *pointerpointer;\n\t\t\tT* allocationtarget = reinterpret_cast<T*>(data_adjusted);\n\t\t\tpointerreference = allocationtarget;\n\t\t\treturn allocationtarget;\n\t\t}\n\n\t\ttemplate <typename T, typename Real>\n\t\tReal* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) {\n\t\t\ttypedef std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of<T*>::value > 1 || std::alignment_of<unique_tag>::value > 1 || std::alignment_of<unique_destructor>::value > 1\n\t\t\t          || std::alignment_of<Real>::value > 1)\n#endif\n\t\t\t     >\n\t\t\t     use_align;\n\t\t\tif (!use_align::value) {\n\t\t\t\tpref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real)));\n\t\t\t\tdx = static_cast<detail::unique_destructor*>(static_cast<void*>(pref + 1));\n\t\t\t\tid = static_cast<unique_tag*>(static_cast<void*>(dx + 1));\n\t\t\t\tReal* mem = static_cast<Real*>(static_cast<void*>(id + 1));\n\t\t\t\treturn mem;\n\t\t\t}\n\n\t\t\tstatic const std::size_t initial_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(nullptr);\n\t\t\tstatic const std::size_t misaligned_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(reinterpret_cast<void*>(0x1));\n\n\t\t\tvoid* pointer_adjusted;\n\t\t\tvoid* dx_adjusted;\n\t\t\tvoid* id_adjusted;\n\t\t\tvoid* data_adjusted;\n\t\t\tbool result = attempt_alloc_unique(L,\n\t\t\t     std::alignment_of_v<T*>,\n\t\t\t     sizeof(T*),\n\t\t\t     std::alignment_of_v<Real>,\n\t\t\t     sizeof(Real),\n\t\t\t     initial_size,\n\t\t\t     pointer_adjusted,\n\t\t\t     dx_adjusted,\n\t\t\t     id_adjusted,\n\t\t\t     data_adjusted);\n\t\t\tif (!result) {\n\t\t\t\t// we're likely to get something that fails to perform the proper allocation a second time,\n\t\t\t\t// so we use the suggested_new_size bump to help us out here\n\t\t\t\tpointer_adjusted = nullptr;\n\t\t\t\tdx_adjusted = nullptr;\n\t\t\t\tid_adjusted = nullptr;\n\t\t\t\tdata_adjusted = nullptr;\n\t\t\t\tresult = attempt_alloc_unique(L,\n\t\t\t\t     std::alignment_of_v<T*>,\n\t\t\t\t     sizeof(T*),\n\t\t\t\t     std::alignment_of_v<Real>,\n\t\t\t\t     sizeof(Real),\n\t\t\t\t     misaligned_size,\n\t\t\t\t     pointer_adjusted,\n\t\t\t\t     dx_adjusted,\n\t\t\t\t     id_adjusted,\n\t\t\t\t     data_adjusted);\n\t\t\t\tif (!result) {\n\t\t\t\t\tif (pointer_adjusted == nullptr) {\n\t\t\t\t\t\tluaL_error(L, \"aligned allocation of userdata block (pointer section) for '%s' failed\", detail::demangle<T>().c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse if (dx_adjusted == nullptr) {\n\t\t\t\t\t\tluaL_error(L, \"aligned allocation of userdata block (deleter section) for '%s' failed\", detail::demangle<T>().c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tluaL_error(L, \"aligned allocation of userdata block (data section) for '%s' failed\", detail::demangle<T>().c_str());\n\t\t\t\t\t}\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpref = static_cast<T**>(pointer_adjusted);\n\t\t\tdx = static_cast<detail::unique_destructor*>(dx_adjusted);\n\t\t\tid = static_cast<unique_tag*>(id_adjusted);\n\t\t\tReal* mem = static_cast<Real*>(data_adjusted);\n\t\t\treturn mem;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tT* user_allocate(lua_State* L) {\n\t\t\ttypedef std::integral_constant<bool,\n#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_)\n\t\t\t     false\n#else\n\t\t\t     (std::alignment_of_v<T> > 1)\n#endif\n\t\t\t     >\n\t\t\t     use_align;\n\t\t\tif (!use_align::value) {\n\t\t\t\tT* pointer = static_cast<T*>(lua_newuserdata(L, sizeof(T)));\n\t\t\t\treturn pointer;\n\t\t\t}\n\n\t\t\tstatic const std::size_t initial_size = aligned_space_for<T>(nullptr);\n\t\t\tstatic const std::size_t misaligned_size = aligned_space_for<T>(reinterpret_cast<void*>(0x1));\n\n\t\t\tstd::size_t allocated_size = initial_size;\n\t\t\tvoid* unadjusted = lua_newuserdata(L, allocated_size);\n\t\t\tvoid* adjusted = align(std::alignment_of_v<T>, sizeof(T), unadjusted, allocated_size);\n\t\t\tif (adjusted == nullptr) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\t// try again, add extra space for alignment padding\n\t\t\t\tallocated_size = misaligned_size;\n\t\t\t\tunadjusted = lua_newuserdata(L, allocated_size);\n\t\t\t\tadjusted = align(std::alignment_of_v<T>, sizeof(T), unadjusted, allocated_size);\n\t\t\t\tif (adjusted == nullptr) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\tluaL_error(L, \"cannot properly align memory for '%s'\", detail::demangle<T>().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn static_cast<T*>(adjusted);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint usertype_alloc_destruct(lua_State* L) {\n\t\t\tvoid* memory = lua_touserdata(L, 1);\n\t\t\tmemory = align_usertype_pointer(memory);\n\t\t\tT** pdata = static_cast<T**>(memory);\n\t\t\tT* data = *pdata;\n\t\t\tstd::allocator<T> alloc {};\n\t\t\tstd::allocator_traits<std::allocator<T>>::destroy(alloc, data);\n\t\t\treturn 0;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint unique_destruct(lua_State* L) {\n\t\t\tvoid* memory = lua_touserdata(L, 1);\n\t\t\tmemory = align_usertype_unique_destructor(memory);\n\t\t\tunique_destructor& dx = *static_cast<unique_destructor*>(memory);\n\t\t\tmemory = align_usertype_unique_tag<true>(memory);\n\t\t\t(dx)(memory);\n\t\t\treturn 0;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint user_alloc_destruct(lua_State* L) {\n\t\t\tvoid* memory = lua_touserdata(L, 1);\n\t\t\tmemory = align_user<T>(memory);\n\t\t\tT* data = static_cast<T*>(memory);\n\t\t\tstd::allocator<T> alloc;\n\t\t\tstd::allocator_traits<std::allocator<T>>::destroy(alloc, data);\n\t\t\treturn 0;\n\t\t}\n\n\t\ttemplate <typename T, typename Real>\n\t\tvoid usertype_unique_alloc_destroy(void* memory) {\n\t\t\tmemory = align_usertype_unique<Real, true>(memory);\n\t\t\tReal* target = static_cast<Real*>(memory);\n\t\t\tstd::allocator<Real> alloc;\n\t\t\tstd::allocator_traits<std::allocator<Real>>::destroy(alloc, target);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint cannot_destruct(lua_State* L) {\n\t\t\treturn luaL_error(L,\n\t\t\t     \"cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= \"\n\t\t\t     \"delete' and thusly this type is being destroyed without properly destructing, invoking undefined \"\n\t\t\t     \"behavior: please bind a usertype and specify a custom destructor to define the behavior properly\",\n\t\t\t     detail::demangle<T>().data());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tvoid reserve(T&, std::size_t) {\n\t\t}\n\n\t\ttemplate <typename T, typename Al>\n\t\tvoid reserve(std::vector<T, Al>& vec, std::size_t hint) {\n\t\t\tvec.reserve(hint);\n\t\t}\n\n\t\ttemplate <typename T, typename Tr, typename Al>\n\t\tvoid reserve(std::basic_string<T, Tr, Al>& str, std::size_t hint) {\n\t\t\tstr.reserve(hint);\n\t\t}\n\n\t\tinline bool property_always_true(meta_function) {\n\t\t\treturn true;\n\t\t}\n\n\t\tstruct properties_enrollment_allowed {\n\t\t\tint& times_through;\n\t\t\tstd::bitset<64>& properties;\n\t\t\tautomagic_enrollments& enrollments;\n\n\t\t\tproperties_enrollment_allowed(int& times, std::bitset<64>& props, automagic_enrollments& enroll)\n\t\t\t: times_through(times), properties(props), enrollments(enroll) {\n\t\t\t}\n\n\t\t\tbool operator()(meta_function mf) const {\n\t\t\t\tbool p = properties[static_cast<int>(mf)];\n\t\t\t\tif (times_through > 0) {\n\t\t\t\t\treturn p;\n\t\t\t\t}\n\t\t\t\tswitch (mf) {\n\t\t\t\tcase meta_function::length:\n\t\t\t\t\treturn enrollments.length_operator && !p;\n\t\t\t\tcase meta_function::pairs:\n\t\t\t\t\treturn enrollments.pairs_operator && !p;\n\t\t\t\tcase meta_function::call:\n\t\t\t\t\treturn enrollments.call_operator && !p;\n\t\t\t\tcase meta_function::less_than:\n\t\t\t\t\treturn enrollments.less_than_operator && !p;\n\t\t\t\tcase meta_function::less_than_or_equal_to:\n\t\t\t\t\treturn enrollments.less_than_or_equal_to_operator && !p;\n\t\t\t\tcase meta_function::equal_to:\n\t\t\t\t\treturn enrollments.equal_to_operator && !p;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn !p;\n\t\t\t}\n\t\t};\n\n\t\tstruct indexed_insert {\n\t\t\tlua_reg_table& l;\n\t\t\tint& index;\n\n\t\t\tindexed_insert(lua_reg_table& cont, int& idx) : l(cont), index(idx) {\n\t\t\t}\n\t\t\tvoid operator()(meta_function mf, lua_CFunction f) {\n\t\t\t\tl[index] = luaL_Reg { to_string(mf).c_str(), f };\n\t\t\t\t++index;\n\t\t\t}\n\t\t};\n\t} // namespace detail\n\n\tnamespace stack {\n\n\t\ttemplate <typename T, bool global = false, bool raw = false, typename = void>\n\t\tstruct field_getter;\n\t\ttemplate <typename T, typename P, bool global = false, bool raw = false, typename = void>\n\t\tstruct probe_field_getter;\n\n\t\ttemplate <typename T, bool global = false, bool raw = false, typename = void>\n\t\tstruct field_setter;\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct unqualified_getter;\n\t\ttemplate <typename T, typename = void>\n\t\tstruct qualified_getter;\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct qualified_interop_getter;\n\t\ttemplate <typename T, typename = void>\n\t\tstruct unqualified_interop_getter;\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct popper;\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct unqualified_pusher;\n\n\t\ttemplate <typename T, type t, typename = void>\n\t\tstruct unqualified_checker;\n\t\ttemplate <typename T, type t, typename = void>\n\t\tstruct qualified_checker;\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct unqualified_check_getter;\n\t\ttemplate <typename T, typename = void>\n\t\tstruct qualified_check_getter;\n\n\t\tstruct probe {\n\t\t\tbool success;\n\t\t\tint levels;\n\n\t\t\tprobe(bool s, int l) : success(s), levels(l) {\n\t\t\t}\n\n\t\t\toperator bool() const {\n\t\t\t\treturn success;\n\t\t\t};\n\t\t};\n\n\t\tstruct record {\n\t\t\tint last;\n\t\t\tint used;\n\n\t\t\trecord() noexcept : last(), used() {\n\t\t\t}\n\t\t\tvoid use(int count) noexcept {\n\t\t\t\tlast = count;\n\t\t\t\tused += count;\n\t\t\t}\n\t\t};\n\n\t\tnamespace stack_detail {\n\t\t\ttemplate <typename Function>\n\t\t\tFunction* get_function_pointer(lua_State*, int, record&) noexcept;\n\t\t\ttemplate <typename Function, typename Handler>\n\t\t\tbool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept;\n\t\t} // namespace stack_detail\n\n\t} // namespace stack\n\n\tnamespace meta { namespace meta_detail {\n\n\t\ttemplate <typename T>\n\t\tusing adl_sol_lua_get_test_t = decltype(sol_lua_get(types<T>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>()));\n\n\t\ttemplate <typename T>\n\t\tusing adl_sol_lua_interop_get_test_t\n\t\t\t= decltype(sol_lua_interop_get(types<T>(), static_cast<lua_State*>(nullptr), -1, static_cast<void*>(nullptr), std::declval<stack::record&>()));\n\n\t\ttemplate <typename T>\n\t\tusing adl_sol_lua_check_test_t = decltype(sol_lua_check(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()));\n\n\t\ttemplate <typename T>\n\t\tusing adl_sol_lua_interop_check_test_t\n\t\t\t= decltype(sol_lua_interop_check(types<T>(), static_cast<lua_State*>(nullptr), -1, type::none, no_panic, std::declval<stack::record&>()));\n\n\t\ttemplate <typename T>\n\t\tusing adl_sol_lua_check_get_test_t\n\t\t\t= decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()));\n\n\t\ttemplate <typename... Args>\n\t\tusing adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast<lua_State*>(nullptr), std::declval<Args>()...));\n\n\t\ttemplate <typename T, typename... Args>\n\t\tusing adl_sol_lua_push_exact_test_t = decltype(sol_lua_push(types<T>(), static_cast<lua_State*>(nullptr), std::declval<Args>()...));\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_adl_sol_lua_get_v = meta::is_detected_v<adl_sol_lua_get_test_t, T>;\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_adl_sol_lua_interop_get_v = meta::is_detected_v<adl_sol_lua_interop_get_test_t, T>;\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_adl_sol_lua_check_v = meta::is_detected_v<adl_sol_lua_check_test_t, T>;\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_adl_sol_lua_interop_check_v = meta::is_detected_v<adl_sol_lua_interop_check_test_t, T>;\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_adl_sol_lua_check_get_v = meta::is_detected_v<adl_sol_lua_check_get_test_t, T>;\n\n\t\ttemplate <typename... Args>\n\t\tinline constexpr bool is_adl_sol_lua_push_v = meta::is_detected_v<adl_sol_lua_push_test_t, Args...>;\n\n\t\ttemplate <typename T, typename... Args>\n\t\tinline constexpr bool is_adl_sol_lua_push_exact_v = meta::is_detected_v<adl_sol_lua_push_exact_test_t, T, Args...>;\n\t}} // namespace meta::meta_detail\n\n\tnamespace stack {\n\t\tnamespace stack_detail {\n\t\t\tconstexpr const char* not_enough_stack_space = \"not enough space left on Lua stack\";\n\t\t\tconstexpr const char* not_enough_stack_space_floating = \"not enough space left on Lua stack for a floating point number\";\n\t\t\tconstexpr const char* not_enough_stack_space_integral = \"not enough space left on Lua stack for an integral number\";\n\t\t\tconstexpr const char* not_enough_stack_space_string = \"not enough space left on Lua stack for a string\";\n\t\t\tconstexpr const char* not_enough_stack_space_meta_function_name = \"not enough space left on Lua stack for the name of a meta_function\";\n\t\t\tconstexpr const char* not_enough_stack_space_userdata = \"not enough space left on Lua stack to create a sol3 userdata\";\n\t\t\tconstexpr const char* not_enough_stack_space_generic = \"not enough space left on Lua stack to push valuees\";\n\t\t\tconstexpr const char* not_enough_stack_space_environment = \"not enough space left on Lua stack to retrieve environment\";\n\n\t\t\ttemplate <typename T>\n\t\t\tstruct strip {\n\t\t\t\ttypedef T type;\n\t\t\t};\n\t\t\ttemplate <typename T>\n\t\t\tstruct strip<std::reference_wrapper<T>> {\n\t\t\t\ttypedef T& type;\n\t\t\t};\n\t\t\ttemplate <typename T>\n\t\t\tstruct strip<user<T>> {\n\t\t\t\ttypedef T& type;\n\t\t\t};\n\t\t\ttemplate <typename T>\n\t\t\tstruct strip<non_null<T>> {\n\t\t\t\ttypedef T type;\n\t\t\t};\n\t\t\ttemplate <typename T>\n\t\t\tusing strip_t = typename strip<T>::type;\n\n\t\t\ttemplate <typename C>\n\t\t\tstatic int get_size_hint(C& c) {\n\t\t\t\treturn static_cast<int>(c.size());\n\t\t\t}\n\n\t\t\ttemplate <typename V, typename Al>\n\t\t\tstatic int get_size_hint(const std::forward_list<V, Al>&) {\n\t\t\t\t// forward_list makes me sad\n\t\t\t\treturn static_cast<int>(32);\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tdecltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) {\n\t\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_get_v<Tu>) {\n\t\t\t\t\treturn sol_lua_get(types<Tu>(), L, index, tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tunqualified_getter<Tu> g {};\n\t\t\t\t\t(void)g;\n\t\t\t\t\treturn g.get(L, index, tracking);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tdecltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {\n\t\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_get_v<T>) {\n\t\t\t\t\treturn sol_lua_get(types<T>(), L, index, tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tqualified_getter<T> g {};\n\t\t\t\t\t(void)g;\n\t\t\t\t\treturn g.get(L, index, tracking);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tdecltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {\n\t\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<Tu>) {\n\t\t\t\t\treturn sol_lua_interop_get(types<Tu>(), L, index, unadjusted_pointer, tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)L;\n\t\t\t\t\t(void)index;\n\t\t\t\t\t(void)unadjusted_pointer;\n\t\t\t\t\t(void)tracking;\n\t\t\t\t\tusing Ti = stack_detail::strip_t<Tu>;\n\t\t\t\t\treturn std::pair<bool, Ti*> { false, nullptr };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tdecltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {\n\t\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<T>) {\n\t\t\t\t\treturn sol_lua_interop_get(types<T>(), L, index, unadjusted_pointer, tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn unqualified_interop_get<T>(L, index, unadjusted_pointer, tracking);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename T, typename Handler>\n\t\t\tbool unqualified_interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) {\n\t\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v<Tu>) {\n\t\t\t\t\treturn sol_lua_interop_check(types<Tu>(), L, index, index_type, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)L;\n\t\t\t\t\t(void)index;\n\t\t\t\t\t(void)index_type;\n\t\t\t\t\t(void)handler;\n\t\t\t\t\t(void)tracking;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename T, typename Handler>\n\t\t\tbool interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) {\n\t\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v<T>) {\n\t\t\t\t\treturn sol_lua_interop_check(types<T>(), L, index, index_type, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tusing undefined_method_func = void (*)(stack_reference);\n\n\t\t\tstruct undefined_metatable {\n\t\t\t\tlua_State* L;\n\t\t\t\tconst char* key;\n\t\t\t\tundefined_method_func on_new_table;\n\n\t\t\t\tundefined_metatable(lua_State* l, const char* k, undefined_method_func umf) : L(l), key(k), on_new_table(umf) {\n\t\t\t\t}\n\n\t\t\t\tvoid operator()() const {\n\t\t\t\t\tif (luaL_newmetatable(L, key) == 1) {\n\t\t\t\t\t\ton_new_table(stack_reference(L, -1));\n\t\t\t\t\t}\n\t\t\t\t\tlua_setmetatable(L, -2);\n\t\t\t\t}\n\t\t\t};\n\t\t} // namespace stack_detail\n\n\t\tinline bool maybe_indexable(lua_State* L, int index = -1) {\n\t\t\ttype t = type_of(L, index);\n\t\t\treturn t == type::userdata || t == type::table;\n\t\t}\n\n\t\tinline int top(lua_State* L) {\n\t\t\treturn lua_gettop(L);\n\t\t}\n\n\t\tinline bool is_main_thread(lua_State* L) {\n\t\t\tint ismainthread = lua_pushthread(L);\n\t\t\tlua_pop(L, 1);\n\t\t\treturn ismainthread == 1;\n\t\t}\n\n\t\tinline void coroutine_create_guard(lua_State* L) {\n\t\t\tif (is_main_thread(L)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tint stacksize = lua_gettop(L);\n\t\t\tif (stacksize < 1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (type_of(L, 1) != type::function) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// well now we're screwed...\n\t\t\t// we can clean the stack and pray it doesn't destroy anything?\n\t\t\tlua_pop(L, stacksize);\n\t\t}\n\n\t\tinline void clear(lua_State* L, int table_index) {\n\t\t\tlua_pushnil(L);\n\t\t\twhile (lua_next(L, table_index) != 0) {\n\t\t\t\t// remove value\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\t// duplicate key to protect form rawset\n\t\t\t\tlua_pushvalue(L, -1);\n\t\t\t\t// push new value\n\t\t\t\tlua_pushnil(L);\n\t\t\t\t// table_index%[key] = nil\n\t\t\t\tlua_rawset(L, table_index);\n\t\t\t}\n\t\t}\n\n\t\tinline void clear(reference& r) {\n\t\t\tauto pp = push_pop<false>(r);\n\t\t\tint stack_index = pp.index_of(r);\n\t\t\tclear(r.lua_state(), stack_index);\n\t\t}\n\n\t\tinline void clear(stack_reference& r) {\n\t\t\tclear(r.lua_state(), r.stack_index());\n\t\t}\n\n\t\ttemplate <typename T, typename... Args>\n\t\tint push(lua_State* L, T&& t, Args&&... args) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, T, Args...>) {\n\t\t\t\treturn sol_lua_push(types<T>(), L, std::forward<T>(t), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, T, Args...>) {\n\t\t\t\treturn sol_lua_push(types<Tu>(), L, std::forward<T>(t), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<T, Args...>) {\n\t\t\t\treturn sol_lua_push(L, std::forward<T>(t), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tunqualified_pusher<Tu> p {};\n\t\t\t\t(void)p;\n\t\t\t\treturn p.push(L, std::forward<T>(t), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\t// overload allows to use a pusher of a specific type, but pass in any kind of args\n\t\ttemplate <typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>>\n\t\tint push(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, Arg, Args...>) {\n\t\t\t\treturn sol_lua_push(types<T>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, Arg, Args...>) {\n\t\t\t\treturn sol_lua_push(types<Tu>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<Arg, Args...>) {\n\t\t\t\treturn sol_lua_push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tunqualified_pusher<Tu> p {};\n\t\t\t\t(void)p;\n\t\t\t\treturn p.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename... Args>\n\t\tint push_userdata(lua_State* L, T&& t, Args&&... args) {\n\t\t\tusing U = meta::unqualified_t<T>;\n\t\t\tusing Tr = meta::conditional_t<std::is_pointer_v<U>,\n\t\t\t     detail::as_pointer_tag<std::remove_pointer_t<U>>,\n\t\t\t     meta::conditional_t<is_unique_usertype_v<U>, detail::as_unique_tag<U>, detail::as_value_tag<U>>>;\n\t\t\treturn stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename T, typename Arg, typename... Args>\n\t\tint push_userdata(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\tusing U = meta::unqualified_t<T>;\n\t\t\tusing Tr = meta::conditional_t<std::is_pointer_v<U>,\n\t\t\t     detail::as_pointer_tag<std::remove_pointer_t<U>>,\n\t\t\t     meta::conditional_t<is_unique_usertype_v<U>, detail::as_unique_tag<U>, detail::as_value_tag<U>>>;\n\t\t\treturn stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t}\n\n\t\tnamespace stack_detail {\n\n\t\t\ttemplate <typename T, typename Arg, typename... Args>\n\t\t\tint push_reference(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\t\tusing use_reference_tag = meta::all<std::is_lvalue_reference<T>,\n\t\t\t\t     meta::neg<std::is_const<std::remove_reference_t<T>>>,\n\t\t\t\t     meta::neg<is_lua_primitive<meta::unqualified_t<T>>>,\n\t\t\t\t     meta::neg<is_unique_usertype<meta::unqualified_t<T>>>>;\n\t\t\t\tusing Tr = meta::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>;\n\t\t\t\treturn stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\n\t\t} // namespace stack_detail\n\n\t\ttemplate <typename T, typename... Args>\n\t\tint push_reference(lua_State* L, T&& t, Args&&... args) {\n\t\t\treturn stack_detail::push_reference<T>(L, std::forward<T>(t), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename T, typename Arg, typename... Args>\n\t\tint push_reference(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\treturn stack_detail::push_reference<T>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t}\n\n\t\tinline int multi_push(lua_State*) {\n\t\t\t// do nothing\n\t\t\treturn 0;\n\t\t}\n\n\t\ttemplate <typename T, typename... Args>\n\t\tint multi_push(lua_State* L, T&& t, Args&&... args) {\n\t\t\tint pushcount = push(L, std::forward<T>(t));\n\t\t\tvoid(detail::swallow { (pushcount += stack::push(L, std::forward<Args>(args)), 0)... });\n\t\t\treturn pushcount;\n\t\t}\n\n\t\tinline int multi_push_reference(lua_State*) {\n\t\t\t// do nothing\n\t\t\treturn 0;\n\t\t}\n\n\t\ttemplate <typename T, typename... Args>\n\t\tint multi_push_reference(lua_State* L, T&& t, Args&&... args) {\n\t\t\tint pushcount = push_reference(L, std::forward<T>(t));\n\t\t\tvoid(detail::swallow { (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... });\n\t\t\treturn pushcount;\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_check_v<Tu>) {\n\t\t\t\treturn sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tunqualified_checker<Tu, lua_type_of_v<Tu>> c;\n\t\t\t\t// VC++ has a bad warning here: shut it up\n\t\t\t\t(void)c;\n\t\t\t\treturn c.check(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool unqualified_check(lua_State* L, int index, Handler&& handler) {\n\t\t\trecord tracking {};\n\t\t\treturn unqualified_check<T>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool unqualified_check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\tauto handler = no_panic;\n\t\t\treturn unqualified_check<T>(L, index, handler);\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_check_v<T>) {\n\t\t\t\treturn sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\t\tqualified_checker<T, lua_type_of_v<Tu>> c;\n\t\t\t\t// VC++ has a bad warning here: shut it up\n\t\t\t\t(void)c;\n\t\t\t\treturn c.check(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool check(lua_State* L, int index, Handler&& handler) {\n\t\t\trecord tracking {};\n\t\t\treturn check<T>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\tauto handler = no_panic;\n\t\t\treturn check<T>(L, index, handler);\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool check_usertype(lua_State* L, int index, type, Handler&& handler, record& tracking) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tusing detail_t = meta::conditional_t<std::is_pointer_v<T>, detail::as_pointer_tag<Tu>, detail::as_value_tag<Tu>>;\n\t\t\treturn check<detail_t>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tusing detail_t = meta::conditional_t<std::is_pointer_v<T>, detail::as_pointer_tag<Tu>, detail::as_value_tag<Tu>>;\n\t\t\treturn check<detail_t>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tbool check_usertype(lua_State* L, int index, Handler&& handler) {\n\t\t\trecord tracking {};\n\t\t\treturn check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\tauto handler = no_panic;\n\t\t\treturn check_usertype<T>(L, index, handler);\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tdecltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) {\n\t\t\t\treturn sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<Tu>) {\n\t\t\t\treturn sol_lua_check_get(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tunqualified_check_getter<Tu> cg {};\n\t\t\t\t(void)cg;\n\t\t\t\treturn cg.get(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tdecltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) {\n\t\t\trecord tracking {};\n\t\t\treturn unqualified_check_get<T>(L, index, handler, tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\tauto handler = no_panic;\n\t\t\treturn unqualified_check_get<T>(L, index, handler);\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tdecltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) {\n\t\t\t\treturn sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tqualified_check_getter<T> cg {};\n\t\t\t\t(void)cg;\n\t\t\t\treturn cg.get(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename Handler>\n\t\tdecltype(auto) check_get(lua_State* L, int index, Handler&& handler) {\n\t\t\trecord tracking {};\n\t\t\treturn check_get<T>(L, index, handler, tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\tauto handler = no_panic;\n\t\t\treturn check_get<T>(L, index, handler);\n\t\t}\n\n\t\tnamespace stack_detail {\n\n\t\t\ttemplate <typename Handler>\n\t\t\tbool check_types(lua_State*, int, Handler&&, record&) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttemplate <typename T, typename... Args, typename Handler>\n\t\t\tbool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) {\n\t\t\t\tif (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))\n\t\t\t\t\treturn false;\n\t\t\t\treturn check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\n\t\t\ttemplate <typename... Args, typename Handler>\n\t\t\tbool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\t\treturn check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\n\t\t} // namespace stack_detail\n\n\t\ttemplate <typename... Args, typename Handler>\n\t\tbool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn stack_detail::check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename... Args, typename Handler>\n\t\tbool multi_check(lua_State* L, int index, Handler&& handler) {\n\t\t\trecord tracking {};\n\t\t\treturn multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tbool multi_check(lua_State* L, int index) {\n\t\t\treturn multi_check<Args...>(L, index);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tauto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get<T>(L, index, tracking)) {\n#if SOL_IS_ON(SOL_SAFE_GETTER_I_)\n\t\t\tstatic constexpr bool is_op = meta::is_optional_v<T>;\n\t\t\tif constexpr (is_op) {\n\t\t\t\treturn stack_detail::unchecked_unqualified_get<T>(L, index, tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (is_lua_reference<T>::value) {\n\t\t\t\t\treturn stack_detail::unchecked_unqualified_get<T>(L, index, tracking);\n\t\t\t\t}\n\t\t\t\tauto op = unqualified_check_get<T>(L, index, type_panic_c_str, tracking);\n\t\t\t\treturn *std::move(op);\n\t\t\t}\n#else\n\t\t\treturn stack_detail::unchecked_unqualified_get<T>(L, index, tracking);\n#endif\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) unqualified_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\trecord tracking {};\n\t\t\treturn unqualified_get<T>(L, index, tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tauto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {\n#if SOL_IS_ON(SOL_SAFE_GETTER_I_)\n\t\t\tstatic constexpr bool is_op = meta::is_optional_v<T>;\n\t\t\tif constexpr (is_op) {\n\t\t\t\treturn stack_detail::unchecked_get<T>(L, index, tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (is_lua_reference<T>::value) {\n\t\t\t\t\treturn stack_detail::unchecked_get<T>(L, index, tracking);\n\t\t\t\t}\n\t\t\t\tauto op = check_get<T>(L, index, type_panic_c_str, tracking);\n\t\t\t\treturn *std::move(op);\n\t\t\t}\n#else\n\t\t\treturn stack_detail::unchecked_get<T>(L, index, tracking);\n#endif\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\trecord tracking {};\n\t\t\treturn get<T>(L, index, tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_usertype(lua_State* L, int index, record& tracking) {\n\t\t\tusing UT = meta::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>;\n\t\t\treturn get<UT>(L, index, tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {\n\t\t\trecord tracking {};\n\t\t\treturn get_usertype<T>(L, index, tracking);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) pop(lua_State* L) {\n\t\t\treturn popper<meta::unqualified_t<T>> {}.pop(L);\n\t\t}\n\n\t\ttemplate <bool global = false, bool raw = false, typename Key>\n\t\tvoid get_field(lua_State* L, Key&& key) {\n\t\t\tfield_getter<meta::unqualified_t<Key>, global, raw> {}.get(L, std::forward<Key>(key));\n\t\t}\n\n\t\ttemplate <bool global = false, bool raw = false, typename Key>\n\t\tvoid get_field(lua_State* L, Key&& key, int tableindex) {\n\t\t\tfield_getter<meta::unqualified_t<Key>, global, raw> {}.get(L, std::forward<Key>(key), tableindex);\n\t\t}\n\n\t\ttemplate <bool global = false, typename Key>\n\t\tvoid raw_get_field(lua_State* L, Key&& key) {\n\t\t\tget_field<global, true>(L, std::forward<Key>(key));\n\t\t}\n\n\t\ttemplate <bool global = false, typename Key>\n\t\tvoid raw_get_field(lua_State* L, Key&& key, int tableindex) {\n\t\t\tget_field<global, true>(L, std::forward<Key>(key), tableindex);\n\t\t}\n\n\t\ttemplate <bool global = false, bool raw = false, typename C = detail::non_lua_nil_t, typename Key>\n\t\tprobe probe_get_field(lua_State* L, Key&& key) {\n\t\t\treturn probe_field_getter<meta::unqualified_t<Key>, C, global, raw> {}.get(L, std::forward<Key>(key));\n\t\t}\n\n\t\ttemplate <bool global = false, bool raw = false, typename C = detail::non_lua_nil_t, typename Key>\n\t\tprobe probe_get_field(lua_State* L, Key&& key, int tableindex) {\n\t\t\treturn probe_field_getter<meta::unqualified_t<Key>, C, global, raw> {}.get(L, std::forward<Key>(key), tableindex);\n\t\t}\n\n\t\ttemplate <bool global = false, typename C = detail::non_lua_nil_t, typename Key>\n\t\tprobe probe_raw_get_field(lua_State* L, Key&& key) {\n\t\t\treturn probe_get_field<global, true, C>(L, std::forward<Key>(key));\n\t\t}\n\n\t\ttemplate <bool global = false, typename C = detail::non_lua_nil_t, typename Key>\n\t\tprobe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) {\n\t\t\treturn probe_get_field<global, true, C>(L, std::forward<Key>(key), tableindex);\n\t\t}\n\n\t\ttemplate <bool global = false, bool raw = false, typename Key, typename Value>\n\t\tvoid set_field(lua_State* L, Key&& key, Value&& value) {\n\t\t\tfield_setter<meta::unqualified_t<Key>, global, raw> {}.set(L, std::forward<Key>(key), std::forward<Value>(value));\n\t\t}\n\n\t\ttemplate <bool global = false, bool raw = false, typename Key, typename Value>\n\t\tvoid set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {\n\t\t\tfield_setter<meta::unqualified_t<Key>, global, raw> {}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);\n\t\t}\n\n\t\ttemplate <bool global = false, typename Key, typename Value>\n\t\tvoid raw_set_field(lua_State* L, Key&& key, Value&& value) {\n\t\t\tset_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value));\n\t\t}\n\n\t\ttemplate <bool global = false, typename Key, typename Value>\n\t\tvoid raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {\n\t\t\tset_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);\n\t\t}\n\n\t\ttemplate <typename T, typename F>\n\t\tvoid modify_unique_usertype_as(const stack_reference& obj, F&& f) {\n\t\t\tusing u_traits = unique_usertype_traits<T>;\n\t\t\tvoid* raw = lua_touserdata(obj.lua_state(), obj.stack_index());\n\t\t\tvoid* ptr_memory = detail::align_usertype_pointer(raw);\n\t\t\tvoid* uu_memory = detail::align_usertype_unique<T>(raw);\n\t\t\tT& uu = *static_cast<T*>(uu_memory);\n\t\t\tf(uu);\n\t\t\t*static_cast<void**>(ptr_memory) = static_cast<void*>(u_traits::get(uu));\n\t\t}\n\n\t\ttemplate <typename F>\n\t\tvoid modify_unique_usertype(const stack_reference& obj, F&& f) {\n\t\t\tusing bt = meta::bind_traits<meta::unqualified_t<F>>;\n\t\t\tusing T = typename bt::template arg_at<0>;\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tmodify_unique_usertype_as<Tu>(obj, std::forward<F>(f));\n\t\t}\n\n\t} // namespace stack\n\n\tnamespace detail {\n\n\t\ttemplate <typename T>\n\t\tlua_CFunction make_destructor(std::true_type) {\n\t\t\tif constexpr (is_unique_usertype_v<T>) {\n\t\t\t\treturn &unique_destruct<T>;\n\t\t\t}\n\t\t\telse if constexpr (!std::is_pointer_v<T>) {\n\t\t\t\treturn &usertype_alloc_destruct<T>;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn &cannot_destruct<T>;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tlua_CFunction make_destructor(std::false_type) {\n\t\t\treturn &cannot_destruct<T>;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tlua_CFunction make_destructor() {\n\t\t\treturn make_destructor<T>(std::is_destructible<T>());\n\t\t}\n\n\t\tstruct no_comp {\n\t\t\ttemplate <typename A, typename B>\n\t\t\tbool operator()(A&&, B&&) const {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tint is_check(lua_State* L) {\n\t\t\treturn stack::push(L, stack::check<T>(L, 1, &no_panic));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint member_default_to_string(std::true_type, lua_State* L) {\n\t\t\tdecltype(auto) ts = stack::get<T>(L, 1).to_string();\n\t\t\treturn stack::push(L, std::forward<decltype(ts)>(ts));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint member_default_to_string(std::false_type, lua_State* L) {\n\t\t\treturn luaL_error(L,\n\t\t\t     \"cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member \"\n\t\t\t     \"function, or operator<<(ostream&, ...) present\",\n\t\t\t     detail::demangle<T>().data());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint adl_default_to_string(std::true_type, lua_State* L) {\n\t\t\tusing namespace std;\n\t\t\tdecltype(auto) ts = to_string(stack::get<T>(L, 1));\n\t\t\treturn stack::push(L, std::forward<decltype(ts)>(ts));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint adl_default_to_string(std::false_type, lua_State* L) {\n\t\t\treturn member_default_to_string<T>(meta::supports_to_string_member<T>(), L);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint oss_default_to_string(std::true_type, lua_State* L) {\n\t\t\tstd::ostringstream oss;\n\t\t\toss << stack::unqualified_get<T>(L, 1);\n\t\t\treturn stack::push(L, oss.str());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint oss_default_to_string(std::false_type, lua_State* L) {\n\t\t\treturn adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint default_to_string(lua_State* L) {\n\t\t\treturn oss_default_to_string<T>(meta::supports_op_left_shift<std::ostream, T>(), L);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint default_size(lua_State* L) {\n\t\t\tdecltype(auto) self = stack::unqualified_get<T>(L, 1);\n\t\t\treturn stack::push(L, self.size());\n\t\t}\n\n\t\ttemplate <typename T, typename Op>\n\t\tint comparsion_operator_wrap(lua_State* L) {\n\t\t\tif constexpr (std::is_void_v<T>) {\n\t\t\t\treturn stack::push(L, false);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto maybel = stack::unqualified_check_get<T>(L, 1);\n\t\t\t\tif (!maybel) {\n\t\t\t\t\treturn stack::push(L, false);\n\t\t\t\t}\n\t\t\t\tauto mayber = stack::unqualified_check_get<T>(L, 2);\n\t\t\t\tif (!mayber) {\n\t\t\t\t\treturn stack::push(L, false);\n\t\t\t\t}\n\t\t\t\tdecltype(auto) l = *maybel;\n\t\t\t\tdecltype(auto) r = *mayber;\n\t\t\t\tif constexpr (std::is_same_v<no_comp, Op>) {\n\t\t\t\t\tstd::equal_to<> op;\n\t\t\t\t\treturn stack::push(L, op(detail::ptr(l), detail::ptr(r)));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr (std::is_same_v<std::equal_to<>, Op> // clang-format hack\n\t\t\t\t\t     || std::is_same_v<std::less_equal<>, Op>     //\n\t\t\t\t\t     || std::is_same_v<std::less_equal<>, Op>) {  //\n\t\t\t\t\t\tif (detail::ptr(l) == detail::ptr(r)) {\n\t\t\t\t\t\t\treturn stack::push(L, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tOp op;\n\t\t\t\t\treturn stack::push(L, op(detail::deref(l), detail::deref(r)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename IFx, typename Fx>\n\t\tvoid insert_default_registrations(IFx&& ifx, Fx&& fx);\n\n\t\ttemplate <typename T, bool, bool>\n\t\tstruct get_is_primitive : is_lua_primitive<T> { };\n\n\t\ttemplate <typename T>\n\t\tstruct get_is_primitive<T, true, false>\n\t\t: meta::neg<std::is_reference<decltype(sol_lua_get(types<T>(), nullptr, -1, std::declval<stack::record&>()))>> { };\n\n\t\ttemplate <typename T>\n\t\tstruct get_is_primitive<T, false, true>\n\t\t: meta::neg<std::is_reference<decltype(sol_lua_get(types<meta::unqualified_t<T>>(), nullptr, -1, std::declval<stack::record&>()))>> { };\n\n\t\ttemplate <typename T>\n\t\tstruct get_is_primitive<T, true, true> : get_is_primitive<T, true, false> { };\n\n\t} // namespace detail\n\n\ttemplate <typename T>\n\tstruct is_proxy_primitive\n\t: detail::get_is_primitive<T, meta::meta_detail::is_adl_sol_lua_get_v<T>, meta::meta_detail::is_adl_sol_lua_get_v<meta::unqualified_t<T>>> { };\n\n} // namespace sol\n\n// end of sol/stack_core.hpp\n\n// beginning of sol/stack_check.hpp\n\n// beginning of sol/stack_check_unqualified.hpp\n\n#include <memory>\n#include <functional>\n#include <utility>\n#include <cmath>\n#include <optional>\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n#include <variant>\n#endif // variant shenanigans\n\nnamespace sol { namespace stack {\n\tnamespace stack_detail {\n\t\tinline bool impl_check_metatable(lua_State* L, int index, const std::string& metakey, bool poptable) {\n\t\t\tluaL_getmetatable(L, &metakey[0]);\n\t\t\tconst type expectedmetatabletype = static_cast<type>(lua_type(L, -1));\n\t\t\tif (expectedmetatabletype != type::lua_nil) {\n\t\t\t\tif (lua_rawequal(L, -1, index) == 1) {\n\t\t\t\t\tlua_pop(L, 1 + static_cast<int>(poptable));\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlua_pop(L, 1);\n\t\t\treturn false;\n\t\t}\n\n\t\ttemplate <typename T, bool poptable = true>\n\t\tinline bool check_metatable(lua_State* L, int index = -2) {\n\t\t\treturn impl_check_metatable(L, index, usertype_traits<T>::metatable(), poptable);\n\t\t}\n\n\t\ttemplate <type expected, int (*check_func)(lua_State*, int)>\n\t\tstruct basic_check {\n\t\t\ttemplate <typename Handler>\n\t\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tbool success = check_func(L, index) == 1;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, expected, type_of(L, index), \"\");\n\t\t\t\t}\n\t\t\t\treturn success;\n\t\t\t}\n\t\t};\n\t} // namespace stack_detail\n\n\ttemplate <typename T, typename>\n\tstruct unqualified_interop_checker {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State*, int, type, Handler&&, record&) {\n\t\t\treturn false;\n\t\t}\n\t};\n\n\ttemplate <typename T, typename>\n\tstruct qualified_interop_checker {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) {\n\t\t\treturn stack_detail::unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T, type expected, typename>\n\tstruct unqualified_checker {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (std::is_same_v<T, bool>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tbool success = lua_isboolean(L, index) == 1;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, expected, type_of(L, index), \"\");\n\t\t\t\t}\n\t\t\t\treturn success;\n\t\t\t}\n\t\t\telse if constexpr (meta::any_same_v<T, char /* , char8_t*/, char16_t, char32_t>) {\n\t\t\t\treturn stack::check<std::basic_string<T>>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) {\n\t\t\t\ttracking.use(1);\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\t// Lua 5.3 and greater checks for numeric precision\n#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_)\n\t\t\t\t// imprecise, sloppy conversions\n\t\t\t\tint isnum = 0;\n\t\t\t\tlua_tointegerx(L, index, &isnum);\n\t\t\t\tconst bool success = isnum != 0;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string_integral);\n\t\t\t\t}\n#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)\n\t\t\t\t// this check is precise, do not convert\n\t\t\t\tif (lua_isinteger(L, index) == 1) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tconst bool success = false;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::number, type_of(L, index), detail::not_a_number_integral);\n\t\t\t\t}\n#else\n\t\t\t\t// Numerics are neither safe nor string-convertible\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tconst bool success = t == type::number;\n#endif\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::number, type_of(L, index), detail::not_a_number);\n\t\t\t\t}\n\t\t\t\treturn success;\n#else\n\t\t\t\t// Lua 5.2 and below checks\n#if SOL_IS_OFF(SOL_STRINGS_ARE_NUMBERS_I_)\n\t\t\t\t// must pre-check, because it will convert\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t != type::number) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::number, t, detail::not_a_number);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n#endif // Do not allow strings to be numbers\n\n#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)\n\t\t\t\tint isnum = 0;\n\t\t\t\tconst lua_Number v = lua_tonumberx(L, index, &isnum);\n\t\t\t\tconst bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;\n#else\n\t\t\t\tconst bool success = true;\n#endif // Safe numerics and number precision checking\n\t\t\t\tif (!success) {\n\t\t\t\t\t// Use defines to provide a better error message!\n#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_)\n\t\t\t\t\thandler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string);\n#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)\n\t\t\t\t\thandler(L, index, type::number, t, detail::not_a_number_or_number_string);\n#else\n\t\t\t\t\thandler(L, index, type::number, t, detail::not_a_number);\n#endif\n\t\t\t\t}\n\t\t\t\treturn success;\n#endif\n\t\t\t}\n\t\t\telse if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) {\n\t\t\t\ttracking.use(1);\n#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_)\n\t\t\t\tbool success = lua_isnumber(L, index) == 1;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string);\n\t\t\t\t}\n\t\t\t\treturn success;\n#else\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tbool success = t == type::number;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::number, t, detail::not_a_number);\n\t\t\t\t}\n\t\t\t\treturn success;\n#endif // Strings are Numbers\n\t\t\t}\n\t\t\telse if constexpr (meta::any_same_v<T, type, this_state, this_main_state, this_environment, variadic_args>) {\n\t\t\t\t(void)L;\n\t\t\t\t(void)index;\n\t\t\t\t(void)handler;\n\t\t\t\ttracking.use(0);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (is_unique_usertype_v<T>) {\n\t\t\t\tusing proper_T = typename unique_usertype_traits<T>::type;\n\t\t\t\tconst type indextype = type_of(L, index);\n\t\t\t\ttracking.use(1);\n\t\t\t\tif (indextype != type::userdata) {\n\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value is not a userdata\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tint metatableindex = lua_gettop(L);\n\t\t\t\tif (stack_detail::check_metatable<detail::unique_usertype<proper_T>>(L, metatableindex)) {\n\t\t\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\t\t\tmemory = detail::align_usertype_unique_destructor(memory);\n\t\t\t\t\tdetail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);\n\t\t\t\t\tbool success = &detail::usertype_unique_alloc_destroy<proper_T, T> == pdx;\n\t\t\t\t\tif (!success) {\n\t\t\t\t\t\tmemory = detail::align_usertype_unique_tag<true>(memory);\n#if 0\n\t\t\t\t\t\t// New version\n#else\n\t\t\t\t\t\tconst char*& name_tag = *static_cast<const char**>(memory);\n\t\t\t\t\t\tsuccess = usertype_traits<T>::qualified_name() == name_tag;\n#endif\n\t\t\t\t\t\tif (!success) {\n\t\t\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value is a userdata but is not the correct unique usertype\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn success;\n\t\t\t\t}\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\thandler(L, index, type::userdata, indextype, \"unrecognized userdata (not pushed by sol?)\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if constexpr (meta::any_same_v<T, lua_nil_t, std::nullopt_t, nullopt_t>) {\n\t\t\t\tbool success = lua_isnil(L, index);\n\t\t\t\tif (success) {\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\treturn success;\n\t\t\t\t}\n\t\t\t\ttracking.use(0);\n\t\t\t\tsuccess = lua_isnone(L, index);\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, expected, type_of(L, index), \"\");\n\t\t\t\t}\n\t\t\t\treturn success;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, env_key_t>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\thandler(L, index, type::table, t, \"value cannot not have a valid environment\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) {\n\t\t\t\treturn !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse if constexpr (meta::is_specialization_of_v<T, basic_lua_table>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t != type::table) {\n\t\t\t\t\thandler(L, index, type::table, t, \"value is not a table\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (meta::is_specialization_of_v<T, basic_bytecode>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t != type::function) {\n\t\t\t\t\thandler(L, index, type::function, t, \"value is not a function that can be dumped\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (meta::is_specialization_of_v<T, basic_environment>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\ttype t = type_of(L, -1);\n\t\t\t\tif (t == type::table || t == type::none || t == type::lua_nil) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (t != type::userdata) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\thandler(L, index, type::table, t, \"value does not have a valid metatable\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, metatable_key_t>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\ttype t = type_of(L, -1);\n\t\t\t\tif (t == type::table || t == type::none || t == type::lua_nil) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (t != type::userdata) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\thandler(L, index, expected, t, \"value does not have a valid metatable\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, luaL_Stream*> || std::is_same_v<T, luaL_Stream>) {\n\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\thandler(L, index, expected, t, \"value is not a valid luaL_Stream (has no metatable/is not a valid value)\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tluaL_getmetatable(L, LUA_FILEHANDLE);\n\t\t\t\tif (type_of(L, index) != type::table) {\n\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\thandler(L,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\texpected,\n\t\t\t\t\t\tt,\n\t\t\t\t\t\t\"value is not a valid luaL_Stream (there is no metatable for luaL_Stream -- did you forget to \"\n\t\t\t\t\t\t\"my_lua_state.open_libraries(sol::lib::state) or equivalent?)\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tint is_stream_table = lua_compare(L, -1, -2, LUA_OPEQ);\n\t\t\t\tlua_pop(L, 2);\n\t\t\t\tif (is_stream_table == 0) {\n\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\thandler(L, index, expected, t, \"value is not a valid luaL_Stream (incorrect metatable)\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if constexpr (meta::is_optional_v<T>) {\n\t\t\t\tusing ValueType = typename T::value_type;\n\t\t\t\t(void)handler;\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t == type::none) {\n\t\t\t\t\ttracking.use(0);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (t == type::lua_nil) {\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn stack::unqualified_check<ValueType>(L, index, no_panic, tracking);\n\t\t\t}\n#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\t\telse if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) {\n\t\t\t\treturn stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n#endif\n\t\t\telse if constexpr (expected == type::userdata) {\n\t\t\t\tif constexpr (meta::any_same_v<T, userdata_value> || meta::is_specialization_of_v<T, basic_userdata>) {\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\tbool success = t == type::userdata;\n\t\t\t\t\tif (!success) {\n\t\t\t\t\t\t// expected type, actual type\n\t\t\t\t\t\thandler(L, index, type::userdata, t, \"\");\n\t\t\t\t\t}\n\t\t\t\t\treturn success;\n\t\t\t\t}\n\t\t\t\telse if constexpr (meta::is_specialization_of_v<T, user>) {\n\t\t\t\t\tunqualified_checker<lightuserdata_value, type::userdata> c;\n\t\t\t\t\t(void)c;\n\t\t\t\t\treturn c.check(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr (std::is_pointer_v<T>) {\n\t\t\t\t\t\treturn check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t\t}\n\t\t\t\t\telse if constexpr (meta::is_specialization_of_v<T, std::reference_wrapper>) {\n\t\t\t\t\t\tusing T_internal = typename T::type;\n\t\t\t\t\t\treturn stack::check<T_internal>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr (expected == type::poly) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tbool success = is_lua_reference_v<T> || !lua_isnone(L, index);\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::poly, type_of(L, index), \"\");\n\t\t\t\t}\n\t\t\t\treturn success;\n\t\t\t}\n\t\t\telse if constexpr (expected == type::lightuserdata) {\n\t\t\t\ttracking.use(1);\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tbool success = t == type::userdata || t == type::lightuserdata;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(L, index, type::lightuserdata, t, \"\");\n\t\t\t\t}\n\t\t\t\treturn success;\n\t\t\t}\n\t\t\telse if constexpr (expected == type::function) {\n\t\t\t\tif constexpr (meta::any_same_v<T, lua_CFunction, std::remove_pointer_t<lua_CFunction>, c_closure>) {\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\tbool success = lua_iscfunction(L, index) == 1;\n\t\t\t\t\tif (!success) {\n\t\t\t\t\t\t// expected type, actual type\n\t\t\t\t\t\thandler(L, index, expected, type_of(L, index), \"\");\n\t\t\t\t\t}\n\t\t\t\t\treturn success;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\tif (t == type::lua_nil || t == type::none || t == type::function) {\n\t\t\t\t\t\t// allow for lua_nil to be returned\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tif (t != type::userdata && t != type::table) {\n\t\t\t\t\t\thandler(L, index, type::function, t, \"must be a function or table or a userdata\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Do advanced check for call-style userdata?\n\t\t\t\t\tstatic const auto& callkey = to_string(meta_function::call);\n\t\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\t\t// No metatable, no __call key possible\n\t\t\t\t\t\thandler(L, index, type::function, t, \"value is not a function and does not have overriden metatable\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (lua_isnoneornil(L, -1)) {\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\thandler(L, index, type::function, t, \"value is not a function and does not have valid metatable\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tlua_getfield(L, -1, &callkey[0]);\n\t\t\t\t\tif (lua_isnoneornil(L, -1)) {\n\t\t\t\t\t\tlua_pop(L, 2);\n\t\t\t\t\t\thandler(L, index, type::function, t, \"value's metatable does not have __call overridden in metatable, cannot call this type\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// has call, is definitely a function\n\t\t\t\t\tlua_pop(L, 2);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr (expected == type::table) {\n\t\t\t\ttracking.use(1);\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t == type::table) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (t != type::userdata) {\n\t\t\t\t\thandler(L, index, type::table, t, \"value is not a table or a userdata that can behave like one\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttracking.use(1);\n\t\t\t\tconst type indextype = type_of(L, index);\n\t\t\t\tbool success = expected == indextype;\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type, message\n\t\t\t\t\thandler(L, index, expected, indextype, \"\");\n\t\t\t\t}\n\t\t\t\treturn success;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_checker<non_null<T>, type::userdata> : unqualified_checker<T, lua_type_of_v<T>> { };\n\n\ttemplate <typename T>\n\tstruct unqualified_checker<detail::as_value_tag<T>, type::userdata> {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tconst type indextype = type_of(L, index);\n\t\t\treturn check(types<T>(), L, index, indextype, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename U, typename Handler>\n\t\tstatic bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (\n\t\t\t\tstd::is_same_v<T,\n\t\t\t\t     lightuserdata_value> || std::is_same_v<T, userdata_value> || std::is_same_v<T, userdata> || std::is_same_v<T, lightuserdata>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tif (indextype != type::userdata) {\n\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value is not a valid userdata\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n#if SOL_IS_ON(SOL_USE_INTEROP_I_)\n\t\t\t\tif (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n#endif // interop extensibility\n\t\t\t\ttracking.use(1);\n\t\t\t\tif (indextype != type::userdata) {\n\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value is not a valid userdata\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tint metatableindex = lua_gettop(L);\n\t\t\t\tif (stack_detail::check_metatable<U>(L, metatableindex))\n\t\t\t\t\treturn true;\n\t\t\t\tif (stack_detail::check_metatable<U*>(L, metatableindex))\n\t\t\t\t\treturn true;\n\t\t\t\tif (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))\n\t\t\t\t\treturn true;\n\t\t\t\tif (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))\n\t\t\t\t\treturn true;\n\t\t\t\tbool success = false;\n\t\t\t\tbool has_derived = derive<T>::value || weak_derive<T>::value;\n\t\t\t\tif (has_derived) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_string);\n#endif // make sure stack doesn't overflow\n\t\t\t\t\tauto pn = stack::pop_n(L, 1);\n\t\t\t\t\tlua_pushstring(L, &detail::base_class_check_key()[0]);\n\t\t\t\t\tlua_rawget(L, metatableindex);\n\t\t\t\t\tif (type_of(L, -1) != type::lua_nil) {\n\t\t\t\t\t\tvoid* basecastdata = lua_touserdata(L, -1);\n\t\t\t\t\t\tdetail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata);\n\t\t\t\t\t\tsuccess = ic(usertype_traits<T>::qualified_name());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\tif (!success) {\n\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value at this index does not properly reflect the desired type\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_checker<detail::as_pointer_tag<T>, type::userdata> {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {\n\t\t\tif (indextype == type::lua_nil) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn check_usertype<std::remove_pointer_t<T>>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tconst type indextype = type_of(L, index);\n\t\t\treturn check(L, index, indextype, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n\n\ttemplate <typename... Args>\n\tstruct unqualified_checker<std::tuple<Args...>, type::poly> {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n\n\ttemplate <typename A, typename B>\n\tstruct unqualified_checker<std::pair<A, B>, type::poly> {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n\n\ttemplate <typename... Tn>\n\tstruct unqualified_checker<std::variant<Tn...>, type::poly> {\n\t\ttypedef std::variant<Tn...> V;\n\t\ttypedef std::variant_size<V> V_size;\n\t\ttypedef std::integral_constant<bool, V_size::value == 0> V_is_empty;\n\n\t\ttemplate <typename Handler>\n\t\tstatic bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (V_is_empty::value) {\n\t\t\t\tif (lua_isnone(L, index)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttracking.use(1);\n\t\t\thandler(L, index, type::poly, type_of(L, index), \"value does not fit any type present in the variant\");\n\t\t\treturn false;\n\t\t}\n\n\t\ttemplate <std::size_t I, typename Handler>\n\t\tstatic bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\ttypedef std::variant_alternative_t<I - 1, V> T;\n\t\t\trecord temp_tracking = tracking;\n\t\t\tif (stack::check<T>(L, index, no_panic, temp_tracking)) {\n\t\t\t\ttracking = temp_tracking;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n\n#endif // variant shenanigans\n\n}} // namespace sol::stack\n\n// end of sol/stack_check_unqualified.hpp\n\n// beginning of sol/stack_check_qualified.hpp\n\nnamespace sol {\nnamespace stack {\n\n\ttemplate <typename X, type expected, typename>\n\tstruct qualified_checker {\n\t\ttemplate <typename Handler>\n\t\tstatic bool check(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (!std::is_reference_v<X> && is_unique_usertype_v<X>) {\n\t\t\t\tusing u_traits = unique_usertype_traits<meta::unqualified_t<X>>;\n\t\t\t\tusing T = typename u_traits::type;\n\t\t\t\tif constexpr (is_base_rebindable_non_void_v<u_traits>) {\n\t\t\t\t\tusing rebind_t = typename u_traits::template rebind_base<void>;\n\t\t\t\t\t// we have a unique pointer type that can be\n\t\t\t\t\t// rebound to a base/derived type\n\t\t\t\t\tconst type indextype = type_of(L, index);\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\tif (indextype != type::userdata) {\n\t\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value is not a userdata\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\t\t\tmemory = detail::align_usertype_unique_destructor(memory);\n\t\t\t\t\tdetail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);\n\t\t\t\t\tif (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tif constexpr (derive<T>::value) {\n\t\t\t\t\t\tmemory = detail::align_usertype_unique_tag<true, false>(memory);\n\t\t\t\t\t\tdetail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);\n\t\t\t\t\t\tstring_view ti = usertype_traits<T>::qualified_name();\n\t\t\t\t\t\tstring_view rebind_ti = usertype_traits<rebind_t>::qualified_name();\n\t\t\t\t\t\tif (ic(nullptr, nullptr, ti, rebind_ti) != 0) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\thandler(L, index, type::userdata, indextype, \"value is a userdata but is not the correct unique usertype\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr (!std::is_reference_v<X> && is_container_v<X>) {\n\t\t\t\tif (type_of(L, index) == type::userdata) {\n\t\t\t\t\treturn stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::unqualified_check<nested<X>>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr (!std::is_reference_v<X> && meta::is_specialization_of_v<X, nested>) {\n\t\t\t\tusing NestedX = typename meta::unqualified_t<X>::nested_type;\n\t\t\t\treturn stack::check<NestedX>(L, index, ::std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);\n\t\t\t}\n\t\t}\n\t};\n}\n} // namespace sol::stack\n\n// end of sol/stack_check_qualified.hpp\n\n// end of sol/stack_check.hpp\n\n// beginning of sol/stack_get.hpp\n\n// beginning of sol/stack_get_unqualified.hpp\n\n// beginning of sol/overload.hpp\n\n#include <utility>\n\nnamespace sol {\n\ttemplate <typename... Functions>\n\tstruct overload_set {\n\t\tstd::tuple<Functions...> functions;\n\t\ttemplate <typename Arg, typename... Args, meta::disable<std::is_same<overload_set, meta::unqualified_t<Arg>>> = meta::enabler>\n\t\toverload_set(Arg&& arg, Args&&... args)\n\t\t: functions(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t}\n\t\toverload_set(const overload_set&) = default;\n\t\toverload_set(overload_set&&) = default;\n\t\toverload_set& operator=(const overload_set&) = default;\n\t\toverload_set& operator=(overload_set&&) = default;\n\t};\n\n\ttemplate <typename... Args>\n\tdecltype(auto) overload(Args&&... args) {\n\t\treturn overload_set<std::decay_t<Args>...>(std::forward<Args>(args)...);\n\t}\n} // namespace sol\n\n// end of sol/overload.hpp\n\n// beginning of sol/unicode.hpp\n\n#include <array>\n#include <cstring>\n\nnamespace sol {\n\t// Everything here was lifted pretty much straight out of\n\t// ogonek, because fuck figuring it out=\n\tnamespace unicode {\n\t\tenum class error_code {\n\t\t\tok = 0,\n\t\t\tinvalid_code_point,\n\t\t\tinvalid_code_unit,\n\t\t\tinvalid_leading_surrogate,\n\t\t\tinvalid_trailing_surrogate,\n\t\t\tsequence_too_short,\n\t\t\toverlong_sequence,\n\t\t};\n\n\t\tinline const string_view& to_string(error_code ec) {\n\t\t\tstatic const string_view storage[7] = {\n\t\t\t\t\"ok\",\n\t\t\t\t\"invalid code points\",\n\t\t\t\t\"invalid code unit\",\n\t\t\t\t\"invalid leading surrogate\",\n\t\t\t\t\"invalid trailing surrogate\",\n\t\t\t\t\"sequence too short\",\n\t\t\t\t\"overlong sequence\"\n\t\t\t};\n\t\t\treturn storage[static_cast<std::size_t>(ec)];\n\t\t}\n\n\t\ttemplate <typename It>\n\t\tstruct decoded_result {\n\t\t\terror_code error;\n\t\t\tchar32_t codepoint;\n\t\t\tIt next;\n\t\t};\n\n\t\ttemplate <typename C>\n\t\tstruct encoded_result {\n\t\t\terror_code error;\n\t\t\tstd::size_t code_units_size;\n\t\t\tstd::array<C, 4> code_units;\n\t\t};\n\n\t\tstruct unicode_detail {\n\t\t\t// codepoint related\n\t\t\tstatic constexpr char32_t last_code_point = 0x10FFFF;\n\n\t\t\tstatic constexpr char32_t first_lead_surrogate = 0xD800;\n\t\t\tstatic constexpr char32_t last_lead_surrogate = 0xDBFF;\n\n\t\t\tstatic constexpr char32_t first_trail_surrogate = 0xDC00;\n\t\t\tstatic constexpr char32_t last_trail_surrogate = 0xDFFF;\n\n\t\t\tstatic constexpr char32_t first_surrogate = first_lead_surrogate;\n\t\t\tstatic constexpr char32_t last_surrogate = last_trail_surrogate;\n\n\t\t\tstatic constexpr bool is_lead_surrogate(char32_t u) {\n\t\t\t\treturn u >= first_lead_surrogate && u <= last_lead_surrogate;\n\t\t\t}\n\t\t\tstatic constexpr bool is_trail_surrogate(char32_t u) {\n\t\t\t\treturn u >= first_trail_surrogate && u <= last_trail_surrogate;\n\t\t\t}\n\t\t\tstatic constexpr bool is_surrogate(char32_t u) {\n\t\t\t\treturn u >= first_surrogate && u <= last_surrogate;\n\t\t\t}\n\n\t\t\t// utf8 related\n\t\t\tstatic constexpr auto last_1byte_value = 0x7Fu;\n\t\t\tstatic constexpr auto last_2byte_value = 0x7FFu;\n\t\t\tstatic constexpr auto last_3byte_value = 0xFFFFu;\n\n\t\t\tstatic constexpr auto start_2byte_mask = 0x80u;\n\t\t\tstatic constexpr auto start_3byte_mask = 0xE0u;\n\t\t\tstatic constexpr auto start_4byte_mask = 0xF0u;\n\n\t\t\tstatic constexpr auto continuation_mask = 0xC0u;\n\t\t\tstatic constexpr auto continuation_signature = 0x80u;\n\n\t\t\tstatic constexpr bool is_invalid(unsigned char b) {\n\t\t\t\treturn b == 0xC0 || b == 0xC1 || b > 0xF4;\n\t\t\t}\n\n\t\t\tstatic constexpr bool is_continuation(unsigned char b) {\n\t\t\t\treturn (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature;\n\t\t\t}\n\n\t\t\tstatic constexpr bool is_overlong(char32_t u, std::size_t bytes) {\n\t\t\t\treturn u <= unicode_detail::last_1byte_value || (u <= unicode_detail::last_2byte_value && bytes > 2)\n\t\t\t\t     || (u <= unicode_detail::last_3byte_value && bytes > 3);\n\t\t\t}\n\n\t\t\tstatic constexpr int sequence_length(unsigned char b) {\n\t\t\t\treturn (b & start_2byte_mask) == 0 ? 1\n\t\t\t\t\t: (b & start_3byte_mask) != start_3byte_mask ? 2\n\t\t\t\t\t: (b & start_4byte_mask) != start_4byte_mask ? 3\n\t\t\t\t\t: 4;\n\t\t\t}\n\n\t\t\tstatic constexpr char32_t decode(unsigned char b0, unsigned char b1) {\n\t\t\t\treturn ((b0 & 0x1F) << 6) | (b1 & 0x3F);\n\t\t\t}\n\t\t\tstatic constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2) {\n\t\t\t\treturn ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F);\n\t\t\t}\n\t\t\tstatic constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3) {\n\t\t\t\treturn ((b0 & 0x07) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F);\n\t\t\t}\n\n\t\t\t// utf16 related\n\t\t\tstatic constexpr char32_t last_bmp_value = 0xFFFF;\n\t\t\tstatic constexpr char32_t normalizing_value = 0x10000;\n\t\t\tstatic constexpr int lead_surrogate_bitmask = 0xFFC00;\n\t\t\tstatic constexpr int trail_surrogate_bitmask = 0x3FF;\n\t\t\tstatic constexpr int lead_shifted_bits = 10;\n\t\t\tstatic constexpr char32_t replacement = 0xFFFD;\n\n\t\t\tstatic char32_t combine_surrogates(char16_t lead, char16_t trail) {\n\t\t\t\tauto hi = lead - first_lead_surrogate;\n\t\t\t\tauto lo = trail - first_trail_surrogate;\n\t\t\t\treturn normalizing_value + ((hi << lead_shifted_bits) | lo);\n\t\t\t}\n\t\t};\n\n\t\tinline encoded_result<char> code_point_to_utf8(char32_t codepoint) {\n\t\t\tencoded_result<char> er;\n\t\t\ter.error = error_code::ok;\n\t\t\tif (codepoint <= unicode_detail::last_1byte_value) {\n\t\t\t\ter.code_units_size = 1;\n\t\t\t\ter.code_units = std::array<char, 4>{ { static_cast<char>(codepoint) } };\n\t\t\t}\n\t\t\telse if (codepoint <= unicode_detail::last_2byte_value) {\n\t\t\t\ter.code_units_size = 2;\n\t\t\t\ter.code_units = std::array<char, 4>{{\n\t\t\t\t\tstatic_cast<char>(0xC0 | ((codepoint & 0x7C0) >> 6)),\n\t\t\t\t\tstatic_cast<char>(0x80 | (codepoint & 0x3F)),\n\t\t\t\t}};\n\t\t\t}\n\t\t\telse if (codepoint <= unicode_detail::last_3byte_value) {\n\t\t\t\ter.code_units_size = 3;\n\t\t\t\ter.code_units = std::array<char, 4>{{\n\t\t\t\t\tstatic_cast<char>(0xE0 | ((codepoint & 0xF000) >> 12)),\n\t\t\t\t\tstatic_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)),\n\t\t\t\t\tstatic_cast<char>(0x80 | (codepoint & 0x3F)),\n\t\t\t\t}};\n\t\t\t}\n\t\t\telse {\n\t\t\t\ter.code_units_size = 4;\n\t\t\t\ter.code_units = std::array<char, 4>{ {\n\t\t\t\t\tstatic_cast<char>(0xF0 | ((codepoint & 0x1C0000) >> 18)),\n\t\t\t\t\t\tstatic_cast<char>(0x80 | ((codepoint & 0x3F000) >> 12)),\n\t\t\t\t\t\tstatic_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)),\n\t\t\t\t\t\tstatic_cast<char>(0x80 | (codepoint & 0x3F)),\n\t\t\t\t} };\n\t\t\t}\n\t\t\treturn er;\n\t\t}\n\n\t\tinline encoded_result<char16_t> code_point_to_utf16(char32_t codepoint) {\n\t\t\tencoded_result<char16_t> er;\n\n\t\t\tif (codepoint <= unicode_detail::last_bmp_value) {\n\t\t\t\ter.code_units_size = 1;\n\t\t\t\ter.code_units = std::array<char16_t, 4>{ { static_cast<char16_t>(codepoint) } };\n\t\t\t\ter.error = error_code::ok;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto normal = codepoint - unicode_detail::normalizing_value;\n\t\t\t\tauto lead = unicode_detail::first_lead_surrogate + ((normal & unicode_detail::lead_surrogate_bitmask) >> unicode_detail::lead_shifted_bits);\n\t\t\t\tauto trail = unicode_detail::first_trail_surrogate + (normal & unicode_detail::trail_surrogate_bitmask);\n\t\t\t\ter.code_units = std::array<char16_t, 4>{ {\n\t\t\t\t\tstatic_cast<char16_t>(lead),\n\t\t\t\t\tstatic_cast<char16_t>(trail)\n\t\t\t\t} };\n\t\t\t\ter.code_units_size = 2;\n\t\t\t\ter.error = error_code::ok;\n\t\t\t}\n\t\t\treturn er;\n\t\t}\n\n\t\tinline encoded_result<char32_t> code_point_to_utf32(char32_t codepoint) {\n\t\t\tencoded_result<char32_t> er;\n\t\t\ter.code_units_size = 1;\n\t\t\ter.code_units[0] = codepoint;\n\t\t\ter.error = error_code::ok;\n\t\t\treturn er;\n\t\t}\n\n\t\ttemplate <typename It>\n\t\tinline decoded_result<It> utf8_to_code_point(It it, It last) {\n\t\t\tdecoded_result<It> dr;\n\t\t\tif (it == last) {\n\t\t\t\tdr.next = it;\n\t\t\t\tdr.error = error_code::sequence_too_short;\n\t\t\t\treturn dr;\n\t\t\t}\n\n\t\t\tunsigned char b0 = *it;\n\t\t\tstd::size_t length = unicode_detail::sequence_length(b0);\n\n\t\t\tif (length == 1) {\n\t\t\t\tdr.codepoint = static_cast<char32_t>(b0);\n\t\t\t\tdr.error = error_code::ok;\n\t\t\t\t++it;\n\t\t\t\tdr.next = it;\n\t\t\t\treturn dr;\n\t\t\t}\n\n\t\t\tif (unicode_detail::is_invalid(b0) || unicode_detail::is_continuation(b0)) {\n\t\t\t\tdr.error = error_code::invalid_code_unit;\n\t\t\t\tdr.next = it;\n\t\t\t\treturn dr;\n\t\t\t}\n\n\t\t\t++it;\n\t\t\tstd::array<unsigned char, 4> b;\n\t\t\tb[0] = b0;\n\t\t\tfor (std::size_t i = 1; i < length; ++i) {\n\t\t\t\tb[i] = *it;\n\t\t\t\tif (!unicode_detail::is_continuation(b[i])) {\n\t\t\t\t\tdr.error = error_code::invalid_code_unit;\n\t\t\t\t\tdr.next = it;\n\t\t\t\t\treturn dr;\n\t\t\t\t}\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tchar32_t decoded;\n\t\t\tswitch (length) {\n\t\t\tcase 2:\n\t\t\t\tdecoded = unicode_detail::decode(b[0], b[1]);\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tdecoded = unicode_detail::decode(b[0], b[1], b[2]);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tdecoded = unicode_detail::decode(b[0], b[1], b[2], b[3]);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (unicode_detail::is_overlong(decoded, length)) {\n\t\t\t\tdr.error = error_code::overlong_sequence;\n\t\t\t\treturn dr;\n\t\t\t}\n\t\t\tif (unicode_detail::is_surrogate(decoded) || decoded > unicode_detail::last_code_point) {\n\t\t\t\tdr.error = error_code::invalid_code_point;\n\t\t\t\treturn dr;\n\t\t\t}\n\t\t\t\n\t\t\t// then everything is fine\n\t\t\tdr.codepoint = decoded;\n\t\t\tdr.error = error_code::ok;\n\t\t\tdr.next = it;\n\t\t\treturn dr;\n\t\t}\n\n\t\ttemplate <typename It>\n\t\tinline decoded_result<It> utf16_to_code_point(It it, It last) {\n\t\t\tdecoded_result<It> dr;\n\t\t\tif (it == last) {\n\t\t\t\tdr.next = it;\n\t\t\t\tdr.error = error_code::sequence_too_short;\n\t\t\t\treturn dr;\n\t\t\t}\n\n\t\t\tchar16_t lead = static_cast<char16_t>(*it);\n\t\t\t\n\t\t\tif (!unicode_detail::is_surrogate(lead)) {\n\t\t\t\t++it;\n\t\t\t\tdr.codepoint = static_cast<char32_t>(lead);\n\t\t\t\tdr.next = it;\n\t\t\t\tdr.error = error_code::ok;\n\t\t\t\treturn dr;\n\t\t\t}\n\t\t\tif (!unicode_detail::is_lead_surrogate(lead)) {\n\t\t\t\tdr.error = error_code::invalid_leading_surrogate;\n\t\t\t\tdr.next = it;\n\t\t\t\treturn dr;\n\t\t\t}\n\n\t\t\t++it;\n\t\t\tauto trail = *it;\n\t\t\tif (!unicode_detail::is_trail_surrogate(trail)) {\n\t\t\t\tdr.error = error_code::invalid_trailing_surrogate;\n\t\t\t\tdr.next = it;\n\t\t\t\treturn dr;\n\t\t\t}\n\t\t\t\n\t\t\tdr.codepoint = unicode_detail::combine_surrogates(lead, trail);\n\t\t\tdr.next = ++it;\n\t\t\tdr.error = error_code::ok;\n\t\t\treturn dr;\n\t\t}\n\n\t\ttemplate <typename It>\n\t\tinline decoded_result<It> utf32_to_code_point(It it, It last) {\n\t\t\tdecoded_result<It> dr;\n\t\t\tif (it == last) {\n\t\t\t\tdr.next = it;\n\t\t\t\tdr.error = error_code::sequence_too_short;\n\t\t\t\treturn dr;\n\t\t\t}\n\t\t\tdr.codepoint = static_cast<char32_t>(*it);\n\t\t\tdr.next = ++it;\n\t\t\tdr.error = error_code::ok;\n\t\t\treturn dr;\n\t\t}\n\t}\n}\n// end of sol/unicode.hpp\n\n#include <memory>\n#include <functional>\n#include <utility>\n#include <cstdlib>\n#include <cmath>\n#include <string_view>\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n#include <variant>\n#endif // Apple clang screwed up\n\nnamespace sol { namespace stack {\n\n\tnamespace stack_detail {\n\t\ttemplate <typename Ch>\n\t\tstruct count_code_units_utf {\n\t\t\tstd::size_t needed_size;\n\n\t\t\tcount_code_units_utf() : needed_size(0) {\n\t\t\t}\n\n\t\t\tvoid operator()(const unicode::encoded_result<Ch> er) {\n\t\t\t\tneeded_size += er.code_units_size;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Ch, typename ErCh>\n\t\tstruct copy_code_units_utf {\n\t\t\tCh* target_;\n\n\t\t\tcopy_code_units_utf(Ch* target) : target_(target) {\n\t\t\t}\n\n\t\t\tvoid operator()(const unicode::encoded_result<ErCh> er) {\n\t\t\t\tstd::memcpy(target_, er.code_units.data(), er.code_units_size * sizeof(ErCh));\n\t\t\t\ttarget_ += er.code_units_size;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Ch, typename F>\n\t\tinline void convert(const char* strb, const char* stre, F&& f) {\n\t\t\tchar32_t cp = 0;\n\t\t\tfor (const char* strtarget = strb; strtarget < stre;) {\n\t\t\t\tauto dr = unicode::utf8_to_code_point(strtarget, stre);\n\t\t\t\tif (dr.error != unicode::error_code::ok) {\n\t\t\t\t\tcp = unicode::unicode_detail::replacement;\n\t\t\t\t\t++strtarget;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcp = dr.codepoint;\n\t\t\t\t\tstrtarget = dr.next;\n\t\t\t\t}\n\t\t\t\tif constexpr (std::is_same_v<Ch, char32_t>) {\n\t\t\t\t\tauto er = unicode::code_point_to_utf32(cp);\n\t\t\t\t\tf(er);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tauto er = unicode::code_point_to_utf16(cp);\n\t\t\t\t\tf(er);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename BaseCh, typename S>\n\t\tinline S get_into(lua_State* L, int index, record& tracking) {\n\t\t\tusing Ch = typename S::value_type;\n\t\t\ttracking.use(1);\n\t\t\tsize_t len;\n\t\t\tauto utf8p = lua_tolstring(L, index, &len);\n\t\t\tif (len < 1)\n\t\t\t\treturn S();\n\t\t\tconst char* strb = utf8p;\n\t\t\tconst char* stre = utf8p + len;\n\t\t\tstack_detail::count_code_units_utf<BaseCh> count_units;\n\t\t\tconvert<BaseCh>(strb, stre, count_units);\n\t\t\tS r(count_units.needed_size, static_cast<Ch>(0));\n\t\t\tr.resize(count_units.needed_size);\n\t\t\tCh* target = &r[0];\n\t\t\tstack_detail::copy_code_units_utf<Ch, BaseCh> copy_units(target);\n\t\t\tconvert<BaseCh>(strb, stre, copy_units);\n\t\t\treturn r;\n\t\t}\n\t} // namespace stack_detail\n\n\ttemplate <typename T, typename>\n\tstruct unqualified_getter {\n\t\tstatic decltype(auto) get(lua_State* L, int index, record& tracking) {\n\t\t\tif constexpr (std::is_same_v<T, bool>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn lua_toboolean(L, index) != 0;\n\t\t\t}\n\t\t\telse if constexpr (std::is_enum_v<T>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn static_cast<T>(lua_tointegerx(L, index, nullptr));\n\t\t\t}\n\t\t\telse if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) {\n\t\t\t\ttracking.use(1);\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\tif (lua_isinteger(L, index) != 0) {\n\t\t\t\t\treturn static_cast<T>(lua_tointeger(L, index));\n\t\t\t\t}\n#endif\n\t\t\t\treturn static_cast<T>(llround(lua_tonumber(L, index)));\n\t\t\t}\n\t\t\telse if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn static_cast<T>(lua_tonumber(L, index));\n\t\t\t}\n\t\t\telse if constexpr (is_lua_reference_v<T>) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn T(L, index);\n\t\t\t}\n\t\t\telse if constexpr (is_unique_usertype_v<T>) {\n\t\t\t\tusing Real = typename unique_usertype_traits<T>::actual_type;\n\n\t\t\t\ttracking.use(1);\n\t\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\t\tmemory = detail::align_usertype_unique<Real>(memory);\n\t\t\t\tReal* mem = static_cast<Real*>(memory);\n\t\t\t\treturn *mem;\n\t\t\t}\n\t\t\telse if constexpr (meta::is_optional_v<T>) {\n\t\t\t\tusing ValueType = typename T::value_type;\n\t\t\t\treturn unqualified_check_getter<ValueType>::template get_using<T>(L, index, no_panic, tracking);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, luaL_Stream*>) {\n\t\t\t\tluaL_Stream* pstream = static_cast<luaL_Stream*>(lua_touserdata(L, index));\n\t\t\t\treturn pstream;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, luaL_Stream>) {\n\t\t\t\tluaL_Stream* pstream = static_cast<luaL_Stream*>(lua_touserdata(L, index));\n\t\t\t\treturn *pstream;\n\t\t\t}\n#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\t\telse if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) {\n\t\t\t\treturn stack_detail::get_function_pointer<std::remove_pointer_t<T>>(L, index, tracking);\n\t\t\t}\n#endif\n\t\t\telse {\n\t\t\t\treturn stack_detail::unchecked_unqualified_get<detail::as_value_tag<T>>(L, index, tracking);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename X, typename>\n\tstruct qualified_getter {\n\t\tstatic decltype(auto) get(lua_State* L, int index, record& tracking) {\n\t\t\tusing Tu = meta::unqualified_t<X>;\n\t\t\tstatic constexpr bool is_userdata_of_some_kind\n\t\t\t\t= !std::is_reference_v<\n\t\t\t\t       X> && is_container_v<Tu> && std::is_default_constructible_v<Tu> && !is_lua_primitive_v<Tu> && !is_transparent_argument_v<Tu>;\n\t\t\tif constexpr (is_userdata_of_some_kind) {\n\t\t\t\tif (type_of(L, index) == type::userdata) {\n\t\t\t\t\treturn static_cast<Tu>(stack_detail::unchecked_unqualified_get<Tu>(L, index, tracking));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu> && !is_base_rebindable_non_void_v<unique_usertype_traits<Tu>>) {\n\t\t\t\tusing u_traits = unique_usertype_traits<Tu>;\n\t\t\t\tusing T = typename u_traits::type;\n\t\t\t\tusing Real = typename u_traits::actual_type;\n\t\t\t\ttracking.use(1);\n\t\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\t\tmemory = detail::align_usertype_unique_destructor(memory);\n\t\t\t\tdetail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);\n\t\t\t\tif (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {\n\t\t\t\t\tmemory = detail::align_usertype_unique_tag<true, false>(memory);\n\t\t\t\t\tmemory = detail::align_usertype_unique<Real, true, false>(memory);\n\t\t\t\t\tReal* mem = static_cast<Real*>(memory);\n\t\t\t\t\treturn static_cast<Real>(*mem);\n\t\t\t\t}\n\t\t\t\tReal r(nullptr);\n\t\t\t\tif constexpr (!derive<T>::value) {\n\t\t\t\t\t// TODO: abort / terminate, maybe only in debug modes?\n\t\t\t\t\treturn static_cast<Real>(std::move(r));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tmemory = detail::align_usertype_unique_tag<true, false>(memory);\n\t\t\t\t\tdetail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);\n\t\t\t\t\tmemory = detail::align_usertype_unique<Real, true, false>(memory);\n\t\t\t\t\tstring_view ti = usertype_traits<T>::qualified_name();\n\t\t\t\t\tint cast_operation;\n\t\t\t\t\tif constexpr (is_base_rebindable_v<u_traits>) {\n\t\t\t\t\t\tusing rebind_t = typename u_traits::template rebind_base<void>;\n\t\t\t\t\t\tstring_view rebind_ti = usertype_traits<rebind_t>::qualified_name();\n\t\t\t\t\t\tcast_operation = ic(memory, &r, ti, rebind_ti);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tstring_view rebind_ti(\"\");\n\t\t\t\t\t\tcast_operation = ic(memory, &r, ti, rebind_ti);\n\t\t\t\t\t}\n\t\t\t\t\tswitch (cast_operation) {\n\t\t\t\t\tcase 1: {\n\t\t\t\t\t\t// it's a perfect match,\n\t\t\t\t\t\t// alias memory directly\n\t\t\t\t\t\tReal* mem = static_cast<Real*>(memory);\n\t\t\t\t\t\treturn static_cast<Real>(*mem);\n\t\t\t\t\t}\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\t// it's a base match, return the\n\t\t\t\t\t\t// aliased creation\n\t\t\t\t\t\treturn static_cast<Real>(std::move(r));\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// uh oh..\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// TODO: abort / terminate, maybe only in debug modes?\n\t\t\t\t\treturn static_cast<Real>(r);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack_detail::unchecked_unqualified_get<Tu>(L, index, tracking);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<as_table_t<T>> {\n\t\tusing Tu = meta::unqualified_t<T>;\n\n\t\ttemplate <typename V>\n\t\tstatic void push_back_at_end(std::true_type, types<V>, lua_State* L, T& cont, std::size_t) {\n\t\t\tcont.push_back(stack::get<V>(L, -lua_size<V>::value));\n\t\t}\n\n\t\ttemplate <typename V>\n\t\tstatic void push_back_at_end(std::false_type, types<V> t, lua_State* L, T& cont, std::size_t idx) {\n\t\t\tinsert_at_end(meta::has_insert<Tu>(), t, L, cont, idx);\n\t\t}\n\n\t\ttemplate <typename V>\n\t\tstatic void insert_at_end(std::true_type, types<V>, lua_State* L, T& cont, std::size_t) {\n\t\t\tusing std::cend;\n\t\t\tcont.insert(cend(cont), stack::get<V>(L, -lua_size<V>::value));\n\t\t}\n\n\t\ttemplate <typename V>\n\t\tstatic void insert_at_end(std::false_type, types<V>, lua_State* L, T& cont, std::size_t idx) {\n\t\t\tcont[idx] = stack::get<V>(L, -lua_size<V>::value);\n\t\t}\n\n\t\tstatic bool max_size_check(std::false_type, T&, std::size_t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tstatic bool max_size_check(std::true_type, T& cont, std::size_t idx) {\n\t\t\treturn idx >= cont.max_size();\n\t\t}\n\n\t\tstatic T get(lua_State* L, int relindex, record& tracking) {\n\t\t\treturn get(meta::is_associative<Tu>(), L, relindex, tracking);\n\t\t}\n\n\t\tstatic T get(std::false_type, lua_State* L, int relindex, record& tracking) {\n\t\t\ttypedef typename Tu::value_type V;\n\t\t\treturn get(types<V>(), L, relindex, tracking);\n\t\t}\n\n\t\ttemplate <typename V>\n\t\tstatic T get(types<V> t, lua_State* L, int relindex, record& tracking) {\n\t\t\ttracking.use(1);\n\n\t\t\t// the W4 flag is really great,\n\t\t\t// so great that it can tell my for loops (twice nested)\n\t\t\t// below never actually terminate\n\t\t\t// without hitting where the gotos have infested\n\n\t\t\t// so now I would get the error W4XXX unreachable\n\t\t\t// me that the return cont at the end of this function\n\t\t\t// which is fair until other compilers complain\n\t\t\t// that there isn't a return and that based on\n\t\t\t// SOME MAGICAL FORCE\n\t\t\t// control flow falls off the end of a non-void function\n\t\t\t// so it needs to be there for the compilers that are\n\t\t\t// too flimsy to analyze the basic blocks...\n\t\t\t// (I'm sure I should file a bug but those compilers are already\n\t\t\t// in the wild; it doesn't matter if I fix them,\n\t\t\t// someone else is still going to get some old-ass compiler\n\t\t\t// and then bother me about the unclean build for the 30th\n\t\t\t// time)\n\n\t\t\t// \"Why not an IIFE?\"\n\t\t\t// Because additional lambdas / functions which serve as\n\t\t\t// capture-all-and-then-invoke bloat binary sizes\n\t\t\t// by an actually detectable amount\n\t\t\t// (one user uses sol2 pretty heavily and 22 MB of binary size\n\t\t\t// was saved by reducing reliance on lambdas in templates)\n\n\t\t\t// This would really be solved by having break N;\n\t\t\t// be a real, proper thing...\n\t\t\t// but instead, we have to use labels and gotos\n\t\t\t// and earn the universal vitriol of the dogmatic\n\t\t\t// programming community\n\n\t\t\t// all in all: W4 is great!~\n\n\t\t\tint index = lua_absindex(L, relindex);\n\t\t\tT cont;\n\t\t\tstd::size_t idx = 0;\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t// This method is HIGHLY performant over regular table iteration\n\t\t\t// thanks to the Lua API changes in 5.3\n\t\t\t// Questionable in 5.4\n\t\t\tfor (lua_Integer i = 0;; i += lua_size<V>::value) {\n\t\t\t\tif (max_size_check(meta::has_max_size<Tu>(), cont, idx)) {\n\t\t\t\t\t// see above comment\n\t\t\t\t\tgoto done;\n\t\t\t\t}\n\t\t\t\tbool isnil = false;\n\t\t\t\tfor (int vi = 0; vi < lua_size<V>::value; ++vi) {\n#if defined(LUA_NILINTABLE) && LUA_NILINTABLE && SOL_LUA_VESION_I_ >= 600\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\t\tlua_pushinteger(L, static_cast<lua_Integer>(i + vi));\n\t\t\t\t\tif (lua_keyin(L, index) == 0) {\n\t\t\t\t\t\t// it's time to stop\n\t\t\t\t\t\tisnil = true;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// we have a key, have to get the value\n\t\t\t\t\t\tlua_geti(L, index, i + vi);\n\t\t\t\t\t}\n#else\n\t\t\t\t\ttype vt = static_cast<type>(lua_geti(L, index, i + vi));\n\t\t\t\t\tisnil = vt == type::none || vt == type::lua_nil;\n#endif\n\t\t\t\t\tif (isnil) {\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n#if defined(LUA_NILINTABLE) && LUA_NILINTABLE && SOL_LUA_VESION_I_ >= 600\n\t\t\t\t\t\tlua_pop(L, vi);\n#else\n\t\t\t\t\t\tlua_pop(L, (vi + 1));\n#endif\n\t\t\t\t\t\t// see above comment\n\t\t\t\t\t\tgoto done;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isnil) {\n#if defined(LUA_NILINTABLE) && LUA_NILINTABLE && SOL_LUA_VESION_I_ >= 600\n#else\n\t\t\t\t\tlua_pop(L, lua_size<V>::value);\n#endif\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tpush_back_at_end(meta::has_push_back<Tu>(), t, L, cont, idx);\n\t\t\t\t++idx;\n\t\t\t\tlua_pop(L, lua_size<V>::value);\n\t\t\t}\n#else\n\t\t\t// Zzzz slower but necessary thanks to the lower version API and missing functions qq\n\t\t\tfor (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {\n\t\t\t\tif (idx >= cont.max_size()) {\n\t\t\t\t\t// see above comment\n\t\t\t\t\tgoto done;\n\t\t\t\t}\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 2, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\tbool isnil = false;\n\t\t\t\tfor (int vi = 0; vi < lua_size<V>::value; ++vi) {\n\t\t\t\t\tlua_pushinteger(L, i);\n\t\t\t\t\tlua_gettable(L, index);\n\t\t\t\t\ttype vt = type_of(L, -1);\n\t\t\t\t\tisnil = vt == type::lua_nil;\n\t\t\t\t\tif (isnil) {\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlua_pop(L, (vi + 1));\n\t\t\t\t\t\t// see above comment\n\t\t\t\t\t\tgoto done;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isnil)\n\t\t\t\t\tcontinue;\n\t\t\t\tpush_back_at_end(meta::has_push_back<Tu>(), t, L, cont, idx);\n\t\t\t\t++idx;\n\t\t\t}\n#endif\n\t\tdone:\n\t\t\treturn cont;\n\t\t}\n\n\t\tstatic T get(std::true_type, lua_State* L, int index, record& tracking) {\n\t\t\ttypedef typename Tu::value_type P;\n\t\t\ttypedef typename P::first_type K;\n\t\t\ttypedef typename P::second_type V;\n\t\t\treturn get(types<K, V>(), L, index, tracking);\n\t\t}\n\n\t\ttemplate <typename K, typename V>\n\t\tstatic T get(types<K, V>, lua_State* L, int relindex, record& tracking) {\n\t\t\ttracking.use(1);\n\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 3, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\n\t\t\tT associative;\n\t\t\tint index = lua_absindex(L, relindex);\n\t\t\tlua_pushnil(L);\n\t\t\twhile (lua_next(L, index) != 0) {\n\t\t\t\tdecltype(auto) key = stack::check_get<K>(L, -2);\n\t\t\t\tif (!key) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tassociative.emplace(std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));\n\t\t\t\tlua_pop(L, 1);\n\t\t\t}\n\t\t\treturn associative;\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Al>\n\tstruct unqualified_getter<as_table_t<std::forward_list<T, Al>>> {\n\t\ttypedef std::forward_list<T, Al> C;\n\n\t\tstatic C get(lua_State* L, int relindex, record& tracking) {\n\t\t\treturn get(meta::has_key_value_pair<C>(), L, relindex, tracking);\n\t\t}\n\n\t\tstatic C get(std::true_type, lua_State* L, int index, record& tracking) {\n\t\t\ttypedef typename T::value_type P;\n\t\t\ttypedef typename P::first_type K;\n\t\t\ttypedef typename P::second_type V;\n\t\t\treturn get(types<K, V>(), L, index, tracking);\n\t\t}\n\n\t\tstatic C get(std::false_type, lua_State* L, int relindex, record& tracking) {\n\t\t\ttypedef typename C::value_type V;\n\t\t\treturn get(types<V>(), L, relindex, tracking);\n\t\t}\n\n\t\ttemplate <typename V>\n\t\tstatic C get(types<V>, lua_State* L, int relindex, record& tracking) {\n\t\t\ttracking.use(1);\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 3, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\n\t\t\tint index = lua_absindex(L, relindex);\n\t\t\tC cont;\n\t\t\tauto at = cont.cbefore_begin();\n\t\t\tstd::size_t idx = 0;\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t// This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3\n\t\t\tfor (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {\n\t\t\t\tif (idx >= cont.max_size()) {\n\t\t\t\t\tgoto done;\n\t\t\t\t}\n\t\t\t\tbool isnil = false;\n\t\t\t\tfor (int vi = 0; vi < lua_size<V>::value; ++vi) {\n\t\t\t\t\ttype t = static_cast<type>(lua_geti(L, index, i + vi));\n\t\t\t\t\tisnil = t == type::lua_nil;\n\t\t\t\t\tif (isnil) {\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlua_pop(L, (vi + 1));\n\t\t\t\t\t\tgoto done;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isnil)\n\t\t\t\t\tcontinue;\n\t\t\t\tat = cont.insert_after(at, stack::get<V>(L, -lua_size<V>::value));\n\t\t\t\t++idx;\n\t\t\t}\n#else\n\t\t\t// Zzzz slower but necessary thanks to the lower version API and missing functions qq\n\t\t\tfor (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {\n\t\t\t\tif (idx >= cont.max_size()) {\n\t\t\t\t\tgoto done;\n\t\t\t\t}\n\t\t\t\tbool isnil = false;\n\t\t\t\tfor (int vi = 0; vi < lua_size<V>::value; ++vi) {\n\t\t\t\t\tlua_pushinteger(L, i);\n\t\t\t\t\tlua_gettable(L, index);\n\t\t\t\t\ttype t = type_of(L, -1);\n\t\t\t\t\tisnil = t == type::lua_nil;\n\t\t\t\t\tif (isnil) {\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlua_pop(L, (vi + 1));\n\t\t\t\t\t\tgoto done;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isnil)\n\t\t\t\t\tcontinue;\n\t\t\t\tat = cont.insert_after(at, stack::get<V>(L, -lua_size<V>::value));\n\t\t\t\t++idx;\n\t\t\t}\n#endif\n\t\tdone:\n\t\t\treturn cont;\n\t\t}\n\n\t\ttemplate <typename K, typename V>\n\t\tstatic C get(types<K, V>, lua_State* L, int relindex, record& tracking) {\n\t\t\ttracking.use(1);\n\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 3, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\n\t\t\tC associative;\n\t\t\tauto at = associative.cbefore_begin();\n\t\t\tint index = lua_absindex(L, relindex);\n\t\t\tlua_pushnil(L);\n\t\t\twhile (lua_next(L, index) != 0) {\n\t\t\t\tdecltype(auto) key = stack::check_get<K>(L, -2);\n\t\t\t\tif (!key) {\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tat = associative.emplace_after(at, std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));\n\t\t\t\tlua_pop(L, 1);\n\t\t\t}\n\t\t\treturn associative;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<nested<T>> {\n\t\tstatic T get(lua_State* L, int index, record& tracking) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (is_container_v<Tu>) {\n\t\t\t\tif constexpr (meta::is_associative<Tu>::value) {\n\t\t\t\t\ttypedef typename T::value_type P;\n\t\t\t\t\ttypedef typename P::first_type K;\n\t\t\t\t\ttypedef typename P::second_type V;\n\t\t\t\t\tunqualified_getter<as_table_t<T>> g;\n\t\t\t\t\t// VC++ has a bad warning here: shut it up\n\t\t\t\t\t(void)g;\n\t\t\t\t\treturn g.get(types<K, nested<V>>(), L, index, tracking);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttypedef typename T::value_type V;\n\t\t\t\t\tunqualified_getter<as_table_t<T>> g;\n\t\t\t\t\t// VC++ has a bad warning here: shut it up\n\t\t\t\t\t(void)g;\n\t\t\t\t\treturn g.get(types<nested<V>>(), L, index, tracking);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tunqualified_getter<Tu> g;\n\t\t\t\t// VC++ has a bad warning here: shut it up\n\t\t\t\t(void)g;\n\t\t\t\treturn g.get(L, index, tracking);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<as_container_t<T>> {\n\t\tstatic decltype(auto) get(lua_State* L, int index, record& tracking) {\n\t\t\treturn stack::unqualified_get<T>(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<as_container_t<T>*> {\n\t\tstatic decltype(auto) get(lua_State* L, int index, record& tracking) {\n\t\t\treturn stack::unqualified_get<T*>(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<userdata_value> {\n\t\tstatic userdata_value get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn userdata_value(lua_touserdata(L, index));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<lightuserdata_value> {\n\t\tstatic lightuserdata_value get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn lightuserdata_value(lua_touserdata(L, index));\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<light<T>> {\n\t\tstatic light<T> get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\treturn light<T>(static_cast<T*>(memory));\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<user<T>> {\n\t\tstatic std::add_lvalue_reference_t<T> get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\tmemory = detail::align_user<T>(memory);\n\t\t\treturn *static_cast<std::remove_reference_t<T>*>(memory);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<user<T*>> {\n\t\tstatic T* get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tvoid* memory = lua_touserdata(L, index);\n\t\t\tmemory = detail::align_user<T*>(memory);\n\t\t\treturn static_cast<T*>(memory);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<type> {\n\t\tstatic type get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn static_cast<type>(lua_type(L, index));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<std::string> {\n\t\tstatic std::string get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tstd::size_t len;\n\t\t\tauto str = lua_tolstring(L, index, &len);\n\t\t\treturn std::string(str, len);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<const char*> {\n\t\tstatic const char* get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tsize_t sz;\n\t\t\treturn lua_tolstring(L, index, &sz);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<char> {\n\t\tstatic char get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tsize_t len;\n\t\t\tauto str = lua_tolstring(L, index, &len);\n\t\t\treturn len > 0 ? str[0] : '\\0';\n\t\t}\n\t};\n\n\ttemplate <typename Traits>\n\tstruct unqualified_getter<basic_string_view<char, Traits>> {\n\t\tstatic string_view get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tsize_t sz;\n\t\t\tconst char* str = lua_tolstring(L, index, &sz);\n\t\t\treturn basic_string_view<char, Traits>(str, sz);\n\t\t}\n\t};\n\n\ttemplate <typename Traits, typename Al>\n\tstruct unqualified_getter<std::basic_string<wchar_t, Traits, Al>> {\n\t\tusing S = std::basic_string<wchar_t, Traits, Al>;\n\t\tstatic S get(lua_State* L, int index, record& tracking) {\n\t\t\tusing Ch = meta::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t>;\n\t\t\treturn stack_detail::get_into<Ch, S>(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename Traits, typename Al>\n\tstruct unqualified_getter<std::basic_string<char16_t, Traits, Al>> {\n\t\tstatic std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) {\n\t\t\treturn stack_detail::get_into<char16_t, std::basic_string<char16_t, Traits, Al>>(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename Traits, typename Al>\n\tstruct unqualified_getter<std::basic_string<char32_t, Traits, Al>> {\n\t\tstatic std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) {\n\t\t\treturn stack_detail::get_into<char32_t, std::basic_string<char32_t, Traits, Al>>(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<char16_t> {\n\t\tstatic char16_t get(lua_State* L, int index, record& tracking) {\n\t\t\tstring_view utf8 = stack::get<string_view>(L, index, tracking);\n\t\t\tconst char* strb = utf8.data();\n\t\t\tconst char* stre = utf8.data() + utf8.size();\n\t\t\tchar32_t cp = 0;\n\t\t\tauto dr = unicode::utf8_to_code_point(strb, stre);\n\t\t\tif (dr.error != unicode::error_code::ok) {\n\t\t\t\tcp = unicode::unicode_detail::replacement;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcp = dr.codepoint;\n\t\t\t}\n\t\t\tauto er = unicode::code_point_to_utf16(cp);\n\t\t\treturn er.code_units[0];\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<char32_t> {\n\t\tstatic char32_t get(lua_State* L, int index, record& tracking) {\n\t\t\tstring_view utf8 = stack::get<string_view>(L, index, tracking);\n\t\t\tconst char* strb = utf8.data();\n\t\t\tconst char* stre = utf8.data() + utf8.size();\n\t\t\tchar32_t cp = 0;\n\t\t\tauto dr = unicode::utf8_to_code_point(strb, stre);\n\t\t\tif (dr.error != unicode::error_code::ok) {\n\t\t\t\tcp = unicode::unicode_detail::replacement;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcp = dr.codepoint;\n\t\t\t}\n\t\t\tauto er = unicode::code_point_to_utf32(cp);\n\t\t\treturn er.code_units[0];\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<wchar_t> {\n\t\tstatic wchar_t get(lua_State* L, int index, record& tracking) {\n\t\t\ttypedef meta::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch;\n\t\t\tunqualified_getter<Ch> g;\n\t\t\t(void)g;\n\t\t\tauto c = g.get(L, index, tracking);\n\t\t\treturn static_cast<wchar_t>(c);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<meta_function> {\n\t\tstatic meta_function get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tconst char* name = unqualified_getter<const char*> {}.get(L, index, tracking);\n\t\t\tconst auto& mfnames = meta_function_names();\n\t\t\tfor (std::size_t i = 0; i < mfnames.size(); ++i)\n\t\t\t\tif (mfnames[i] == name)\n\t\t\t\t\treturn static_cast<meta_function>(i);\n\t\t\treturn meta_function::construct;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<lua_nil_t> {\n\t\tstatic lua_nil_t get(lua_State*, int, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn lua_nil;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<std::nullptr_t> {\n\t\tstatic std::nullptr_t get(lua_State*, int, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn nullptr;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<nullopt_t> {\n\t\tstatic nullopt_t get(lua_State*, int, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn nullopt;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<this_state> {\n\t\tstatic this_state get(lua_State* L, int, record& tracking) {\n\t\t\ttracking.use(0);\n\t\t\treturn this_state(L);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<this_main_state> {\n\t\tstatic this_main_state get(lua_State* L, int, record& tracking) {\n\t\t\ttracking.use(0);\n\t\t\treturn this_main_state(main_thread(L, L));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<lua_CFunction> {\n\t\tstatic lua_CFunction get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn lua_tocfunction(L, index);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<c_closure> {\n\t\tstatic c_closure get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn c_closure(lua_tocfunction(L, index), -1);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<error> {\n\t\tstatic error get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\tsize_t sz = 0;\n\t\t\tconst char* err = lua_tolstring(L, index, &sz);\n\t\t\tif (err == nullptr) {\n\t\t\t\treturn error(detail::direct_error, \"\");\n\t\t\t}\n\t\t\treturn error(detail::direct_error, std::string(err, sz));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<void*> {\n\t\tstatic void* get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn lua_touserdata(L, index);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_getter<const void*> {\n\t\tstatic const void* get(lua_State* L, int index, record& tracking) {\n\t\t\ttracking.use(1);\n\t\t\treturn lua_touserdata(L, index);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<detail::as_value_tag<T>> {\n\t\tstatic T* get_no_lua_nil(lua_State* L, int index, record& tracking) {\n\t\t\tvoid* memory = lua_touserdata(L, index);\n#if SOL_IS_ON(SOL_USE_INTEROP_I_)\n\t\t\tauto ugr = stack_detail::interop_get<T>(L, index, memory, tracking);\n\t\t\tif (ugr.first) {\n\t\t\t\treturn ugr.second;\n\t\t\t}\n#endif // interop extensibility\n\t\t\ttracking.use(1);\n\t\t\tvoid* rawdata = detail::align_usertype_pointer(memory);\n\t\t\tvoid** pudata = static_cast<void**>(rawdata);\n\t\t\tvoid* udata = *pudata;\n\t\t\treturn get_no_lua_nil_from(L, udata, index, tracking);\n\t\t}\n\n\t\tstatic T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) {\n\t\t\tbool has_derived = derive<T>::value || weak_derive<T>::value;\n\t\t\tif (has_derived) {\n\t\t\t\tif (lua_getmetatable(L, index) == 1) {\n\t\t\t\t\tlua_getfield(L, -1, &detail::base_class_cast_key()[0]);\n\t\t\t\t\tif (type_of(L, -1) != type::lua_nil) {\n\t\t\t\t\t\tvoid* basecastdata = lua_touserdata(L, -1);\n\t\t\t\t\t\tdetail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata);\n\t\t\t\t\t\t// use the casting function to properly adjust the pointer for the desired T\n\t\t\t\t\t\tudata = ic(udata, usertype_traits<T>::qualified_name());\n\t\t\t\t\t}\n\t\t\t\t\tlua_pop(L, 2);\n\t\t\t\t}\n\t\t\t}\n\t\t\tT* obj = static_cast<T*>(udata);\n\t\t\treturn obj;\n\t\t}\n\n\t\tstatic T& get(lua_State* L, int index, record& tracking) {\n\t\t\treturn *get_no_lua_nil(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<detail::as_pointer_tag<T>> {\n\t\tstatic T* get(lua_State* L, int index, record& tracking) {\n\t\t\ttype t = type_of(L, index);\n\t\t\tif (t == type::lua_nil) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tunqualified_getter<detail::as_value_tag<T>> g;\n\t\t\t// Avoid VC++ warning\n\t\t\t(void)g;\n\t\t\treturn g.get_no_lua_nil(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<non_null<T*>> {\n\t\tstatic T* get(lua_State* L, int index, record& tracking) {\n\t\t\tunqualified_getter<detail::as_value_tag<T>> g;\n\t\t\t// Avoid VC++ warning\n\t\t\t(void)g;\n\t\t\treturn g.get_no_lua_nil(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<T&> {\n\t\tstatic T& get(lua_State* L, int index, record& tracking) {\n\t\t\tunqualified_getter<detail::as_value_tag<T>> g;\n\t\t\t// Avoid VC++ warning\n\t\t\t(void)g;\n\t\t\treturn g.get(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<std::reference_wrapper<T>> {\n\t\tstatic T& get(lua_State* L, int index, record& tracking) {\n\t\t\tunqualified_getter<T&> g;\n\t\t\t// Avoid VC++ warning\n\t\t\t(void)g;\n\t\t\treturn g.get(L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_getter<T*> {\n\t\tstatic T* get(lua_State* L, int index, record& tracking) {\n#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\t\tif constexpr (std::is_function_v<T>) {\n\t\t\t\treturn stack_detail::get_function_pointer<T>(L, index, tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tunqualified_getter<detail::as_pointer_tag<T>> g;\n\t\t\t\t// Avoid VC++ warning\n\t\t\t\t(void)g;\n\t\t\t\treturn g.get(L, index, tracking);\n\t\t\t}\n#else\n\t\t\tunqualified_getter<detail::as_pointer_tag<T>> g;\n\t\t\t// Avoid VC++ warning\n\t\t\t(void)g;\n\t\t\treturn g.get(L, index, tracking);\n#endif\n\t\t}\n\t};\n\n\ttemplate <typename... Tn>\n\tstruct unqualified_getter<std::tuple<Tn...>> {\n\t\ttypedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R;\n\n\t\ttemplate <typename... Args>\n\t\tstatic R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) {\n\t\t\t// Fuck you too, VC++\n\t\t\treturn R { std::forward<Args>(args)... };\n\t\t}\n\n\t\ttemplate <std::size_t I, std::size_t... Ix, typename... Args>\n\t\tstatic R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, Args&&... args) {\n\t\t\t// Fuck you too, VC++\n\t\t\ttypedef std::tuple_element_t<I, std::tuple<Tn...>> T;\n\t\t\treturn apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<Args>(args)..., stack::get<T>(L, index + tracking.used, tracking));\n\t\t}\n\n\t\tstatic R get(lua_State* L, int index, record& tracking) {\n\t\t\treturn apply(std::make_index_sequence<sizeof...(Tn)>(), L, index, tracking);\n\t\t}\n\t};\n\n\ttemplate <typename A, typename B>\n\tstruct unqualified_getter<std::pair<A, B>> {\n\t\tstatic decltype(auto) get(lua_State* L, int index, record& tracking) {\n\t\t\treturn std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))> { stack::get<A>(L, index, tracking),\n\t\t\t\tstack::get<B>(L, index + tracking.used, tracking) };\n\t\t}\n\t};\n\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n\n\ttemplate <typename... Tn>\n\tstruct unqualified_getter<std::variant<Tn...>> {\n\t\tusing V = std::variant<Tn...>;\n\n\t\tstatic V get_one(std::integral_constant<std::size_t, std::variant_size_v<V>>, lua_State* L, int index, record& tracking) {\n\t\t\t(void)L;\n\t\t\t(void)index;\n\t\t\t(void)tracking;\n\t\t\tif constexpr (std::variant_size_v<V> == 0) {\n\t\t\t\treturn V();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// using T = std::variant_alternative_t<0, V>;\n\t\t\t\tstd::abort();\n\t\t\t\t// return V(std::in_place_index<0>, stack::get<T>(L, index, tracking));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <std::size_t I>\n\t\tstatic V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) {\n\t\t\ttypedef std::variant_alternative_t<I, V> T;\n\t\t\trecord temp_tracking = tracking;\n\t\t\tif (stack::check<T>(L, index, no_panic, temp_tracking)) {\n\t\t\t\ttracking = temp_tracking;\n\t\t\t\treturn V(std::in_place_index<I>, stack::get<T>(L, index));\n\t\t\t}\n\t\t\treturn get_one(std::integral_constant<std::size_t, I + 1>(), L, index, tracking);\n\t\t}\n\n\t\tstatic V get(lua_State* L, int index, record& tracking) {\n\t\t\treturn get_one(std::integral_constant<std::size_t, 0>(), L, index, tracking);\n\t\t}\n\t};\n#endif // variant\n\n}} // namespace sol::stack\n\n// end of sol/stack_get_unqualified.hpp\n\n// beginning of sol/stack_get_qualified.hpp\n\nnamespace sol {\nnamespace stack {\n\n\t// There are no more enable_ifs that can be used here,\n\t// so this is just for posterity, I guess?\n\t// maybe I'll fill this file in later.\n\n}\n} // namespace sol::stack\n\n// end of sol/stack_get_qualified.hpp\n\n// end of sol/stack_get.hpp\n\n// beginning of sol/stack_check_get.hpp\n\n// beginning of sol/stack_check_get_unqualified.hpp\n\n#include <cstdlib>\n#include <cmath>\n#include <optional>\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n#include <variant>\n#endif // variant shenanigans (thanks, Mac OSX)\n\nnamespace sol { namespace stack {\n\ttemplate <typename T, typename>\n\tstruct unqualified_check_getter {\n\t\ttypedef decltype(stack_detail::unchecked_unqualified_get<T>(nullptr, -1, std::declval<record&>())) R;\n\n\t\ttemplate <typename Optional, typename Handler>\n\t\tstatic Optional get_using(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (!meta::meta_detail::is_adl_sol_lua_check_v<T> && !meta::meta_detail::is_adl_sol_lua_get_v<T>) {\n\t\t\t\tif constexpr (is_lua_reference_v<T>) {\n\t\t\t\t\t// actually check if it's none here, otherwise\n\t\t\t\t\t// we'll have a none object inside an optional!\n\t\t\t\t\tbool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);\n\t\t\t\t\tif (!success) {\n\t\t\t\t\t\t// expected type, actual type\n\t\t\t\t\t\ttracking.use(static_cast<int>(success));\n\t\t\t\t\t\thandler(L, index, type::poly, type_of(L, index), \"\");\n\t\t\t\t\t\treturn detail::associated_nullopt_v<Optional>;\n\t\t\t\t\t}\n\t\t\t\t\treturn stack_detail::unchecked_get<T>(L, index, tracking);\n\t\t\t\t}\n\t\t\t\telse if constexpr ((std::is_integral_v<T> || std::is_same_v<T, lua_Integer>)&&!std::is_same_v<T, bool>) {\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\t\tif (lua_isinteger(L, index) != 0) {\n\t\t\t\t\t\ttracking.use(1);\n\t\t\t\t\t\treturn static_cast<T>(lua_tointeger(L, index));\n\t\t\t\t\t}\n#endif\n\t\t\t\t\tint isnum = 0;\n\t\t\t\t\tconst lua_Number value = lua_tonumberx(L, index, &isnum);\n\t\t\t\t\tif (isnum != 0) {\n#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)\n\t\t\t\t\t\tconst auto integer_value = llround(value);\n\t\t\t\t\t\tif (static_cast<lua_Number>(integer_value) == value) {\n\t\t\t\t\t\t\ttracking.use(1);\n\t\t\t\t\t\t\treturn static_cast<T>(integer_value);\n\t\t\t\t\t\t}\n#else\n\t\t\t\t\t\ttracking.use(1);\n\t\t\t\t\t\treturn static_cast<T>(value);\n#endif\n\t\t\t\t\t}\n\t\t\t\t\tconst type t = type_of(L, index);\n\t\t\t\t\ttracking.use(static_cast<int>(t != type::none));\n\t\t\t\t\thandler(L, index, type::number, t, \"not an integer\");\n\t\t\t\t\treturn detail::associated_nullopt_v<Optional>;\n\t\t\t\t}\n\t\t\t\telse if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) {\n\t\t\t\t\tint isnum = 0;\n\t\t\t\t\tlua_Number value = lua_tonumberx(L, index, &isnum);\n\t\t\t\t\tif (isnum == 0) {\n\t\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\t\ttracking.use(static_cast<int>(t != type::none));\n\t\t\t\t\t\thandler(L, index, type::number, t, \"not a valid floating point number\");\n\t\t\t\t\t\treturn detail::associated_nullopt_v<Optional>;\n\t\t\t\t\t}\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\treturn static_cast<T>(value);\n\t\t\t\t}\n\t\t\t\telse if constexpr (std::is_enum_v<T> && !meta::any_same_v<T, meta_function, type>) {\n\t\t\t\t\tint isnum = 0;\n\t\t\t\t\tlua_Integer value = lua_tointegerx(L, index, &isnum);\n\t\t\t\t\tif (isnum == 0) {\n\t\t\t\t\t\ttype t = type_of(L, index);\n\t\t\t\t\t\ttracking.use(static_cast<int>(t != type::none));\n\t\t\t\t\t\thandler(L, index, type::number, t, \"not a valid enumeration value\");\n\t\t\t\t\t\treturn detail::associated_nullopt_v<Optional>;\n\t\t\t\t\t}\n\t\t\t\t\ttracking.use(1);\n\t\t\t\t\treturn static_cast<T>(value);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {\n\t\t\t\t\t\ttracking.use(static_cast<int>(!lua_isnone(L, index)));\n\t\t\t\t\t\treturn detail::associated_nullopt_v<Optional>;\n\t\t\t\t\t}\n\t\t\t\t\treturn stack_detail::unchecked_unqualified_get<T>(L, index, tracking);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {\n\t\t\t\t\ttracking.use(static_cast<int>(!lua_isnone(L, index)));\n\t\t\t\t\treturn detail::associated_nullopt_v<Optional>;\n\t\t\t\t}\n\t\t\t\treturn stack_detail::unchecked_unqualified_get<T>(L, index, tracking);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Handler>\n\t\tstatic optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn get_using<optional<R>>(L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n\ttemplate <typename... Tn, typename C>\n\tstruct unqualified_check_getter<std::variant<Tn...>, C> {\n\t\ttypedef std::variant<Tn...> V;\n\t\ttypedef std::variant_size<V> V_size;\n\t\ttypedef std::integral_constant<bool, V_size::value == 0> V_is_empty;\n\n\t\ttemplate <typename Handler>\n\t\tstatic optional<V> get_empty(std::true_type, lua_State*, int, Handler&&, record&) {\n\t\t\treturn nullopt;\n\t\t}\n\n\t\ttemplate <typename Handler>\n\t\tstatic optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) {\n\t\t\t// This should never be reached...\n\t\t\t// please check your code and understand what you did to bring yourself here\n\t\t\t// maybe file a bug report, or 5\n\t\t\thandler(\n\t\t\t\tL, index, type::poly, type_of(L, index), \"this variant code should never be reached: if it has, you have done something so terribly wrong\");\n\t\t\treturn nullopt;\n\t\t}\n\n\t\ttemplate <typename Handler>\n\t\tstatic optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <std::size_t I, typename Handler>\n\t\tstatic optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\ttypedef std::variant_alternative_t<I - 1, V> T;\n\t\t\tif (stack::check<T>(L, index, no_panic, tracking)) {\n\t\t\t\treturn V(std::in_place_index<I - 1>, stack::get<T>(L, index));\n\t\t\t}\n\t\t\treturn get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\n\t\ttemplate <typename Handler>\n\t\tstatic optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\treturn get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);\n\t\t}\n\t};\n#endif // standard variant\n}}     // namespace sol::stack\n\n// end of sol/stack_check_get_unqualified.hpp\n\n// beginning of sol/stack_check_get_qualified.hpp\n\nnamespace sol { namespace stack {\n\ttemplate <typename T, typename C>\n\tstruct qualified_check_getter {\n\t\ttypedef decltype(stack_detail::unchecked_get<T>(nullptr, -1, std::declval<record&>())) R;\n\n\t\ttemplate <typename Handler>\n\t\tstatic optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\tif constexpr (is_lua_reference_v<T>) {\n\t\t\t\t// actually check if it's none here, otherwise\n\t\t\t\t// we'll have a none object inside an optional!\n\t\t\t\tbool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\ttracking.use(static_cast<int>(success));\n\t\t\t\t\thandler(L, index, type::poly, type_of(L, index), \"\");\n\t\t\t\t\treturn nullopt;\n\t\t\t\t}\n\t\t\t\treturn stack_detail::unchecked_get<T>(L, index, tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!check<T>(L, index, std::forward<Handler>(handler))) {\n\t\t\t\t\ttracking.use(static_cast<int>(!lua_isnone(L, index)));\n\t\t\t\t\treturn nullopt;\n\t\t\t\t}\n\t\t\t\treturn stack_detail::unchecked_get<T>(L, index, tracking);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct qualified_getter<T, std::enable_if_t<meta::is_optional_v<T>>> {\n\t\tstatic T get(lua_State* L, int index, record& tracking) {\n\t\t\tusing ValueType = typename meta::unqualified_t<T>::value_type;\n\t\t\tif constexpr (is_lua_reference_v<ValueType>) {\n\t\t\t\t// actually check if it's none here, otherwise\n\t\t\t\t// we'll have a none object inside an optional!\n\t\t\t\tbool success = lua_isnoneornil(L, index) == 0 && stack::check<ValueType>(L, index, no_panic);\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\ttracking.use(static_cast<int>(success));\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\treturn stack_detail::unchecked_get<ValueType>(L, index, tracking);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!check<ValueType>(L, index, &no_panic)) {\n\t\t\t\t\ttracking.use(static_cast<int>(!lua_isnone(L, index)));\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\treturn stack_detail::unchecked_get<ValueType>(L, index, tracking);\n\t\t\t}\n\t\t}\n\t};\n\n}} // namespace sol::stack\n\n// end of sol/stack_check_get_qualified.hpp\n\n// end of sol/stack_check_get.hpp\n\n// beginning of sol/stack_push.hpp\n\n#include <memory>\n#include <type_traits>\n#include <cassert>\n#include <limits>\n#include <cmath>\n#include <string_view>\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n#include <variant>\n#endif // Can use variant\n\nnamespace sol { namespace stack {\n\tnamespace stack_detail {\n\t\ttemplate <typename T>\n\t\tinline bool integer_value_fits(const T& value) {\n\t\t\tif constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v<T> && sizeof(T) == sizeof(lua_Integer))) {\n\t\t\t\t(void)value;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto u_min = static_cast<std::intmax_t>((std::numeric_limits<lua_Integer>::min)());\n\t\t\t\tauto u_max = static_cast<std::uintmax_t>((std::numeric_limits<lua_Integer>::max)());\n\t\t\t\tauto t_min = static_cast<std::intmax_t>((std::numeric_limits<T>::min)());\n\t\t\t\tauto t_max = static_cast<std::uintmax_t>((std::numeric_limits<T>::max)());\n\t\t\t\treturn (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) {\n\t\t\tif constexpr (meta::any_same_v<std::underlying_type_t<T>, char /*, char8_t*/, char16_t, char32_t>) {\n\t\t\t\tif constexpr (std::is_signed_v<T>) {\n\t\t\t\t\treturn stack::push(L, static_cast<std::int_least32_t>(value));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::push(L, static_cast<std::uint_least32_t>(value));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack::push(L, static_cast<std::underlying_type_t<T>>(value));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) {\n\t\t\treturn 0;\n\t\t}\n\t} // namespace stack_detail\n\n\tinline int push_environment_of(lua_State* L, int index = -1) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_environment);\n#endif // make sure stack doesn't overflow\n#if SOL_LUA_VESION_I_ < 502\n\t\t// Use lua_getfenv\n\t\tlua_getfenv(L, index);\n#else\n\t\t// Use upvalues as explained in Lua 5.2 and beyond's manual\n\t\tif (lua_getupvalue(L, index, 1) == nullptr) {\n\t\t\tpush(L, lua_nil);\n\t\t\treturn 1;\n\t\t}\n#endif\n\t\treturn 1;\n\t}\n\n\ttemplate <typename T>\n\tint push_environment_of(const T& target) {\n\t\ttarget.push();\n\t\treturn push_environment_of(target.lua_state(), -1) + 1;\n\t}\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<detail::as_value_tag<T>> {\n\t\ttemplate <typename F, typename... Args>\n\t\tstatic int push_fx(lua_State* L, F&& f, Args&&... args) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);\n#endif // make sure stack doesn't overflow\n       // Basically, we store all user-data like this:\n       // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new\n       // data in the first sizeof(T*) bytes, and then however many bytes it takes to\n       // do the actual object. Things that are std::ref or plain T* are stored as\n       // just the sizeof(T*), and nothing else.\n\t\t\tT* obj = detail::usertype_allocate<T>(L);\n\t\t\tf();\n\t\t\tstd::allocator<T> alloc {};\n\t\t\tstd::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...);\n\t\t\treturn 1;\n\t\t}\n\n\t\ttemplate <typename K, typename... Args>\n\t\tstatic int push_keyed(lua_State* L, K&& k, Args&&... args) {\n\t\t\tstack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on<T>);\n\t\t\treturn push_fx(L, fx, std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename Arg, typename... Args>\n\t\tstatic int push(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>) {\n\t\t\t\t(void)arg;\n\t\t\t\treturn push_fx(L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn push_keyed(L, usertype_traits<T>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\tstatic int push(lua_State* L) {\n\t\t\treturn push_keyed(L, usertype_traits<T>::metatable());\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<detail::as_pointer_tag<T>> {\n\t\ttypedef meta::unqualified_t<T> U;\n\n\t\ttemplate <typename F>\n\t\tstatic int push_fx(lua_State* L, F&& f, T* obj) {\n\t\t\tif (obj == nullptr)\n\t\t\t\treturn stack::push(L, lua_nil);\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);\n#endif // make sure stack doesn't overflow\n\t\t\tT** pref = detail::usertype_allocate_pointer<T>(L);\n\t\t\tf();\n\t\t\t*pref = obj;\n\t\t\treturn 1;\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tstatic int push_keyed(lua_State* L, K&& k, T* obj) {\n\t\t\tstack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on<U*>);\n\t\t\treturn push_fx(L, fx, obj);\n\t\t}\n\n\t\ttemplate <typename Arg, typename... Args>\n\t\tstatic int push(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>) {\n\t\t\t\t(void)arg;\n\t\t\t\treturn push_fx(L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn push_keyed(L, usertype_traits<U*>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<detail::as_reference_tag> {\n\t\ttemplate <typename T>\n\t\tstatic int push(lua_State* L, T&& obj) {\n\t\t\treturn stack::push(L, detail::ptr(obj));\n\t\t}\n\t};\n\n\tnamespace stack_detail {\n\t\ttemplate <typename T>\n\t\tstruct uu_pusher {\n\t\t\tusing u_traits = unique_usertype_traits<T>;\n\t\t\tusing P = typename u_traits::type;\n\t\t\tusing Real = typename u_traits::actual_type;\n\n\t\t\ttemplate <typename Arg, typename... Args>\n\t\t\tstatic int push(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\t\tif constexpr (std::is_base_of_v<Real, meta::unqualified_t<Arg>>) {\n\t\t\t\t\tif (u_traits::is_null(arg)) {\n\t\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t\t}\n\t\t\t\t\treturn push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename... Args>\n\t\t\tstatic int push_deep(lua_State* L, Args&&... args) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);\n#endif // make sure stack doesn't overflow\n\t\t\t\tP** pref = nullptr;\n\t\t\t\tdetail::unique_destructor* fx = nullptr;\n\t\t\t\tdetail::unique_tag* id = nullptr;\n\t\t\t\tReal* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id);\n\t\t\t\tif (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {\n\t\t\t\t\tdetail::lua_reg_table l {};\n\t\t\t\t\tint index = 0;\n\t\t\t\t\tdetail::indexed_insert insert_fx(l, index);\n\t\t\t\t\tdetail::insert_default_registrations<P>(insert_fx, detail::property_always_true);\n\t\t\t\t\tl[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() };\n\t\t\t\t\tluaL_setfuncs(L, l, 0);\n\t\t\t\t}\n\t\t\t\tlua_setmetatable(L, -2);\n\t\t\t\t*fx = detail::usertype_unique_alloc_destroy<P, Real>;\n\t\t\t\t*id = &detail::inheritance<P>::template type_unique_cast<Real>;\n\t\t\t\tdetail::default_construct::construct(mem, std::forward<Args>(args)...);\n\t\t\t\t*pref = unique_usertype_traits<T>::get(*mem);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\t} // namespace stack_detail\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<detail::as_unique_tag<T>> {\n\t\ttemplate <typename... Args>\n\t\tstatic int push(lua_State* L, Args&&... args) {\n\t\t\tstack_detail::uu_pusher<T> p;\n\t\t\t(void)p;\n\t\t\treturn p.push(L, std::forward<Args>(args)...);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename>\n\tstruct unqualified_pusher {\n\t\ttemplate <typename... Args>\n\t\tstatic int push(lua_State* L, Args&&... args) {\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (is_lua_reference_v<Tu>) {\n\t\t\t\tusing int_arr = int[];\n\t\t\t\tint_arr p { (std::forward<Args>(args).push(L))... };\n\t\t\t\treturn p[0];\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<Tu, bool>) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushboolean(L, std::forward<Args>(args)...);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if constexpr (std::is_integral_v<Tu> || std::is_same_v<Tu, lua_Integer>) {\n\t\t\t\tconst Tu& value(std::forward<Args>(args)...);\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_integral);\n#endif // make sure stack doesn't overflow\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\tif (stack_detail::integer_value_fits<Tu>(value)) {\n\t\t\t\t\tlua_pushinteger(L, static_cast<lua_Integer>(value));\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n#endif // Lua 5.3 and above\n#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)\n\t\t\t\tif (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t\t\t\t// Is this really worth it?\n\t\t\t\t\tassert(false && \"integer value will be misrepresented in lua\");\n\t\t\t\t\tlua_pushinteger(L, static_cast<lua_Integer>(value));\n\t\t\t\t\treturn 1;\n#else\n\t\t\t\t\tthrow error(detail::direct_error, \"integer value will be misrepresented in lua\");\n#endif // No Exceptions\n\t\t\t\t}\n#endif // Safe Numerics and Number Precision Check\n\t\t\t\tlua_pushnumber(L, static_cast<lua_Number>(value));\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if constexpr (std::is_floating_point_v<Tu> || std::is_same_v<Tu, lua_Number>) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_floating);\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushnumber(L, std::forward<Args>(args)...);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<Tu, luaL_Stream*>) {\n\t\t\t\tluaL_Stream* source { std::forward<Args>(args)... };\n\t\t\t\tluaL_Stream* stream = static_cast<luaL_Stream*>(lua_newuserdata(L, sizeof(luaL_Stream)));\n\t\t\t\tstream->f = source->f;\n#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_)\n\t\t\t\tstream->closef = source->closef;\n#endif // LuaJIT and Lua 5.1 and below do not have\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<Tu, luaL_Stream>) {\n\t\t\t\tluaL_Stream& source(std::forward<Args>(args)...);\n\t\t\t\tluaL_Stream* stream = static_cast<luaL_Stream*>(lua_newuserdata(L, sizeof(luaL_Stream)));\n\t\t\t\tstream->f = source.f;\n#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_)\n\t\t\t\tstream->closef = source.closef;\n#endif // LuaJIT and Lua 5.1 and below do not have\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if constexpr (std::is_enum_v<Tu>) {\n\t\t\t\treturn stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (std::is_pointer_v<Tu>) {\n\t\t\t\treturn stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (is_unique_usertype_v<Tu>) {\n\t\t\t\treturn stack::push<detail::as_unique_tag<T>>(L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<std::reference_wrapper<T>> {\n\t\tstatic int push(lua_State* L, const std::reference_wrapper<T>& t) {\n\t\t\treturn stack::push(L, std::addressof(detail::deref(t.get())));\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<detail::as_table_tag<T>> {\n\t\tusing has_kvp = meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>;\n\n\t\tstatic int push(lua_State* L, const T& tablecont) {\n\t\t\treturn push(has_kvp(), std::false_type(), L, tablecont);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const T& tablecont, nested_tag_t) {\n\t\t\treturn push(has_kvp(), std::true_type(), L, tablecont);\n\t\t}\n\n\t\tstatic int push(std::true_type, lua_State* L, const T& tablecont) {\n\t\t\treturn push(has_kvp(), std::true_type(), L, tablecont);\n\t\t}\n\n\t\tstatic int push(std::false_type, lua_State* L, const T& tablecont) {\n\t\t\treturn push(has_kvp(), std::false_type(), L, tablecont);\n\t\t}\n\n\t\ttemplate <bool is_nested>\n\t\tstatic int push(std::true_type, std::integral_constant<bool, is_nested>, lua_State* L, const T& tablecont) {\n\t\t\tauto& cont = detail::deref(detail::unwrap(tablecont));\n\t\t\tlua_createtable(L, static_cast<int>(cont.size()), 0);\n\t\t\tint tableindex = lua_gettop(L);\n\t\t\tfor (const auto& pair : cont) {\n\t\t\t\tif (is_nested) {\n\t\t\t\t\tset_field(L, pair.first, as_nested_ref(pair.second), tableindex);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tset_field(L, pair.first, pair.second, tableindex);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\ttemplate <bool is_nested>\n\t\tstatic int push(std::false_type, std::integral_constant<bool, is_nested>, lua_State* L, const T& tablecont) {\n\t\t\tauto& cont = detail::deref(detail::unwrap(tablecont));\n\t\t\tlua_createtable(L, stack_detail::get_size_hint(cont), 0);\n\t\t\tint tableindex = lua_gettop(L);\n\t\t\tstd::size_t index = 1;\n\t\t\tfor (const auto& i : cont) {\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\tint p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i);\n\t\t\t\tfor (int pi = 0; pi < p; ++pi) {\n\t\t\t\t\tlua_seti(L, tableindex, static_cast<lua_Integer>(index++));\n\t\t\t\t}\n#else\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushinteger(L, static_cast<lua_Integer>(index));\n\t\t\t\tint p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i);\n\t\t\t\tif (p == 1) {\n\t\t\t\t\t++index;\n\t\t\t\t\tlua_settable(L, tableindex);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tint firstindex = tableindex + 1 + 1;\n\t\t\t\t\tfor (int pi = 0; pi < p; ++pi) {\n\t\t\t\t\t\tstack::push(L, index);\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\t\t\tlua_pushvalue(L, firstindex);\n\t\t\t\t\t\tlua_settable(L, tableindex);\n\t\t\t\t\t\t++index;\n\t\t\t\t\t\t++firstindex;\n\t\t\t\t\t}\n\t\t\t\t\tlua_pop(L, 1 + p);\n\t\t\t\t}\n#endif // Lua Version 5.3 and others\n\t\t\t}\n\t\t\t// TODO: figure out a better way to do this...?\n\t\t\t// set_field(L, -1, cont.size());\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<as_table_t<T>> {\n\t\tstatic int push(lua_State* L, const T& v) {\n\t\t\tusing inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>;\n\t\t\tif constexpr (is_container_v<inner_t>) {\n\t\t\t\treturn stack::push<detail::as_table_tag<T>>(L, v);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack::push(L, v);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<nested<T>> {\n\t\tstatic int push(lua_State* L, const T& tablecont) {\n\t\t\tusing Tu = meta::unwrap_unqualified_t<T>;\n\t\t\tusing inner_t = std::remove_pointer_t<Tu>;\n\t\t\tif constexpr (is_container_v<inner_t>) {\n\t\t\t\treturn stack::push<detail::as_table_tag<T>>(L, tablecont, nested_tag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack::push<Tu>(L, tablecont);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<std::initializer_list<T>> {\n\t\tstatic int push(lua_State* L, const std::initializer_list<T>& il) {\n\t\t\tunqualified_pusher<detail::as_table_tag<std::initializer_list<T>>> p {};\n\t\t\t// silence annoying VC++ warning\n\t\t\t(void)p;\n\t\t\treturn p.push(L, il);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<lua_nil_t> {\n\t\tstatic int push(lua_State* L, lua_nil_t) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushnil(L);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<stack_count> {\n\t\tstatic int push(lua_State*, stack_count st) {\n\t\t\treturn st.count;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<metatable_key_t> {\n\t\tstatic int push(lua_State* L, metatable_key_t) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlstring(L, to_string(meta_function::metatable).c_str(), 4);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<std::remove_pointer_t<lua_CFunction>> {\n\t\tstatic int push(lua_State* L, lua_CFunction func, int n = 0) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushcclosure(L, func, n);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<lua_CFunction> {\n\t\tstatic int push(lua_State* L, lua_CFunction func, int n = 0) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushcclosure(L, func, n);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\ttemplate <>\n\tstruct unqualified_pusher<std::remove_pointer_t<detail::lua_CFunction_noexcept>> {\n\t\tstatic int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushcclosure(L, func, n);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<detail::lua_CFunction_noexcept> {\n\t\tstatic int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushcclosure(L, func, n);\n\t\t\treturn 1;\n\t\t}\n\t};\n#endif // noexcept function type\n\n\ttemplate <>\n\tstruct unqualified_pusher<c_closure> {\n\t\tstatic int push(lua_State* L, c_closure cc) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushcclosure(L, cc.c_function, cc.upvalues);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <typename Arg, typename... Args>\n\tstruct unqualified_pusher<closure<Arg, Args...>> {\n\t\ttemplate <std::size_t... I, typename T>\n\t\tstatic int push(std::index_sequence<I...>, lua_State* L, T&& c) {\n\t\t\tusing f_tuple = decltype(std::forward<T>(c).upvalues);\n\t\t\tint pushcount = multi_push(L, std::get<I>(std::forward<f_tuple>(std::forward<T>(c).upvalues))...);\n\t\t\treturn stack::push(L, c_closure(c.c_function, pushcount));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tstatic int push(lua_State* L, T&& c) {\n\t\t\treturn push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward<T>(c));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<void*> {\n\t\tstatic int push(lua_State* L, void* userdata) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlightuserdata(L, userdata);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<const void*> {\n\t\tstatic int push(lua_State* L, const void* userdata) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlightuserdata(L, const_cast<void*>(userdata));\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<lightuserdata_value> {\n\t\tstatic int push(lua_State* L, lightuserdata_value userdata) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlightuserdata(L, userdata);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<light<T>> {\n\t\tstatic int push(lua_State* L, light<T> l) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlightuserdata(L, static_cast<void*>(l.value));\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<user<T>> {\n\t\ttemplate <bool with_meta = true, typename Key, typename... Args>\n\t\tstatic int push_with(lua_State* L, Key&& name, Args&&... args) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);\n#endif // make sure stack doesn't overflow\n       // A dumb pusher\n\t\t\tT* data = detail::user_allocate<T>(L);\n\t\t\tif (with_meta) {\n\t\t\t\t// Make sure we have a plain GC set for this data\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\tif (luaL_newmetatable(L, name) != 0) {\n\t\t\t\t\tlua_CFunction cdel = detail::user_alloc_destruct<T>;\n\t\t\t\t\tlua_pushcclosure(L, cdel, 0);\n\t\t\t\t\tlua_setfield(L, -2, \"__gc\");\n\t\t\t\t}\n\t\t\t\tlua_setmetatable(L, -2);\n\t\t\t}\n\t\t\tstd::allocator<T> alloc {};\n\t\t\tstd::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...);\n\t\t\treturn 1;\n\t\t}\n\n\t\ttemplate <typename Arg, typename... Args>\n\t\tstatic int push(lua_State* L, Arg&& arg, Args&&... args) {\n\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Arg>, metatable_key_t>) {\n\t\t\t\tconst auto name = &arg[0];\n\t\t\t\treturn push_with<true>(L, name, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<meta::unqualified_t<Arg>, no_metatable_t>) {\n\t\t\t\t(void)arg;\n\t\t\t\tconst auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];\n\t\t\t\treturn push_with<false>(L, name, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];\n\t\t\t\treturn push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\tstatic int push(lua_State* L, const user<T>& u) {\n\t\t\tconst auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];\n\t\t\treturn push_with(L, name, u.value);\n\t\t}\n\n\t\tstatic int push(lua_State* L, user<T>&& u) {\n\t\t\tconst auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];\n\t\t\treturn push_with(L, name, std::move(u.value));\n\t\t}\n\n\t\tstatic int push(lua_State* L, no_metatable_t, const user<T>& u) {\n\t\t\tconst auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];\n\t\t\treturn push_with<false>(L, name, u.value);\n\t\t}\n\n\t\tstatic int push(lua_State* L, no_metatable_t, user<T>&& u) {\n\t\t\tconst auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];\n\t\t\treturn push_with<false>(L, name, std::move(u.value));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<userdata_value> {\n\t\tstatic int push(lua_State* L, userdata_value data) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);\n#endif // make sure stack doesn't overflow\n\t\t\tvoid** ud = detail::usertype_allocate_pointer<void>(L);\n\t\t\t*ud = data.value;\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<const char*> {\n\t\tstatic int push_sized(lua_State* L, const char* str, std::size_t len) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_string);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlstring(L, str, len);\n\t\t\treturn 1;\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char* str) {\n\t\t\tif (str == nullptr)\n\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\treturn push_sized(L, str, std::char_traits<char>::length(str));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char* strb, const char* stre) {\n\t\t\treturn push_sized(L, strb, stre - strb);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char* str, std::size_t len) {\n\t\t\treturn push_sized(L, str, len);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<char*> {\n\t\tstatic int push_sized(lua_State* L, const char* str, std::size_t len) {\n\t\t\tunqualified_pusher<const char*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push_sized(L, str, len);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char* str) {\n\t\t\tunqualified_pusher<const char*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char* strb, const char* stre) {\n\t\t\tunqualified_pusher<const char*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, strb, stre);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char* str, std::size_t len) {\n\t\t\tunqualified_pusher<const char*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str, len);\n\t\t}\n\t};\n\n\ttemplate <size_t N>\n\tstruct unqualified_pusher<char[N]> {\n\t\tstatic int push(lua_State* L, const char (&str)[N]) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_string);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlstring(L, str, std::char_traits<char>::length(str));\n\t\t\treturn 1;\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char (&str)[N], std::size_t sz) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_string);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlstring(L, str, sz);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<char> {\n\t\tstatic int push(lua_State* L, char c) {\n\t\t\tconst char str[2] = { c, '\\0' };\n\t\t\treturn stack::push(L, static_cast<const char*>(str), 1);\n\t\t}\n\t};\n\n\ttemplate <typename Ch, typename Traits, typename Al>\n\tstruct unqualified_pusher<std::basic_string<Ch, Traits, Al>> {\n\t\tstatic int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str) {\n\t\t\tif constexpr (!std::is_same_v<Ch, char>) {\n\t\t\t\treturn stack::push(L, str.data(), str.size());\n\t\t\t}\n\t\t\telse {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_string);\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushlstring(L, str.c_str(), str.size());\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\n\t\tstatic int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str, std::size_t sz) {\n\t\t\tif constexpr (!std::is_same_v<Ch, char>) {\n\t\t\t\treturn stack::push(L, str.data(), sz);\n\t\t\t}\n\t\t\telse {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_string);\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushlstring(L, str.c_str(), sz);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename Ch, typename Traits>\n\tstruct unqualified_pusher<basic_string_view<Ch, Traits>> {\n\t\tstatic int push(lua_State* L, const basic_string_view<Ch, Traits>& sv) {\n\t\t\treturn stack::push(L, sv.data(), sv.length());\n\t\t}\n\n\t\tstatic int push(lua_State* L, const basic_string_view<Ch, Traits>& sv, std::size_t n) {\n\t\t\treturn stack::push(L, sv.data(), n);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<meta_function> {\n\t\tstatic int push(lua_State* L, meta_function m) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name);\n#endif // make sure stack doesn't overflow\n\t\t\tconst std::string& str = to_string(m);\n\t\t\tlua_pushlstring(L, str.c_str(), str.size());\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<absolute_index> {\n\t\tstatic int push(lua_State* L, absolute_index ai) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushvalue(L, ai);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<raw_index> {\n\t\tstatic int push(lua_State* L, raw_index ri) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushvalue(L, ri);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<ref_index> {\n\t\tstatic int push(lua_State* L, ref_index ri) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_rawgeti(L, LUA_REGISTRYINDEX, ri);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<const wchar_t*> {\n\t\tstatic int push(lua_State* L, const wchar_t* wstr) {\n\t\t\treturn push(L, wstr, std::char_traits<wchar_t>::length(wstr));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const wchar_t* wstr, std::size_t sz) {\n\t\t\treturn push(L, wstr, wstr + sz);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) {\n\t\t\tif constexpr (sizeof(wchar_t) == 2) {\n\t\t\t\tconst char16_t* sb = reinterpret_cast<const char16_t*>(strb);\n\t\t\t\tconst char16_t* se = reinterpret_cast<const char16_t*>(stre);\n\t\t\t\treturn stack::push(L, sb, se);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst char32_t* sb = reinterpret_cast<const char32_t*>(strb);\n\t\t\t\tconst char32_t* se = reinterpret_cast<const char32_t*>(stre);\n\t\t\t\treturn stack::push(L, sb, se);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<wchar_t*> {\n\t\tstatic int push(lua_State* L, const wchar_t* str) {\n\t\t\tunqualified_pusher<const wchar_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) {\n\t\t\tunqualified_pusher<const wchar_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, strb, stre);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const wchar_t* str, std::size_t len) {\n\t\t\tunqualified_pusher<const wchar_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str, len);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<const char16_t*> {\n\t\tstatic int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) {\n\t\t\tchar* target = start;\n\t\t\tchar32_t cp = 0;\n\t\t\tfor (const char16_t* strtarget = strb; strtarget < stre;) {\n\t\t\t\tauto dr = unicode::utf16_to_code_point(strtarget, stre);\n\t\t\t\tif (dr.error != unicode::error_code::ok) {\n\t\t\t\t\tcp = unicode::unicode_detail::replacement;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcp = dr.codepoint;\n\t\t\t\t}\n\t\t\t\tauto er = unicode::code_point_to_utf8(cp);\n\t\t\t\tconst char* utf8data = er.code_units.data();\n\t\t\t\tstd::memcpy(target, utf8data, er.code_units_size);\n\t\t\t\ttarget += er.code_units_size;\n\t\t\t\tstrtarget = dr.next;\n\t\t\t}\n\n\t\t\treturn stack::push(L, start, target);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char16_t* u16str) {\n\t\t\treturn push(L, u16str, std::char_traits<char16_t>::length(u16str));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char16_t* u16str, std::size_t sz) {\n\t\t\treturn push(L, u16str, u16str + sz);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char16_t* strb, const char16_t* stre) {\n\t\t\tchar sbo[SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_];\n\t\t\t// if our max string space is small enough, use SBO\n\t\t\t// right off the bat\n\t\t\tstd::size_t max_possible_code_units = (stre - strb) * 4;\n\t\t\tif (max_possible_code_units <= SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) {\n\t\t\t\treturn convert_into(L, sbo, max_possible_code_units, strb, stre);\n\t\t\t}\n\t\t\t// otherwise, we must manually count/check size\n\t\t\tstd::size_t needed_size = 0;\n\t\t\tfor (const char16_t* strtarget = strb; strtarget < stre;) {\n\t\t\t\tauto dr = unicode::utf16_to_code_point(strtarget, stre);\n\t\t\t\tauto er = unicode::code_point_to_utf8(dr.codepoint);\n\t\t\t\tneeded_size += er.code_units_size;\n\t\t\t\tstrtarget = dr.next;\n\t\t\t}\n\t\t\tif (needed_size < SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) {\n\t\t\t\treturn convert_into(L, sbo, needed_size, strb, stre);\n\t\t\t}\n\t\t\tstd::string u8str(\"\", 0);\n\t\t\tu8str.resize(needed_size);\n\t\t\tchar* target = const_cast<char*>(u8str.data());\n\t\t\treturn convert_into(L, target, needed_size, strb, stre);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<char16_t*> {\n\t\tstatic int push(lua_State* L, const char16_t* str) {\n\t\t\tunqualified_pusher<const char16_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char16_t* strb, const char16_t* stre) {\n\t\t\tunqualified_pusher<const char16_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, strb, stre);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char16_t* str, std::size_t len) {\n\t\t\tunqualified_pusher<const char16_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str, len);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<const char32_t*> {\n\t\tstatic int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) {\n\t\t\tchar* target = start;\n\t\t\tchar32_t cp = 0;\n\t\t\tfor (const char32_t* strtarget = strb; strtarget < stre;) {\n\t\t\t\tauto dr = unicode::utf32_to_code_point(strtarget, stre);\n\t\t\t\tif (dr.error != unicode::error_code::ok) {\n\t\t\t\t\tcp = unicode::unicode_detail::replacement;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcp = dr.codepoint;\n\t\t\t\t}\n\t\t\t\tauto er = unicode::code_point_to_utf8(cp);\n\t\t\t\tconst char* data = er.code_units.data();\n\t\t\t\tstd::memcpy(target, data, er.code_units_size);\n\t\t\t\ttarget += er.code_units_size;\n\t\t\t\tstrtarget = dr.next;\n\t\t\t}\n\t\t\treturn stack::push(L, start, target);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char32_t* u32str) {\n\t\t\treturn push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char32_t* u32str, std::size_t sz) {\n\t\t\treturn push(L, u32str, u32str + sz);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char32_t* strb, const char32_t* stre) {\n\t\t\tchar sbo[SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_];\n\t\t\t// if our max string space is small enough, use SBO\n\t\t\t// right off the bat\n\t\t\tstd::size_t max_possible_code_units = (stre - strb) * 4;\n\t\t\tif (max_possible_code_units <= SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) {\n\t\t\t\treturn convert_into(L, sbo, max_possible_code_units, strb, stre);\n\t\t\t}\n\t\t\t// otherwise, we must manually count/check size\n\t\t\tstd::size_t needed_size = 0;\n\t\t\tfor (const char32_t* strtarget = strb; strtarget < stre;) {\n\t\t\t\tauto dr = unicode::utf32_to_code_point(strtarget, stre);\n\t\t\t\tauto er = unicode::code_point_to_utf8(dr.codepoint);\n\t\t\t\tneeded_size += er.code_units_size;\n\t\t\t\tstrtarget = dr.next;\n\t\t\t}\n\t\t\tif (needed_size < SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) {\n\t\t\t\treturn convert_into(L, sbo, needed_size, strb, stre);\n\t\t\t}\n\t\t\tstd::string u8str(\"\", 0);\n\t\t\tu8str.resize(needed_size);\n\t\t\tchar* target = const_cast<char*>(u8str.data());\n\t\t\treturn convert_into(L, target, needed_size, strb, stre);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<char32_t*> {\n\t\tstatic int push(lua_State* L, const char32_t* str) {\n\t\t\tunqualified_pusher<const char32_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char32_t* strb, const char32_t* stre) {\n\t\t\tunqualified_pusher<const char32_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, strb, stre);\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char32_t* str, std::size_t len) {\n\t\t\tunqualified_pusher<const char32_t*> p {};\n\t\t\t(void)p;\n\t\t\treturn p.push(L, str, len);\n\t\t}\n\t};\n\n\ttemplate <size_t N>\n\tstruct unqualified_pusher<wchar_t[N]> {\n\t\tstatic int push(lua_State* L, const wchar_t (&str)[N]) {\n\t\t\treturn push(L, str, std::char_traits<wchar_t>::length(str));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) {\n\t\t\tconst wchar_t* str_ptr = static_cast<const wchar_t*>(str);\n\t\t\treturn stack::push<const wchar_t*>(L, str_ptr, str_ptr + sz);\n\t\t}\n\t};\n\n\ttemplate <size_t N>\n\tstruct unqualified_pusher<char16_t[N]> {\n\t\tstatic int push(lua_State* L, const char16_t (&str)[N]) {\n\t\t\treturn push(L, str, std::char_traits<char16_t>::length(str));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) {\n\t\t\tconst char16_t* str_ptr = static_cast<const char16_t*>(str);\n\t\t\treturn stack::push<const char16_t*>(L, str_ptr, str_ptr + sz);\n\t\t}\n\t};\n\n\ttemplate <size_t N>\n\tstruct unqualified_pusher<char32_t[N]> {\n\t\tstatic int push(lua_State* L, const char32_t (&str)[N]) {\n\t\t\treturn push(L, str, std::char_traits<char32_t>::length(str));\n\t\t}\n\n\t\tstatic int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) {\n\t\t\tconst char32_t* str_ptr = static_cast<const char32_t*>(str);\n\t\t\treturn stack::push<const char32_t*>(L, str_ptr, str_ptr + sz);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<wchar_t> {\n\t\tstatic int push(lua_State* L, wchar_t c) {\n\t\t\tconst wchar_t str[2] = { c, '\\0' };\n\t\t\treturn stack::push(L, static_cast<const wchar_t*>(str), 1);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<char16_t> {\n\t\tstatic int push(lua_State* L, char16_t c) {\n\t\t\tconst char16_t str[2] = { c, '\\0' };\n\t\t\treturn stack::push(L, static_cast<const char16_t*>(str), 1);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<char32_t> {\n\t\tstatic int push(lua_State* L, char32_t c) {\n\t\t\tconst char32_t str[2] = { c, '\\0' };\n\t\t\treturn stack::push(L, static_cast<const char32_t*>(str), 1);\n\t\t}\n\t};\n\n\ttemplate <typename... Args>\n\tstruct unqualified_pusher<std::tuple<Args...>> {\n\t\ttemplate <std::size_t... I, typename T>\n\t\tstatic int push(std::index_sequence<I...>, lua_State* L, T&& t) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, static_cast<int>(sizeof...(I)), detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tint pushcount = 0;\n\t\t\t(void)detail::swallow { 0, (pushcount += stack::push(L, std::get<I>(std::forward<T>(t))), 0)... };\n\t\t\treturn pushcount;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tstatic int push(lua_State* L, T&& t) {\n\t\t\treturn push(std::index_sequence_for<Args...>(), L, std::forward<T>(t));\n\t\t}\n\t};\n\n\ttemplate <typename A, typename B>\n\tstruct unqualified_pusher<std::pair<A, B>> {\n\t\ttemplate <typename T>\n\t\tstatic int push(lua_State* L, T&& t) {\n\t\t\tint pushcount = stack::push(L, std::get<0>(std::forward<T>(t)));\n\t\t\tpushcount += stack::push(L, std::get<1>(std::forward<T>(t)));\n\t\t\treturn pushcount;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct unqualified_pusher<T, std::enable_if_t<meta::is_optional_v<T>>> {\n\t\tusing ValueType = typename meta::unqualified_t<T>::value_type;\n\n\t\ttemplate <typename Optional>\n\t\tstatic int push(lua_State* L, Optional&& op) {\n\t\t\tusing QualifiedValueType = meta::conditional_t<std::is_lvalue_reference_v<Optional>, ValueType&, ValueType&&>;\n\t\t\tif (!op) {\n\t\t\t\treturn stack::push(L, nullopt);\n\t\t\t}\n\t\t\treturn stack::push(L, static_cast<QualifiedValueType>(op.value()));\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<nullopt_t> {\n\t\tstatic int push(lua_State* L, nullopt_t) {\n\t\t\treturn stack::push(L, lua_nil);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<std::nullptr_t> {\n\t\tstatic int push(lua_State* L, std::nullptr_t) {\n\t\t\treturn stack::push(L, lua_nil);\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<this_state> {\n\t\tstatic int push(lua_State*, const this_state&) {\n\t\t\treturn 0;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<this_main_state> {\n\t\tstatic int push(lua_State*, const this_main_state&) {\n\t\t\treturn 0;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct unqualified_pusher<new_table> {\n\t\tstatic int push(lua_State* L, const new_table& nt) {\n\t\t\tlua_createtable(L, nt.sequence_hint, nt.map_hint);\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <typename Allocator>\n\tstruct unqualified_pusher<basic_bytecode<Allocator>> {\n\t\ttemplate <typename T>\n\t\tstatic int push(lua_State* L, T&& bc, const char* bytecode_name) {\n\t\t\tconst auto first = bc.data();\n\t\t\tconst auto bcsize = bc.size();\n\t\t\t// pushes either the function, or an error\n\t\t\t// if it errors, shit goes south, and people can test that upstream\n\t\t\t(void)luaL_loadbuffer(\n\t\t\t\tL, reinterpret_cast<const char*>(first), static_cast<std::size_t>(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name);\n\t\t\treturn 1;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tstatic int push(lua_State* L, T&& bc) {\n\t\t\treturn push(L, std::forward<bc>(bc), \"bytecode\");\n\t\t}\n\t};\n\n#if SOL_IS_ON(SOL_STD_VARIANT_I_)\n\tnamespace stack_detail {\n\n\t\tstruct push_function {\n\t\t\tlua_State* L;\n\n\t\t\tpush_function(lua_State* L) : L(L) {\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tint operator()(T&& value) const {\n\t\t\t\treturn stack::push<T>(L, std::forward<T>(value));\n\t\t\t}\n\t\t};\n\n\t} // namespace stack_detail\n\n\ttemplate <typename... Tn>\n\tstruct unqualified_pusher<std::variant<Tn...>> {\n\t\tstatic int push(lua_State* L, const std::variant<Tn...>& v) {\n\t\t\treturn std::visit(stack_detail::push_function(L), v);\n\t\t}\n\n\t\tstatic int push(lua_State* L, std::variant<Tn...>&& v) {\n\t\t\treturn std::visit(stack_detail::push_function(L), std::move(v));\n\t\t}\n\t};\n#endif // Variant because Clang is terrible\n\n}} // namespace sol::stack\n\n// end of sol/stack_push.hpp\n\n// beginning of sol/stack_pop.hpp\n\n#include <utility>\n#include <tuple>\n\nnamespace sol {\nnamespace stack {\n\ttemplate <typename T, typename>\n\tstruct popper {\n\t\tinline static decltype(auto) pop(lua_State* L) {\n\t\t\tif constexpr (is_stack_based_v<meta::unqualified_t<T>>) {\n\t\t\t\tstatic_assert(!is_stack_based_v<meta::unqualified_t<T>>,\n\t\t\t\t\t\"You cannot pop something that lives solely on the stack: it will not remain on the stack when popped and thusly will go out of \"\n\t\t\t\t\t\"scope!\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\trecord tracking{};\n\t\t\t\tdecltype(auto) r = get<T>(L, -lua_size<T>::value, tracking);\n\t\t\t\tlua_pop(L, tracking.used);\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\t};\n}\n} // namespace sol::stack\n\n// end of sol/stack_pop.hpp\n\n// beginning of sol/stack_field.hpp\n\nnamespace sol { namespace stack {\n\ttemplate <typename T, bool global, bool raw, typename>\n\tstruct field_getter {\n\t\tstatic constexpr int default_table_index = meta::conditional_t < meta::is_c_str_v<T>\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t|| (std::is_integral_v<T> && !std::is_same_v<T, bool>)\n#endif // integer  global keys 5.3 or better\n\t\t\t|| (raw && std::is_void_v<std::remove_pointer_t<T>>),\n\t\t\t                std::integral_constant<int, -1>, std::integral_constant<int, -2> > ::value;\n\n\t\ttemplate <typename Key>\n\t\tvoid get(lua_State* L, Key&& key, int tableindex = default_table_index) {\n\t\t\tif constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t> || std::is_same_v<T, create_if_nil_t>) {\n\t\t\t\t(void)L;\n\t\t\t\t(void)key;\n\t\t\t\t(void)tableindex;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, env_key_t>) {\n\t\t\t\t(void)key;\n#if SOL_LUA_VESION_I_ < 502\n\t\t\t\t// Use lua_setfenv\n\t\t\t\tlua_getfenv(L, tableindex);\n#else\n\t\t\t\t// Use upvalues as explained in Lua 5.2 and beyond's manual\n\t\t\t\tif (lua_getupvalue(L, tableindex, 1) == nullptr) {\n\t\t\t\t\tpush(L, lua_nil);\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, metatable_key_t>) {\n\t\t\t\t(void)key;\n\t\t\t\tif (lua_getmetatable(L, tableindex) == 0)\n\t\t\t\t\tpush(L, lua_nil);\n\t\t\t}\n\t\t\telse if constexpr (raw) {\n\t\t\t\tif constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {\n\t\t\t\t\tlua_rawgeti(L, tableindex, static_cast<lua_Integer>(key));\n\t\t\t\t}\n#if SOL_LUA_VESION_I_ >= 502\n\t\t\t\telse if constexpr (std::is_void_v<std::remove_pointer_t<T>>) {\n\t\t\t\t\tlua_rawgetp(L, tableindex, key);\n\t\t\t\t}\n#endif // Lua 5.2.x+\n\t\t\t\telse {\n\t\t\t\t\tpush(L, std::forward<Key>(key));\n\t\t\t\t\tlua_rawget(L, tableindex);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif constexpr (meta::is_c_str_v<T>) {\n\t\t\t\t\tif constexpr (global) {\n\t\t\t\t\t\t(void)tableindex;\n\t\t\t\t\t\tlua_getglobal(L, &key[0]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tlua_getfield(L, tableindex, &key[0]);\n\t\t\t\t\t}\n\t\t\t\t}\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\telse if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {\n\t\t\t\t\tlua_geti(L, tableindex, static_cast<lua_Integer>(key));\n\t\t\t\t}\n#endif // Lua 5.3.x+\n\t\t\t\telse {\n\t\t\t\t\tpush(L, std::forward<Key>(key));\n\t\t\t\t\tlua_gettable(L, tableindex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename... Args, bool b, bool raw, typename C>\n\tstruct field_getter<std::tuple<Args...>, b, raw, C> {\n\t\ttemplate <std::size_t... I, typename Keys>\n\t\tvoid apply(std::index_sequence<0, I...>, lua_State* L, Keys&& keys, int tableindex) {\n\t\t\tget_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex);\n\t\t\tvoid(detail::swallow { (get_field<false, raw>(L, std::get<I>(std::forward<Keys>(keys))), 0)... });\n\t\t\treference saved(L, -1);\n\t\t\tlua_pop(L, static_cast<int>(sizeof...(I)));\n\t\t\tsaved.push();\n\t\t}\n\n\t\ttemplate <typename Keys>\n\t\tvoid get(lua_State* L, Keys&& keys) {\n\t\t\tapply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), lua_absindex(L, -1));\n\t\t}\n\n\t\ttemplate <typename Keys>\n\t\tvoid get(lua_State* L, Keys&& keys, int tableindex) {\n\t\t\tapply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), tableindex);\n\t\t}\n\t};\n\n\ttemplate <typename A, typename B, bool b, bool raw, typename C>\n\tstruct field_getter<std::pair<A, B>, b, raw, C> {\n\t\ttemplate <typename Keys>\n\t\tvoid get(lua_State* L, Keys&& keys, int tableindex) {\n\t\t\tget_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex);\n\t\t\tget_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys)));\n\t\t\treference saved(L, -1);\n\t\t\tlua_pop(L, static_cast<int>(2));\n\t\t\tsaved.push();\n\t\t}\n\n\t\ttemplate <typename Keys>\n\t\tvoid get(lua_State* L, Keys&& keys) {\n\t\t\tget_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)));\n\t\t\tget_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys)));\n\t\t\treference saved(L, -1);\n\t\t\tlua_pop(L, static_cast<int>(2));\n\t\t\tsaved.push();\n\t\t}\n\t};\n\n\ttemplate <typename T, bool global, bool raw, typename>\n\tstruct field_setter {\n\t\tstatic constexpr int default_table_index\n\t\t\t= meta::conditional_t < (meta::is_c_str_v<T> || meta::is_string_of_v<T, char>) || (std::is_integral_v<T> && !std::is_same_v<T, bool>)\n\t\t\t|| (std::is_integral_v<T> && !std::is_same_v<T, bool>) || (raw && std::is_void_v<std::remove_pointer_t<T>>),\n\t\t\tstd::integral_constant<int, -2>, std::integral_constant<int, -3> > ::value;\n\n\t\ttemplate <typename Key, typename Value>\n\t\tvoid set(lua_State* L, Key&& key, Value&& value, int tableindex = default_table_index) {\n\t\t\tif constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t>) {\n\t\t\t\t(void)L;\n\t\t\t\t(void)key;\n\t\t\t\t(void)value;\n\t\t\t\t(void)tableindex;\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, metatable_key_t>) {\n\t\t\t\t(void)key;\n\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\tlua_setmetatable(L, tableindex);\n\t\t\t}\n\t\t\telse if constexpr (raw) {\n\t\t\t\tif constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {\n\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\tlua_rawseti(L, tableindex, static_cast<lua_Integer>(key));\n\t\t\t\t}\n#if SOL_LUA_VESION_I_ >= 502\n\t\t\t\telse if constexpr (std::is_void_v<std::remove_pointer_t<T>>) {\n\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\tlua_rawsetp(L, tableindex, std::forward<Key>(key));\n\t\t\t\t}\n#endif // Lua 5.2.x\n\t\t\t\telse {\n\t\t\t\t\tpush(L, std::forward<Key>(key));\n\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\tlua_rawset(L, tableindex);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif constexpr (meta::is_c_str_v<T> || meta::is_string_of_v<T, char>) {\n\t\t\t\t\tif constexpr (global) {\n\t\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\t\tlua_setglobal(L, &key[0]);\n\t\t\t\t\t\t(void)tableindex;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\t\tlua_setfield(L, tableindex, &key[0]);\n\t\t\t\t\t}\n\t\t\t\t}\n#if SOL_LUA_VESION_I_ >= 503\n\t\t\t\telse if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {\n\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\tlua_seti(L, tableindex, static_cast<lua_Integer>(key));\n\t\t\t\t}\n#endif // Lua 5.3.x\n\t\t\t\telse {\n\t\t\t\t\tpush(L, std::forward<Key>(key));\n\t\t\t\t\tpush(L, std::forward<Value>(value));\n\t\t\t\t\tlua_settable(L, tableindex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename... Args, bool b, bool raw, typename C>\n\tstruct field_setter<std::tuple<Args...>, b, raw, C> {\n\t\ttemplate <bool g, std::size_t I, typename Keys, typename Value>\n\t\tvoid apply(std::index_sequence<I>, lua_State* L, Keys&& keys, Value&& value, int tableindex) {\n\t\t\tI < 1 ? set_field<g, raw>(L, std::get<I>(std::forward<Keys>(keys)), std::forward<Value>(value), tableindex)\n\t\t\t\t : set_field<g, raw>(L, std::get<I>(std::forward<Keys>(keys)), std::forward<Value>(value));\n\t\t}\n\n\t\ttemplate <bool g, std::size_t I0, std::size_t I1, std::size_t... I, typename Keys, typename Value>\n\t\tvoid apply(std::index_sequence<I0, I1, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) {\n\t\t\tI0 < 1 ? get_field<g, raw>(L, std::get<I0>(std::forward<Keys>(keys)), tableindex)\n\t\t\t\t  : get_field<g, raw>(L, std::get<I0>(std::forward<Keys>(keys)), -1);\n\t\t\tapply<false>(std::index_sequence<I1, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), -1);\n\t\t}\n\n\t\ttemplate <bool g, std::size_t I0, std::size_t... I, typename Keys, typename Value>\n\t\tvoid top_apply(std::index_sequence<I0, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) {\n\t\t\tapply<g>(std::index_sequence<I0, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex);\n\t\t\tlua_pop(L, static_cast<int>(sizeof...(I)));\n\t\t}\n\n\t\ttemplate <typename Keys, typename Value>\n\t\tvoid set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -3) {\n\t\t\ttop_apply<b>(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex);\n\t\t}\n\t};\n\n\ttemplate <typename A, typename B, bool b, bool raw, typename C>\n\tstruct field_setter<std::pair<A, B>, b, raw, C> {\n\t\ttemplate <typename Keys, typename Value>\n\t\tvoid set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) {\n\t\t\tget_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex);\n\t\t\tset_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys)), std::forward<Value>(value), lua_gettop(L));\n\t\t\tlua_pop(L, 1);\n\t\t}\n\t};\n}} // namespace sol::stack\n\n// end of sol/stack_field.hpp\n\n// beginning of sol/stack_probe.hpp\n\nnamespace sol {\nnamespace stack {\n\ttemplate <typename T, typename P, bool b, bool raw, typename>\n\tstruct probe_field_getter {\n\t\ttemplate <typename Key>\n\t\tprobe get(lua_State* L, Key&& key, int tableindex = -2) {\n\t\t\tif constexpr(!b) {\n\t\t\t\tif (!maybe_indexable(L, tableindex)) {\n\t\t\t\t\treturn probe(false, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t\tget_field<b, raw>(L, std::forward<Key>(key), tableindex);\n\t\t\treturn probe(check<P>(L), 1);\n\t\t}\n\t};\n\n\ttemplate <typename A, typename B, typename P, bool b, bool raw, typename C>\n\tstruct probe_field_getter<std::pair<A, B>, P, b, raw, C> {\n\t\ttemplate <typename Keys>\n\t\tprobe get(lua_State* L, Keys&& keys, int tableindex = -2) {\n\t\t\tif (!b && !maybe_indexable(L, tableindex)) {\n\t\t\t\treturn probe(false, 0);\n\t\t\t}\n\t\t\tget_field<b, raw>(L, std::get<0>(keys), tableindex);\n\t\t\tif (!maybe_indexable(L)) {\n\t\t\t\treturn probe(false, 1);\n\t\t\t}\n\t\t\tget_field<false, raw>(L, std::get<1>(keys), tableindex);\n\t\t\treturn probe(check<P>(L), 2);\n\t\t}\n\t};\n\n\ttemplate <typename... Args, typename P, bool b, bool raw, typename C>\n\tstruct probe_field_getter<std::tuple<Args...>, P, b, raw, C> {\n\t\ttemplate <std::size_t I, typename Keys>\n\t\tprobe apply(std::index_sequence<I>, int sofar, lua_State* L, Keys&& keys, int tableindex) {\n\t\t\tget_field<(I<1) && b, raw>(L, std::get<I>(keys), tableindex);\n\t\t\treturn probe(check<P>(L), sofar);\n\t\t}\n\n\t\ttemplate <std::size_t I, std::size_t I1, std::size_t... In, typename Keys>\n\t\tprobe apply(std::index_sequence<I, I1, In...>, int sofar, lua_State* L, Keys&& keys, int tableindex) {\n\t\t\tget_field < I<1 && b, raw>(L, std::get<I>(keys), tableindex);\n\t\t\tif (!maybe_indexable(L)) {\n\t\t\t\treturn probe(false, sofar);\n\t\t\t}\n\t\t\treturn apply(std::index_sequence<I1, In...>(), sofar + 1, L, std::forward<Keys>(keys), -1);\n\t\t}\n\n\t\ttemplate <typename Keys>\n\t\tprobe get(lua_State* L, Keys&& keys, int tableindex = -2) {\n\t\t\tif constexpr (!b) {\n\t\t\t\tif (!maybe_indexable(L, tableindex)) {\n\t\t\t\t\treturn probe(false, 0);\n\t\t\t\t}\n\t\t\t\treturn apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex);\n\t\t\t}\n\t\t}\n\t};\n}\n} // namespace sol::stack\n\n// end of sol/stack_probe.hpp\n\n#include <cstring>\n#include <array>\n\nnamespace sol {\n\tnamespace detail {\n\t\tusing typical_chunk_name_t = char[SOL_ID_SIZE_I_];\n\t\tusing typical_file_chunk_name_t = char[SOL_FILE_ID_SIZE_I_];\n\n\t\tinline const std::string& default_chunk_name() {\n\t\t\tstatic const std::string name = \"\";\n\t\t\treturn name;\n\t\t}\n\n\t\ttemplate <std::size_t N>\n\t\tconst char* make_chunk_name(const string_view& code, const std::string& chunkname, char (&basechunkname)[N]) {\n\t\t\tif (chunkname.empty()) {\n\t\t\t\tauto it = code.cbegin();\n\t\t\t\tauto e = code.cend();\n\t\t\t\tstd::size_t i = 0;\n\t\t\t\tstatic const std::size_t n = N - 4;\n\t\t\t\tfor (i = 0; i < n && it != e; ++i, ++it) {\n\t\t\t\t\tbasechunkname[i] = *it;\n\t\t\t\t}\n\t\t\t\tif (it != e) {\n\t\t\t\t\tfor (std::size_t c = 0; c < 3; ++i, ++c) {\n\t\t\t\t\t\tbasechunkname[i] = '.';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbasechunkname[i] = '\\0';\n\t\t\t\treturn &basechunkname[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn chunkname.c_str();\n\t\t\t}\n\t\t}\n\n\t\tinline void clear_entries(stack_reference r) {\n\t\t\tstack::push(r.lua_state(), lua_nil);\n\t\t\twhile (lua_next(r.lua_state(), -2)) {\n\t\t\t\tabsolute_index key(r.lua_state(), -2);\n\t\t\t\tauto pn = stack::pop_n(r.lua_state(), 1);\n\t\t\t\tstack::set_field<false, true>(r.lua_state(), key, lua_nil, r.stack_index());\n\t\t\t}\n\t\t}\n\n\t\tinline void clear_entries(const reference& registry_reference) {\n\t\t\tauto pp = stack::push_pop(registry_reference);\n\t\t\tstack_reference ref(registry_reference.lua_state(), -1);\n\t\t\tclear_entries(ref);\n\t\t}\n\t} // namespace detail\n\n\tnamespace stack {\n\t\tnamespace stack_detail {\n\t\t\ttemplate <typename T>\n\t\t\tinline int push_as_upvalues(lua_State* L, T& item) {\n\t\t\t\ttypedef std::decay_t<T> TValue;\n\t\t\t\tstatic const std::size_t itemsize = sizeof(TValue);\n\t\t\t\tstatic const std::size_t voidsize = sizeof(void*);\n\t\t\t\tstatic const std::size_t voidsizem1 = voidsize - 1;\n\t\t\t\tstatic const std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;\n\t\t\t\ttypedef std::array<void*, data_t_count> data_t;\n\n\t\t\t\tdata_t data { {} };\n\t\t\t\tstd::memcpy(&data[0], std::addressof(item), itemsize);\n\t\t\t\tint pushcount = 0;\n\t\t\t\tfor (const auto& v : data) {\n\t\t\t\t\tlua_pushlightuserdata(L, v);\n\t\t\t\t\tpushcount += 1;\n\t\t\t\t}\n\t\t\t\treturn pushcount;\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tinline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 2) {\n\t\t\t\tstatic const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*);\n\t\t\t\ttypedef std::array<void*, data_t_count> data_t;\n\t\t\t\tdata_t voiddata { {} };\n\t\t\t\tfor (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {\n\t\t\t\t\tvoiddata[i] = lua_touserdata(L, upvalue_index(index++));\n\t\t\t\t}\n\t\t\t\treturn std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);\n\t\t\t}\n\n\t\t\ttemplate <typename T>\n\t\t\tinline std::pair<T, int> get_as_upvalues_using_function(lua_State* L, int function_index = -1) {\n\t\t\t\tstatic const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*);\n\t\t\t\ttypedef std::array<void*, data_t_count> data_t;\n\t\t\t\tfunction_index = lua_absindex(L, function_index);\n\t\t\t\tint index = 0;\n\t\t\t\tdata_t voiddata { {} };\n\t\t\t\tfor (std::size_t d = 0; d < sizeof(T); d += sizeof(void*)) {\n\t\t\t\t\t// first upvalue is nullptr to respect environment shenanigans\n\t\t\t\t\t// So +2 instead of +1\n\t\t\t\t\tconst char* upvalue_name = lua_getupvalue(L, function_index, index + 2);\n\t\t\t\t\tif (upvalue_name == nullptr) {\n\t\t\t\t\t\t// We should freak out here...\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tvoiddata[index] = lua_touserdata(L, -1);\n\t\t\t\t\t++index;\n\t\t\t\t}\n\t\t\t\tlua_pop(L, index);\n\t\t\t\treturn std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);\n\t\t\t}\n\n\t\t\ttemplate <typename Fx, typename... Args>\n\t\t\tstatic decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) {\n\t\t\t\treturn std::forward<Fx>(fx)(std::forward<Args>(args)...);\n\t\t\t}\n\n\t\t\ttemplate <typename Fx, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename... FxArgs>\n\t\t\tstatic decltype(auto) eval(\n\t\t\t     types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) {\n\t\t\t\treturn eval(types<Args...>(),\n\t\t\t\t     std::index_sequence<Is...>(),\n\t\t\t\t     L,\n\t\t\t\t     start,\n\t\t\t\t     tracking,\n\t\t\t\t     std::forward<Fx>(fx),\n\t\t\t\t     std::forward<FxArgs>(fxargs)...,\n\t\t\t\t     stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking));\n\t\t\t}\n\n\t\t\ttemplate <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs>\n\t\t\tinline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {\n\t\t\t\tstatic_assert(meta::all<meta::is_not_move_only<Args>...>::value,\n\t\t\t\t     \"One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take \"\n\t\t\t\t     \"a reference and std::move it manually if this was your intention.\");\n\t\t\t\tif constexpr (checkargs) {\n\t\t\t\t\targument_handler<types<R, Args...>> handler {};\n\t\t\t\t\tmulti_check<Args...>(L, start, handler);\n\t\t\t\t}\n\t\t\t\trecord tracking {};\n\t\t\t\tif constexpr (std::is_void_v<R>) {\n\t\t\t\t\teval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);\n\t\t\t\t}\n\t\t\t}\n\t\t} // namespace stack_detail\n\n\t\ttemplate <typename T>\n\t\tint set_ref(lua_State* L, T&& arg, int tableindex = -2) {\n\t\t\tpush(L, std::forward<T>(arg));\n\t\t\treturn luaL_ref(L, tableindex);\n\t\t}\n\n\t\ttemplate <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs>\n\t\tinline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {\n\t\t\tusing args_indices = std::make_index_sequence<sizeof...(Args)>;\n\t\t\tif constexpr (std::is_void_v<R>) {\n\t\t\t\tstack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs>\n\t\tinline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {\n\t\t\tif constexpr (std::is_void_v<R>) {\n\t\t\t\tcall<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs>\n\t\tinline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {\n\t\t\tusing expected_count_t = meta::count_for_pack<lua_size, Args...>;\n\t\t\tif constexpr (std::is_void_v<R>) {\n\t\t\t\tcall<check_args>(tr,\n\t\t\t\t     ta,\n\t\t\t\t     L,\n\t\t\t\t     (std::max)(static_cast<int>(lua_gettop(L) - expected_count_t::value), static_cast<int>(0)),\n\t\t\t\t     std::forward<Fx>(fx),\n\t\t\t\t     std::forward<FxArgs>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn call<check_args>(tr,\n\t\t\t\t     ta,\n\t\t\t\t     L,\n\t\t\t\t     (std::max)(static_cast<int>(lua_gettop(L) - expected_count_t::value), static_cast<int>(0)),\n\t\t\t\t     std::forward<Fx>(fx),\n\t\t\t\t     std::forward<FxArgs>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args,\n\t\t     typename Fx, typename... FxArgs>\n\t\tinline int call_into_lua(types<Ret0, Ret...> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {\n\t\t\tif constexpr (std::is_void_v<Ret0>) {\n\t\t\t\tcall<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);\n\t\t\t\tif constexpr (clean_stack) {\n\t\t\t\t\tlua_settop(L, 0);\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t(void)tr;\n\t\t\t\tdecltype(auto) r\n\t\t\t\t     = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);\n\t\t\t\tusing R = meta::unqualified_t<decltype(r)>;\n\t\t\t\tusing is_stack = meta::any<is_stack_based<R>, std::is_same<R, absolute_index>, std::is_same<R, ref_index>, std::is_same<R, raw_index>>;\n\t\t\t\tif constexpr (clean_stack && !is_stack::value) {\n\t\t\t\t\tlua_settop(L, 0);\n\t\t\t\t}\n\t\t\t\treturn push_reference(L, std::forward<decltype(r)>(r));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... FxArgs>\n\t\tinline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {\n\t\t\tusing traits_type = lua_bind_traits<meta::unqualified_t<Fx>>;\n\t\t\tusing args_list = typename traits_type::args_list;\n\t\t\tusing returns_list = typename traits_type::returns_list;\n\t\t\treturn call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);\n\t\t}\n\n\t\tinline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) {\n\t\t\tif (lua_gettop(L) < 1) {\n\t\t\t\treturn call_syntax::dot;\n\t\t\t}\n\t\t\tluaL_getmetatable(L, key.data());\n\t\t\tauto pn = pop_n(L, 1);\n\t\t\tif (lua_compare(L, -1, index, LUA_OPEQ) != 1) {\n\t\t\t\treturn call_syntax::dot;\n\t\t\t}\n\t\t\treturn call_syntax::colon;\n\t\t}\n\n\t\tinline void script(\n\t\t     lua_State* L, lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(\"lua_Reader\", chunkname, basechunkname);\n\t\t\tif (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t}\n\n\t\tinline void script(\n\t\t     lua_State* L, const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);\n\t\t\tif (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t}\n\n\t\tinline void script_file(lua_State* L, const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\tif (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t}\n\n\t\tinline void luajit_exception_handler(lua_State* L, int (*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) {\n#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_)\n\t\t\tif (L == nullptr) {\n\t\t\t\treturn;\n\t\t\t}\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tlua_pushlightuserdata(L, (void*)handler);\n\t\t\tauto pn = pop_n(L, 1);\n\t\t\tluaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);\n#else\n\t\t\t(void)L;\n\t\t\t(void)handler;\n#endif\n\t\t}\n\n\t\tinline void luajit_exception_off(lua_State* L) {\n#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_)\n\t\t\tif (L == nullptr) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tluaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF);\n#else\n\t\t\t(void)L;\n#endif\n\t\t}\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/stack.hpp\n\n// beginning of sol/object.hpp\n\n// beginning of sol/make_reference.hpp\n\nnamespace sol {\n\n\ttemplate <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T>\n\tR make_reference(lua_State* L, T&& value) {\n\t\tint backpedal = stack::push(L, std::forward<T>(value));\n\t\tR r = stack::get<R>(L, -backpedal);\n\t\tif (should_pop) {\n\t\t\tlua_pop(L, backpedal);\n\t\t}\n\t\treturn r;\n\t}\n\n\ttemplate <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args>\n\tR make_reference(lua_State* L, Args&&... args) {\n\t\tint backpedal = stack::push<T>(L, std::forward<Args>(args)...);\n\t\tR r = stack::get<R>(L, -backpedal);\n\t\tif (should_pop) {\n\t\t\tlua_pop(L, backpedal);\n\t\t}\n\t\treturn r;\n\t}\n\n\ttemplate <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T>\n\tR make_reference_userdata(lua_State* L, T&& value) {\n\t\tint backpedal = stack::push_userdata(L, std::forward<T>(value));\n\t\tR r = stack::get<R>(L, -backpedal);\n\t\tif (should_pop) {\n\t\t\tlua_pop(L, backpedal);\n\t\t}\n\t\treturn r;\n\t}\n\n\ttemplate <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args>\n\tR make_reference_userdata(lua_State* L, Args&&... args) {\n\t\tint backpedal = stack::push_userdata<T>(L, std::forward<Args>(args)...);\n\t\tR r = stack::get<R>(L, -backpedal);\n\t\tif (should_pop) {\n\t\t\tlua_pop(L, backpedal);\n\t\t}\n\t\treturn r;\n\t}\n\n} // namespace sol\n\n// end of sol/make_reference.hpp\n\n// beginning of sol/object_base.hpp\n\nnamespace sol {\n\n\ttemplate <typename ref_t>\n\tclass basic_object_base : public ref_t {\n\tprivate:\n\t\tusing base_t = ref_t;\n\t\t\n\t\ttemplate <typename T>\n\t\tdecltype(auto) as_stack(std::true_type) const {\n\t\t\treturn stack::get<T>(base_t::lua_state(), base_t::stack_index());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) as_stack(std::false_type) const {\n\t\t\tbase_t::push();\n\t\t\treturn stack::pop<T>(base_t::lua_state());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool is_stack(std::true_type) const {\n\t\t\treturn stack::check<T>(base_t::lua_state(), base_t::stack_index(), no_panic);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool is_stack(std::false_type) const {\n\t\t\tint r = base_t::registry_index();\n\t\t\tif (r == LUA_REFNIL)\n\t\t\t\treturn meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false;\n\t\t\tif (r == LUA_NOREF)\n\t\t\t\treturn false;\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\treturn stack::check<T>(base_t::lua_state(), -1, no_panic);\n\t\t}\n\n\tpublic:\n\t\tbasic_object_base() noexcept = default;\n\t\tbasic_object_base(const basic_object_base&) = default;\n\t\tbasic_object_base(basic_object_base&&) = default;\n\t\tbasic_object_base& operator=(const basic_object_base&) = default;\n\t\tbasic_object_base& operator=(basic_object_base&&) = default;\n\t\ttemplate <typename T, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object_base>>> = meta::enabler>\n\t\tbasic_object_base(T&& arg, Args&&... args)\n\t\t: base_t(std::forward<T>(arg), std::forward<Args>(args)...) {\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) as() const {\n\t\t\treturn as_stack<T>(is_stack_based<base_t>());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool is() const {\n\t\t\treturn is_stack<T>(is_stack_based<base_t>());\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/object_base.hpp\n\nnamespace sol {\n\n\ttemplate <typename base_type>\n\tclass basic_object : public basic_object_base<base_type> {\n\tprivate:\n\t\ttypedef basic_object_base<base_type> base_t;\n\n\t\ttemplate <bool invert_and_pop = false>\n\t\tbasic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L, int index = -1) noexcept\n\t\t: base_t(L, index) {\n\t\t\tif (invert_and_pop) {\n\t\t\t\tlua_pop(L, -index);\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tbasic_object(detail::no_safety_tag, lua_nil_t n) : base_t(n) {\n\t\t}\n\t\tbasic_object(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {\n\t\t}\n\t\tbasic_object(lua_State* L, detail::global_tag t) : base_t(L, t) {\n\t\t}\n\t\tbasic_object(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_object(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {\n\t\t}\n\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_object(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) {\n\t\t}\n\n\tpublic:\n\t\tbasic_object() noexcept = default;\n\t\ttemplate <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_object(T&& r)\n\t\t: base_t(std::forward<T>(r)) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_object(lua_State* L, T&& r)\n\t\t: base_t(L, std::forward<T>(r)) {\n\t\t}\n\t\tbasic_object(lua_nil_t r)\n\t\t: base_t(r) {\n\t\t}\n\t\tbasic_object(const basic_object&) = default;\n\t\tbasic_object(basic_object&&) = default;\n\t\tbasic_object(const stack_reference& r) noexcept\n\t\t: basic_object(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_object(stack_reference&& r) noexcept\n\t\t: basic_object(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <typename Super>\n\t\tbasic_object(const proxy_base<Super>& r) noexcept\n\t\t: basic_object(r.operator basic_object()) {\n\t\t}\n\t\ttemplate <typename Super>\n\t\tbasic_object(proxy_base<Super>&& r) noexcept\n\t\t: basic_object(r.operator basic_object()) {\n\t\t}\n\t\tbasic_object(lua_State* L, lua_nil_t r) noexcept\n\t\t: base_t(L, r) {\n\t\t}\n\t\tbasic_object(lua_State* L, int index = -1) noexcept\n\t\t: base_t(L, index) {\n\t\t}\n\t\tbasic_object(lua_State* L, absolute_index index) noexcept\n\t\t: base_t(L, index) {\n\t\t}\n\t\tbasic_object(lua_State* L, raw_index index) noexcept\n\t\t: base_t(L, index) {\n\t\t}\n\t\tbasic_object(lua_State* L, ref_index index) noexcept\n\t\t: base_t(L, index) {\n\t\t}\n\t\ttemplate <typename T, typename... Args>\n\t\tbasic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept\n\t\t: basic_object(std::integral_constant<bool, !is_stack_based<base_t>::value>(), L, -stack::push<T>(L, std::forward<Args>(args)...)) {\n\t\t}\n\t\ttemplate <typename T, typename... Args>\n\t\tbasic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept\n\t\t: basic_object(L, in_place_type<T>, std::forward<T>(arg), std::forward<Args>(args)...) {\n\t\t}\n\t\tbasic_object& operator=(const basic_object&) = default;\n\t\tbasic_object& operator=(basic_object&&) = default;\n\t\tbasic_object& operator=(const base_type& b) {\n\t\t\tbase_t::operator=(b);\n\t\t\treturn *this;\n\t\t}\n\t\tbasic_object& operator=(base_type&& b) {\n\t\t\tbase_t::operator=(std::move(b));\n\t\t\treturn *this;\n\t\t}\n\t\ttemplate <typename Super>\n\t\tbasic_object& operator=(const proxy_base<Super>& r) {\n\t\t\tthis->operator=(r.operator basic_object());\n\t\t\treturn *this;\n\t\t}\n\t\ttemplate <typename Super>\n\t\tbasic_object& operator=(proxy_base<Super>&& r) {\n\t\t\tthis->operator=(r.operator basic_object());\n\t\t\treturn *this;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tobject make_object(lua_State* L, T&& value) {\n\t\treturn make_reference<object, true>(L, std::forward<T>(value));\n\t}\n\n\ttemplate <typename T, typename... Args>\n\tobject make_object(lua_State* L, Args&&... args) {\n\t\treturn make_reference<T, object, true>(L, std::forward<Args>(args)...);\n\t}\n\n\ttemplate <typename T>\n\tobject make_object_userdata(lua_State* L, T&& value) {\n\t\treturn make_reference_userdata<object, true>(L, std::forward<T>(value));\n\t}\n\n\ttemplate <typename T, typename... Args>\n\tobject make_object_userdata(lua_State* L, Args&&... args) {\n\t\treturn make_reference_userdata<T, object, true>(L, std::forward<Args>(args)...);\n\t}\n} // namespace sol\n\n// end of sol/object.hpp\n\n// beginning of sol/function.hpp\n\n// beginning of sol/unsafe_function.hpp\n\n// beginning of sol/function_result.hpp\n\n// beginning of sol/protected_function_result.hpp\n\n// beginning of sol/proxy_base.hpp\n\nnamespace sol {\n\tstruct proxy_base_tag {};\n\n\tnamespace detail {\n\t\ttemplate <typename T>\n\t\tusing proxy_key_t = meta::conditional_t<meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>, T,\n\t\t     std::tuple<meta::conditional_t<std::is_array_v<meta::unqualified_t<T>>, std::remove_reference_t<T>&, meta::unqualified_t<T>>>>;\n\t}\n\n\ttemplate <typename Super>\n\tstruct proxy_base : proxy_base_tag {\n\t\toperator std::string() const {\n\t\t\tconst Super& super = *static_cast<const Super*>(static_cast<const void*>(this));\n\t\t\treturn super.template get<std::string>();\n\t\t}\n\n\t\ttemplate <typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, is_proxy_primitive<meta::unqualified_t<T>>> = meta::enabler>\n\t\toperator T() const {\n\t\t\tconst Super& super = *static_cast<const Super*>(static_cast<const void*>(this));\n\t\t\treturn super.template get<T>();\n\t\t}\n\n\t\ttemplate <typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, meta::neg<is_proxy_primitive<meta::unqualified_t<T>>>> = meta::enabler>\n\t\toperator T&() const {\n\t\t\tconst Super& super = *static_cast<const Super*>(static_cast<const void*>(this));\n\t\t\treturn super.template get<T&>();\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\tconst Super& super = *static_cast<const Super*>(static_cast<const void*>(this));\n\t\t\treturn super.lua_state();\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/proxy_base.hpp\n\n// beginning of sol/stack_iterator.hpp\n\n#include <limits>\n#include <iterator>\n\nnamespace sol {\n\ttemplate <typename proxy_t, bool is_const>\n\tstruct stack_iterator {\n\t\ttypedef meta::conditional_t<is_const, const proxy_t, proxy_t> reference;\n\t\ttypedef meta::conditional_t<is_const, const proxy_t*, proxy_t*> pointer;\n\t\ttypedef proxy_t value_type;\n\t\ttypedef std::ptrdiff_t difference_type;\n\t\ttypedef std::random_access_iterator_tag iterator_category;\n\t\tlua_State* L;\n\t\tint index;\n\t\tint stacktop;\n\t\tproxy_t sp;\n\n\t\tstack_iterator()\n\t\t\t: L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() {\n\t\t}\n\t\tstack_iterator(const stack_iterator<proxy_t, true>& r)\n\t\t\t: L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) {\n\t\t}\n\t\tstack_iterator(lua_State* luastate, int idx, int topidx)\n\t\t\t: L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {\n\t\t}\n\n\t\treference operator*() {\n\t\t\treturn proxy_t(L, index);\n\t\t}\n\n\t\treference operator*() const {\n\t\t\treturn proxy_t(L, index);\n\t\t}\n\n\t\tpointer operator->() {\n\t\t\tsp = proxy_t(L, index);\n\t\t\treturn &sp;\n\t\t}\n\n\t\tpointer operator->() const {\n\t\t\tconst_cast<proxy_t&>(sp) = proxy_t(L, index);\n\t\t\treturn &sp;\n\t\t}\n\n\t\tstack_iterator& operator++() {\n\t\t\t++index;\n\t\t\treturn *this;\n\t\t}\n\n\t\tstack_iterator operator++(int) {\n\t\t\tauto r = *this;\n\t\t\tthis->operator++();\n\t\t\treturn r;\n\t\t}\n\n\t\tstack_iterator& operator--() {\n\t\t\t--index;\n\t\t\treturn *this;\n\t\t}\n\n\t\tstack_iterator operator--(int) {\n\t\t\tauto r = *this;\n\t\t\tthis->operator--();\n\t\t\treturn r;\n\t\t}\n\n\t\tstack_iterator& operator+=(difference_type idx) {\n\t\t\tindex += static_cast<int>(idx);\n\t\t\treturn *this;\n\t\t}\n\n\t\tstack_iterator& operator-=(difference_type idx) {\n\t\t\tindex -= static_cast<int>(idx);\n\t\t\treturn *this;\n\t\t}\n\n\t\tdifference_type operator-(const stack_iterator& r) const {\n\t\t\treturn index - r.index;\n\t\t}\n\n\t\tstack_iterator operator+(difference_type idx) const {\n\t\t\tstack_iterator r = *this;\n\t\t\tr += idx;\n\t\t\treturn r;\n\t\t}\n\n\t\treference operator[](difference_type idx) const {\n\t\t\treturn proxy_t(L, index + static_cast<int>(idx));\n\t\t}\n\n\t\tbool operator==(const stack_iterator& r) const {\n\t\t\tif (stacktop == (std::numeric_limits<int>::max)()) {\n\t\t\t\treturn r.index == r.stacktop;\n\t\t\t}\n\t\t\telse if (r.stacktop == (std::numeric_limits<int>::max)()) {\n\t\t\t\treturn index == stacktop;\n\t\t\t}\n\t\t\treturn index == r.index;\n\t\t}\n\n\t\tbool operator!=(const stack_iterator& r) const {\n\t\t\treturn !(this->operator==(r));\n\t\t}\n\n\t\tbool operator<(const stack_iterator& r) const {\n\t\t\treturn index < r.index;\n\t\t}\n\n\t\tbool operator>(const stack_iterator& r) const {\n\t\t\treturn index > r.index;\n\t\t}\n\n\t\tbool operator<=(const stack_iterator& r) const {\n\t\t\treturn index <= r.index;\n\t\t}\n\n\t\tbool operator>=(const stack_iterator& r) const {\n\t\t\treturn index >= r.index;\n\t\t}\n\t};\n\n\ttemplate <typename proxy_t, bool is_const>\n\tinline stack_iterator<proxy_t, is_const> operator+(typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) {\n\t\treturn r + n;\n\t}\n} // namespace sol\n\n// end of sol/stack_iterator.hpp\n\n// beginning of sol/stack_proxy.hpp\n\n// beginning of sol/stack_proxy_base.hpp\n\nnamespace sol {\n\tstruct stack_proxy_base : public proxy_base<stack_proxy_base> {\n\tprivate:\n\t\tlua_State* L;\n\t\tint index;\n\n\tpublic:\n\t\tstack_proxy_base()\n\t\t\t: L(nullptr), index(0) {\n\t\t}\n\t\tstack_proxy_base(lua_State* L, int index)\n\t\t\t: L(L), index(index) {\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get() const {\n\t\t\treturn stack::get<T>(L, stack_index());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool is() const {\n\t\t\treturn stack::check<T>(L, stack_index());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) as() const {\n\t\t\treturn get<T>();\n\t\t}\n\n\t\ttype get_type() const noexcept {\n\t\t\treturn type_of(lua_state(), stack_index());\n\t\t}\n\n\t\tint push() const {\n\t\t\treturn push(L);\n\t\t}\n\n\t\tint push(lua_State* Ls) const {\n\t\t\tlua_pushvalue(Ls, index);\n\t\t\treturn 1;\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\treturn L;\n\t\t}\n\t\tint stack_index() const {\n\t\t\treturn index;\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_getter<stack_proxy_base> {\n\t\t\tstatic stack_proxy_base get(lua_State* L, int index = -1) {\n\t\t\t\treturn stack_proxy_base(L, index);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<stack_proxy_base> {\n\t\t\tstatic int push(lua_State*, const stack_proxy_base& ref) {\n\t\t\t\treturn ref.push();\n\t\t\t}\n\t\t};\n\t} // namespace stack\n\n} // namespace sol\n\n// end of sol/stack_proxy_base.hpp\n\nnamespace sol {\n\tstruct stack_proxy : public stack_proxy_base {\n\tpublic:\n\t\tstack_proxy() : stack_proxy_base() {\n\t\t}\n\t\tstack_proxy(lua_State* L, int index) : stack_proxy_base(L, index) {\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args);\n\n\t\ttemplate <typename... Args>\n\t\tdecltype(auto) operator()(Args&&... args) {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_getter<stack_proxy> {\n\t\t\tstatic stack_proxy get(lua_State* L, int index, record& tracking) {\n\t\t\t\ttracking.use(0);\n\t\t\t\treturn stack_proxy(L, index);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<stack_proxy> {\n\t\t\tstatic int push(lua_State*, const stack_proxy& ref) {\n\t\t\t\treturn ref.push();\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/stack_proxy.hpp\n\n#include <cstdint>\n\nnamespace sol {\n\tstruct protected_function_result : public proxy_base<protected_function_result> {\n\tprivate:\n\t\tlua_State* L;\n\t\tint index;\n\t\tint returncount;\n\t\tint popcount;\n\t\tcall_status err;\n\n\tpublic:\n\t\ttypedef stack_proxy reference_type;\n\t\ttypedef stack_proxy value_type;\n\t\ttypedef stack_proxy* pointer;\n\t\ttypedef std::ptrdiff_t difference_type;\n\t\ttypedef std::size_t size_type;\n\t\ttypedef stack_iterator<stack_proxy, false> iterator;\n\t\ttypedef stack_iterator<stack_proxy, true> const_iterator;\n\t\ttypedef std::reverse_iterator<iterator> reverse_iterator;\n\t\ttypedef std::reverse_iterator<const_iterator> const_reverse_iterator;\n\n\t\tprotected_function_result() noexcept = default;\n\t\tprotected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept\n\t\t: L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) {\n\t\t}\n\n\t\t// We do not want anyone to copy these around willy-nilly\n\t\t// Will likely break people, but also will probably get rid of quiet bugs that have\n\t\t// been lurking. (E.g., Vanilla Lua will just quietly discard over-pops and under-pops:\n\t\t// LuaJIT and other Lua engines will implode and segfault at random later times.)\n\t\tprotected_function_result(const protected_function_result&) = delete;\n\t\tprotected_function_result& operator=(const protected_function_result&) = delete;\n\n\t\tprotected_function_result(protected_function_result&& o) noexcept\n\t\t: L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) {\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but we will be thorough\n\t\t\to.abandon();\n\t\t}\n\t\tprotected_function_result& operator=(protected_function_result&& o) noexcept {\n\t\t\tL = o.L;\n\t\t\tindex = o.index;\n\t\t\treturncount = o.returncount;\n\t\t\tpopcount = o.popcount;\n\t\t\terr = o.err;\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but we will be thorough\n\t\t\to.abandon();\n\t\t\treturn *this;\n\t\t}\n\n\t\tprotected_function_result(const unsafe_function_result& o) = delete;\n\t\tprotected_function_result& operator=(const unsafe_function_result& o) = delete;\n\t\tprotected_function_result(unsafe_function_result&& o) noexcept;\n\t\tprotected_function_result& operator=(unsafe_function_result&& o) noexcept;\n\n\t\tcall_status status() const noexcept {\n\t\t\treturn err;\n\t\t}\n\n\t\tbool valid() const noexcept {\n\t\t\treturn status() == call_status::ok || status() == call_status::yielded;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get(int index_offset = 0) const {\n\t\t\tusing UT = meta::unqualified_t<T>;\n\t\t\tint target = index + index_offset;\n\t\t\tif constexpr (meta::is_optional_v<UT>) {\n\t\t\t\tusing ValueType = typename UT::value_type;\n\t\t\t\tif constexpr (std::is_same_v<ValueType, error>) {\n\t\t\t\t\tif (valid()) {\n\t\t\t\t\t\treturn UT();\n\t\t\t\t\t}\n\t\t\t\t\treturn UT(error(detail::direct_error, stack::get<std::string>(L, target)));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!valid()) {\n\t\t\t\t\t\treturn UT();\n\t\t\t\t\t}\n\t\t\t\t\treturn stack::get<UT>(L, target);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif constexpr (std::is_same_v<T, error>) {\n#if SOL_IS_ON(SOL_SAFE_PROXIES_I_)\n\t\t\t\t\tif (valid()) {\n\t\t\t\t\t\ttype t = type_of(L, target);\n\t\t\t\t\t\ttype_panic_c_str(L, target, t, type::none, \"bad get from protected_function_result (is an error)\");\n\t\t\t\t\t}\n#endif // Check Argument Safety\n\t\t\t\t\treturn error(detail::direct_error, stack::get<std::string>(L, target));\n\t\t\t\t}\n\t\t\t\telse {\n#if SOL_IS_ON(SOL_SAFE_PROXIES_I_)\n\t\t\t\t\tif (!valid()) {\n\t\t\t\t\t\ttype t = type_of(L, target);\n\t\t\t\t\t\ttype_panic_c_str(L, target, t, type::none, \"bad get from protected_function_result (is not an error)\");\n\t\t\t\t\t}\n#endif // Check Argument Safety\n\t\t\t\t\treturn stack::get<T>(L, target);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttype get_type(int index_offset = 0) const noexcept {\n\t\t\treturn type_of(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\tstack_proxy operator[](difference_type index_offset) const {\n\t\t\treturn stack_proxy(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\titerator begin() {\n\t\t\treturn iterator(L, index, stack_index() + return_count());\n\t\t}\n\t\titerator end() {\n\t\t\treturn iterator(L, stack_index() + return_count(), stack_index() + return_count());\n\t\t}\n\t\tconst_iterator begin() const {\n\t\t\treturn const_iterator(L, index, stack_index() + return_count());\n\t\t}\n\t\tconst_iterator end() const {\n\t\t\treturn const_iterator(L, stack_index() + return_count(), stack_index() + return_count());\n\t\t}\n\t\tconst_iterator cbegin() const {\n\t\t\treturn begin();\n\t\t}\n\t\tconst_iterator cend() const {\n\t\t\treturn end();\n\t\t}\n\n\t\treverse_iterator rbegin() {\n\t\t\treturn std::reverse_iterator<iterator>(begin());\n\t\t}\n\t\treverse_iterator rend() {\n\t\t\treturn std::reverse_iterator<iterator>(end());\n\t\t}\n\t\tconst_reverse_iterator rbegin() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(begin());\n\t\t}\n\t\tconst_reverse_iterator rend() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(end());\n\t\t}\n\t\tconst_reverse_iterator crbegin() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(cbegin());\n\t\t}\n\t\tconst_reverse_iterator crend() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(cend());\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn L;\n\t\t};\n\t\tint stack_index() const noexcept {\n\t\t\treturn index;\n\t\t};\n\t\tint return_count() const noexcept {\n\t\t\treturn returncount;\n\t\t};\n\t\tint pop_count() const noexcept {\n\t\t\treturn popcount;\n\t\t};\n\t\tvoid abandon() noexcept {\n\t\t\t// L = nullptr;\n\t\t\tindex = 0;\n\t\t\treturncount = 0;\n\t\t\tpopcount = 0;\n\t\t\terr = call_status::runtime;\n\t\t}\n\t\t~protected_function_result() {\n\t\t\tstack::remove(L, index, popcount);\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<protected_function_result> {\n\t\t\tstatic int push(lua_State* L, const protected_function_result& pfr) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, static_cast<int>(pfr.pop_count()), detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\tint p = 0;\n\t\t\t\tfor (int i = 0; i < pfr.pop_count(); ++i) {\n\t\t\t\t\tlua_pushvalue(L, i + pfr.stack_index());\n\t\t\t\t\t++p;\n\t\t\t\t}\n\t\t\t\treturn p;\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/protected_function_result.hpp\n\n// beginning of sol/unsafe_function_result.hpp\n\n#include <cstdint>\n\nnamespace sol {\n\tstruct unsafe_function_result : public proxy_base<unsafe_function_result> {\n\tprivate:\n\t\tlua_State* L;\n\t\tint index;\n\t\tint returncount;\n\n\tpublic:\n\t\ttypedef stack_proxy reference_type;\n\t\ttypedef stack_proxy value_type;\n\t\ttypedef stack_proxy* pointer;\n\t\ttypedef std::ptrdiff_t difference_type;\n\t\ttypedef std::size_t size_type;\n\t\ttypedef stack_iterator<stack_proxy, false> iterator;\n\t\ttypedef stack_iterator<stack_proxy, true> const_iterator;\n\t\ttypedef std::reverse_iterator<iterator> reverse_iterator;\n\t\ttypedef std::reverse_iterator<const_iterator> const_reverse_iterator;\n\n\t\tunsafe_function_result() noexcept = default;\n\t\tunsafe_function_result(lua_State* Ls, int idx = -1, int retnum = 0) noexcept : L(Ls), index(idx), returncount(retnum) {\n\t\t}\n\n\t\t// We do not want anyone to copy these around willy-nilly\n\t\t// Will likely break people, but also will probably get rid of quiet bugs that have\n\t\t// been lurking. (E.g., Vanilla Lua will just quietly discard over-pops and under-pops:\n\t\t// LuaJIT and other Lua engines will implode and segfault at random later times.)\n\t\tunsafe_function_result(const unsafe_function_result&) = delete;\n\t\tunsafe_function_result& operator=(const unsafe_function_result&) = delete;\n\n\t\tunsafe_function_result(unsafe_function_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount) {\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but will be thorough\n\t\t\to.abandon();\n\t\t}\n\t\tunsafe_function_result& operator=(unsafe_function_result&& o) noexcept {\n\t\t\tL = o.L;\n\t\t\tindex = o.index;\n\t\t\treturncount = o.returncount;\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but will be thorough\n\t\t\to.abandon();\n\t\t\treturn *this;\n\t\t}\n\n\t\tunsafe_function_result(const protected_function_result& o) = delete;\n\t\tunsafe_function_result& operator=(const protected_function_result& o) = delete;\n\t\tunsafe_function_result(protected_function_result&& o) noexcept;\n\t\tunsafe_function_result& operator=(protected_function_result&& o) noexcept;\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get(difference_type index_offset = 0) const {\n\t\t\treturn stack::get<T>(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\ttype get_type(difference_type index_offset = 0) const noexcept {\n\t\t\treturn type_of(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\tstack_proxy operator[](difference_type index_offset) const {\n\t\t\treturn stack_proxy(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\titerator begin() {\n\t\t\treturn iterator(L, index, stack_index() + return_count());\n\t\t}\n\t\titerator end() {\n\t\t\treturn iterator(L, stack_index() + return_count(), stack_index() + return_count());\n\t\t}\n\t\tconst_iterator begin() const {\n\t\t\treturn const_iterator(L, index, stack_index() + return_count());\n\t\t}\n\t\tconst_iterator end() const {\n\t\t\treturn const_iterator(L, stack_index() + return_count(), stack_index() + return_count());\n\t\t}\n\t\tconst_iterator cbegin() const {\n\t\t\treturn begin();\n\t\t}\n\t\tconst_iterator cend() const {\n\t\t\treturn end();\n\t\t}\n\n\t\treverse_iterator rbegin() {\n\t\t\treturn std::reverse_iterator<iterator>(begin());\n\t\t}\n\t\treverse_iterator rend() {\n\t\t\treturn std::reverse_iterator<iterator>(end());\n\t\t}\n\t\tconst_reverse_iterator rbegin() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(begin());\n\t\t}\n\t\tconst_reverse_iterator rend() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(end());\n\t\t}\n\t\tconst_reverse_iterator crbegin() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(cbegin());\n\t\t}\n\t\tconst_reverse_iterator crend() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(cend());\n\t\t}\n\n\t\tcall_status status() const noexcept {\n\t\t\treturn call_status::ok;\n\t\t}\n\n\t\tbool valid() const noexcept {\n\t\t\treturn status() == call_status::ok || status() == call_status::yielded;\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\treturn L;\n\t\t};\n\t\tint stack_index() const {\n\t\t\treturn index;\n\t\t};\n\t\tint return_count() const {\n\t\t\treturn returncount;\n\t\t};\n\t\tvoid abandon() noexcept {\n\t\t\t// L = nullptr;\n\t\t\tindex = 0;\n\t\t\treturncount = 0;\n\t\t}\n\t\t~unsafe_function_result() {\n\t\t\tlua_pop(L, returncount);\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<unsafe_function_result> {\n\t\t\tstatic int push(lua_State* L, const unsafe_function_result& fr) {\n\t\t\t\tint p = 0;\n\t\t\t\tfor (int i = 0; i < fr.return_count(); ++i) {\n\t\t\t\t\tlua_pushvalue(L, i + fr.stack_index());\n\t\t\t\t\t++p;\n\t\t\t\t}\n\t\t\t\treturn p;\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/unsafe_function_result.hpp\n\n#include <cstdint>\n\nnamespace sol {\n\n\tnamespace detail {\n\t\ttemplate <>\n\t\tstruct is_speshul<unsafe_function_result> : std::true_type {};\n\t\ttemplate <>\n\t\tstruct is_speshul<protected_function_result> : std::true_type {};\n\n\t\ttemplate <std::size_t I, typename... Args, typename T>\n\t\tstack_proxy get(types<Args...>, meta::index_value<0>, meta::index_value<I>, const T& fr) {\n\t\t\treturn stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));\n\t\t}\n\n\t\ttemplate <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>\n\t\tstack_proxy get(types<Arg, Args...>, meta::index_value<N>, meta::index_value<I>, const T& fr) {\n\t\t\treturn get(types<Args...>(), meta::index_value<N - 1>(), meta::index_value<I + lua_size<Arg>::value>(), fr);\n\t\t}\n\t} // namespace detail\n\n\ttemplate <>\n\tstruct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};\n\n\ttemplate <>\n\tstruct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};\n\n\ttemplate <std::size_t I>\n\tstack_proxy get(const unsafe_function_result& fr) {\n\t\treturn stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));\n\t}\n\n\ttemplate <std::size_t I, typename... Args>\n\tstack_proxy get(types<Args...> t, const unsafe_function_result& fr) {\n\t\treturn detail::get(t, meta::index_value<I>(), meta::index_value<0>(), fr);\n\t}\n\n\ttemplate <std::size_t I>\n\tstack_proxy get(const protected_function_result& fr) {\n\t\treturn stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));\n\t}\n\n\ttemplate <std::size_t I, typename... Args>\n\tstack_proxy get(types<Args...> t, const protected_function_result& fr) {\n\t\treturn detail::get(t, meta::index_value<I>(), meta::index_value<0>(), fr);\n\t}\n} // namespace sol\n\n// end of sol/function_result.hpp\n\n// beginning of sol/function_types.hpp\n\n// beginning of sol/function_types_core.hpp\n\n// beginning of sol/wrapper.hpp\n\nnamespace sol {\n\n\tnamespace detail {\n\t\ttemplate <typename T>\n\t\tusing array_return_type = meta::conditional_t<std::is_array<T>::value, std::add_lvalue_reference_t<T>, T>;\n\t}\n\n\ttemplate <typename F, typename = void>\n\tstruct wrapper {\n\t\ttypedef lua_bind_traits<meta::unqualified_t<F>> traits_type;\n\t\ttypedef typename traits_type::args_list args_list;\n\t\ttypedef typename traits_type::args_list free_args_list;\n\t\ttypedef typename traits_type::returns_list returns_list;\n\n\t\ttemplate <typename... Args>\n\t\tstatic decltype(auto) call(F& f, Args&&... args) {\n\t\t\treturn f(std::forward<Args>(args)...);\n\t\t}\n\n\t\tstruct caller {\n\t\t\ttemplate <typename... Args>\n\t\t\tdecltype(auto) operator()(F& fx, Args&&... args) const {\n\t\t\t\treturn call(fx, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\t};\n\n\ttemplate <typename F>\n\tstruct wrapper<F, std::enable_if_t<std::is_function<std::remove_pointer_t<meta::unqualified_t<F>>>::value>> {\n\t\ttypedef lua_bind_traits<std::remove_pointer_t<meta::unqualified_t<F>>> traits_type;\n\t\ttypedef typename traits_type::args_list args_list;\n\t\ttypedef typename traits_type::args_list free_args_list;\n\t\ttypedef typename traits_type::returns_list returns_list;\n\n\t\ttemplate <F fx, typename... Args>\n\t\tstatic decltype(auto) invoke(Args&&... args) {\n\t\t\treturn fx(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tstatic decltype(auto) call(F& fx, Args&&... args) {\n\t\t\treturn fx(std::forward<Args>(args)...);\n\t\t}\n\n\t\tstruct caller {\n\t\t\ttemplate <typename... Args>\n\t\t\tdecltype(auto) operator()(F& fx, Args&&... args) const {\n\t\t\t\treturn call(fx, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <F fx>\n\t\tstruct invoker {\n\t\t\ttemplate <typename... Args>\n\t\t\tdecltype(auto) operator()(Args&&... args) const {\n\t\t\t\treturn invoke<fx>(std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\t};\n\n\ttemplate <typename F>\n\tstruct wrapper<F, std::enable_if_t<std::is_member_object_pointer<meta::unqualified_t<F>>::value>> {\n\t\ttypedef lua_bind_traits<meta::unqualified_t<F>> traits_type;\n\t\ttypedef typename traits_type::object_type object_type;\n\t\ttypedef typename traits_type::return_type return_type;\n\t\ttypedef typename traits_type::args_list args_list;\n\t\ttypedef types<object_type&, return_type> free_args_list;\n\t\ttypedef typename traits_type::returns_list returns_list;\n\n\t\ttemplate <F fx>\n\t\tstatic auto call(object_type& mem) -> detail::array_return_type<decltype(mem.*fx)> {\n\t\t\treturn mem.*fx;\n\t\t}\n\n\t\ttemplate <F fx, typename Arg, typename... Args>\n\t\tstatic decltype(auto) invoke(object_type& mem, Arg&& arg, Args&&...) {\n\t\t\treturn mem.*fx = std::forward<Arg>(arg);\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tstatic auto call(Fx&& fx, object_type& mem) -> detail::array_return_type<decltype(mem.*fx)> {\n\t\t\treturn mem.*fx;\n\t\t}\n\n\t\ttemplate <typename Fx, typename Arg, typename... Args>\n\t\tstatic void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&...) {\n\t\t\tusing actual_type = meta::unqualified_t<detail::array_return_type<decltype(mem.*fx)>>;\n\t\t\tif constexpr (std::is_array_v<actual_type>) {\n\t\t\t\tusing std::cbegin;\n\t\t\t\tusing std::cend;\n\t\t\t\tauto first = cbegin(arg);\n\t\t\t\tauto last = cend(arg);\n\t\t\t\tfor (std::size_t i = 0; first != last; ++i, ++first) {\n\t\t\t\t\t(mem.*fx)[i] = *first;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t(mem.*fx) = std::forward<Arg>(arg);\n\t\t\t}\n\t\t}\n\n\t\tstruct caller {\n\t\t\ttemplate <typename Fx, typename... Args>\n\t\t\tdecltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const {\n\t\t\t\treturn call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <F fx>\n\t\tstruct invoker {\n\t\t\ttemplate <typename... Args>\n\t\t\tdecltype(auto) operator()(Args&&... args) const {\n\t\t\t\treturn invoke<fx>(std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\t};\n\n\ttemplate <typename F, typename R, typename O, typename... FArgs>\n\tstruct member_function_wrapper {\n\t\ttypedef O object_type;\n\t\ttypedef lua_bind_traits<F> traits_type;\n\t\ttypedef typename traits_type::args_list args_list;\n\t\ttypedef types<object_type&, FArgs...> free_args_list;\n\t\ttypedef meta::tuple_types<R> returns_list;\n\n\t\ttemplate <F fx, typename... Args>\n\t\tstatic R invoke(O& mem, Args&&... args) {\n\t\t\treturn (mem.*fx)(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename Fx, typename... Args>\n\t\tstatic R call(Fx&& fx, O& mem, Args&&... args) {\n\t\t\treturn (mem.*fx)(std::forward<Args>(args)...);\n\t\t}\n\n\t\tstruct caller {\n\t\t\ttemplate <typename Fx, typename... Args>\n\t\t\tdecltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const {\n\t\t\t\treturn call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <F fx>\n\t\tstruct invoker {\n\t\t\ttemplate <typename... Args>\n\t\t\tdecltype(auto) operator()(O& mem, Args&&... args) const {\n\t\t\t\treturn invoke<fx>(mem, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\t};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...)> : public member_function_wrapper<R (O::*)(Args...), R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const> : public member_function_wrapper<R (O::*)(Args...) const, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const volatile> : public member_function_wrapper<R (O::*)(Args...) const volatile, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...)&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const volatile&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...)&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const volatile&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) &&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const&&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const volatile&&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) &&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const&&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const volatile&&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> {};\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t// noexcept has become a part of a function's type\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) noexcept> : public member_function_wrapper<R (O::*)(Args...) noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const noexcept> : public member_function_wrapper<R (O::*)(Args...) const noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const volatile noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) & noexcept> : public member_function_wrapper<R (O::*)(Args...) & noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const volatile& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) & noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) & noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const volatile& noexcept>\n\t: public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) && noexcept> : public member_function_wrapper<R (O::*)(Args...) & noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args...) const volatile&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) && noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) & noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> {};\n\n\ttemplate <typename R, typename O, typename... Args>\n\tstruct wrapper<R (O::*)(Args..., ...) const volatile&& noexcept>\n\t: public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> {};\n\n#endif // noexcept is part of a function's type\n\n} // namespace sol\n\n// end of sol/wrapper.hpp\n\n#include <memory>\n\nnamespace sol {\nnamespace function_detail {\n\ttemplate <typename Fx, int start = 1, bool is_yielding = false>\n\tint call(lua_State* L) {\n\t\tFx& fx = stack::get<user<Fx>>(L, upvalue_index(start));\n\t\tint nr = fx(L);\n\t\tif (is_yielding) {\n\t\t\treturn lua_yield(L, nr);\n\t\t}\n\t\telse {\n\t\t\treturn nr;\n\t\t}\n\t}\n}\n} // namespace sol::function_detail\n\n// end of sol/function_types_core.hpp\n\n// beginning of sol/function_types_templated.hpp\n\n// beginning of sol/call.hpp\n\n// beginning of sol/property.hpp\n\n#include <type_traits>\n#include <utility>\n\nnamespace sol {\n\tnamespace detail {\n\t\tstruct no_prop {};\n\t}\n\n\ttemplate <typename R, typename W>\n\tstruct property_wrapper : detail::ebco<R, 0>, detail::ebco<W, 1> {\n\tprivate:\n\t\tusing read_base_t = detail::ebco<R, 0>;\n\t\tusing write_base_t = detail::ebco<W, 1>;\n\n\tpublic:\n\t\ttemplate <typename Rx, typename Wx>\n\t\tproperty_wrapper(Rx&& r, Wx&& w)\n\t\t: read_base_t(std::forward<Rx>(r)), write_base_t(std::forward<Wx>(w)) {\n\t\t}\n\n\t\tW& write() {\n\t\t\treturn write_base_t::value();\n\t\t}\n\n\t\tconst W& write() const {\n\t\t\treturn write_base_t::value();\n\t\t}\n\n\t\tR& read() {\n\t\t\treturn read_base_t::value();\n\t\t}\n\n\t\tconst R& read() const {\n\t\t\treturn read_base_t::value();\n\t\t}\n\t};\n\n\ttemplate <typename F, typename G>\n\tinline decltype(auto) property(F&& f, G&& g) {\n\t\ttypedef lua_bind_traits<meta::unqualified_t<F>> left_traits;\n\t\ttypedef lua_bind_traits<meta::unqualified_t<G>> right_traits;\n\t\tif constexpr (left_traits::free_arity < right_traits::free_arity) {\n\t\t\treturn property_wrapper<std::decay_t<F>, std::decay_t<G>>(std::forward<F>(f), std::forward<G>(g));\n\t\t}\n\t\telse {\n\t\t\treturn property_wrapper<std::decay_t<G>, std::decay_t<F>>(std::forward<G>(g), std::forward<F>(f));\n\t\t}\n\t}\n\n\ttemplate <typename F>\n\tinline decltype(auto) property(F&& f) {\n\t\ttypedef lua_bind_traits<meta::unqualified_t<F>> left_traits;\n\t\tif constexpr (left_traits::free_arity < 2) {\n\t\t\treturn property_wrapper<std::decay_t<F>, detail::no_prop>(std::forward<F>(f), detail::no_prop());\n\t\t}\n\t\telse {\n\t\t\treturn property_wrapper<detail::no_prop, std::decay_t<F>>(detail::no_prop(), std::forward<F>(f));\n\t\t}\n\t}\n\n\ttemplate <typename F>\n\tinline decltype(auto) readonly_property(F&& f) {\n\t\treturn property_wrapper<std::decay_t<F>, detail::no_prop>(std::forward<F>(f), detail::no_prop());\n\t}\n\n\ttemplate <typename F>\n\tinline decltype(auto) writeonly_property(F&& f) {\n\t\treturn property_wrapper<detail::no_prop, std::decay_t<F>>(detail::no_prop(), std::forward<F>(f));\n\t}\n\n\ttemplate <typename T>\n\tstruct readonly_wrapper : detail::ebco<T> {\n\tprivate:\n\t\tusing base_t = detail::ebco<T>;\n\n\tpublic:\n\t\tusing base_t::base_t;\n\n\t\toperator T&() {\n\t\t\treturn base_t::value();\n\t\t}\n\t\toperator const T&() const {\n\t\t\treturn base_t::value();\n\t\t}\n\t};\n\n\t// Allow someone to make a member variable readonly (const)\n\ttemplate <typename R, typename T>\n\tinline auto readonly(R T::*v) {\n\t\treturn readonly_wrapper<meta::unqualified_t<decltype(v)>>(v);\n\t}\n\n\ttemplate <typename T>\n\tstruct var_wrapper : detail::ebco<T> {\n\tprivate:\n\t\tusing base_t = detail::ebco<T>;\n\n\tpublic:\n\t\tusing base_t::base_t;\n\t};\n\n\ttemplate <typename V>\n\tinline auto var(V&& v) {\n\t\ttypedef std::decay_t<V> T;\n\t\treturn var_wrapper<T>(std::forward<V>(v));\n\t}\n\n\tnamespace meta {\n\t\ttemplate <typename T>\n\t\tstruct is_member_object : std::is_member_object_pointer<T> {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_member_object<readonly_wrapper<T>> : std::true_type {};\n\n\t\ttemplate <typename T>\n\t\tinline constexpr bool is_member_object_v = is_member_object<T>::value;\n\t} // namespace meta\n\n} // namespace sol\n\n// end of sol/property.hpp\n\n// beginning of sol/protect.hpp\n\n#include <utility>\n\nnamespace sol {\n\n\ttemplate <typename T>\n\tstruct protect_t {\n\t\tT value;\n\n\t\ttemplate <typename Arg, typename... Args, meta::disable<std::is_same<protect_t, meta::unqualified_t<Arg>>> = meta::enabler>\n\t\tprotect_t(Arg&& arg, Args&&... args)\n\t\t: value(std::forward<Arg>(arg), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tprotect_t(const protect_t&) = default;\n\t\tprotect_t(protect_t&&) = default;\n\t\tprotect_t& operator=(const protect_t&) = default;\n\t\tprotect_t& operator=(protect_t&&) = default;\n\t};\n\n\ttemplate <typename T>\n\tauto protect(T&& value) {\n\t\treturn protect_t<std::decay_t<T>>(std::forward<T>(value));\n\t}\n\n} // namespace sol\n\n// end of sol/protect.hpp\n\nnamespace sol {\n\tnamespace u_detail {\n\n\t} // namespace u_detail\n\n\tnamespace policy_detail {\n\t\ttemplate <int I, int... In>\n\t\tinline void handle_policy(static_stack_dependencies<I, In...>, lua_State* L, int&) {\n\t\t\tif constexpr (sizeof...(In) == 0) {\n\t\t\t\t(void)L;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tabsolute_index ai(L, I);\n\t\t\t\tif (type_of(L, ai) != type::userdata) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlua_createtable(L, static_cast<int>(sizeof...(In)), 0);\n\t\t\t\tstack_reference deps(L, -1);\n\t\t\t\tauto per_dep = [&L, &deps](int i) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\t\tlua_pushvalue(L, i);\n\t\t\t\t\tluaL_ref(L, deps.stack_index());\n\t\t\t\t};\n\t\t\t\t(void)per_dep;\n\t\t\t\t(void)detail::swallow{ int(), (per_dep(In), int())... };\n\t\t\t\tlua_setuservalue(L, ai);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <int... In>\n\t\tinline void handle_policy(returns_self_with<In...>, lua_State* L, int& pushed) {\n\t\t\tpushed = stack::push(L, raw_index(1));\n\t\t\thandle_policy(static_stack_dependencies<-1, In...>(), L, pushed);\n\t\t}\n\n\t\tinline void handle_policy(const stack_dependencies& sdeps, lua_State* L, int&) {\n\t\t\tabsolute_index ai(L, sdeps.target);\n\t\t\tif (type_of(L, ai) != type::userdata) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlua_createtable(L, static_cast<int>(sdeps.size()), 0);\n\t\t\tstack_reference deps(L, -1);\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\tluaL_checkstack(L, static_cast<int>(sdeps.size()), detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\tfor (std::size_t i = 0; i < sdeps.size(); ++i) {\n\t\t\t\tlua_pushvalue(L, sdeps.stack_indices[i]);\n\t\t\t\tluaL_ref(L, deps.stack_index());\n\t\t\t}\n\t\t\tlua_setuservalue(L, ai);\n\t\t}\n\n\t\ttemplate <typename P, meta::disable<std::is_base_of<detail::policy_base_tag, meta::unqualified_t<P>>> = meta::enabler>\n\t\tinline void handle_policy(P&& p, lua_State* L, int& pushed) {\n\t\t\tpushed = std::forward<P>(p)(L, pushed);\n\t\t}\n\t} // namespace policy_detail\n\n\tnamespace function_detail {\n\t\tinline int no_construction_error(lua_State* L) {\n\t\t\treturn luaL_error(L, \"sol: cannot call this constructor (tagged as non-constructible)\");\n\t\t}\n\t} // namespace function_detail\n\n\tnamespace call_detail {\n\n\t\ttemplate <typename R, typename W>\n\t\tinline auto& pick(std::true_type, property_wrapper<R, W>& f) {\n\t\t\treturn f.read();\n\t\t}\n\n\t\ttemplate <typename R, typename W>\n\t\tinline auto& pick(std::false_type, property_wrapper<R, W>& f) {\n\t\t\treturn f.write();\n\t\t}\n\n\t\ttemplate <typename T, typename List>\n\t\tstruct void_call : void_call<T, meta::function_args_t<List>> {};\n\n\t\ttemplate <typename T, typename... Args>\n\t\tstruct void_call<T, types<Args...>> {\n\t\t\tstatic void call(Args...) {\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, bool checked, bool clean_stack>\n\t\tstruct constructor_match {\n\t\t\tT* obj_;\n\n\t\t\tconstructor_match(T* o) : obj_(o) {\n\t\t\t}\n\n\t\t\ttemplate <typename Fx, std::size_t I, typename... R, typename... Args>\n\t\t\tint operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {\n\t\t\t\tdetail::default_construct func{};\n\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, obj_);\n\t\t\t}\n\t\t};\n\n\t\tnamespace overload_detail {\n\t\t\ttemplate <std::size_t... M, typename Match, typename... Args>\n\t\t\tinline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {\n\t\t\t\treturn luaL_error(L, \"sol: no matching function call takes this number of arguments and the specified types\");\n\t\t\t}\n\n\t\t\ttemplate <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>\n\t\t\tinline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L,\n\t\t\t     int fxarity, int start, Args&&... args) {\n\t\t\t\ttypedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits;\n\t\t\t\ttypedef meta::tuple_types<typename traits::return_type> return_types;\n\t\t\t\ttypedef typename traits::free_args_list args_list;\n\t\t\t\t// compile-time eliminate any functions that we know ahead of time are of improper arity\n\t\t\t\tif constexpr (!traits::runtime_variadics_t::value\n\t\t\t\t     && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {\n\t\t\t\t\treturn overload_match_arity(types<Fxs...>(),\n\t\t\t\t\t     std::index_sequence<In...>(),\n\t\t\t\t\t     std::index_sequence<M...>(),\n\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t     L,\n\t\t\t\t\t     fxarity,\n\t\t\t\t\t     start,\n\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr (!traits::runtime_variadics_t::value) {\n\t\t\t\t\t\tif (traits::free_arity != fxarity) {\n\t\t\t\t\t\t\treturn overload_match_arity(types<Fxs...>(),\n\t\t\t\t\t\t\t     std::index_sequence<In...>(),\n\t\t\t\t\t\t\t     std::index_sequence<traits::free_arity, M...>(),\n\t\t\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t\t\t     L,\n\t\t\t\t\t\t\t     fxarity,\n\t\t\t\t\t\t\t     start,\n\t\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tstack::record tracking{};\n\t\t\t\t\tif (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) {\n\t\t\t\t\t\treturn overload_match_arity(types<Fxs...>(),\n\t\t\t\t\t\t     std::index_sequence<In...>(),\n\t\t\t\t\t\t     std::index_sequence<M...>(),\n\t\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t\t     L,\n\t\t\t\t\t\t     fxarity,\n\t\t\t\t\t\t     start,\n\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t\treturn matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <std::size_t... M, typename Match, typename... Args>\n\t\t\tinline int overload_match_arity_single(\n\t\t\t     types<>, std::index_sequence<>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {\n\t\t\t\treturn overload_match_arity(types<>(),\n\t\t\t\t     std::index_sequence<>(),\n\t\t\t\t     std::index_sequence<M...>(),\n\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t     L,\n\t\t\t\t     fxarity,\n\t\t\t\t     start,\n\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t}\n\n\t\t\ttemplate <typename Fx, std::size_t I, std::size_t... M, typename Match, typename... Args>\n\t\t\tinline int overload_match_arity_single(\n\t\t\t     types<Fx>, std::index_sequence<I>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {\n\t\t\t\ttypedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits;\n\t\t\t\ttypedef meta::tuple_types<typename traits::return_type> return_types;\n\t\t\t\ttypedef typename traits::free_args_list args_list;\n\t\t\t\t// compile-time eliminate any functions that we know ahead of time are of improper arity\n\t\t\t\tif constexpr (!traits::runtime_variadics_t::value\n\t\t\t\t     && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {\n\t\t\t\t\treturn overload_match_arity(types<>(),\n\t\t\t\t\t     std::index_sequence<>(),\n\t\t\t\t\t     std::index_sequence<M...>(),\n\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t     L,\n\t\t\t\t\t     fxarity,\n\t\t\t\t\t     start,\n\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\tif constexpr (!traits::runtime_variadics_t::value) {\n\t\t\t\t\tif (traits::free_arity != fxarity) {\n\t\t\t\t\t\treturn overload_match_arity(types<>(),\n\t\t\t\t\t\t     std::index_sequence<>(),\n\t\t\t\t\t\t     std::index_sequence<traits::free_arity, M...>(),\n\t\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t\t     L,\n\t\t\t\t\t\t     fxarity,\n\t\t\t\t\t\t     start,\n\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);\n\t\t\t}\n\n\t\t\ttemplate <typename Fx, typename Fx1, typename... Fxs, std::size_t I, std::size_t I1, std::size_t... In, std::size_t... M, typename Match,\n\t\t\t     typename... Args>\n\t\t\tinline int overload_match_arity_single(types<Fx, Fx1, Fxs...>, std::index_sequence<I, I1, In...>, std::index_sequence<M...>, Match&& matchfx,\n\t\t\t     lua_State* L, int fxarity, int start, Args&&... args) {\n\t\t\t\ttypedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits;\n\t\t\t\ttypedef meta::tuple_types<typename traits::return_type> return_types;\n\t\t\t\ttypedef typename traits::free_args_list args_list;\n\t\t\t\t// compile-time eliminate any functions that we know ahead of time are of improper arity\n\t\t\t\tif constexpr (!traits::runtime_variadics_t::value\n\t\t\t\t     && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {\n\t\t\t\t\treturn overload_match_arity(types<Fx1, Fxs...>(),\n\t\t\t\t\t     std::index_sequence<I1, In...>(),\n\t\t\t\t\t     std::index_sequence<M...>(),\n\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t     L,\n\t\t\t\t\t     fxarity,\n\t\t\t\t\t     start,\n\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr (!traits::runtime_variadics_t::value) {\n\t\t\t\t\t\tif (traits::free_arity != fxarity) {\n\t\t\t\t\t\t\treturn overload_match_arity(types<Fx1, Fxs...>(),\n\t\t\t\t\t\t\t     std::index_sequence<I1, In...>(),\n\t\t\t\t\t\t\t     std::index_sequence<traits::free_arity, M...>(),\n\t\t\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t\t\t     L,\n\t\t\t\t\t\t\t     fxarity,\n\t\t\t\t\t\t\t     start,\n\t\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tstack::record tracking{};\n\t\t\t\t\tif (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) {\n\t\t\t\t\t\treturn overload_match_arity(types<Fx1, Fxs...>(),\n\t\t\t\t\t\t     std::index_sequence<I1, In...>(),\n\t\t\t\t\t\t     std::index_sequence<M...>(),\n\t\t\t\t\t\t     std::forward<Match>(matchfx),\n\t\t\t\t\t\t     L,\n\t\t\t\t\t\t     fxarity,\n\t\t\t\t\t\t     start,\n\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t\treturn matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t}\n\t\t} // namespace overload_detail\n\n\t\ttemplate <typename... Functions, typename Match, typename... Args>\n\t\tinline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {\n\t\t\treturn overload_detail::overload_match_arity_single(types<Functions...>(),\n\t\t\t     std::make_index_sequence<sizeof...(Functions)>(),\n\t\t\t     std::index_sequence<>(),\n\t\t\t     std::forward<Match>(matchfx),\n\t\t\t     L,\n\t\t\t     fxarity,\n\t\t\t     start,\n\t\t\t     std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Functions, typename Match, typename... Args>\n\t\tinline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {\n\t\t\tint fxarity = lua_gettop(L) - (start - 1);\n\t\t\treturn overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename T, typename... TypeLists, typename Match, typename... Args>\n\t\tinline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {\n\t\t\t// use same overload resolution matching as all other parts of the framework\n\t\t\treturn overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(\n\t\t\t     std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename T, bool checked, bool clean_stack, typename... TypeLists>\n\t\tinline int construct_trampolined(lua_State* L) {\n\t\t\tstatic const auto& meta = usertype_traits<T>::metatable();\n\t\t\tint argcount = lua_gettop(L);\n\t\t\tcall_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;\n\t\t\targcount -= static_cast<int>(syntax);\n\n\t\t\tT* obj = detail::usertype_allocate<T>(L);\n\t\t\treference userdataref(L, -1);\n\t\t\tstack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>);\n\t\t\tumf();\n\n\t\t\t// put userdata at the first index\n\t\t\tlua_insert(L, 1);\n\t\t\tconstruct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, 1 + static_cast<int>(syntax));\n\n\t\t\tuserdataref.push();\n\t\t\treturn 1;\n\t\t}\n\n\t\ttemplate <typename T, bool checked, bool clean_stack, typename... TypeLists>\n\t\tinline int construct(lua_State* L) {\n\t\t\treturn detail::static_trampoline<&construct_trampolined<T, checked, clean_stack, TypeLists...>>(L);\n\t\t}\n\n\t\ttemplate <typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename = void>\n\t\tstruct agnostic_lua_call_wrapper {\n\t\t\ttemplate <typename Fx, typename... Args>\n\t\t\tstatic int call(lua_State* L, Fx&& f, Args&&... args) {\n\t\t\t\tusing uFx = meta::unqualified_t<Fx>;\n\t\t\t\tstatic constexpr bool is_ref = is_lua_reference_v<uFx>;\n\t\t\t\tif constexpr (is_ref) {\n\t\t\t\t\tif constexpr (is_index) {\n\t\t\t\t\t\treturn stack::push(L, std::forward<Fx>(f), std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tstd::forward<Fx>(f) = stack::unqualified_get<F>(L, boost + (is_variable ? 3 : 1));\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing wrap = wrapper<uFx>;\n\t\t\t\t\tusing traits_type = typename wrap::traits_type;\n\t\t\t\t\tusing fp_t = typename traits_type::function_pointer_type;\n\t\t\t\t\tconstexpr bool is_function_pointer_convertible\n\t\t\t\t\t     = std::is_class_v<uFx> && std::is_convertible_v<std::decay_t<Fx>, fp_t>;\n\t\t\t\t\tif constexpr (is_function_pointer_convertible) {\n\t\t\t\t\t\tfp_t fx = f;\n\t\t\t\t\t\treturn agnostic_lua_call_wrapper<fp_t, is_index, is_variable, checked, boost, clean_stack>{}.call(\n\t\t\t\t\t\t     L, fx, std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tusing returns_list = typename wrap::returns_list;\n\t\t\t\t\t\tusing args_list = typename wrap::free_args_list;\n\t\t\t\t\t\tusing caller = typename wrap::caller;\n\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t     returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<var_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttemplate <typename F>\n\t\t\tstatic int call(lua_State* L, F&& f) {\n\t\t\t\tif constexpr (is_index) {\n\t\t\t\t\tconstexpr bool is_stack = is_stack_based_v<meta::unqualified_t<decltype(detail::unwrap(f.value()))>>;\n\t\t\t\t\tif constexpr (clean_stack && !is_stack) {\n\t\t\t\t\t\tlua_settop(L, 0);\n\t\t\t\t\t}\n\t\t\t\t\treturn stack::push_reference(L, detail::unwrap(f.value()));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr (std::is_const_v<meta::unwrapped_t<T>>) {\n\t\t\t\t\t\t(void)f;\n\t\t\t\t\t\treturn luaL_error(L, \"sol: cannot write to a readonly (const) variable\");\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tusing R = meta::unwrapped_t<T>;\n\t\t\t\t\t\tif constexpr (std::is_assignable_v<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>) {\n\t\t\t\t\t\t\tdetail::unwrap(f.value()) = stack::unqualified_get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1));\n\t\t\t\t\t\t\tif (clean_stack) {\n\t\t\t\t\t\t\t\tlua_settop(L, 0);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn luaL_error(L, \"sol: cannot write to this variable: copy assignment/constructor not available\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<lua_CFunction_ref, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, lua_CFunction_ref f) {\n\t\t\t\treturn f(L);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, lua_CFunction f) {\n\t\t\t\treturn f(L);\n\t\t\t}\n\t\t};\n\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\ttemplate <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, detail::lua_CFunction_noexcept f) {\n\t\t\t\treturn f(L);\n\t\t\t}\n\t\t};\n#endif // noexcept function types\n\n\t\ttemplate <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<detail::no_prop, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, const detail::no_prop&) {\n\t\t\t\treturn luaL_error(L, is_index ? \"sol: cannot read from a writeonly property\" : \"sol: cannot write to a readonly property\");\n\t\t\t}\n\t\t};\n\n\t\ttemplate <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, const no_construction&) {\n\t\t\t\treturn function_detail::no_construction_error(L);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State*, const bases<Args...>&) {\n\t\t\t\t// Uh. How did you even call this, lul\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, std::reference_wrapper<T> f) {\n\t\t\t\tagnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack> alcw{};\n\t\t\t\treturn alcw.call(L, f.get());\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename F, bool is_index, bool is_variable, bool checked = detail::default_safe_function_calls, int boost = 0,\n\t\t     bool clean_stack = true, typename = void>\n\t\tstruct lua_call_wrapper {\n\t\t\ttemplate <typename Fx, typename... Args>\n\t\t\tstatic int call(lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\t\tif constexpr (std::is_member_function_pointer_v<F>) {\n\t\t\t\t\tusing wrap = wrapper<F>;\n\t\t\t\t\tusing object_type = typename wrap::object_type;\n\t\t\t\t\tif constexpr (sizeof...(Args) < 1) {\n\t\t\t\t\t\tusing Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;\n\t\t\t\t\t\tstatic_assert(std::is_base_of_v<object_type, Ta>, \"It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \\\"T\\\" but then bind member methods from a complete unrelated class. Check things over!\");\n#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)\n\t\t\t\t\t\tauto maybeo = stack::check_get<Ta*>(L, 1);\n\t\t\t\t\t\tif (!maybeo || maybeo.value() == nullptr) {\n\t\t\t\t\t\t\treturn luaL_error(L,\n\t\t\t\t\t\t\t     \"sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are \"\n\t\t\t\t\t\t\t     \"preceeded by the \"\n\t\t\t\t\t\t\t     \"actual object with '.' syntax)\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tobject_type* o = static_cast<object_type*>(maybeo.value());\n\t\t\t\t\t\treturn call(L, std::forward<Fx>(fx), *o);\n#else\n\t\t\t\t\t\tobject_type& o = static_cast<object_type&>(*stack::unqualified_get<non_null<Ta*>>(L, 1));\n\t\t\t\t\t\treturn call(L, std::forward<Fx>(fx), o);\n#endif // Safety\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tusing returns_list = typename wrap::returns_list;\n\t\t\t\t\t\tusing args_list = typename wrap::args_list;\n\t\t\t\t\t\tusing caller = typename wrap::caller;\n\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if constexpr (std::is_member_object_pointer_v<F>) {\n\t\t\t\t\tusing wrap = wrapper<F>;\n\t\t\t\t\tusing object_type = typename wrap::object_type;\n\t\t\t\t\tif constexpr (is_index) {\n\t\t\t\t\t\tif constexpr (sizeof...(Args) < 1) {\n\t\t\t\t\t\t\tusing Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;\n\t\t\t\t\t\t\tstatic_assert(std::is_base_of_v<object_type, Ta>, \"It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \\\"T\\\" but then bind member methods from a complete unrelated class. Check things over!\");\n#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)\n\t\t\t\t\t\t\tauto maybeo = stack::check_get<Ta*>(L, 1);\n\t\t\t\t\t\t\tif (!maybeo || maybeo.value() == nullptr) {\n\t\t\t\t\t\t\t\tif (is_variable) {\n\t\t\t\t\t\t\t\t\treturn luaL_error(L, \"sol: 'self' argument is lua_nil (bad '.' access?)\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn luaL_error(L, \"sol: 'self' argument is lua_nil (pass 'self' as first argument)\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tobject_type* o = static_cast<object_type*>(maybeo.value());\n\t\t\t\t\t\t\treturn call(L, std::forward<Fx>(fx), *o);\n#else\n\t\t\t\t\t\t\tobject_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));\n\t\t\t\t\t\t\treturn call(L, std::forward<Fx>(fx), o);\n#endif // Safety\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tusing returns_list = typename wrap::returns_list;\n\t\t\t\t\t\t\tusing caller = typename wrap::caller;\n\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(returns_list(),\n\t\t\t\t\t\t\t     types<>(),\n\t\t\t\t\t\t\t     L,\n\t\t\t\t\t\t\t     boost + (is_variable ? 3 : 2),\n\t\t\t\t\t\t\t     caller(),\n\t\t\t\t\t\t\t     std::forward<Fx>(fx),\n\t\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tusing traits_type = lua_bind_traits<F>;\n\t\t\t\t\t\tusing return_type = typename traits_type::return_type;\n\t\t\t\t\t\tconstexpr bool ret_is_const = std::is_const_v<std::remove_reference_t<return_type>>;\n\t\t\t\t\t\tif constexpr (ret_is_const) {\n\t\t\t\t\t\t\t(void)fx;\n\t\t\t\t\t\t\t(void)detail::swallow{ 0, (static_cast<void>(args), 0)... };\n\t\t\t\t\t\t\treturn luaL_error(L, \"sol: cannot write to a readonly (const) variable\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tusing u_return_type = meta::unqualified_t<return_type>;\n\t\t\t\t\t\t\tconstexpr bool is_assignable = std::is_copy_assignable_v<u_return_type> || std::is_array_v<u_return_type>;\n\t\t\t\t\t\t\tif constexpr (!is_assignable) {\n\t\t\t\t\t\t\t\t(void)fx;\n\t\t\t\t\t\t\t\t(void)detail::swallow{ 0, ((void)args, 0)... };\n\t\t\t\t\t\t\t\treturn luaL_error(L, \"sol: cannot write to this variable: copy assignment/constructor not available\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tusing args_list = typename wrap::args_list;\n\t\t\t\t\t\t\t\tusing caller = typename wrap::caller;\n\t\t\t\t\t\t\t\tif constexpr (sizeof...(Args) > 0) {\n\t\t\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(types<void>(),\n\t\t\t\t\t\t\t\t\t     args_list(),\n\t\t\t\t\t\t\t\t\t     L,\n\t\t\t\t\t\t\t\t\t     boost + (is_variable ? 3 : 2),\n\t\t\t\t\t\t\t\t\t     caller(),\n\t\t\t\t\t\t\t\t\t     std::forward<Fx>(fx),\n\t\t\t\t\t\t\t\t\t     std::forward<Args>(args)...);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tusing Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;\n#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)\n\t\t\t\t\t\t\t\t\tauto maybeo = stack::check_get<Ta*>(L, 1);\n\t\t\t\t\t\t\t\t\tif (!maybeo || maybeo.value() == nullptr) {\n\t\t\t\t\t\t\t\t\t\tif (is_variable) {\n\t\t\t\t\t\t\t\t\t\t\treturn luaL_error(L, \"sol: received nil for 'self' argument (bad '.' access?)\");\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\treturn luaL_error(L, \"sol: received nil for 'self' argument (pass 'self' as first argument)\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tobject_type* po = static_cast<object_type*>(maybeo.value());\n\t\t\t\t\t\t\t\t\tobject_type& o = *po;\n#else\n\t\t\t\t\t\t\t\t\tobject_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));\n#endif // Safety\n\n\t\t\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t\t\t\t     types<void>(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), o);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tagnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> alcw{};\n\t\t\t\t\treturn alcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, readonly_wrapper<F>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tusing traits_type = lua_bind_traits<F>;\n\t\t\tusing wrap = wrapper<F>;\n\t\t\tusing object_type = typename wrap::object_type;\n\n\t\t\tstatic int call(lua_State* L, readonly_wrapper<F>&& rw) {\n\t\t\t\tif constexpr (!is_index) {\n\t\t\t\t\t(void)rw;\n\t\t\t\t\treturn luaL_error(L, \"sol: cannot write to a sol::readonly variable\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;\n\t\t\t\t\treturn lcw.call(L, std::move(rw.value()));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic int call(lua_State* L, readonly_wrapper<F>&& rw, object_type& o) {\n\t\t\t\tif constexpr (!is_index) {\n\t\t\t\t\t(void)o;\n\t\t\t\t\treturn call(L, std::move(rw));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;\n\t\t\t\t\treturn lcw.call(L, rw.value(), o);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic int call(lua_State* L, const readonly_wrapper<F>& rw) {\n\t\t\t\tif constexpr (!is_index) {\n\t\t\t\t\t(void)rw;\n\t\t\t\t\treturn luaL_error(L, \"sol: cannot write to a sol::readonly variable\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;\n\t\t\t\t\treturn lcw.call(L, rw.value());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic int call(lua_State* L, const readonly_wrapper<F>& rw, object_type& o) {\n\t\t\t\tif constexpr (!is_index) {\n\t\t\t\t\t(void)o;\n\t\t\t\t\treturn call(L, rw);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;\n\t\t\t\t\treturn lcw.call(L, rw.value(), o);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef constructor_list<Args...> F;\n\n\t\t\tstatic int call(lua_State* L, F&) {\n\t\t\t\tconst auto& meta = usertype_traits<T>::metatable();\n\t\t\t\tint argcount = lua_gettop(L);\n\t\t\t\tcall_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;\n\t\t\t\targcount -= static_cast<int>(syntax);\n\n\t\t\t\tT* obj = detail::usertype_allocate<T>(L);\n\t\t\t\treference userdataref(L, -1);\n\t\t\t\tstack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>);\n\t\t\t\tumf();\n\n\t\t\t\t// put userdata at the first index\n\t\t\t\tlua_insert(L, 1);\n\t\t\t\tconstruct_match<T, Args...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, boost + 1 + 1 + static_cast<int>(syntax));\n\n\t\t\t\tuserdataref.push();\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef constructor_wrapper<Cxs...> F;\n\n\t\t\tstruct onmatch {\n\t\t\t\ttemplate <typename Fx, std::size_t I, typename... R, typename... Args>\n\t\t\t\tint operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {\n\t\t\t\t\tconst auto& meta = usertype_traits<T>::metatable();\n\t\t\t\t\tT* obj = detail::usertype_allocate<T>(L);\n\t\t\t\t\treference userdataref(L, -1);\n\t\t\t\t\tstack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>);\n\t\t\t\t\tumf();\n\n\t\t\t\t\tauto& func = std::get<I>(f.functions);\n\t\t\t\t\t// put userdata at the first index\n\t\t\t\t\tlua_insert(L, 1);\n\t\t\t\t\tstack::call_into_lua<checked, clean_stack>(r, a, L, boost + 1 + start, func, detail::implicit_wrapper<T>(obj));\n\n\t\t\t\t\tuserdataref.push();\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic int call(lua_State* L, F& f) {\n\t\t\t\tcall_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1);\n\t\t\t\tint syntaxval = static_cast<int>(syntax);\n\t\t\t\tint argcount = lua_gettop(L) - syntaxval;\n\t\t\t\treturn construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, C> {\n\n\t\t\ttemplate <typename F>\n\t\t\tstatic int call(lua_State* L, F&& f) {\n\t\t\t\tif constexpr (std::is_void_v<Fx>) {\n\t\t\t\t\treturn detail::usertype_alloc_destruct<T>(L);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing uFx = meta::unqualified_t<Fx>;\n\t\t\t\t\tlua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\t\treturn lcw.call(L, std::forward<F>(f).fx);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef overload_set<Fs...> F;\n\n\t\t\tstruct on_match {\n\t\t\t\ttemplate <typename Fx, std::size_t I, typename... R, typename... Args>\n\t\t\t\tint operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {\n\t\t\t\t\tauto& f = std::get<I>(fx.functions);\n\t\t\t\t\treturn lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic int call(lua_State* L, F& fx) {\n\t\t\t\treturn overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef factory_wrapper<Fs...> F;\n\n\t\t\tstruct on_match {\n\t\t\t\ttemplate <typename Fx, std::size_t I, typename... R, typename... Args>\n\t\t\t\tint operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {\n\t\t\t\t\tauto& f = std::get<I>(fx.functions);\n\t\t\t\t\treturn lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic int call(lua_State* L, F& fx) {\n\t\t\t\treturn overload_match_arity<Fs...>(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef meta::conditional_t<is_index, R, W> P;\n\t\t\ttypedef meta::unqualified_t<P> U;\n\t\t\ttypedef wrapper<U> wrap;\n\t\t\ttypedef lua_bind_traits<U> traits_type;\n\t\t\ttypedef meta::unqualified_t<typename traits_type::template arg_at<0>> object_type;\n\n\t\t\ttemplate <typename F, typename... Args>\n\t\t\tstatic int call(lua_State* L, F&& f, Args&&... args) {\n\t\t\t\tconstexpr bool is_specialized = meta::any<std::is_same<U, detail::no_prop>,\n\t\t\t\t     meta::is_specialization_of<U, var_wrapper>,\n\t\t\t\t     meta::is_specialization_of<U, constructor_wrapper>,\n\t\t\t\t     meta::is_specialization_of<U, constructor_list>,\n\t\t\t\t     std::is_member_pointer<U>>::value;\n\t\t\t\tif constexpr (is_specialized) {\n\t\t\t\t\tif constexpr (is_index) {\n\t\t\t\t\t\tdecltype(auto) p = f.read();\n\t\t\t\t\t\tlua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\t\t\treturn lcw.call(L, p, std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdecltype(auto) p = f.write();\n\t\t\t\t\t\tlua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\t\t\treturn lcw.call(L, p, std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconstexpr bool non_class_object_type = meta::any<std::is_void<object_type>,\n\t\t\t\t\t     meta::boolean<lua_type_of<meta::unwrap_unqualified_t<object_type>>::value != type::userdata>>::value;\n\t\t\t\t\tif constexpr (non_class_object_type) {\n\t\t\t\t\t\t// The type being void means we don't have any arguments, so it might be a free functions?\n\t\t\t\t\t\tusing args_list = typename traits_type::free_args_list;\n\t\t\t\t\t\tusing returns_list = typename wrap::returns_list;\n\t\t\t\t\t\tusing caller = typename wrap::caller;\n\t\t\t\t\t\tif constexpr (is_index) {\n\t\t\t\t\t\t\tdecltype(auto) pf = f.read();\n\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t\t     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tdecltype(auto) pf = f.write();\n\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t\t     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tusing args_list = meta::pop_front_type_t<typename traits_type::free_args_list>;\n\t\t\t\t\t\tusing Ta = T;\n\t\t\t\t\t\tusing Oa = std::remove_pointer_t<object_type>;\n#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)\n\t\t\t\t\t\tauto maybeo = stack::check_get<Ta*>(L, 1);\n\t\t\t\t\t\tif (!maybeo || maybeo.value() == nullptr) {\n\t\t\t\t\t\t\tif (is_variable) {\n\t\t\t\t\t\t\t\treturn luaL_error(L, \"sol: 'self' argument is lua_nil (bad '.' access?)\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn luaL_error(L, \"sol: 'self' argument is lua_nil (pass 'self' as first argument)\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tOa* o = static_cast<Oa*>(maybeo.value());\n#else\n\t\t\t\t\t\tOa* o = static_cast<Oa*>(stack::get<non_null<Ta*>>(L, 1));\n#endif // Safety\n\t\t\t\t\t\tusing returns_list = typename wrap::returns_list;\n\t\t\t\t\t\tusing caller = typename wrap::caller;\n\t\t\t\t\t\tif constexpr (is_index) {\n\t\t\t\t\t\t\tdecltype(auto) pf = f.read();\n\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t\t     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper<Oa>(*o));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tdecltype(auto) pf = f.write();\n\t\t\t\t\t\t\treturn stack::call_into_lua<checked, clean_stack>(\n\t\t\t\t\t\t\t     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper<Oa>(*o));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef protect_t<V> F;\n\n\t\t\ttemplate <typename... Args>\n\t\t\tstatic int call(lua_State* L, F& fx, Args&&... args) {\n\t\t\t\treturn lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack>{}.call(L, fx.value, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename F, typename... Policies, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, policy_wrapper<F, Policies...>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttypedef policy_wrapper<F, Policies...> P;\n\n\t\t\ttemplate <std::size_t... In>\n\t\t\tstatic int call(std::index_sequence<In...>, lua_State* L, P& fx) {\n\t\t\t\tint pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C>{}.call(L, fx.value);\n\t\t\t\t(void)detail::swallow{ int(), (policy_detail::handle_policy(std::get<In>(fx.policies), L, pushed), int())... };\n\t\t\t\treturn pushed;\n\t\t\t}\n\n\t\t\tstatic int call(lua_State* L, P& fx) {\n\t\t\t\ttypedef typename P::indices indices;\n\t\t\t\treturn call(indices(), L, fx);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename Y, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, yielding_t<Y>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\ttemplate <typename F>\n\t\t\tstatic int call(lua_State* L, F&& f) {\n\t\t\t\treturn lua_call_wrapper<T, meta::unqualified_t<Y>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.func);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>\n\t\tstruct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> {\n\t\t\tstatic int call(lua_State* L, const function_arguments<Sig, P>& f) {\n\t\t\t\tlua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\treturn lcw.call(L, std::get<0>(f.arguments));\n\t\t\t}\n\n\t\t\tstatic int call(lua_State* L, function_arguments<Sig, P>&& f) {\n\t\t\t\tlua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\treturn lcw.call(L, std::get<0>(std::move(f.arguments)));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = detail::default_safe_function_calls, bool clean_stack = true,\n\t\t     typename Fx, typename... Args>\n\t\tinline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\tusing uFx = meta::unqualified_t<Fx>;\n\t\t\tif constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {\n\t\t\t\tusing real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>;\n\t\t\t\tlua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\treturn lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{};\n\t\t\t\treturn lcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls,\n\t\t     bool clean_stack = true>\n\t\tinline int call_user(lua_State* L) {\n\t\t\tauto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));\n\t\t\tusing uFx = meta::unqualified_t<F>;\n\t\t\tint nr = call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);\n\t\t\tif constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct is_var_bind : std::false_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_var_bind<T, std::enable_if_t<is_lua_reference_or_proxy<T>::value>> : std::true_type {};\n\n\t\ttemplate <>\n\t\tstruct is_var_bind<detail::no_prop> : std::true_type {};\n\n\t\ttemplate <typename R, typename W>\n\t\tstruct is_var_bind<property_wrapper<R, W>> : std::true_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_var_bind<var_wrapper<T>> : std::true_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> {};\n\n\t\ttemplate <typename F, typename... Policies>\n\t\tstruct is_var_bind<policy_wrapper<F, Policies...>> : is_var_bind<meta::unqualified_t<F>> {};\n\t} // namespace call_detail\n\n\ttemplate <typename T>\n\tstruct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};\n\n\ttemplate <typename T>\n\tusing is_var_wrapper = meta::is_specialization_of<T, var_wrapper>;\n\n\ttemplate <typename T>\n\tstruct is_function_binding : meta::neg<is_variable_binding<T>> {};\n\n} // namespace sol\n\n// end of sol/call.hpp\n\nnamespace sol {\n\tnamespace function_detail {\n\t\ttemplate <typename F, F fx>\n\t\tinline int call_wrapper_variable(std::false_type, lua_State* L) {\n\t\t\ttypedef meta::bind_traits<meta::unqualified_t<F>> traits_type;\n\t\t\ttypedef typename traits_type::args_list args_list;\n\t\t\ttypedef meta::tuple_types<typename traits_type::return_type> return_type;\n\t\t\treturn stack::call_into_lua(return_type(), args_list(), L, 1, fx);\n\t\t}\n\n\t\ttemplate <typename R, typename V, V, typename T>\n\t\tinline int call_set_assignable(std::false_type, T&&, lua_State* L) {\n\t\t\treturn luaL_error(L, \"cannot write to this type: copy assignment/constructor not available\");\n\t\t}\n\n\t\ttemplate <typename R, typename V, V variable, typename T>\n\t\tinline int call_set_assignable(std::true_type, lua_State* L, T&& mem) {\n\t\t\t(mem.*variable) = stack::get<R>(L, 2);\n\t\t\treturn 0;\n\t\t}\n\n\t\ttemplate <typename R, typename V, V, typename T>\n\t\tinline int call_set_variable(std::false_type, lua_State* L, T&&) {\n\t\t\treturn luaL_error(L, \"cannot write to a const variable\");\n\t\t}\n\n\t\ttemplate <typename R, typename V, V variable, typename T>\n\t\tinline int call_set_variable(std::true_type, lua_State* L, T&& mem) {\n\t\t\treturn call_set_assignable<R, V, variable>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, std::forward<T>(mem));\n\t\t}\n\n\t\ttemplate <typename V, V variable>\n\t\tinline int call_wrapper_variable(std::true_type, lua_State* L) {\n\t\t\ttypedef meta::bind_traits<meta::unqualified_t<V>> traits_type;\n\t\t\ttypedef typename traits_type::object_type T;\n\t\t\ttypedef typename traits_type::return_type R;\n\t\t\tauto& mem = stack::get<T>(L, 1);\n\t\t\tswitch (lua_gettop(L)) {\n\t\t\tcase 1: {\n\t\t\t\tdecltype(auto) r = (mem.*variable);\n\t\t\t\tstack::push_reference(L, std::forward<decltype(r)>(r));\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tcase 2:\n\t\t\t\treturn call_set_variable<R, V, variable>(meta::neg<std::is_const<R>>(), L, mem);\n\t\t\tdefault:\n\t\t\t\treturn luaL_error(L, \"incorrect number of arguments to member variable function call\");\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename F, F fx>\n\t\tinline int call_wrapper_function(std::false_type, lua_State* L) {\n\t\t\treturn call_wrapper_variable<F, fx>(std::is_member_object_pointer<F>(), L);\n\t\t}\n\n\t\ttemplate <typename F, F fx>\n\t\tinline int call_wrapper_function(std::true_type, lua_State* L) {\n\t\t\treturn call_detail::call_wrapped<void, false, false>(L, fx);\n\t\t}\n\n\t\ttemplate <typename F, F fx>\n\t\tint call_wrapper_entry(lua_State* L) noexcept(meta::bind_traits<F>::is_noexcept) {\n\t\t\treturn call_wrapper_function<F, fx>(std::is_member_function_pointer<meta::unqualified_t<F>>(), L);\n\t\t}\n\n\t\ttemplate <typename... Fxs>\n\t\tstruct c_call_matcher {\n\t\t\ttemplate <typename Fx, std::size_t I, typename R, typename... Args>\n\t\t\tint operator()(types<Fx>, meta::index_value<I>, types<R>, types<Args...>, lua_State* L, int, int) const {\n\t\t\t\ttypedef meta::at_in_pack_t<I, Fxs...> target;\n\t\t\t\treturn target::call(L);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename F, F fx>\n\t\tinline int c_call_raw(std::true_type, lua_State* L) {\n\t\t\treturn fx(L);\n\t\t}\n\n\t\ttemplate <typename F, F fx>\n\t\tinline int c_call_raw(std::false_type, lua_State* L) {\n#ifdef __clang__\n\t\t\treturn detail::trampoline(L, function_detail::call_wrapper_entry<F, fx>);\n#else\n\t\t\treturn detail::typed_static_trampoline<decltype(&function_detail::call_wrapper_entry<F, fx>), (&function_detail::call_wrapper_entry<F, fx>)>(L);\n#endif // fuck you clang :c\n\t\t}\n\n\t} // namespace function_detail\n\n\ttemplate <typename F, F fx>\n\tinline int c_call(lua_State* L) {\n\t\ttypedef meta::unqualified_t<F> Fu;\n\t\ttypedef std::integral_constant<bool,\n\t\t     std::is_same<Fu, lua_CFunction>::value\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\t          || std::is_same<Fu, detail::lua_CFunction_noexcept>::value\n#endif\n\t\t     >\n\t\t     is_raw;\n\t\treturn function_detail::c_call_raw<F, fx>(is_raw(), L);\n\t}\n\n\ttemplate <typename F, F f>\n\tstruct wrap {\n\t\ttypedef F type;\n\n\t\tstatic int call(lua_State* L) {\n\t\t\treturn c_call<type, f>(L);\n\t\t}\n\t};\n\n\ttemplate <typename... Fxs>\n\tinline int c_call(lua_State* L) {\n\t\tif constexpr (sizeof...(Fxs) < 2) {\n\t\t\tusing target = meta::at_in_pack_t<0, Fxs...>;\n\t\t\treturn target::call(L);\n\t\t}\n\t\telse {\n\t\t\treturn call_detail::overload_match_arity<typename Fxs::type...>(function_detail::c_call_matcher<Fxs...>(), L, lua_gettop(L), 1);\n\t\t}\n\t}\n\n} // namespace sol\n\n// end of sol/function_types_templated.hpp\n\n// beginning of sol/function_types_stateless.hpp\n\nnamespace sol { namespace function_detail {\n\ttemplate <typename Function, bool is_yielding>\n\tstruct upvalue_free_function {\n\t\tusing function_type = std::remove_pointer_t<std::decay_t<Function>>;\n\t\tusing traits_type = meta::bind_traits<function_type>;\n\n\t\tstatic int real_call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\tauto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);\n\t\t\tfunction_type* fx = udata.first;\n\t\t\treturn call_detail::call_wrapped<void, true, false>(L, fx);\n\t\t}\n\n\t\tstatic int call(lua_State* L) {\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct upvalue_member_function {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef lua_bind_traits<function_type> traits_type;\n\n\t\tstatic int real_call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\t// Layout:\n\t\t\t// idx 1...n: verbatim data of member function pointer\n\t\t\t// idx n + 1: is the object's void pointer\n\t\t\t// We don't need to store the size, because the other side is templated\n\t\t\t// with the same member function pointer type\n\t\t\tfunction_type& memfx = stack::get<user<function_type>>(L, upvalue_index(2));\n\t\t\tauto& item = *static_cast<T*>(stack::get<void*>(L, upvalue_index(3)));\n\t\t\treturn call_detail::call_wrapped<T, true, false, -1>(L, memfx, item);\n\t\t}\n\n\t\tstatic int call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct upvalue_member_variable {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef lua_bind_traits<function_type> traits_type;\n\n\t\tstatic int real_call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\t// Layout:\n\t\t\t// idx 1...n: verbatim data of member variable pointer\n\t\t\t// idx n + 1: is the object's void pointer\n\t\t\t// We don't need to store the size, because the other side is templated\n\t\t\t// with the same member function pointer type\n\t\t\tauto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);\n\t\t\tauto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);\n\t\t\tauto& mem = *objdata.first;\n\t\t\tfunction_type& var = memberdata.first;\n\t\t\tswitch (lua_gettop(L)) {\n\t\t\tcase 0:\n\t\t\t\treturn call_detail::call_wrapped<T, true, false, -1>(L, var, mem);\n\t\t\tcase 1:\n\t\t\t\treturn call_detail::call_wrapped<T, false, false, -1>(L, var, mem);\n\t\t\tdefault:\n\t\t\t\treturn luaL_error(L, \"sol: incorrect number of arguments to member variable function\");\n\t\t\t}\n\t\t}\n\n\t\tstatic int call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct upvalue_member_variable<T, readonly_wrapper<Function>, is_yielding> {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef lua_bind_traits<function_type> traits_type;\n\n\t\tstatic int real_call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\t// Layout:\n\t\t\t// idx 1...n: verbatim data of member variable pointer\n\t\t\t// idx n + 1: is the object's void pointer\n\t\t\t// We don't need to store the size, because the other side is templated\n\t\t\t// with the same member function pointer type\n\t\t\tauto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);\n\t\t\tauto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);\n\t\t\tauto& mem = *objdata.first;\n\t\t\tfunction_type& var = memberdata.first;\n\t\t\tswitch (lua_gettop(L)) {\n\t\t\tcase 0:\n\t\t\t\treturn call_detail::call_wrapped<T, true, false, -1>(L, var, mem);\n\t\t\tdefault:\n\t\t\t\treturn luaL_error(L, \"sol: incorrect number of arguments to member variable function\");\n\t\t\t}\n\t\t}\n\n\t\tstatic int call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct upvalue_this_member_function {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef lua_bind_traits<function_type> traits_type;\n\n\t\tstatic int real_call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\t// Layout:\n\t\t\t// idx 1...n: verbatim data of member variable pointer\n\t\t\tfunction_type& memfx = stack::get<user<function_type>>(L, upvalue_index(2));\n\t\t\treturn call_detail::call_wrapped<T, false, false>(L, memfx);\n\t\t}\n\n\t\tstatic int call(lua_State* L)\n#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n\t\t// MSVC is broken, what a surprise...\n#else\n\t\t\tnoexcept(traits_type::is_noexcept)\n#endif\n\t\t{\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct upvalue_this_member_variable {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\n\t\tstatic int real_call(lua_State* L) noexcept(false) {\n\t\t\t// Layout:\n\t\t\t// idx 1...n: verbatim data of member variable pointer\n\t\t\tauto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);\n\t\t\tfunction_type& var = memberdata.first;\n\t\t\tswitch (lua_gettop(L)) {\n\t\t\tcase 1:\n\t\t\t\treturn call_detail::call_wrapped<T, true, false>(L, var);\n\t\t\tcase 2:\n\t\t\t\treturn call_detail::call_wrapped<T, false, false>(L, var);\n\t\t\tdefault:\n\t\t\t\treturn luaL_error(L, \"sol: incorrect number of arguments to member variable function\");\n\t\t\t}\n\t\t}\n\n\t\tstatic int call(lua_State* L) {\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct upvalue_this_member_variable<T, readonly_wrapper<Function>, is_yielding> {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef lua_bind_traits<function_type> traits_type;\n\n\t\tstatic int real_call(lua_State* L) noexcept(false) {\n\t\t\t// Layout:\n\t\t\t// idx 1...n: verbatim data of member variable pointer\n\t\t\tauto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);\n\t\t\tfunction_type& var = memberdata.first;\n\t\t\tswitch (lua_gettop(L)) {\n\t\t\tcase 1:\n\t\t\t\treturn call_detail::call_wrapped<T, true, false>(L, var);\n\t\t\tdefault:\n\t\t\t\treturn luaL_error(L, \"sol: incorrect number of arguments to member variable function\");\n\t\t\t}\n\t\t}\n\n\t\tstatic int call(lua_State* L) {\n\t\t\tint nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\treturn call(L);\n\t\t}\n\t};\n}} // namespace sol::function_detail\n\n// end of sol/function_types_stateless.hpp\n\n// beginning of sol/function_types_stateful.hpp\n\nnamespace sol {\nnamespace function_detail {\n\ttemplate <typename Func, bool is_yielding, bool no_trampoline>\n\tstruct functor_function {\n\t\ttypedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type;\n\t\tfunction_type fx;\n\n\t\ttemplate <typename... Args>\n\t\tfunctor_function(function_type f, Args&&... args)\n\t\t: fx(std::move(f), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tint call(lua_State* L) {\n\t\t\tint nr = call_detail::call_wrapped<void, true, false>(L, fx);\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\tif (!no_trampoline) {\n\t\t\t\tauto f = [&](lua_State*) -> int { return this->call(L); };\n\t\t\t\treturn detail::trampoline(L, f);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn call(L);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct member_function {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef meta::function_return_t<function_type> return_type;\n\t\ttypedef meta::function_args_t<function_type> args_lists;\n\t\tfunction_type invocation;\n\t\tT member;\n\n\t\ttemplate <typename... Args>\n\t\tmember_function(function_type f, Args&&... args)\n\t\t: invocation(std::move(f)), member(std::forward<Args>(args)...) {\n\t\t}\n\n\t\tint call(lua_State* L) {\n\t\t\tint nr = call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member)));\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\tauto f = [&](lua_State*) -> int { return this->call(L); };\n\t\t\treturn detail::trampoline(L, f);\n\t\t}\n\t};\n\n\ttemplate <typename T, typename Function, bool is_yielding>\n\tstruct member_variable {\n\t\ttypedef std::remove_pointer_t<std::decay_t<Function>> function_type;\n\t\ttypedef typename meta::bind_traits<function_type>::return_type return_type;\n\t\ttypedef typename meta::bind_traits<function_type>::args_list args_lists;\n\t\tfunction_type var;\n\t\tT member;\n\t\ttypedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M;\n\n\t\ttemplate <typename... Args>\n\t\tmember_variable(function_type v, Args&&... args)\n\t\t: var(std::move(v)), member(std::forward<Args>(args)...) {\n\t\t}\n\n\t\tint call(lua_State* L) {\n\t\t\tint nr;\n\t\t\t{\n\t\t\t\tM mem = detail::unwrap(detail::deref(member));\n\t\t\t\tswitch (lua_gettop(L)) {\n\t\t\t\tcase 0:\n\t\t\t\t\tnr = call_detail::call_wrapped<T, true, false, -1>(L, var, mem);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tnr = call_detail::call_wrapped<T, false, false, -1>(L, var, mem);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tnr = luaL_error(L, \"sol: incorrect number of arguments to member variable function\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (is_yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\tauto f = [&](lua_State*) -> int { return this->call(L); };\n\t\t\treturn detail::trampoline(L, f);\n\t\t}\n\t};\n}\n} // namespace sol::function_detail\n\n// end of sol/function_types_stateful.hpp\n\n// beginning of sol/function_types_overloaded.hpp\n\nnamespace sol {\nnamespace function_detail {\n\ttemplate <int start_skew, typename... Functions>\n\tstruct overloaded_function {\n\t\ttypedef std::tuple<Functions...> overload_list;\n\t\ttypedef std::make_index_sequence<sizeof...(Functions)> indices;\n\t\toverload_list overloads;\n\n\t\toverloaded_function(overload_list set)\n\t\t: overloads(std::move(set)) {\n\t\t}\n\n\t\toverloaded_function(Functions... fxs)\n\t\t: overloads(fxs...) {\n\t\t}\n\n\t\ttemplate <typename Fx, std::size_t I, typename... R, typename... Args>\n\t\tstatic int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) {\n\t\t\tauto& func = std::get<I>(ol);\n\t\t\tint nr = call_detail::call_wrapped<void, true, false, start_skew>(L, func);\n\t\t\treturn nr;\n\t\t}\n\n\t\tint operator()(lua_State* L) {\n\t\t\tauto mfx = [](auto&&... args) { return call(std::forward<decltype(args)>(args)...); };\n\t\t\treturn call_detail::overload_match<Functions...>(mfx, L, 1 + start_skew, overloads);\n\t\t}\n\t};\n}\n} // namespace sol::function_detail\n\n// end of sol/function_types_overloaded.hpp\n\n// beginning of sol/resolve.hpp\n\nnamespace sol {\n\n#ifndef __clang__\n\t// constexpr is fine for not-clang\n\n\tnamespace detail {\n\t\ttemplate <typename R, typename... Args, typename F, typename = std::invoke_result_t<meta::unqualified_t<F>, Args...>>\n\t\tinline constexpr auto resolve_i(types<R(Args...)>, F &&) -> R (meta::unqualified_t<F>::*)(Args...) {\n\t\t\tusing Sig = R(Args...);\n\t\t\ttypedef meta::unqualified_t<F> Fu;\n\t\t\treturn static_cast<Sig Fu::*>(&Fu::operator());\n\t\t}\n\n\t\ttemplate <typename F, typename U = meta::unqualified_t<F>>\n\t\tinline constexpr auto resolve_f(std::true_type, F&& f)\n\t\t     -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) {\n\t\t\treturn resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f));\n\t\t}\n\n\t\ttemplate <typename F>\n\t\tinline constexpr void resolve_f(std::false_type, F&&) {\n\t\t\tstatic_assert(\n\t\t\t     meta::has_deducible_signature<F>::value, \"Cannot use no-template-parameter call with an overloaded functor: specify the signature\");\n\t\t}\n\n\t\ttemplate <typename F, typename U = meta::unqualified_t<F>>\n\t\tinline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) {\n\t\t\treturn resolve_f(meta::has_deducible_signature<U> {}, std::forward<F>(f));\n\t\t}\n\n\t\ttemplate <typename... Args, typename F, typename R = std::invoke_result_t<F&, Args...>>\n\t\tinline constexpr auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) {\n\t\t\treturn resolve_i(types<R(Args...)>(), std::forward<F>(f));\n\t\t}\n\n\t\ttemplate <typename Sig, typename C>\n\t\tinline constexpr Sig C::*resolve_v(std::false_type, Sig C::*mem_func_ptr) {\n\t\t\treturn mem_func_ptr;\n\t\t}\n\n\t\ttemplate <typename Sig, typename C>\n\t\tinline constexpr Sig C::*resolve_v(std::true_type, Sig C::*mem_variable_ptr) {\n\t\t\treturn mem_variable_ptr;\n\t\t}\n\t} // namespace detail\n\n\ttemplate <typename... Args, typename R>\n\tinline constexpr auto resolve(R fun_ptr(Args...)) -> R (*)(Args...) {\n\t\treturn fun_ptr;\n\t}\n\n\ttemplate <typename Sig>\n\tinline constexpr Sig* resolve(Sig* fun_ptr) {\n\t\treturn fun_ptr;\n\t}\n\n\ttemplate <typename... Args, typename R, typename C>\n\tinline constexpr auto resolve(R (C::*mem_ptr)(Args...)) -> R (C::*)(Args...) {\n\t\treturn mem_ptr;\n\t}\n\n\ttemplate <typename Sig, typename C>\n\tinline constexpr Sig C::*resolve(Sig C::*mem_ptr) {\n\t\treturn detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr);\n\t}\n\n\ttemplate <typename... Sig, typename F, meta::disable<std::is_function<meta::unqualified_t<F>>> = meta::enabler>\n\tinline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) {\n\t\treturn detail::resolve_i(types<Sig...>(), std::forward<F>(f));\n\t}\n#else\n\n\t// Clang has distinct problems with constexpr arguments,\n\t// so don't use the constexpr versions inside of clang.\n\n\tnamespace detail {\n\t\ttemplate <typename R, typename... Args, typename F, typename = std::invoke_result_t<meta::unqualified_t<F>, Args...>>\n\t\tinline auto resolve_i(types<R(Args...)>, F &&) -> R (meta::unqualified_t<F>::*)(Args...) {\n\t\t\tusing Sig = R(Args...);\n\t\t\ttypedef meta::unqualified_t<F> Fu;\n\t\t\treturn static_cast<Sig Fu::*>(&Fu::operator());\n\t\t}\n\n\t\ttemplate <typename F, typename U = meta::unqualified_t<F>>\n\t\tinline auto resolve_f(std::true_type, F&& f)\n\t\t     -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) {\n\t\t\treturn resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f));\n\t\t}\n\n\t\ttemplate <typename F>\n\t\tinline void resolve_f(std::false_type, F&&) {\n\t\t\tstatic_assert(\n\t\t\t     meta::has_deducible_signature<F>::value, \"Cannot use no-template-parameter call with an overloaded functor: specify the signature\");\n\t\t}\n\n\t\ttemplate <typename F, typename U = meta::unqualified_t<F>>\n\t\tinline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) {\n\t\t\treturn resolve_f(meta::has_deducible_signature<U> {}, std::forward<F>(f));\n\t\t}\n\n\t\ttemplate <typename... Args, typename F, typename R = std::invoke_result_t<F&, Args...>>\n\t\tinline auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) {\n\t\t\treturn resolve_i(types<R(Args...)>(), std::forward<F>(f));\n\t\t}\n\n\t\ttemplate <typename Sig, typename C>\n\t\tinline Sig C::*resolve_v(std::false_type, Sig C::*mem_func_ptr) {\n\t\t\treturn mem_func_ptr;\n\t\t}\n\n\t\ttemplate <typename Sig, typename C>\n\t\tinline Sig C::*resolve_v(std::true_type, Sig C::*mem_variable_ptr) {\n\t\t\treturn mem_variable_ptr;\n\t\t}\n\t} // namespace detail\n\n\ttemplate <typename... Args, typename R>\n\tinline auto resolve(R fun_ptr(Args...)) -> R (*)(Args...) {\n\t\treturn fun_ptr;\n\t}\n\n\ttemplate <typename Sig>\n\tinline Sig* resolve(Sig* fun_ptr) {\n\t\treturn fun_ptr;\n\t}\n\n\ttemplate <typename... Args, typename R, typename C>\n\tinline auto resolve(R (C::*mem_ptr)(Args...)) -> R (C::*)(Args...) {\n\t\treturn mem_ptr;\n\t}\n\n\ttemplate <typename Sig, typename C>\n\tinline Sig C::*resolve(Sig C::*mem_ptr) {\n\t\treturn detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr);\n\t}\n\n\ttemplate <typename... Sig, typename F>\n\tinline auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) {\n\t\treturn detail::resolve_i(types<Sig...>(), std::forward<F>(f));\n\t}\n\n#endif\n\n} // namespace sol\n\n// end of sol/resolve.hpp\n\nnamespace sol {\n\tnamespace function_detail {\n\t\ttemplate <typename T>\n\t\tstruct class_indicator {\n\t\t\tusing type = T;\n\t\t};\n\n\t\tstruct call_indicator { };\n\n\t\ttemplate <bool yielding>\n\t\tint lua_c_wrapper(lua_State* L) {\n\t\t\tlua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2));\n\t\t\tint nr = cf(L);\n\t\t\tif constexpr (yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool yielding>\n\t\tint lua_c_noexcept_wrapper(lua_State* L) noexcept {\n\t\t\tdetail::lua_CFunction_noexcept cf = reinterpret_cast<detail::lua_CFunction_noexcept>(lua_tocfunction(L, lua_upvalueindex(2)));\n\t\t\tint nr = cf(L);\n\t\t\tif constexpr (yielding) {\n\t\t\t\treturn lua_yield(L, nr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn nr;\n\t\t\t}\n\t\t}\n\n\t\tstruct c_function_invocation { };\n\n\t\ttemplate <bool is_yielding, typename Fx, typename... Args>\n\t\tvoid select(lua_State* L, Fx&& fx, Args&&... args);\n\n\t\ttemplate <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>\n\t\tvoid select_set_fx(lua_State* L, Args&&... args) {\n\t\t\tlua_CFunction freefunc = no_trampoline ? detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>\n\t\t\t                                       : function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>;\n\n\t\t\tint upvalues = 0;\n\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\tupvalues += stack::push<user<Fx>>(L, std::forward<Args>(args)...);\n\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t}\n\n\t\ttemplate <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>\n\t\tvoid select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\tusing dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>;\n\t\t\tusing fx_ptr_t = R (*)(A...);\n\t\t\tconstexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>;\n\t\t\tif constexpr (is_convertible) {\n\t\t\t\tfx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));\n\t\t\t\tselect<is_yielding>(L, std::move(fxptr), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tusing F = function_detail::functor_function<dFx, false, true>;\n\t\t\t\tselect_set_fx<is_yielding, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool is_yielding, typename Fx, typename... Args>\n\t\tvoid select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\ttypedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;\n\t\t\tselect_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <bool is_yielding, typename Fx, typename... Args>\n\t\tvoid select_member_variable(lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\tusing uFx = meta::unqualified_t<Fx>;\n\t\t\tif constexpr (sizeof...(Args) < 1) {\n\t\t\t\tusing C = typename meta::bind_traits<uFx>::object_type;\n\t\t\t\tlua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;\n\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::stack_detail::push_as_upvalues(L, fx);\n\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t}\n\t\t\telse if constexpr (sizeof...(Args) < 2) {\n\t\t\t\tusing Tu = typename meta::meta_detail::unqualified_non_alias<Args...>::type;\n\t\t\t\tconstexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;\n\t\t\t\tif constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {\n\t\t\t\t\tlua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call;\n\n\t\t\t\t\tint upvalues = 0;\n\t\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\t\tupvalues += stack::stack_detail::push_as_upvalues(L, fx);\n\t\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t\t}\n\t\t\t\telse if constexpr (is_reference) {\n\t\t\t\t\ttypedef std::decay_t<Fx> dFx;\n\t\t\t\t\tdFx memfxptr(std::forward<Fx>(fx));\n\t\t\t\t\tauto userptr = detail::ptr(std::forward<Args>(args)...);\n\t\t\t\t\tlua_CFunction freefunc\n\t\t\t\t\t     = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;\n\n\t\t\t\t\tint upvalues = 0;\n\t\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\t\tupvalues += stack::stack_detail::push_as_upvalues(L, memfxptr);\n\t\t\t\t\tupvalues += stack::push(L, static_cast<void const*>(userptr));\n\t\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;\n\t\t\t\t\tusing F = function_detail::member_variable<Tu, clean_fx, is_yielding>;\n\t\t\t\t\tselect_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tusing C = typename meta::bind_traits<uFx>::object_type;\n\t\t\t\tusing clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;\n\t\t\t\tusing F = function_detail::member_variable<C, clean_fx, is_yielding>;\n\t\t\t\tselect_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool is_yielding, typename Fx, typename T, typename... Args>\n\t\tvoid select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) {\n\t\t\tusing dFx = std::decay_t<Fx>;\n\t\t\tusing Tu = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {\n\t\t\t\t(void)obj;\n\t\t\t\tusing C = typename Tu::type;\n\t\t\t\tlua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;\n\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconstexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;\n\t\t\t\tif constexpr (is_reference) {\n\t\t\t\t\tauto userptr = detail::ptr(std::forward<T>(obj));\n\t\t\t\t\tlua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx, is_yielding>::call;\n\n\t\t\t\t\tint upvalues = 0;\n\t\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\t\tupvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t\t\tupvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));\n\t\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing F = function_detail::member_function<Tu, dFx, is_yielding>;\n\t\t\t\t\tselect_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool is_yielding, typename Fx, typename... Args>\n\t\tvoid select_member_function(lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\tusing dFx = std::decay_t<Fx>;\n\t\t\tif constexpr (sizeof...(Args) < 1) {\n\t\t\t\tusing C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type;\n\t\t\t\tlua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;\n\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx));\n\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tselect_member_function_with<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool is_yielding, typename Fx, typename... Args>\n\t\tvoid select(lua_State* L, Fx&& fx, Args&&... args) {\n\t\t\tusing uFx = meta::unqualified_t<Fx>;\n\t\t\tif constexpr (is_lua_reference_v<uFx>) {\n\t\t\t\t// TODO: hoist into lambda in this case for yielding???\n\t\t\t\tstack::push(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (is_lua_c_function_v<uFx>) {\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push(L, std::forward<Fx>(fx));\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\t\t\tif constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) {\n\t\t\t\t\tdetail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>;\n\t\t\t\t\tlua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), 2);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlua_CFunction cf = &lua_c_wrapper<is_yielding>;\n\t\t\t\t\tlua_pushcclosure(L, cf, 2);\n\t\t\t\t}\n#else\n\t\t\t\tlua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>;\n\t\t\t\tlua_pushcclosure(L, cf, 2);\n#endif\n\t\t\t}\n\t\t\telse if constexpr (std::is_function_v<std::remove_pointer_t<uFx>>) {\n\t\t\t\tstd::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t\tlua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call;\n\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::stack_detail::push_as_upvalues(L, target);\n\t\t\t\tstack::push(L, c_closure(freefunc, upvalues));\n\t\t\t}\n\t\t\telse if constexpr (std::is_member_function_pointer_v<uFx>) {\n\t\t\t\tselect_member_function<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse if constexpr (meta::is_member_object_v<uFx>) {\n\t\t\t\tselect_member_variable<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tselect_convertible<is_yielding>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);\n\t\t\t}\n\t\t}\n\t} // namespace function_detail\n\n\tnamespace stack {\n\t\ttemplate <typename... Sigs>\n\t\tstruct unqualified_pusher<function_sig<Sigs...>> {\n\t\t\ttemplate <bool is_yielding, typename Arg0, typename... Args>\n\t\t\tstatic int push(lua_State* L, Arg0&& arg0, Args&&... args) {\n\t\t\t\tif constexpr (meta::is_specialization_of_v<meta::unqualified_t<Arg0>, std::function>) {\n\t\t\t\t\tif constexpr (is_yielding) {\n\t\t\t\t\t\treturn stack::push<meta::unqualified_t<Arg0>>(L, detail::yield_tag, std::forward<Arg0>(arg0), std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn stack::push(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfunction_detail::select<is_yielding>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename Arg0, typename... Args>\n\t\t\tstatic int push(lua_State* L, Arg0&& arg0, Args&&... args) {\n\t\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Arg0>, detail::yield_tag_t>) {\n\t\t\t\t\tpush<true>(L, std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse if constexpr (meta::is_specialization_of_v<meta::unqualified_t<Arg0>, yielding_t>) {\n\t\t\t\t\tpush<true>(L, std::forward<Arg0>(arg0).func, std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpush<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<yielding_t<T>> {\n\t\t\ttemplate <typename... Args>\n\t\t\tstatic int push(lua_State* L, const yielding_t<T>& f, Args&&... args) {\n\t\t\t\tif constexpr (meta::is_specialization_of_v<meta::unqualified_t<T>, std::function>) {\n\t\t\t\t\treturn stack::push<T>(L, detail::yield_tag, f.func, std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfunction_detail::select<true>(L, f.func, std::forward<Args>(args)...);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename... Args>\n\t\t\tstatic int push(lua_State* L, yielding_t<T>&& f, Args&&... args) {\n\t\t\t\tif constexpr (meta::is_specialization_of_v<meta::unqualified_t<T>, std::function>) {\n\t\t\t\t\treturn stack::push<T>(L, detail::yield_tag, std::move(f.func), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfunction_detail::select<true>(L, std::move(f.func), std::forward<Args>(args)...);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Args>\n\t\tstruct unqualified_pusher<function_arguments<T, Args...>> {\n\t\t\ttemplate <std::size_t... I, typename FP>\n\t\t\tstatic int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {\n\t\t\t\treturn stack::push<T>(L, std::get<I>(std::forward<FP>(fp).arguments)...);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const function_arguments<T, Args...>& fp) {\n\t\t\t\treturn push_func(std::make_index_sequence<sizeof...(Args)>(), L, fp);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, function_arguments<T, Args...>&& fp) {\n\t\t\t\treturn push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::move(fp));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Signature>\n\t\tstruct unqualified_pusher<std::function<Signature>> {\n\t\t\tstatic int push(lua_State* L, detail::yield_tag_t, const std::function<Signature>& fx) {\n\t\t\t\tif (fx) {\n\t\t\t\t\tfunction_detail::select<true>(L, fx);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, detail::yield_tag_t, std::function<Signature>&& fx) {\n\t\t\t\tif (fx) {\n\t\t\t\t\tfunction_detail::select<true>(L, std::move(fx));\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const std::function<Signature>& fx) {\n\t\t\t\tif (fx) {\n\t\t\t\t\tfunction_detail::select<false>(L, fx);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, std::function<Signature>&& fx) {\n\t\t\t\tif (fx) {\n\t\t\t\t\tfunction_detail::select<false>(L, std::move(fx));\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Signature>\n\t\tstruct unqualified_pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {\n\t\t\ttemplate <typename... Args>\n\t\t\tstatic int push(lua_State* L, Args&&... args) {\n\t\t\t\tfunction_detail::select<false>(L, std::forward<Args>(args)...);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Signature>\n\t\tstruct unqualified_pusher<Signature,\n\t\t     std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>,\n\t\t          meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>\n#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)\n\t\t          ,\n\t\t          meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>,\n\t\t          meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>>\n#endif // noexcept function types\n\t\t          >::value>> {\n\t\t\ttemplate <typename F>\n\t\t\tstatic int push(lua_State* L, F&& f) {\n\t\t\t\tfunction_detail::select<false>(L, std::forward<F>(f));\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename... Functions>\n\t\tstruct unqualified_pusher<overload_set<Functions...>> {\n\t\t\tstatic int push(lua_State* L, overload_set<Functions...>&& set) {\n\t\t\t\tusing F = function_detail::overloaded_function<0, Functions...>;\n\t\t\t\tfunction_detail::select_set_fx<false, false, F>(L, std::move(set.functions));\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const overload_set<Functions...>& set) {\n\t\t\t\tusing F = function_detail::overloaded_function<0, Functions...>;\n\t\t\t\tfunction_detail::select_set_fx<false, false, F>(L, set.functions);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<protect_t<T>> {\n\t\t\tstatic int push(lua_State* L, protect_t<T>&& pw) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<protect_t<T>>>(L, std::move(pw.value));\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const protect_t<T>& pw) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<protect_t<T>>>(L, pw.value);\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename F, typename G>\n\t\tstruct unqualified_pusher<property_wrapper<F, G>> {\n\t\t\tstatic int push(lua_State* L, property_wrapper<F, G>&& pw) {\n\t\t\t\tif constexpr (std::is_void_v<F>) {\n\t\t\t\t\treturn stack::push(L, std::move(pw.write()));\n\t\t\t\t}\n\t\t\t\telse if constexpr (std::is_void_v<G>) {\n\t\t\t\t\treturn stack::push(L, std::move(pw.read()));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::push(L, overload(std::move(pw.read()), std::move(pw.write())));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const property_wrapper<F, G>& pw) {\n\t\t\t\tif constexpr (std::is_void_v<F>) {\n\t\t\t\t\treturn stack::push(L, pw.write);\n\t\t\t\t}\n\t\t\t\telse if constexpr (std::is_void_v<G>) {\n\t\t\t\t\treturn stack::push(L, pw.read);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::push(L, overload(pw.read, pw.write));\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<var_wrapper<T>> {\n\t\t\tstatic int push(lua_State* L, var_wrapper<T>&& vw) {\n\t\t\t\treturn stack::push(L, std::move(vw.value()));\n\t\t\t}\n\t\t\tstatic int push(lua_State* L, const var_wrapper<T>& vw) {\n\t\t\t\treturn stack::push(L, vw.value());\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename... Functions>\n\t\tstruct unqualified_pusher<factory_wrapper<Functions...>> {\n\t\t\tstatic int push(lua_State* L, const factory_wrapper<Functions...>& fw) {\n\t\t\t\tusing F = function_detail::overloaded_function<0, Functions...>;\n\t\t\t\tfunction_detail::select_set_fx<false, false, F>(L, fw.functions);\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, factory_wrapper<Functions...>&& fw) {\n\t\t\t\tusing F = function_detail::overloaded_function<0, Functions...>;\n\t\t\t\tfunction_detail::select_set_fx<false, false, F>(L, std::move(fw.functions));\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const factory_wrapper<Functions...>& fw, function_detail::call_indicator) {\n\t\t\t\tusing F = function_detail::overloaded_function<1, Functions...>;\n\t\t\t\tfunction_detail::select_set_fx<false, false, F>(L, fw.functions);\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, factory_wrapper<Functions...>&& fw, function_detail::call_indicator) {\n\t\t\t\tusing F = function_detail::overloaded_function<1, Functions...>;\n\t\t\t\tfunction_detail::select_set_fx<false, false, F>(L, std::move(fw.functions));\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<no_construction> {\n\t\t\tstatic int push(lua_State* L, no_construction) {\n\t\t\t\tlua_CFunction cf = &function_detail::no_construction_error;\n\t\t\t\treturn stack::push(L, cf);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, no_construction c, function_detail::call_indicator) {\n\t\t\t\treturn push(L, c);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<detail::tagged<T, no_construction>> {\n\t\t\tstatic int push(lua_State* L, detail::tagged<T, no_construction>) {\n\t\t\t\tlua_CFunction cf = &function_detail::no_construction_error;\n\t\t\t\treturn stack::push(L, cf);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, no_construction c, function_detail::call_indicator) {\n\t\t\t\treturn push(L, c);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Lists>\n\t\tstruct unqualified_pusher<detail::tagged<T, constructor_list<Lists...>>> {\n\t\t\tstatic int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) {\n\t\t\t\tlua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>;\n\t\t\t\treturn stack::push(L, cf);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, constructor_list<Lists...>) {\n\t\t\t\tlua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>;\n\t\t\t\treturn stack::push(L, cf);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename L0, typename... Lists>\n\t\tstruct unqualified_pusher<constructor_list<L0, Lists...>> {\n\t\t\ttypedef constructor_list<L0, Lists...> cl_t;\n\t\t\tstatic int push(lua_State* L, cl_t cl) {\n\t\t\t\ttypedef typename meta::bind_traits<L0>::return_type T;\n\t\t\t\treturn stack::push<detail::tagged<T, cl_t>>(L, cl);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename... Fxs>\n\t\tstruct unqualified_pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> {\n\t\t\tstatic int push(lua_State* L, detail::tagged<T, constructor_wrapper<Fxs...>>&& c) {\n\t\t\t\treturn push(L, std::move(c.value()));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const detail::tagged<T, const constructor_wrapper<Fxs...>>& c) {\n\t\t\t\treturn push(L, c.value());\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, constructor_wrapper<Fxs...>&& c) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<constructor_wrapper<Fxs...>>>(L, std::move(c));\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const constructor_wrapper<Fxs...>& c) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<constructor_wrapper<Fxs...>>>(L, c);\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename F, typename... Fxs>\n\t\tstruct unqualified_pusher<constructor_wrapper<F, Fxs...>> {\n\t\t\tstatic int push(lua_State* L, const constructor_wrapper<F, Fxs...>& c) {\n\t\t\t\ttypedef typename meta::bind_traits<F>::template arg_at<0> arg0;\n\t\t\t\ttypedef meta::unqualified_t<std::remove_pointer_t<arg0>> T;\n\t\t\t\treturn stack::push<detail::tagged<T, constructor_wrapper<F, Fxs...>>>(L, c);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, constructor_wrapper<F, Fxs...>&& c) {\n\t\t\t\ttypedef typename meta::bind_traits<F>::template arg_at<0> arg0;\n\t\t\t\ttypedef meta::unqualified_t<std::remove_pointer_t<arg0>> T;\n\t\t\t\treturn stack::push<detail::tagged<T, constructor_wrapper<F, Fxs...>>>(L, std::move(c));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<detail::tagged<T, destructor_wrapper<void>>> {\n\t\t\tstatic int push(lua_State* L, destructor_wrapper<void>) {\n\t\t\t\tlua_CFunction cf = detail::usertype_alloc_destruct<T>;\n\t\t\t\treturn stack::push(L, cf);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename Fx>\n\t\tstruct unqualified_pusher<detail::tagged<T, destructor_wrapper<Fx>>> {\n\t\t\tstatic int push(lua_State* L, destructor_wrapper<Fx>&& c) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c));\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const destructor_wrapper<Fx>& c) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c);\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Fx>\n\t\tstruct unqualified_pusher<destructor_wrapper<Fx>> {\n\t\t\tstatic int push(lua_State* L, destructor_wrapper<Fx>&& c) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c));\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const destructor_wrapper<Fx>& c) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c);\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename F, typename... Policies>\n\t\tstruct unqualified_pusher<policy_wrapper<F, Policies...>> {\n\t\t\tusing P = policy_wrapper<F, Policies...>;\n\n\t\t\tstatic int push(lua_State* L, const P& p) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<P>>(L, p);\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, P&& p) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<P>>(L, std::move(p));\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename F, typename... Policies>\n\t\tstruct unqualified_pusher<detail::tagged<T, policy_wrapper<F, Policies...>>> {\n\t\t\tusing P = policy_wrapper<F, Policies...>;\n\t\t\tusing Tagged = detail::tagged<T, P>;\n\n\t\t\tstatic int push(lua_State* L, const Tagged& p) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<T, false, false, P, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<P>>(L, p.value());\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, Tagged&& p) {\n\t\t\t\tlua_CFunction cf = call_detail::call_user<T, false, false, P, 2>;\n\t\t\t\tint upvalues = 0;\n\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\tupvalues += stack::push<user<P>>(L, std::move(p.value()));\n\t\t\t\treturn stack::push(L, c_closure(cf, upvalues));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<push_invoke_t<T>> {\n\t\t\tstatic int push(lua_State* L, push_invoke_t<T>&& pi) {\n\t\t\t\tif constexpr (std::is_invocable_v<std::add_rvalue_reference_t<T>, lua_State*>) {\n\t\t\t\t\treturn stack::push(L, std::move(pi.value())(L));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::push(L, std::move(pi.value())());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const push_invoke_t<T>& pi) {\n\t\t\t\tif constexpr (std::is_invocable_v<const T, lua_State*>) {\n\t\t\t\t\treturn stack::push(L, pi.value()(L));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn stack::push(L, pi.value()());\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tnamespace stack_detail {\n\t\t\ttemplate <typename Function, typename Handler>\n\t\t\tbool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept {\n#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\t\t\ttracking.use(1);\n\t\t\t\tbool success = lua_iscfunction(L, index) == 1;\n\t\t\t\tif (success) {\n\t\t\t\t\t// there must be at LEAST 2 upvalues; otherwise, we didn't serialize it.\n\t\t\t\t\tconst char* upvalue_name = lua_getupvalue(L, index, 2);\n\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\tsuccess = upvalue_name != nullptr;\n\t\t\t\t}\n\t\t\t\tif (!success) {\n\t\t\t\t\t// expected type, actual type\n\t\t\t\t\thandler(\n\t\t\t\t\t     L, index, type::function, type_of(L, index), \"type must be a Lua C Function gotten from a function pointer serialized by sol2\");\n\t\t\t\t}\n\t\t\t\treturn success;\n#else\n\t\t\t\treturn false;\n#endif\n\t\t\t}\n\n\t\t\ttemplate <typename Function>\n\t\t\tFunction* get_function_pointer(lua_State* L, int index, record& tracking) noexcept {\n#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\t\t\ttracking.use(1);\n\t\t\t\tauto udata = stack::stack_detail::get_as_upvalues_using_function<Function*>(L, index);\n\t\t\t\tFunction* fx = udata.first;\n\t\t\t\treturn fx;\n#else\n\t\t\t\tstatic_assert(meta::meta_detail::always_true<Function>::value,\n#if SOL_IS_DEFAULT_OFF(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)\n\t\t\t\t     \"You are attempting to retrieve a function pointer type. \"\n\t\t\t\t     \"This is inherently unsafe in sol2. In order to do this, you must turn on the \"\n\t\t\t\t     \"SOL_GET_FUNCTION_POINTER_UNSAFE configuration macro, as detailed in the documentation. \"\n\t\t\t\t     \"Please be careful!\"\n#else\n\t\t\t\t     \"You are attempting to retrieve a function pointer type. \"\n\t\t\t\t     \"You explicitly turned off the ability to do this by defining \"\n\t\t\t\t     \"SOL_GET_FUNCTION_POINTER_UNSAFE or similar to be off. \"\n\t\t\t\t     \"Please reconsider this!\"\n#endif\n\t\t\t\t);\n\t\t\t\treturn nullptr;\n#endif\n\t\t\t}\n\t\t} // namespace stack_detail\n\t}      // namespace stack\n} // namespace sol\n\n// end of sol/function_types.hpp\n\n// beginning of sol/dump_handler.hpp\n\n#include <cstdint>\n#include <exception>\n\nnamespace sol {\n\n\tclass dump_error : public error {\n\tprivate:\n\t\tint ec_;\n\n\tpublic:\n\t\tdump_error(int error_code_) : error(\"dump returned non-zero error of \" + std::to_string(error_code_)), ec_(error_code_) {\n\t\t}\n\n\t\tint error_code() const {\n\t\t\treturn ec_;\n\t\t}\n\t};\n\n\tinline int dump_pass_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {\n\t\t(void)L;\n\t\t(void)writer_function;\n\t\t(void)userdata;\n\t\t(void)strip;\n\t\treturn result_code;\n\t}\n\n\tinline int dump_panic_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {\n\t\t(void)L;\n\t\t(void)writer_function;\n\t\t(void)userdata;\n\t\t(void)strip;\n\t\treturn luaL_error(L, \"a non-zero error code (%d) was returned by the lua_Writer for the dump function\", result_code);\n\t}\n\n\tinline int dump_throw_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\treturn dump_panic_on_error(L, result_code, writer_function, userdata, strip);\n#else\n\t\t(void)L;\n\t\t(void)writer_function;\n\t\t(void)userdata;\n\t\t(void)strip;\n\t\tthrow dump_error(result_code);\n#endif // no exceptions stuff\n\t}\n\n} // namespace sol\n\n// end of sol/dump_handler.hpp\n\n#include <cstdint>\n\nnamespace sol {\n\ttemplate <typename ref_t, bool aligned = false>\n\tclass basic_function : public basic_object<ref_t> {\n\tprivate:\n\t\tusing base_t = basic_object<ref_t>;\n\n\t\tvoid luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {\n\t\t\tlua_call(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount));\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename... Ret>\n\t\tauto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {\n\t\t\tluacall(n, lua_size<std::tuple<Ret...>>::value);\n\t\t\treturn stack::pop<std::tuple<Ret...>>(lua_state());\n\t\t}\n\n\t\ttemplate <std::size_t I, typename Ret, meta::enable<meta::neg<std::is_void<Ret>>> = meta::enabler>\n\t\tRet invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {\n\t\t\tluacall(n, lua_size<Ret>::value);\n\t\t\treturn stack::pop<Ret>(lua_state());\n\t\t}\n\n\t\ttemplate <std::size_t I>\n\t\tvoid invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {\n\t\t\tluacall(n, 0);\n\t\t}\n\n\t\tunsafe_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {\n\t\t\tint stacksize = lua_gettop(lua_state());\n\t\t\tint firstreturn = (std::max)(1, stacksize - static_cast<int>(n));\n\t\t\tluacall(n, LUA_MULTRET);\n\t\t\tint poststacksize = lua_gettop(lua_state());\n\t\t\tint returncount = poststacksize - (firstreturn - 1);\n\t\t\treturn unsafe_function_result(lua_state(), firstreturn, returncount);\n\t\t}\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_function() = default;\n\t\ttemplate <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_function(T&& r) noexcept\n\t\t: base_t(std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_function<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler{};\n\t\t\t\tstack::check<basic_function>(lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_function(const basic_function&) = default;\n\t\tbasic_function& operator=(const basic_function&) = default;\n\t\tbasic_function(basic_function&&) = default;\n\t\tbasic_function& operator=(basic_function&&) = default;\n\t\tbasic_function(const stack_reference& r)\n\t\t: basic_function(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_function(stack_reference&& r)\n\t\t: basic_function(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_function(lua_nil_t n)\n\t\t: base_t(n) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_function(lua_State* L, T&& r)\n\t\t: base_t(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_function>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_function(lua_State* L, int index = -1)\n\t\t: base_t(L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_function>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_function(lua_State* L, ref_index index)\n\t\t: base_t(L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_function>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tint dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const {\n\t\t\tthis->push();\n\t\t\tauto ppn = stack::push_popper_n<false>(this->lua_state(), 1);\n\t\t\tint r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0);\n\t\t\tif (r != 0) {\n\t\t\t\treturn on_error(this->lua_state(), r, writer, userdata, strip);\n\t\t\t}\n\t\t\treturn r;\n\t\t}\n\n\t\tint dump(lua_Writer writer, void* userdata, bool strip = false) const {\n\t\t\treturn dump(writer, userdata, strip, &dump_throw_on_error);\n\t\t}\n\n\t\ttemplate <typename Container = bytecode>\n\t\tContainer dump() const {\n\t\t\tContainer bc;\n\t\t\t(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_panic_on_error);\n\t\t\treturn bc;\n\t\t}\n\n\t\ttemplate <typename Container = bytecode, typename Fx>\n\t\tContainer dump(Fx&& on_error) const {\n\t\t\tContainer bc;\n\t\t\t(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error));\n\t\t\treturn bc;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tunsafe_function_result operator()(Args&&... args) const {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) operator()(types<Ret...>, Args&&... args) const {\n\t\t\treturn call<Ret...>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args) const {\n\t\t\tif (!aligned) {\n\t\t\t\tbase_t::push();\n\t\t\t}\n\t\t\tint pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);\n\t\t\treturn invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), static_cast<std::ptrdiff_t>(pushcount));\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/unsafe_function.hpp\n\n// beginning of sol/protected_function.hpp\n\n// beginning of sol/protected_handler.hpp\n\n#include <cstdint>\n\nnamespace sol {\n\tnamespace detail {\n\t\tinline const char(&default_handler_name())[9]{\n\t\t\tstatic const char name[9] = \"sol.\\xF0\\x9F\\x94\\xA9\";\n\t\t\treturn name;\n\t\t}\n\n\t\ttemplate <bool b, typename target_t = reference>\n\t\tstruct protected_handler {\n\t\t\ttypedef is_stack_based<target_t> is_stack;\n\t\t\tconst target_t& target;\n\t\t\tint stackindex;\n\n\t\t\tprotected_handler(std::false_type, const target_t& target)\n\t\t\t\t: target(target), stackindex(0) {\n\t\t\t\tif (b) {\n\t\t\t\t\tstackindex = lua_gettop(target.lua_state()) + 1;\n\t\t\t\t\ttarget.push();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprotected_handler(std::true_type, const target_t& target)\n\t\t\t\t: target(target), stackindex(0) {\n\t\t\t\tif (b) {\n\t\t\t\t\tstackindex = target.stack_index();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprotected_handler(const target_t& target)\n\t\t\t\t: protected_handler(is_stack(), target) {\n\t\t\t}\n\n\t\t\tbool valid() const noexcept {\n\t\t\t\treturn b;\n\t\t\t}\n\n\t\t\t~protected_handler() {\n\t\t\t\tif constexpr (!is_stack::value) {\n\t\t\t\t\tif (stackindex != 0) {\n\t\t\t\t\t\tlua_remove(target.lua_state(), stackindex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename base_t, typename T>\n\t\tbasic_function<base_t> force_cast(T& p) {\n\t\t\treturn p;\n\t\t}\n\n\t\ttemplate <typename Reference, bool is_main_ref = false>\n\t\tstatic Reference get_default_handler(lua_State* L) {\n\t\t\tif (is_stack_based<Reference>::value || L == nullptr)\n\t\t\t\treturn Reference(L, lua_nil);\n\t\t\tL = is_main_ref ? main_thread(L, L) : L;\n\t\t\tlua_getglobal(L, default_handler_name());\n\t\t\tauto pp = stack::pop_n(L, 1);\n\t\t\treturn Reference(L, -1);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tstatic void set_default_handler(lua_State* L, const T& ref) {\n\t\t\tif (L == nullptr) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!ref.valid()) {\n#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)\n\t\t\t\tluaL_checkstack(L, 1, detail::not_enough_stack_space_generic);\n#endif // make sure stack doesn't overflow\n\t\t\t\tlua_pushnil(L);\n\t\t\t\tlua_setglobal(L, default_handler_name());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tref.push(L);\n\t\t\t\tlua_setglobal(L, default_handler_name());\n\t\t\t}\n\t\t}\n\t} // namespace detail\n} // namespace sol\n\n// end of sol/protected_handler.hpp\n\n#include <cstdint>\n#include <algorithm>\n\nnamespace sol {\n\t\n\tnamespace detail {\n\t\ttemplate <bool b, typename handler_t>\n\t\tinline void handle_protected_exception(lua_State* L, optional<const std::exception&> maybe_ex, const char* error, detail::protected_handler<b, handler_t>& h) {\n\t\t\th.stackindex = 0;\n\t\t\tif (b) {\n\t\t\t\th.target.push();\n\t\t\t\tdetail::call_exception_handler(L, maybe_ex, error);\n\t\t\t\tlua_call(L, 1, 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdetail::call_exception_handler(L, maybe_ex, error);\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate <typename ref_t, bool aligned = false, typename handler_t = reference>\n\tclass basic_protected_function : public basic_object<ref_t> {\n\tprivate:\n\t\tusing base_t = basic_object<ref_t>;\n\n\tpublic:\n\t\tusing is_stack_handler = is_stack_based<handler_t>;\n\n\t\tstatic handler_t get_default_handler(lua_State* L) {\n\t\t\treturn detail::get_default_handler<handler_t, is_main_threaded<base_t>::value>(L);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tstatic void set_default_handler(const T& ref) {\n\t\t\tdetail::set_default_handler(ref.lua_state(), ref);\n\t\t}\n\n\tprivate:\n\t\ttemplate <bool b>\n\t\tcall_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::protected_handler<b, handler_t>& h) const {\n\t\t\treturn static_cast<call_status>(lua_pcall(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex));\n\t\t}\n\n\t\ttemplate <std::size_t... I, bool b, typename... Ret>\n\t\tauto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {\n\t\t\tluacall(n, sizeof...(Ret), h);\n\t\t\treturn stack::pop<std::tuple<Ret...>>(lua_state());\n\t\t}\n\n\t\ttemplate <std::size_t I, bool b, typename Ret>\n\t\tRet invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {\n\t\t\tluacall(n, 1, h);\n\t\t\treturn stack::pop<Ret>(lua_state());\n\t\t}\n\n\t\ttemplate <std::size_t I, bool b>\n\t\tvoid invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {\n\t\t\tluacall(n, 0, h);\n\t\t}\n\n\t\ttemplate <bool b>\n\t\tprotected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {\n\t\t\tint stacksize = lua_gettop(lua_state());\n\t\t\tint poststacksize = stacksize;\n\t\t\tint firstreturn = 1;\n\t\t\tint returncount = 0;\n\t\t\tcall_status code = call_status::ok;\n#if !defined(SOL_NO_EXCEPTIONS) || !SOL_NO_EXCEPTIONS\n#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT)\n\t\t\ttry {\n#endif // Safe Exception Propagation\n#endif // No Exceptions\n\t\t\t\tfirstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid() && !is_stack_handler::value)));\n\t\t\t\tcode = luacall(n, LUA_MULTRET, h);\n\t\t\t\tpoststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid() && !is_stack_handler::value);\n\t\t\t\treturncount = poststacksize - (firstreturn - 1);\n#ifndef SOL_NO_EXCEPTIONS\n#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT)\n\t\t\t}\n\t\t\t// Handle C++ errors thrown from C++ functions bound inside of lua\n\t\t\tcatch (const char* error) {\n\t\t\t\tdetail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error, h);\n\t\t\t\tfirstreturn = lua_gettop(lua_state());\n\t\t\t\treturn protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);\n\t\t\t}\n\t\t\tcatch (const std::string& error) {\n\t\t\t\tdetail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error.c_str(), h);\n\t\t\t\tfirstreturn = lua_gettop(lua_state());\n\t\t\t\treturn protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);\n\t\t\t}\n\t\t\tcatch (const std::exception& error) {\n\t\t\t\tdetail::handle_protected_exception(lua_state(), optional<const std::exception&>(error), error.what(), h);\n\t\t\t\tfirstreturn = lua_gettop(lua_state());\n\t\t\t\treturn protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);\n\t\t\t}\n#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION)\n\t\t\t// LuaJIT cannot have the catchall when the safe propagation is on\n\t\t\t// but LuaJIT will swallow all C++ errors \n\t\t\t// if we don't at least catch std::exception ones\n\t\t\tcatch (...) {\n\t\t\t\tdetail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), detail::protected_function_error, h);\n\t\t\t\tfirstreturn = lua_gettop(lua_state());\n\t\t\t\treturn protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);\n\t\t\t}\n#endif // LuaJIT\n#else\n\t\t\t// do not handle exceptions: they can be propogated into C++ and keep all type information / rich information\n#endif // Safe Exception Propagation\n#endif // Exceptions vs. No Exceptions\n\t\t\treturn protected_function_result(lua_state(), firstreturn, returncount, returncount, code);\n\t\t}\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\thandler_t error_handler;\n\n\t\tbasic_protected_function() = default;\n\t\ttemplate <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_protected_function(T&& r) noexcept\n\t\t: base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_function<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler{};\n\t\t\t\tstack::check<basic_protected_function>(lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_protected_function(const basic_protected_function&) = default;\n\t\tbasic_protected_function& operator=(const basic_protected_function&) = default;\n\t\tbasic_protected_function(basic_protected_function&&) = default;\n\t\tbasic_protected_function& operator=(basic_protected_function&&) = default;\n\t\tbasic_protected_function(const basic_function<base_t>& b)\n\t\t: basic_protected_function(b, get_default_handler(b.lua_state())) {\n\t\t}\n\t\tbasic_protected_function(basic_function<base_t>&& b)\n\t\t: basic_protected_function(std::move(b), get_default_handler(b.lua_state())) {\n\t\t}\n\t\tbasic_protected_function(const basic_function<base_t>& b, handler_t eh)\n\t\t: base_t(b), error_handler(std::move(eh)) {\n\t\t}\n\t\tbasic_protected_function(basic_function<base_t>&& b, handler_t eh)\n\t\t: base_t(std::move(b)), error_handler(std::move(eh)) {\n\t\t}\n\t\tbasic_protected_function(const stack_reference& r)\n\t\t: basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {\n\t\t}\n\t\tbasic_protected_function(stack_reference&& r)\n\t\t: basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {\n\t\t}\n\t\tbasic_protected_function(const stack_reference& r, handler_t eh)\n\t\t: basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {\n\t\t}\n\t\tbasic_protected_function(stack_reference&& r, handler_t eh)\n\t\t: basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {\n\t\t}\n\n\t\ttemplate <typename Super>\n\t\tbasic_protected_function(const proxy_base<Super>& p)\n\t\t: basic_protected_function(p, get_default_handler(p.lua_state())) {\n\t\t}\n\t\ttemplate <typename Super>\n\t\tbasic_protected_function(proxy_base<Super>&& p)\n\t\t: basic_protected_function(std::move(p), get_default_handler(p.lua_state())) {\n\t\t}\n\t\ttemplate <typename Proxy, typename Handler, meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler>\n\t\tbasic_protected_function(Proxy&& p, Handler&& eh)\n\t\t: basic_protected_function(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) {\n\t\t}\n\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_protected_function(lua_State* L, T&& r)\n\t\t: basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_protected_function(lua_State* L, T&& r, handler_t eh)\n\t\t: base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_protected_function>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\t\n\t\tbasic_protected_function(lua_nil_t n)\n\t\t\t: base_t(n), error_handler(n) {\n\t\t}\n\n\t\tbasic_protected_function(lua_State* L, int index = -1)\n\t\t: basic_protected_function(L, index, get_default_handler(L)) {\n\t\t}\n\t\tbasic_protected_function(lua_State* L, int index, handler_t eh)\n\t\t: base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_protected_function>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_protected_function(lua_State* L, absolute_index index)\n\t\t: basic_protected_function(L, index, get_default_handler(L)) {\n\t\t}\n\t\tbasic_protected_function(lua_State* L, absolute_index index, handler_t eh)\n\t\t: base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_protected_function>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_protected_function(lua_State* L, raw_index index)\n\t\t: basic_protected_function(L, index, get_default_handler(L)) {\n\t\t}\n\t\tbasic_protected_function(lua_State* L, raw_index index, handler_t eh)\n\t\t: base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_protected_function>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_protected_function(lua_State* L, ref_index index)\n\t\t: basic_protected_function(L, index, get_default_handler(L)) {\n\t\t}\n\t\tbasic_protected_function(lua_State* L, ref_index index, handler_t eh)\n\t\t: base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_protected_function>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tint dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const {\n\t\t\tthis->push();\n\t\t\tauto ppn = stack::push_popper_n<false>(this->lua_state(), 1);\n\t\t\tint r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0);\n\t\t\tif (r != 0) {\n\t\t\t\treturn on_error(this->lua_state(), r, writer, userdata, strip);\n\t\t\t}\n\t\t\treturn r;\n\t\t}\n\n\t\tint dump(lua_Writer writer, void* userdata, bool strip = false) const {\n\t\t\treturn dump(writer, userdata, strip, &dump_pass_on_error);\n\t\t}\n\n\t\ttemplate <typename Container = bytecode>\n\t\tContainer dump() const {\n\t\t\tContainer bc;\n\t\t\t(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_throw_on_error);\n\t\t\treturn bc;\n\t\t}\n\n\t\ttemplate <typename Container = bytecode, typename Fx>\n\t\tContainer dump(Fx&& on_error) const {\n\t\t\tContainer bc;\n\t\t\t(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error));\n\t\t\treturn bc;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tprotected_function_result operator()(Args&&... args) const {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) operator()(types<Ret...>, Args&&... args) const {\n\t\t\treturn call<Ret...>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args) const {\n\t\t\tif constexpr (!aligned) {\n\t\t\t\t// we do not expect the function to already be on the stack: push it\n\t\t\t\tif (error_handler.valid()) {\n\t\t\t\t\tdetail::protected_handler<true, handler_t> h(error_handler);\n\t\t\t\t\tbase_t::push();\n\t\t\t\t\tint pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);\n\t\t\t\t\treturn invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdetail::protected_handler<false, handler_t> h(error_handler);\n\t\t\t\t\tbase_t::push();\n\t\t\t\t\tint pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);\n\t\t\t\t\treturn invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// the function is already on the stack at the right location\n\t\t\t\tif (error_handler.valid()) {\n\t\t\t\t\t// the handler will be pushed onto the stack manually,\n\t\t\t\t\t// since it's not already on the stack this means we need to push our own\n\t\t\t\t\t// function on the stack too and swap things to be in-place\n\t\t\t\t\tif constexpr (!is_stack_handler::value) {\n\t\t\t\t\t\t// so, we need to remove the function at the top and then dump the handler out ourselves\n\t\t\t\t\t\tbase_t::push();\n\t\t\t\t\t}\n\t\t\t\t\tdetail::protected_handler<true, handler_t> h(error_handler);\n\t\t\t\t\tif constexpr (!is_stack_handler::value) {\n\t\t\t\t\t\tlua_replace(lua_state(), -3);\n\t\t\t\t\t\th.stackindex = lua_absindex(lua_state(), -2);\n\t\t\t\t\t}\n\t\t\t\t\tint pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);\n\t\t\t\t\treturn invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdetail::protected_handler<false, handler_t> h(error_handler);\n\t\t\t\t\tint pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);\n\t\t\t\t\treturn invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/protected_function.hpp\n\n#include <functional>\n\nnamespace sol {\n\ttemplate <typename... Ret, typename... Args>\n\tdecltype(auto) stack_proxy::call(Args&&... args) {\n\t\tstack_function sf(this->lua_state(), this->stack_index());\n\t\treturn sf.template call<Ret...>(std::forward<Args>(args)...);\n\t}\n\n\tinline protected_function_result::protected_function_result(unsafe_function_result&& o) noexcept\n\t: L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()), popcount(o.return_count()), err(o.status()) {\n\t\t// Must be manual, otherwise destructor will screw us\n\t\t// return count being 0 is enough to keep things clean\n\t\t// but we will be thorough\n\t\to.abandon();\n\t}\n\n\tinline protected_function_result& protected_function_result::operator=(unsafe_function_result&& o) noexcept {\n\t\tL = o.lua_state();\n\t\tindex = o.stack_index();\n\t\treturncount = o.return_count();\n\t\tpopcount = o.return_count();\n\t\terr = o.status();\n\t\t// Must be manual, otherwise destructor will screw us\n\t\t// return count being 0 is enough to keep things clean\n\t\t// but we will be thorough\n\t\to.abandon();\n\t\treturn *this;\n\t}\n\n\tinline unsafe_function_result::unsafe_function_result(protected_function_result&& o) noexcept\n\t: L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()) {\n\t\t// Must be manual, otherwise destructor will screw us\n\t\t// return count being 0 is enough to keep things clean\n\t\t// but we will be thorough\n\t\to.abandon();\n\t}\n\tinline unsafe_function_result& unsafe_function_result::operator=(protected_function_result&& o) noexcept {\n\t\tL = o.lua_state();\n\t\tindex = o.stack_index();\n\t\treturncount = o.return_count();\n\t\t// Must be manual, otherwise destructor will screw us\n\t\t// return count being 0 is enough to keep things clean\n\t\t// but we will be thorough\n\t\to.abandon();\n\t\treturn *this;\n\t}\n\n\tnamespace detail {\n\t\ttemplate <typename... R>\n\t\tstruct std_shim {\n\t\t\tunsafe_function lua_func_;\n\n\t\t\tstd_shim(unsafe_function lua_func) : lua_func_(std::move(lua_func)) {\n\t\t\t}\n\n\t\t\ttemplate <typename... Args>\n\t\t\tmeta::return_type_t<R...> operator()(Args&&... args) {\n\t\t\t\treturn lua_func_.call<R...>(std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct std_shim<void> {\n\t\t\tunsafe_function lua_func_;\n\n\t\t\tstd_shim(unsafe_function lua_func) : lua_func_(std::move(lua_func)) {\n\t\t\t}\n\n\t\t\ttemplate <typename... Args>\n\t\t\tvoid operator()(Args&&... args) {\n\t\t\t\tlua_func_.call<void>(std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\t} // namespace detail\n\n\tnamespace stack {\n\t\ttemplate <typename Signature>\n\t\tstruct unqualified_getter<std::function<Signature>> {\n\t\t\ttypedef meta::bind_traits<Signature> fx_t;\n\t\t\ttypedef typename fx_t::args_list args_lists;\n\t\t\ttypedef meta::tuple_types<typename fx_t::return_type> return_types;\n\n\t\t\ttemplate <typename... R>\n\t\t\tstatic std::function<Signature> get_std_func(types<R...>, lua_State* L, int index) {\n\t\t\t\tdetail::std_shim<R...> fx(unsafe_function(L, index));\n\t\t\t\treturn fx;\n\t\t\t}\n\n\t\t\tstatic std::function<Signature> get(lua_State* L, int index, record& tracking) {\n\t\t\t\ttracking.use(1);\n\t\t\t\ttype t = type_of(L, index);\n\t\t\t\tif (t == type::none || t == type::lua_nil) {\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t\treturn get_std_func(return_types(), L, index);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename Allocator>\n\t\tstruct unqualified_getter<basic_bytecode<Allocator>> {\n\t\t\tstatic basic_bytecode<Allocator> get(lua_State* L, int index, record& tracking) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tstack_function sf(L, index);\n\t\t\t\treturn sf.dump(&dump_panic_on_error);\n\t\t\t}\n\t\t};\n\t} // namespace stack\n\n} // namespace sol\n\n// end of sol/function.hpp\n\n// beginning of sol/usertype.hpp\n\n// beginning of sol/usertype_core.hpp\n\n// beginning of sol/deprecate.hpp\n\n#ifndef SOL_DEPRECATED\n#ifdef _MSC_VER\n#define SOL_DEPRECATED __declspec(deprecated)\n#elif __GNUC__\n#define SOL_DEPRECATED __attribute__((deprecated))\n#else\n#define SOL_DEPRECATED [[deprecated]]\n#endif // compilers\n#endif // SOL_DEPRECATED\n\nnamespace sol {\nnamespace detail {\n\ttemplate <typename T>\n\tstruct SOL_DEPRECATED deprecate_type {\n\t\tusing type = T;\n\t};\n}\n} // namespace sol::detail\n\n// end of sol/deprecate.hpp\n\n// beginning of sol/usertype_container_launch.hpp\n\n// beginning of sol/usertype_container.hpp\n\nnamespace sol {\n\n\ttemplate <typename T>\n\tstruct usertype_container;\n\n\tnamespace container_detail {\n\n\t\ttemplate <typename T>\n\t\tstruct has_clear_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::clear));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_empty_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::empty));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_erase_after_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(\n\t\t\t     decltype(std::declval<C>().erase_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct has_find_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_find_test<T, std::enable_if_t<meta::is_lookup<T>::value>> {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::key_type>>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_erase_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(std::declval<C>().erase(std::declval<typename C::iterator>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_erase_key_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(std::declval<C>().erase(std::declval<typename C::key_type>()))*);\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_find_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::find));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_index_of_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::index_of));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_insert_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::insert));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_erase_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::erase));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_index_set_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::index_set));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_index_get_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::index_get));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_set_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::set));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_get_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::get));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_at_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::at));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_pairs_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::pairs));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_ipairs_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::ipairs));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_next_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::next));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_add_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::add));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct has_traits_size_test {\n\t\tprivate:\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_yes_t test(decltype(&C::size));\n\t\t\ttemplate <typename C>\n\t\t\tstatic meta::sfinae_no_t test(...);\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tusing has_clear = meta::boolean<has_clear_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_empty = meta::boolean<has_empty_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_find = meta::boolean<has_find_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_erase = meta::boolean<has_erase_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_erase_key = meta::boolean<has_erase_key_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_erase_after = meta::boolean<has_erase_after_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_get = meta::boolean<has_traits_get_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_at = meta::boolean<has_traits_at_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_set = meta::boolean<has_traits_set_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_index_get = meta::boolean<has_traits_index_get_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_index_set = meta::boolean<has_traits_index_set_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_pairs = meta::boolean<has_traits_pairs_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_ipairs = meta::boolean<has_traits_ipairs_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_next = meta::boolean<has_traits_next_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_add = meta::boolean<has_traits_add_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_size = meta::boolean<has_traits_size_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_clear = has_clear<T>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_empty = has_empty<T>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_find = meta::boolean<has_traits_find_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_index_of = meta::boolean<has_traits_index_of_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_insert = meta::boolean<has_traits_insert_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tusing has_traits_erase = meta::boolean<has_traits_erase_test<T>::value>;\n\n\t\ttemplate <typename T>\n\t\tstruct is_forced_container : is_container<T> {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_forced_container<as_container_t<T>> : std::true_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct container_decay {\n\t\t\ttypedef T type;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct container_decay<as_container_t<T>> {\n\t\t\ttypedef T type;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tusing container_decay_t = typename container_decay<meta::unqualified_t<T>>::type;\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_key(std::false_type, T&& t) {\n\t\t\treturn std::forward<T>(t);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_key(std::true_type, T&& t) {\n\t\t\treturn t.first;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_value(std::false_type, T&& t) {\n\t\t\treturn std::forward<T>(t);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_value(std::true_type, T&& t) {\n\t\t\treturn t.second;\n\t\t}\n\n\t\ttemplate <typename X, typename = void>\n\t\tstruct usertype_container_default {\n\t\tprivate:\n\t\t\ttypedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;\n\n\t\tpublic:\n\t\t\ttypedef lua_nil_t iterator;\n\t\t\ttypedef lua_nil_t value_type;\n\n\t\t\tstatic int at(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'at(index)' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int get(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'get(key)' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int index_get(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'container[key]' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int set(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'set(key, value)' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int index_set(lua_State* L) {\n\t\t\t\treturn luaL_error(\n\t\t\t\t     L, \"sol: cannot call 'container[key] = value' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int add(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'add' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int insert(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'insert' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int find(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'find' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int index_of(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'index_of' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int size(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'end' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int clear(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'clear' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int empty(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'empty' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int erase(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'erase' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int next(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'next' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int pairs(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call '__pairs/pairs' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int ipairs(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call '__ipairs' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic iterator begin(lua_State* L, T&) {\n\t\t\t\tluaL_error(L, \"sol: cannot call 'being' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t\treturn lua_nil;\n\t\t\t}\n\n\t\t\tstatic iterator end(lua_State* L, T&) {\n\t\t\t\tluaL_error(L, \"sol: cannot call 'end' on type '%s': it is not recognized as a container\", detail::demangle<T>().c_str());\n\t\t\t\treturn lua_nil;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename X>\n\t\tstruct usertype_container_default<X,\n\t\t     std::enable_if_t<meta::all<is_forced_container<meta::unqualified_t<X>>, meta::has_value_type<meta::unqualified_t<container_decay_t<X>>>,\n\t\t          meta::has_iterator<meta::unqualified_t<container_decay_t<X>>>>::value>> {\n\t\tprivate:\n\t\t\tusing T = std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>>;\n\n\t\tprivate:\n\t\t\tusing deferred_uc = usertype_container<X>;\n\t\t\tusing is_associative = meta::is_associative<T>;\n\t\t\tusing is_lookup = meta::is_lookup<T>;\n\t\t\tusing is_ordered = meta::is_ordered<T>;\n\t\t\tusing is_matched_lookup = meta::is_matched_lookup<T>;\n\t\t\tusing iterator = typename T::iterator;\n\t\t\tusing value_type = typename T::value_type;\n\t\t\ttypedef meta::conditional_t<is_matched_lookup::value, std::pair<value_type, value_type>,\n\t\t\t     meta::conditional_t<is_associative::value || is_lookup::value, value_type, std::pair<std::ptrdiff_t, value_type>>>\n\t\t\t     KV;\n\t\t\ttypedef typename KV::first_type K;\n\t\t\ttypedef typename KV::second_type V;\n\t\t\ttypedef meta::conditional_t<is_matched_lookup::value, std::ptrdiff_t, K> next_K;\n\t\t\ttypedef decltype(*std::declval<iterator&>()) iterator_return;\n\t\t\ttypedef meta::conditional_t<is_associative::value || is_matched_lookup::value, std::add_lvalue_reference_t<V>,\n\t\t\t     meta::conditional_t<is_lookup::value, V, iterator_return>>\n\t\t\t     captured_type;\n\t\t\ttypedef typename meta::iterator_tag<iterator>::type iterator_category;\n\t\t\ttypedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator;\n\t\t\ttypedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_move_only(std::declval<captured_type>()))> push_type;\n\t\t\ttypedef std::is_copy_assignable<V> is_copyable;\n\t\t\ttypedef meta::neg<meta::any<std::is_const<V>, std::is_const<std::remove_reference_t<iterator_return>>, meta::neg<is_copyable>>> is_writable;\n\t\t\ttypedef meta::unqualified_t<decltype(get_key(is_associative(), std::declval<std::add_lvalue_reference_t<value_type>>()))> key_type;\n\t\t\ttypedef meta::all<std::is_integral<K>, meta::neg<meta::any<is_associative, is_lookup>>> is_linear_integral;\n\n\t\t\tstruct iter {\n\t\t\t\tT& source;\n\t\t\t\titerator it;\n\t\t\t\tstd::size_t i;\n\n\t\t\t\titer(T& source, iterator it) : source(source), it(std::move(it)), i(0) {\n\t\t\t\t}\n\n\t\t\t\t~iter() {\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic auto& get_src(lua_State* L) {\n#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)\n\t\t\t\tauto p = stack::unqualified_check_get<T*>(L, 1);\n\t\t\t\tif (!p) {\n\t\t\t\t\tluaL_error(L,\n\t\t\t\t\t     \"sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)\",\n\t\t\t\t\t     detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\tif (p.value() == nullptr) {\n\t\t\t\t\tluaL_error(\n\t\t\t\t\t     L, \"sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\treturn *p.value();\n#else\n\t\t\t\treturn stack::unqualified_get<T>(L, 1);\n#endif // Safe getting with error\n\t\t\t}\n\n\t\t\tstatic detail::error_result at_category(std::input_iterator_tag, lua_State* L, T& self, std::ptrdiff_t pos) {\n\t\t\t\tpos += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (pos < 0) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\tauto it = deferred_uc::begin(L, self);\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tif (it == e) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\twhile (pos > 0) {\n\t\t\t\t\t--pos;\n\t\t\t\t\t++it;\n\t\t\t\t\tif (it == e) {\n\t\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t}\n\n\t\t\tstatic detail::error_result at_category(std::random_access_iterator_tag, lua_State* L, T& self, std::ptrdiff_t pos) {\n\t\t\t\tstd::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));\n\t\t\t\tpos += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (pos < 0 || pos >= len) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\tauto it = std::next(deferred_uc::begin(L, self), pos);\n\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t}\n\n\t\t\tstatic detail::error_result at_start(lua_State* L, T& self, std::ptrdiff_t pos) {\n\t\t\t\treturn at_category(iterator_category(), L, self, pos);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result get_associative(std::true_type, lua_State* L, Iter& it) {\n\t\t\t\tdecltype(auto) v = *it;\n\t\t\t\treturn stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(v.second));\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result get_associative(std::false_type, lua_State* L, Iter& it) {\n\t\t\t\treturn stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it));\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {\n\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (key < 0) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\tauto it = deferred_uc::begin(L, self);\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tif (it == e) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\twhile (key > 0) {\n\t\t\t\t\t--key;\n\t\t\t\t\t++it;\n\t\t\t\t\tif (it == e) {\n\t\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) {\n\t\t\t\tstd::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));\n\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (key < 0 || key >= len) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\tauto it = std::next(deferred_uc::begin(L, self), key);\n\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_it(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn get_category(iterator_category(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_comparative(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\tauto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); };\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tauto it = std::find_if(deferred_uc::begin(L, self), e, std::ref(fx));\n\t\t\t\tif (it == e) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_comparative(std::false_type, lua_State*, T&, K&) {\n\t\t\t\treturn detail::error_result(\"cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'\",\n\t\t\t\t     detail::demangle<T>().data(),\n\t\t\t\t     detail::demangle<K>().data());\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_it(std::false_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn get_comparative(meta::supports_op_equal<K, key_type>(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_associative(std::true_type, iterator& it, stack_object value) {\n\t\t\t\tdecltype(auto) v = *it;\n\t\t\t\tv.second = value.as<V>();\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_associative(std::false_type, iterator& it, stack_object value) {\n\t\t\t\tdecltype(auto) v = *it;\n\t\t\t\tv = value.as<V>();\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) {\n\t\t\t\treturn set_associative(is_associative(), it, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) {\n\t\t\t\treturn detail::error_result(\n\t\t\t\t     \"cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)\", detail::demangle<T>().data());\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {\n\t\t\t\tdecltype(auto) key = okey.as<K>();\n\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tauto it = deferred_uc::begin(L, self);\n\t\t\t\tauto backit = it;\n\t\t\t\tfor (; key > 0 && it != e; --key, ++it) {\n\t\t\t\t\tbackit = it;\n\t\t\t\t}\n\t\t\t\tif (it == e) {\n\t\t\t\t\tif (key == 0) {\n\t\t\t\t\t\treturn add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it);\n\t\t\t\t\t}\n\t\t\t\t\treturn detail::error_result(\"out of bounds (too big) for set on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\treturn set_writable(is_writable(), L, self, it, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {\n\t\t\t\tdecltype(auto) key = okey.as<K>();\n\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (key < 0) {\n\t\t\t\t\treturn detail::error_result(\"sol: out of bounds (too small) for set on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\tstd::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));\n\t\t\t\tif (key == len) {\n\t\t\t\t\treturn add_copyable(is_copyable(), L, self, std::move(value));\n\t\t\t\t}\n\t\t\t\telse if (key >= len) {\n\t\t\t\t\treturn detail::error_result(\"sol: out of bounds (too big) for set on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\tauto it = std::next(deferred_uc::begin(L, self), key);\n\t\t\t\treturn set_writable(is_writable(), L, self, it, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {\n\t\t\t\tdecltype(auto) key = okey.as<K>();\n\t\t\t\tif (!is_writable::value) {\n\t\t\t\t\treturn detail::error_result(\n\t\t\t\t\t     \"cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)\", detail::demangle<T>().data());\n\t\t\t\t}\n\t\t\t\tauto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); };\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tauto it = std::find_if(deferred_uc::begin(L, self), e, std::ref(fx));\n\t\t\t\tif (it == e) {\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\treturn set_writable(is_writable(), L, self, it, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) {\n\t\t\t\treturn detail::error_result(\"cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key\",\n\t\t\t\t     detail::demangle<T>().data(),\n\t\t\t\t     detail::demangle<K>().data());\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) {\n\t\t\t\tif constexpr (meta::has_insert<T>::value) {\n\t\t\t\t\tself.insert(it, value_type(key, value.as<V>()));\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)self;\n\t\t\t\t\t(void)it;\n\t\t\t\t\t(void)key;\n\t\t\t\t\treturn detail::error_result(\n\t\t\t\t\t     \"cannot call 'set' on '%s': there is no 'insert' function on this associative type\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) {\n\t\t\t\tif constexpr (meta::has_insert<T>::value) {\n\t\t\t\t\tself.insert(it, key);\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)self;\n\t\t\t\t\t(void)it;\n\t\t\t\t\t(void)key;\n\t\t\t\t\treturn detail::error_result(\n\t\t\t\t\t     \"cannot call 'set' on '%s': there is no 'insert' function on this non-associative type\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {\n\t\t\t\tdecltype(auto) key = okey.as<K>();\n\t\t\t\tauto it = self.find(key);\n\t\t\t\tif (it == deferred_uc::end(L, self)) {\n\t\t\t\t\treturn set_associative_insert(is_associative(), L, self, it, key, std::move(value));\n\t\t\t\t}\n\t\t\t\treturn set_writable(is_writable(), L, self, it, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {\n\t\t\t\treturn set_comparative(meta::supports_op_equal<K, key_type>(), L, self, std::move(key), std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {\n\t\t\t\treturn set_category(iterator_category(), L, self, std::move(key), std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {\n\t\t\t\treturn set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value));\n\t\t\t}\n\n\t\t\ttemplate <bool idx_of = false>\n\t\t\tstatic detail::error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) {\n\t\t\t\tif constexpr (!is_ordered::value && idx_of) {\n\t\t\t\t\t(void)L;\n\t\t\t\t\t(void)self;\n\t\t\t\t\treturn detail::error_result(\"cannot perform an 'index_of': '%s's is not an ordered container\", detail::demangle<T>().data());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdecltype(auto) key = stack::unqualified_get<K>(L, 2);\n\t\t\t\t\tauto it = self.find(key);\n\t\t\t\t\tif (it == deferred_uc::end(L, self)) {\n\t\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t\t}\n\t\t\t\t\tif constexpr (idx_of) {\n\t\t\t\t\t\tauto dist = std::distance(deferred_uc::begin(L, self), it);\n\t\t\t\t\t\tdist -= deferred_uc::index_adjustment(L, self);\n\t\t\t\t\t\treturn stack::push(L, dist);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <bool idx_of = false>\n\t\t\tstatic detail::error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) {\n\t\t\t\tif constexpr (!is_ordered::value && idx_of) {\n\t\t\t\t\t(void)L;\n\t\t\t\t\t(void)self;\n\t\t\t\t\treturn detail::error_result(\"cannot perform an 'index_of': '%s's is not an ordered container\", detail::demangle<T>().data());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdecltype(auto) value = stack::unqualified_get<V>(L, 2);\n\t\t\t\t\tauto it = self.find(value);\n\t\t\t\t\tif (it == deferred_uc::end(L, self)) {\n\t\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t\t}\n\t\t\t\t\tif constexpr (idx_of) {\n\t\t\t\t\t\tauto dist = std::distance(deferred_uc::begin(L, self), it);\n\t\t\t\t\t\tdist -= deferred_uc::index_adjustment(L, self);\n\t\t\t\t\t\treturn stack::push(L, dist);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <bool idx_of = false>\n\t\t\tstatic detail::error_result find_has(std::true_type, lua_State* L, T& self) {\n\t\t\t\treturn find_has_associative_lookup<idx_of>(meta::any<is_lookup, is_associative>(), L, self);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result find_associative_lookup(std::true_type, lua_State* L, T&, Iter& it, std::size_t) {\n\t\t\t\treturn get_associative(is_associative(), L, it);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result find_associative_lookup(std::false_type, lua_State* L, T& self, Iter&, std::size_t idx) {\n\t\t\t\tidx -= deferred_uc::index_adjustment(L, self);\n\t\t\t\treturn stack::push(L, idx);\n\t\t\t}\n\n\t\t\ttemplate <bool = false>\n\t\t\tstatic detail::error_result find_comparative(std::false_type, lua_State*, T&) {\n\t\t\t\treturn detail::error_result(\"cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable\",\n\t\t\t\t     detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\ttemplate <bool idx_of = false>\n\t\t\tstatic detail::error_result find_comparative(std::true_type, lua_State* L, T& self) {\n\t\t\t\tdecltype(auto) value = stack::unqualified_get<V>(L, 2);\n\t\t\t\tauto it = deferred_uc::begin(L, self);\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tstd::size_t idx = 0;\n\t\t\t\tfor (;; ++it, ++idx) {\n\t\t\t\t\tif (it == e) {\n\t\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t\t}\n\t\t\t\t\tif (value == get_value(is_associative(), *it)) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn find_associative_lookup(meta::all<meta::boolean<!idx_of>, meta::any<is_lookup, is_associative>>(), L, self, it, idx);\n\t\t\t}\n\n\t\t\ttemplate <bool idx_of = false>\n\t\t\tstatic detail::error_result find_has(std::false_type, lua_State* L, T& self) {\n\t\t\t\treturn find_comparative<idx_of>(meta::supports_op_equal<V>(), L, self);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, Iter&) {\n\t\t\t\treturn add_insert_after(std::false_type(), L, self, value);\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) {\n\t\t\t\treturn detail::error_result(\"cannot call 'add' on type '%s': no suitable insert/push_back C++ functions\", detail::demangle<T>().data());\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) {\n\t\t\t\tself.insert_after(pos, value.as<V>());\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) {\n\t\t\t\tauto backit = self.before_begin();\n\t\t\t\t{\n\t\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\t\tfor (auto it = deferred_uc::begin(L, self); it != e; ++backit, ++it) {\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn add_insert_after(std::true_type(), L, self, value, backit);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) {\n\t\t\t\tself.insert(pos, value.as<V>());\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_insert(std::true_type, lua_State* L, T& self, stack_object value) {\n\t\t\t\tauto pos = deferred_uc::end(L, self);\n\t\t\t\treturn add_insert(std::true_type(), L, self, value, pos);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) {\n\t\t\t\treturn add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value), pos);\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value) {\n\t\t\t\treturn add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value));\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, Iter&) {\n\t\t\t\tself.push_back(value.as<V>());\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) {\n\t\t\t\tself.push_back(value.as<V>());\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) {\n\t\t\t\treturn add_insert(meta::has_insert<T>(), L, self, value, pos);\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {\n\t\t\t\treturn add_insert(meta::has_insert<T>(), L, self, value);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, Iter& pos) {\n\t\t\t\tif constexpr (meta::has_insert<T>::value) {\n\t\t\t\t\tself.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L, 3)));\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)L;\n\t\t\t\t\t(void)self;\n\t\t\t\t\t(void)key;\n\t\t\t\t\t(void)pos;\n\t\t\t\t\treturn detail::error_result(\n\t\t\t\t\t     \"cannot call 'insert' on '%s': there is no 'insert' function on this associative type\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key) {\n\t\t\t\tauto pos = deferred_uc::end(L, self);\n\t\t\t\treturn add_associative(std::true_type(), L, self, std::move(key), pos);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) {\n\t\t\t\treturn add_push_back(meta::has_push_back<T>(), L, self, value, pos);\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value) {\n\t\t\t\treturn add_push_back(meta::has_push_back<T>(), L, self, value);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value, Iter& pos) {\n\t\t\t\treturn add_associative(is_associative(), L, self, std::move(value), pos);\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value) {\n\t\t\t\treturn add_associative(is_associative(), L, self, value);\n\t\t\t}\n\n\t\t\ttemplate <typename Iter>\n\t\t\tstatic detail::error_result add_copyable(std::false_type, lua_State* L, T& self, stack_object value, Iter&) {\n\t\t\t\treturn add_copyable(std::false_type(), L, self, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result add_copyable(std::false_type, lua_State*, T&, stack_object) {\n\t\t\t\treturn detail::error_result(\"cannot call 'add' on '%s': value_type is non-copyable\", detail::demangle<T>().data());\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) {\n\t\t\t\t// TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity?\n\t\t\t\treturn add_copyable(std::true_type(), L, self, std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {\n\t\t\t\tauto it = deferred_uc::begin(L, self);\n\t\t\t\tauto key = where.as<K>();\n\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\tstd::advance(it, key);\n\t\t\t\tself.insert(it, value.as<V>());\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) {\n\t\t\t\tauto key = where.as<K>();\n\t\t\t\tauto backit = self.before_begin();\n\t\t\t\t{\n\t\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\t\tfor (auto it = deferred_uc::begin(L, self); key > 0; ++backit, ++it, --key) {\n\t\t\t\t\t\tif (backit == e) {\n\t\t\t\t\t\t\treturn detail::error_result(\"sol: out of bounds (too big) for set on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tself.insert_after(backit, value.as<V>());\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) {\n\t\t\t\treturn detail::error_result(\n\t\t\t\t     \"cannot call 'insert' on '%s': no suitable or similar functionality detected on this container\", detail::demangle<T>().data());\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {\n\t\t\t\treturn insert_lookup(meta::any<is_associative, is_lookup>(), L, self, std::move(key), std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {\n\t\t\t\treturn insert_after_has(meta::has_insert_after<T>(), L, self, where, value);\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {\n\t\t\t\treturn insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));\n\t\t\t}\n\n\t\t\tstatic detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) {\n\t\t\t\treturn detail::error_result(\"cannot call 'insert' on '%s': value_type is non-copyable\", detail::demangle<T>().data());\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_integral(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\tauto it = deferred_uc::begin(L, self);\n\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\tstd::advance(it, key);\n\t\t\t\tself.erase(it);\n\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_integral(std::false_type, lua_State* L, T& self, const K& key) {\n\t\t\t\tauto fx = [&](const value_type& r) -> bool { return key == r; };\n\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\tauto it = std::find_if(deferred_uc::begin(L, self), e, std::ref(fx));\n\t\t\t\tif (it == e) {\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\tself.erase(it);\n\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) {\n\t\t\t\tself.erase(key);\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn erase_integral(std::is_integral<K>(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_after_has(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\tauto backit = self.before_begin();\n\t\t\t\t{\n\t\t\t\t\tkey += deferred_uc::index_adjustment(L, self);\n\t\t\t\t\tauto e = deferred_uc::end(L, self);\n\t\t\t\t\tfor (auto it = deferred_uc::begin(L, self); key > 0; ++backit, ++it, --key) {\n\t\t\t\t\t\tif (backit == e) {\n\t\t\t\t\t\t\treturn detail::error_result(\"sol: out of bounds for erase on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tself.erase_after(backit);\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_after_has(std::false_type, lua_State*, T&, const K&) {\n\t\t\t\treturn detail::error_result(\"sol: cannot call erase on '%s'\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_key_has(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_key_has(std::false_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn erase_after_has(has_erase_after<T>(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_has(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_has(std::false_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn erase_key_has(has_erase_key<T>(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic auto size_has(std::false_type, lua_State* L, T& self) {\n\t\t\t\treturn std::distance(deferred_uc::begin(L, self), deferred_uc::end(L, self));\n\t\t\t}\n\n\t\t\tstatic auto size_has(std::true_type, lua_State*, T& self) {\n\t\t\t\treturn self.size();\n\t\t\t}\n\n\t\t\tstatic void clear_has(std::true_type, lua_State*, T& self) {\n\t\t\t\tself.clear();\n\t\t\t}\n\n\t\t\tstatic void clear_has(std::false_type, lua_State* L, T&) {\n\t\t\t\tluaL_error(L, \"sol: cannot call clear on '%s'\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic bool empty_has(std::true_type, lua_State*, T& self) {\n\t\t\t\treturn self.empty();\n\t\t\t}\n\n\t\t\tstatic bool empty_has(std::false_type, lua_State* L, T& self) {\n\t\t\t\treturn deferred_uc::begin(L, self) == deferred_uc::end(L, self);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_associative_find(std::true_type, lua_State* L, T& self, K& key) {\n\t\t\t\tauto it = self.find(key);\n\t\t\t\tif (it == deferred_uc::end(L, self)) {\n\t\t\t\t\tstack::push(L, lua_nil);\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\treturn get_associative(std::true_type(), L, it);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_associative_find(std::false_type, lua_State* L, T& self, K& key) {\n\t\t\t\treturn get_it(is_linear_integral(), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result get_start(lua_State* L, T& self, K& key) {\n\t\t\t\treturn get_associative_find(std::integral_constant < bool, is_associative::value&& has_find<T>::value > (), L, self, key);\n\t\t\t}\n\n\t\t\tstatic detail::error_result set_start(lua_State* L, T& self, stack_object key, stack_object value) {\n\t\t\t\treturn set_it(is_linear_integral(), L, self, std::move(key), std::move(value));\n\t\t\t}\n\n\t\t\tstatic std::size_t size_start(lua_State* L, T& self) {\n\t\t\t\treturn size_has(meta::has_size<T>(), L, self);\n\t\t\t}\n\n\t\t\tstatic void clear_start(lua_State* L, T& self) {\n\t\t\t\tclear_has(has_clear<T>(), L, self);\n\t\t\t}\n\n\t\t\tstatic bool empty_start(lua_State* L, T& self) {\n\t\t\t\treturn empty_has(has_empty<T>(), L, self);\n\t\t\t}\n\n\t\t\tstatic detail::error_result erase_start(lua_State* L, T& self, K& key) {\n\t\t\t\treturn erase_has(has_erase<T>(), L, self, key);\n\t\t\t}\n\n\t\t\ttemplate <bool ip>\n\t\t\tstatic int next_associative(std::true_type, lua_State* L) {\n\t\t\t\titer& i = stack::unqualified_get<user<iter>>(L, 1);\n\t\t\t\tauto& source = i.source;\n\t\t\t\tauto& it = i.it;\n\t\t\t\tif (it == deferred_uc::end(L, source)) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\tint p;\n\t\t\t\tif constexpr (ip) {\n\t\t\t\t\t++i.i;\n\t\t\t\t\tp = stack::push_reference(L, i.i);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tp = stack::push_reference(L, it->first);\n\t\t\t\t}\n\t\t\t\tp += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(it->second));\n\t\t\t\tstd::advance(it, 1);\n\t\t\t\treturn p;\n\t\t\t}\n\n\t\t\ttemplate <bool>\n\t\t\tstatic int next_associative(std::false_type, lua_State* L) {\n\t\t\t\titer& i = stack::unqualified_get<user<iter>>(L, 1);\n\t\t\t\tauto& source = i.source;\n\t\t\t\tauto& it = i.it;\n\t\t\t\tnext_K k = stack::unqualified_get<next_K>(L, 2);\n\t\t\t\tif (it == deferred_uc::end(L, source)) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\tint p;\n\t\t\t\tif constexpr (std::is_integral_v<next_K>) {\n\t\t\t\t\tp = stack::push_reference(L, k + 1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tp = stack::stack_detail::push_reference(L, k + 1);\n\t\t\t\t}\n\t\t\t\tp += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it));\n\t\t\t\tstd::advance(it, 1);\n\t\t\t\treturn p;\n\t\t\t}\n\n\t\t\ttemplate <bool ip>\n\t\t\tstatic int next_iter(lua_State* L) {\n\t\t\t\ttypedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc;\n\t\t\t\treturn next_associative<ip>(is_assoc(), L);\n\t\t\t}\n\n\t\t\ttemplate <bool ip>\n\t\t\tstatic int pairs_associative(std::true_type, lua_State* L) {\n\t\t\t\tauto& src = get_src(L);\n\t\t\t\tstack::push(L, next_iter<ip>);\n\t\t\t\tstack::push<user<iter>>(L, src, deferred_uc::begin(L, src));\n\t\t\t\tstack::push(L, lua_nil);\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\ttemplate <bool ip>\n\t\t\tstatic int pairs_associative(std::false_type, lua_State* L) {\n\t\t\t\tauto& src = get_src(L);\n\t\t\t\tstack::push(L, next_iter<ip>);\n\t\t\t\tstack::push<user<iter>>(L, src, deferred_uc::begin(L, src));\n\t\t\t\tstack::push(L, 0);\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\tpublic:\n\t\t\tstatic int at(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er;\n\t\t\t\t{\n\t\t\t\t\tstd::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L, 2);\n\t\t\t\t\ter = at_start(L, self, pos);\n\t\t\t\t}\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int get(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er;\n\t\t\t\t{\n\t\t\t\t\tdecltype(auto) key = stack::unqualified_get<K>(L);\n\t\t\t\t\ter = get_start(L, self, key);\n\t\t\t\t}\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int index_get(lua_State* L) {\n\t\t\t\treturn get(L);\n\t\t\t}\n\n\t\t\tstatic int set(lua_State* L) {\n\t\t\t\tstack_object value = stack_object(L, raw_index(3));\n\t\t\t\tif constexpr (is_linear_integral::value) {\n\t\t\t\t\t// for non-associative containers,\n\t\t\t\t\t// erasure only happens if it is the\n\t\t\t\t\t// last index in the container\n\t\t\t\t\tauto key = stack::get<K>(L, 2);\n\t\t\t\t\tauto self_size = deferred_uc::size(L);\n\t\t\t\t\tif (key == static_cast<K>(self_size)) {\n\t\t\t\t\t\tif (type_of(L, 3) == type::lua_nil) {\n\t\t\t\t\t\t\treturn erase(L);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (type_of(L, 3) == type::lua_nil) {\n\t\t\t\t\t\treturn erase(L);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er = set_start(L, self, stack_object(L, raw_index(2)), std::move(value));\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int index_set(lua_State* L) {\n\t\t\t\treturn set(L);\n\t\t\t}\n\n\t\t\tstatic int add(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er = add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)));\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int insert(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er = insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int find(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er = find_has(has_find<T>(), L, self);\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int index_of(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er = find_has<true>(has_find<T>(), L, self);\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic iterator begin(lua_State*, T& self) {\n\t\t\t\tif constexpr (meta::has_begin_end_v<T>) {\n\t\t\t\t\treturn self.begin();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing std::begin;\n\t\t\t\t\treturn begin(self);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic iterator end(lua_State*, T& self) {\n\t\t\t\tif constexpr (meta::has_begin_end_v<T>) {\n\t\t\t\t\treturn self.end();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing std::end;\n\t\t\t\t\treturn end(self);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic int size(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tstd::size_t r = size_start(L, self);\n\t\t\t\treturn stack::push(L, r);\n\t\t\t}\n\n\t\t\tstatic int clear(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tclear_start(L, self);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tstatic int erase(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\tdetail::error_result er;\n\t\t\t\t{\n\t\t\t\t\tdecltype(auto) key = stack::unqualified_get<K>(L, 2);\n\t\t\t\t\ter = erase_start(L, self, key);\n\t\t\t\t}\n\t\t\t\treturn handle_errors(L, er);\n\t\t\t}\n\n\t\t\tstatic int empty(lua_State* L) {\n\t\t\t\tauto& self = get_src(L);\n\t\t\t\treturn stack::push(L, empty_start(L, self));\n\t\t\t}\n\n\t\t\tstatic std::ptrdiff_t index_adjustment(lua_State*, T&) {\n\t\t\t\treturn static_cast<std::ptrdiff_t>((SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_));\n\t\t\t}\n\n\t\t\tstatic int pairs(lua_State* L) {\n\t\t\t\ttypedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc;\n\t\t\t\treturn pairs_associative<false>(is_assoc(), L);\n\t\t\t}\n\n\t\t\tstatic int ipairs(lua_State* L) {\n\t\t\t\ttypedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc;\n\t\t\t\treturn pairs_associative<true>(is_assoc(), L);\n\t\t\t}\n\n\t\t\tstatic int next(lua_State* L) {\n\t\t\t\treturn stack::push(L, next_iter<false>);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename X>\n\t\tstruct usertype_container_default<X, std::enable_if_t<std::is_array<std::remove_pointer_t<meta::unwrap_unqualified_t<X>>>::value>> {\n\t\tprivate:\n\t\t\ttypedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;\n\t\t\ttypedef usertype_container<X> deferred_uc;\n\n\t\tpublic:\n\t\t\ttypedef std::remove_extent_t<T> value_type;\n\t\t\ttypedef value_type* iterator;\n\n\t\tprivate:\n\t\t\tstruct iter {\n\t\t\t\tT& source;\n\t\t\t\titerator it;\n\n\t\t\t\titer(T& source, iterator it) : source(source), it(std::move(it)) {\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic auto& get_src(lua_State* L) {\n\t\t\t\tauto p = stack::unqualified_check_get<T*>(L, 1);\n#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)\n\t\t\t\tif (!p) {\n\t\t\t\t\tluaL_error(L,\n\t\t\t\t\t     \"sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)\",\n\t\t\t\t\t     detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\tif (p.value() == nullptr) {\n\t\t\t\t\tluaL_error(\n\t\t\t\t\t     L, \"sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)\", detail::demangle<T>().c_str());\n\t\t\t\t}\n#endif // Safe getting with error\n\t\t\t\treturn *p.value();\n\t\t\t}\n\n\t\t\tstatic int find(std::true_type, lua_State* L) {\n\t\t\t\tT& self = get_src(L);\n\t\t\t\tdecltype(auto) value = stack::unqualified_get<value_type>(L, 2);\n\t\t\t\tstd::size_t N = std::extent<T>::value;\n\t\t\t\tfor (std::size_t idx = 0; idx < N; ++idx) {\n\t\t\t\t\tusing v_t = std::add_const_t<decltype(self[idx])>;\n\t\t\t\t\tv_t v = self[idx];\n\t\t\t\t\tif (v == value) {\n\t\t\t\t\t\tidx -= deferred_uc::index_adjustment(L, self);\n\t\t\t\t\t\treturn stack::push(L, idx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t}\n\n\t\t\tstatic int find(std::false_type, lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'find' on '%s': no supported comparison operator for the value type\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int next_iter(lua_State* L) {\n\t\t\t\titer& i = stack::unqualified_get<user<iter>>(L, 1);\n\t\t\t\tauto& source = i.source;\n\t\t\t\tauto& it = i.it;\n\t\t\t\tstd::size_t k = stack::unqualified_get<std::size_t>(L, 2);\n\t\t\t\tif (it == deferred_uc::end(L, source)) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tint p;\n\t\t\t\tp = stack::push(L, k + 1);\n\t\t\t\tp += stack::push_reference(L, detail::deref_move_only(*it));\n\t\t\t\tstd::advance(it, 1);\n\t\t\t\treturn p;\n\t\t\t}\n\n\t\tpublic:\n\t\t\tstatic int clear(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'clear' on type '%s': cannot remove all items from a fixed array\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int erase(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'erase' on type '%s': cannot remove an item from fixed arrays\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int add(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'add' on type '%s': cannot add to fixed arrays\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int insert(lua_State* L) {\n\t\t\t\treturn luaL_error(L, \"sol: cannot call 'insert' on type '%s': cannot insert new entries into fixed arrays\", detail::demangle<T>().c_str());\n\t\t\t}\n\n\t\t\tstatic int at(lua_State* L) {\n\t\t\t\treturn get(L);\n\t\t\t}\n\n\t\t\tstatic int get(lua_State* L) {\n\t\t\t\tT& self = get_src(L);\n\t\t\t\tstd::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L, 2);\n\t\t\t\tidx += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) {\n\t\t\t\t\treturn stack::push(L, lua_nil);\n\t\t\t\t}\n\t\t\t\treturn stack::push_reference(L, detail::deref_move_only(self[idx]));\n\t\t\t}\n\n\t\t\tstatic int index_get(lua_State* L) {\n\t\t\t\treturn get(L);\n\t\t\t}\n\n\t\t\tstatic int set(lua_State* L) {\n\t\t\t\tT& self = get_src(L);\n\t\t\t\tstd::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L, 2);\n\t\t\t\tidx += deferred_uc::index_adjustment(L, self);\n\t\t\t\tif (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value)) {\n\t\t\t\t\treturn luaL_error(L, \"sol: index out of bounds (too big) for set on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\tif (idx < 0) {\n\t\t\t\t\treturn luaL_error(L, \"sol: index out of bounds (too small) for set on '%s'\", detail::demangle<T>().c_str());\n\t\t\t\t}\n\t\t\t\tself[idx] = stack::unqualified_get<value_type>(L, 3);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tstatic int index_set(lua_State* L) {\n\t\t\t\treturn set(L);\n\t\t\t}\n\n\t\t\tstatic int index_of(lua_State* L) {\n\t\t\t\treturn find(L);\n\t\t\t}\n\n\t\t\tstatic int find(lua_State* L) {\n\t\t\t\treturn find(meta::supports_op_equal<value_type, value_type>(), L);\n\t\t\t}\n\n\t\t\tstatic int size(lua_State* L) {\n\t\t\t\treturn stack::push(L, std::extent<T>::value);\n\t\t\t}\n\n\t\t\tstatic int empty(lua_State* L) {\n\t\t\t\treturn stack::push(L, std::extent<T>::value > 0);\n\t\t\t}\n\n\t\t\tstatic int pairs(lua_State* L) {\n\t\t\t\tauto& src = get_src(L);\n\t\t\t\tstack::push(L, next_iter);\n\t\t\t\tstack::push<user<iter>>(L, src, deferred_uc::begin(L, src));\n\t\t\t\tstack::push(L, 0);\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tstatic int ipairs(lua_State* L) {\n\t\t\t\treturn pairs(L);\n\t\t\t}\n\n\t\t\tstatic int next(lua_State* L) {\n\t\t\t\treturn stack::push(L, next_iter);\n\t\t\t}\n\n\t\t\tstatic std::ptrdiff_t index_adjustment(lua_State*, T&) {\n\t\t\t\treturn (SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_);\n\t\t\t}\n\n\t\t\tstatic iterator begin(lua_State*, T& self) {\n\t\t\t\treturn std::addressof(self[0]);\n\t\t\t}\n\n\t\t\tstatic iterator end(lua_State*, T& self) {\n\t\t\t\treturn std::addressof(self[0]) + std::extent<T>::value;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename X>\n\t\tstruct usertype_container_default<usertype_container<X>> : usertype_container_default<X> {};\n\t} // namespace container_detail\n\n\ttemplate <typename T>\n\tstruct usertype_container : container_detail::usertype_container_default<T> {};\n\n} // namespace sol\n\n// end of sol/usertype_container.hpp\n\n#include <unordered_map>\n\nnamespace sol {\n\n\tnamespace container_detail {\n\t\ttemplate <typename X>\n\t\tstruct u_c_launch {\n\t\t\tusing T = std::remove_pointer_t<meta::unqualified_t<X>>;\n\t\t\tusing uc = usertype_container<T>;\n\t\t\tusing default_uc = usertype_container_default<T>;\n\n\t\t\tstatic inline int real_index_get_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::index_get(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_index_get_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::index_get(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_index_call(lua_State* L) {\n\t\t\t\tstatic const std::unordered_map<string_view, lua_CFunction> calls {\n\t\t\t\t\t{ \"at\", &real_at_call },\n\t\t\t\t\t{ \"get\", &real_get_call },\n\t\t\t\t\t{ \"set\", &real_set_call },\n\t\t\t\t\t{ \"size\", &real_length_call },\n\t\t\t\t\t{ \"add\", &real_add_call },\n\t\t\t\t\t{ \"empty\", &real_empty_call },\n\t\t\t\t\t{ \"insert\", &real_insert_call },\n\t\t\t\t\t{ \"clear\", &real_clear_call },\n\t\t\t\t\t{ \"find\", &real_find_call },\n\t\t\t\t\t{ \"index_of\", &real_index_of_call },\n\t\t\t\t\t{ \"erase\", &real_erase_call },\n\t\t\t\t\t{ \"pairs\", &pairs_call },\n\t\t\t\t\t{ \"next\", &next_call },\n\t\t\t\t};\n\t\t\t\tauto maybenameview = stack::unqualified_check_get<string_view>(L, 2);\n\t\t\t\tif (maybenameview) {\n\t\t\t\t\tconst string_view& name = *maybenameview;\n\t\t\t\t\tauto it = calls.find(name);\n\t\t\t\t\tif (it != calls.cend()) {\n\t\t\t\t\t\treturn stack::push(L, it->second);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn real_index_get_traits(container_detail::has_traits_index_get<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_at_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::at(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_at_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::at(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_at_call(lua_State* L) {\n\t\t\t\treturn real_at_traits(container_detail::has_traits_at<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_get_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::get(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_get_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::get(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_get_call(lua_State* L) {\n\t\t\t\treturn real_get_traits(container_detail::has_traits_get<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_set_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::set(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_set_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::set(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_set_call(lua_State* L) {\n\t\t\t\treturn real_set_traits(container_detail::has_traits_set<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_index_set_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::index_set(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_index_set_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::index_set(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_new_index_call(lua_State* L) {\n\t\t\t\treturn real_index_set_traits(container_detail::has_traits_index_set<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_pairs_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::pairs(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_pairs_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::pairs(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_pairs_call(lua_State* L) {\n\t\t\t\treturn real_pairs_traits(container_detail::has_traits_pairs<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_ipairs_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::ipairs(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_ipairs_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::ipairs(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_ipairs_call(lua_State* L) {\n\t\t\t\treturn real_ipairs_traits(container_detail::has_traits_ipairs<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_next_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::next(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_next_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::next(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_next_call(lua_State* L) {\n\t\t\t\treturn real_next_traits(container_detail::has_traits_next<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_size_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::size(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_size_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::size(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_length_call(lua_State* L) {\n\t\t\t\treturn real_size_traits(container_detail::has_traits_size<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_add_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::add(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_add_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::add(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_add_call(lua_State* L) {\n\t\t\t\treturn real_add_traits(container_detail::has_traits_add<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_insert_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::insert(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_insert_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::insert(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_insert_call(lua_State* L) {\n\t\t\t\treturn real_insert_traits(container_detail::has_traits_insert<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_clear_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::clear(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_clear_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::clear(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_clear_call(lua_State* L) {\n\t\t\t\treturn real_clear_traits(container_detail::has_traits_clear<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_empty_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::empty(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_empty_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::empty(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_empty_call(lua_State* L) {\n\t\t\t\treturn real_empty_traits(container_detail::has_traits_empty<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_erase_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::erase(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_erase_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::erase(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_erase_call(lua_State* L) {\n\t\t\t\treturn real_erase_traits(container_detail::has_traits_erase<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_find_traits(std::true_type, lua_State* L) {\n\t\t\t\treturn uc::find(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_find_traits(std::false_type, lua_State* L) {\n\t\t\t\treturn default_uc::find(L);\n\t\t\t}\n\n\t\t\tstatic inline int real_find_call(lua_State* L) {\n\t\t\t\treturn real_find_traits(container_detail::has_traits_find<uc>(), L);\n\t\t\t}\n\n\t\t\tstatic inline int real_index_of_call(lua_State* L) {\n\t\t\t\tif constexpr (container_detail::has_traits_index_of<uc>()) {\n\t\t\t\t\treturn uc::index_of(L);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn default_uc::index_of(L);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic inline int add_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int erase_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int insert_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int clear_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int empty_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int find_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int index_of_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_index_of_call), (&real_index_of_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int length_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int pairs_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int ipairs_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_ipairs_call), (&real_ipairs_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int next_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_next_call), (&real_next_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int at_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_at_call), (&real_at_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int get_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int set_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int index_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L);\n\t\t\t}\n\n\t\t\tstatic inline int new_index_call(lua_State* L) {\n\t\t\t\treturn detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L);\n\t\t\t}\n\t\t};\n\t} // namespace container_detail\n\n\tnamespace stack {\n\t\tnamespace stack_detail {\n\t\t\ttemplate <typename T, bool is_shim = false>\n\t\t\tstruct metatable_setup {\n\t\t\t\tlua_State* L;\n\n\t\t\t\tmetatable_setup(lua_State* L) : L(L) {\n\t\t\t\t}\n\n\t\t\t\tvoid operator()() {\n\t\t\t\t\tusing meta_usertype_container\n\t\t\t\t\t     = container_detail::u_c_launch<meta::conditional_t<is_shim, as_container_t<std::remove_pointer_t<T>>, std::remove_pointer_t<T>>>;\n\t\t\t\t\tstatic const char* metakey\n\t\t\t\t\t     = is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0];\n\t\t\t\t\tstatic const std::array<luaL_Reg, 20> reg = { {\n\t\t\t\t\t\t// clang-format off\n\t\t\t\t\t\t{ \"__pairs\", &meta_usertype_container::pairs_call },\n\t\t\t\t\t\t{ \"__ipairs\", &meta_usertype_container::ipairs_call },\n\t\t\t\t\t\t{ \"__len\", &meta_usertype_container::length_call },\n\t\t\t\t\t\t{ \"__index\", &meta_usertype_container::index_call },\n\t\t\t\t\t\t{ \"__newindex\", &meta_usertype_container::new_index_call },\n\t\t\t\t\t\t{ \"pairs\", &meta_usertype_container::pairs_call },\n\t\t\t\t\t\t{ \"next\", &meta_usertype_container::next_call },\n\t\t\t\t\t\t{ \"at\", &meta_usertype_container::at_call },\n\t\t\t\t\t\t{ \"get\", &meta_usertype_container::get_call },\n\t\t\t\t\t\t{ \"set\", &meta_usertype_container::set_call },\n\t\t\t\t\t\t{ \"size\", &meta_usertype_container::length_call },\n\t\t\t\t\t\t{ \"empty\", &meta_usertype_container::empty_call },\n\t\t\t\t\t\t{ \"clear\", &meta_usertype_container::clear_call },\n\t\t\t\t\t\t{ \"insert\", &meta_usertype_container::insert_call },\n\t\t\t\t\t\t{ \"add\", &meta_usertype_container::add_call },\n\t\t\t\t\t\t{ \"find\", &meta_usertype_container::find_call },\n\t\t\t\t\t\t{ \"index_of\", &meta_usertype_container::index_of_call },\n\t\t\t\t\t\t{ \"erase\", &meta_usertype_container::erase_call },\n\t\t\t\t\t\tstd::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ \"__gc\", &detail::usertype_alloc_destruct<T> },\n\t\t\t\t\t\t{ nullptr, nullptr }\n\t\t\t\t\t\t// clang-format on \n\t\t\t\t\t} };\n\n\t\t\t\t\tif (luaL_newmetatable(L, metakey) == 1) {\n\t\t\t\t\t\tluaL_setfuncs(L, reg.data(), 0);\n\t\t\t\t\t}\n\t\t\t\t\tlua_setmetatable(L, -2);\n\t\t\t\t}\n\t\t\t};\n\t\t} // namespace stack_detail\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<as_container_t<T>> {\n\t\t\tusing C = meta::unqualified_t<T>;\n\n\t\t\tstatic int push_lvalue(std::true_type, lua_State* L, const C& cont) {\n\t\t\t\tstack_detail::metatable_setup<C*, true> fx(L);\n\t\t\t\treturn stack::push<detail::as_pointer_tag<const C>>(L, detail::with_function_tag(), fx, detail::ptr(cont));\n\t\t\t}\n\n\t\t\tstatic int push_lvalue(std::false_type, lua_State* L, const C& cont) {\n\t\t\t\tstack_detail::metatable_setup<C, true> fx(L);\n\t\t\t\treturn stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, cont);\n\t\t\t}\n\n\t\t\tstatic int push_rvalue(std::true_type, lua_State* L, C&& cont) {\n\t\t\t\tstack_detail::metatable_setup<C, true> fx(L);\n\t\t\t\treturn stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, std::move(cont));\n\t\t\t}\n\n\t\t\tstatic int push_rvalue(std::false_type, lua_State* L, const C& cont) {\n\t\t\t\treturn push_lvalue(std::is_lvalue_reference<T>(), L, cont);\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, const as_container_t<T>& as_cont) {\n\t\t\t\treturn push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.value());\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, as_container_t<T>&& as_cont) {\n\t\t\t\treturn push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.value()));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<as_container_t<T*>> {\n\t\t\tusing C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>;\n\n\t\t\tstatic int push(lua_State* L, T* cont) {\n\t\t\t\tstack_detail::metatable_setup<C> fx(L);\n\t\t\t\treturn stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<T, std::enable_if_t<is_container_v<T>>> {\n\t\t\tusing C = T;\n\n\t\t\ttemplate <typename... Args>\n\t\t\tstatic int push(lua_State* L, Args&&... args) {\n\t\t\t\tstack_detail::metatable_setup<C> fx(L);\n\t\t\t\treturn stack::push<detail::as_value_tag<T>>(L, detail::with_function_tag(), fx, std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<T*, std::enable_if_t<is_container_v<T>>> {\n\t\t\tusing C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>;\n\n\t\t\tstatic int push(lua_State* L, T* cont) {\n\t\t\t\tstack_detail::metatable_setup<C> fx(L);\n\t\t\t\treturn stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);\n\t\t\t}\n\t\t};\n\t} // namespace stack\n\n} // namespace sol\n\n// end of sol/usertype_container_launch.hpp\n\n#include <sstream>\n#include <type_traits>\n\nnamespace sol {\n\tnamespace u_detail {\n\t\tconstexpr const lua_Integer toplevel_magic = static_cast<lua_Integer>(0xCCC2CCC1);\n\n\t\tconstexpr const int environment_index = 1;\n\t\tconstexpr const int usertype_storage_index = 2;\n\t\tconstexpr const int usertype_storage_base_index = 3;\n\t\tconstexpr const int exact_function_index = 4;\n\t\tconstexpr const int magic_index = 5;\n\n\t\tconstexpr const int simple_usertype_storage_index = 2;\n\t\tconstexpr const int index_function_index = 3;\n\t\tconstexpr const int new_index_function_index = 4;\n\n\t\tconstexpr const int base_walking_failed_index = -32467;\n\t\tconstexpr const int lookup_failed_index = -42469;\n\n\t\tenum class submetatable_type {\n\t\t\t// must be sequential\n\t\t\tvalue,\n\t\t\treference,\n\t\t\tunique,\n\t\t\tconst_reference,\n\t\t\tconst_value,\n\t\t\t// must be LAST!\n\t\t\tnamed\n\t\t};\n\n\t\tinline auto make_string_view(string_view s) {\n\t\t\treturn s;\n\t\t}\n\n\t\tinline auto make_string_view(call_construction) {\n\t\t\treturn string_view(to_string(meta_function::call_function));\n\t\t}\n\n\t\tinline auto make_string_view(meta_function mf) {\n\t\t\treturn string_view(to_string(mf));\n\t\t}\n\n\t\tinline auto make_string_view(base_classes_tag) {\n\t\t\treturn string_view(detail::base_class_cast_key());\n\t\t}\n\n\t\ttemplate <typename Arg>\n\t\tinline std::string make_string(Arg&& arg) {\n\t\t\tstring_view s = make_string_view(arg);\n\t\t\treturn std::string(s.data(), s.size());\n\t\t}\n\n\t\tinline int is_indexer(string_view s) {\n\t\t\tif (s == to_string(meta_function::index)) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if (s == to_string(meta_function::new_index)) {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tinline int is_indexer(meta_function mf) {\n\t\t\tif (mf == meta_function::index) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if (mf == meta_function::new_index) {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tinline int is_indexer(call_construction) {\n\t\t\treturn 0;\n\t\t}\n\t} // namespace u_detail\n\n\tnamespace detail {\n\n\t\ttemplate <typename T, typename IFx, typename Fx>\n\t\tinline void insert_default_registrations(IFx&& ifx, Fx&& fx) {\n\t\t\t(void)ifx;\n\t\t\t(void)fx;\n\t\t\tif constexpr (is_automagical<T>::value) {\n\t\t\t\tif (fx(meta_function::less_than)) {\n\t\t\t\t\tif constexpr (meta::supports_op_less<T>::value) {\n\t\t\t\t\t\tlua_CFunction f = &comparsion_operator_wrap<T, std::less<>>;\n\t\t\t\t\t\tifx(meta_function::less_than, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (fx(meta_function::less_than_or_equal_to)) {\n\t\t\t\t\tif constexpr (meta::supports_op_less_equal<T>::value) {\n\t\t\t\t\t\tlua_CFunction f = &comparsion_operator_wrap<T, std::less_equal<>>;\n\t\t\t\t\t\tifx(meta_function::less_than_or_equal_to, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (fx(meta_function::equal_to)) {\n\t\t\t\t\tif constexpr (meta::supports_op_equal<T>::value) {\n\t\t\t\t\t\tlua_CFunction f = &comparsion_operator_wrap<T, std::equal_to<>>;\n\t\t\t\t\t\tifx(meta_function::equal_to, f);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tlua_CFunction f = &comparsion_operator_wrap<T, no_comp>;\n\t\t\t\t\t\tifx(meta_function::equal_to, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (fx(meta_function::pairs)) {\n\t\t\t\t\tifx(meta_function::pairs, &container_detail::u_c_launch<as_container_t<T>>::pairs_call);\n\t\t\t\t}\n\t\t\t\tif (fx(meta_function::length)) {\n\t\t\t\t\tif constexpr (meta::has_size<const T>::value || meta::has_size<T>::value) {\n\t\t\t\t\t\tauto f = &default_size<T>;\n\t\t\t\t\t\tifx(meta_function::length, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (fx(meta_function::to_string)) {\n\t\t\t\t\tif constexpr (is_to_stringable<T>::value) {\n\t\t\t\t\t\tauto f = &detail::static_trampoline<&default_to_string<T>>;\n\t\t\t\t\t\tifx(meta_function::to_string, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (fx(meta_function::call_function)) {\n\t\t\t\t\tif constexpr (meta::has_deducible_signature<T>::value) {\n\t\t\t\t\t\tauto f = &c_call<decltype(&T::operator()), &T::operator()>;\n\t\t\t\t\t\tifx(meta_function::call_function, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} // namespace detail\n\n\tnamespace stack { namespace stack_detail {\n\t\ttemplate <typename X>\n\t\tvoid set_undefined_methods_on(stack_reference t) {\n\t\t\tusing T = std::remove_pointer_t<X>;\n\n\t\t\tlua_State* L = t.lua_state();\n\n\t\t\tt.push();\n\n\t\t\tdetail::lua_reg_table l{};\n\t\t\tint index = 0;\n\t\t\tdetail::indexed_insert insert_fx(l, index);\n\t\t\tdetail::insert_default_registrations<T>(insert_fx, detail::property_always_true);\n\t\t\tif constexpr (!std::is_pointer_v<X>) {\n\t\t\t\tl[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() };\n\t\t\t}\n\t\t\tluaL_setfuncs(L, l, 0);\n\n\t\t\t// __type table\n\t\t\tlua_createtable(L, 0, 2);\n\t\t\tconst std::string& name = detail::demangle<T>();\n\t\t\tlua_pushlstring(L, name.c_str(), name.size());\n\t\t\tlua_setfield(L, -2, \"name\");\n\t\t\tlua_CFunction is_func = &detail::is_check<T>;\n\t\t\tlua_pushcclosure(L, is_func, 0);\n\t\t\tlua_setfield(L, -2, \"is\");\n\t\t\tlua_setfield(L, t.stack_index(), to_string(meta_function::type).c_str());\n\n\t\t\tt.pop();\n\t\t}\n\t}} // namespace stack::stack_detail\n} // namespace sol\n\n// end of sol/usertype_core.hpp\n\n// beginning of sol/usertype_storage.hpp\n\n#include <bitset>\n#include <unordered_map>\n\nnamespace sol { namespace u_detail {\n\n\tstruct usertype_storage_base;\n\ttemplate <typename T>\n\tstruct usertype_storage;\n\n\toptional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index);\n\tusertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey);\n\ttemplate <typename T>\n\toptional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L);\n\ttemplate <typename T>\n\tusertype_storage<T>& get_usertype_storage(lua_State* L);\n\n\tusing index_call_function = int(lua_State*, void*);\n\tusing change_indexing_mem_func\n\t\t= void (usertype_storage_base::*)(lua_State*, submetatable_type, void*, stack_reference&, lua_CFunction, lua_CFunction, lua_CFunction, lua_CFunction);\n\n\tstruct index_call_storage {\n\t\tindex_call_function* index;\n\t\tindex_call_function* new_index;\n\t\tvoid* binding_data;\n\t};\n\n\tstruct new_index_call_storage : index_call_storage {\n\t\tvoid* new_binding_data;\n\t};\n\n\tstruct binding_base {\n\t\tvirtual void* data() = 0;\n\t\tvirtual ~binding_base() {\n\t\t}\n\t};\n\n\ttemplate <typename K, typename Fq, typename T = void>\n\tstruct binding : binding_base {\n\t\tusing uF = meta::unqualified_t<Fq>;\n\t\tusing F = meta::conditional_t<meta::is_c_str_of_v<uF, char>\n#ifdef __cpp_char8_t\n\t\t\t     || meta::is_c_str_of_v<uF, char8_t>\n#endif\n\t\t\t     || meta::is_c_str_of_v<uF, char16_t> || meta::is_c_str_of_v<uF, char32_t> || meta::is_c_str_of_v<uF, wchar_t>,\n\t\t\tstd::add_pointer_t<std::add_const_t<std::remove_all_extents_t<Fq>>>, std::decay_t<Fq>>;\n\t\tF data_;\n\n\t\ttemplate <typename... Args>\n\t\tbinding(Args&&... args) : data_(std::forward<Args>(args)...) {\n\t\t}\n\n\t\tvirtual void* data() override {\n\t\t\treturn static_cast<void*>(std::addressof(data_));\n\t\t}\n\n\t\ttemplate <bool is_index = true, bool is_variable = false>\n\t\tstatic inline int call_with_(lua_State* L, void* target) {\n\t\t\tconstexpr int boost = !detail::is_non_factory_constructor<F>::value && std::is_same<K, call_construction>::value ? 1 : 0;\n\t\t\tauto& f = *static_cast<F*>(target);\n\t\t\treturn call_detail::call_wrapped<T, is_index, is_variable, boost>(L, f);\n\t\t}\n\n\t\ttemplate <bool is_index = true, bool is_variable = false>\n\t\tstatic inline int call_(lua_State* L) {\n\t\t\tvoid* f = stack::get<void*>(L, upvalue_index(usertype_storage_index));\n\t\t\treturn call_with_<is_index, is_variable>(L, f);\n\t\t}\n\n\t\ttemplate <bool is_index = true, bool is_variable = false>\n\t\tstatic inline int call(lua_State* L) {\n\t\t\tint r = detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L);\n\t\t\tif constexpr (meta::is_specialization_of_v<uF, yielding_t>) {\n\t\t\t\treturn lua_yield(L, r);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool is_index = true, bool is_variable = false>\n\t\tstatic inline int index_call_with_(lua_State* L, void* target) {\n\t\t\tif constexpr (!is_variable) {\n\t\t\t\tif constexpr (is_lua_c_function_v<std::decay_t<F>>) {\n\t\t\t\t\tauto& f = *static_cast<std::decay_t<F>*>(target);\n\t\t\t\t\treturn stack::push(L, f);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// set up upvalues\n\t\t\t\t\t// for a chained call\n\t\t\t\t\tint upvalues = 0;\n\t\t\t\t\tupvalues += stack::push(L, nullptr);\n\t\t\t\t\tupvalues += stack::push(L, target);\n\t\t\t\t\tauto cfunc = &call<is_index, is_variable>;\n\t\t\t\t\treturn stack::push(L, c_closure(cfunc, upvalues));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconstexpr int boost = !detail::is_non_factory_constructor<F>::value && std::is_same<K, call_construction>::value ? 1 : 0;\n\t\t\t\tauto& f = *static_cast<F*>(target);\n\t\t\t\treturn call_detail::call_wrapped<T, is_index, is_variable, boost>(L, f);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool is_index = true, bool is_variable = false>\n\t\tstatic inline int index_call_(lua_State* L) {\n\t\t\tvoid* f = stack::get<void*>(L, upvalue_index(usertype_storage_index));\n\t\t\treturn index_call_with_<is_index, is_variable>(L, f);\n\t\t}\n\n\t\ttemplate <bool is_index = true, bool is_variable = false>\n\t\tstatic inline int index_call(lua_State* L) {\n\t\t\tint r = detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L);\n\t\t\tif constexpr (meta::is_specialization_of_v<uF, yielding_t>) {\n\t\t\t\treturn lua_yield(L, r);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\t};\n\n\tinline int index_fail(lua_State* L) {\n\t\tif (lua_getmetatable(L, 1) == 1) {\n\t\t\tint metatarget = lua_gettop(L);\n\t\t\tstack::get_field<false, true>(L, stack_reference(L, raw_index(2)), metatarget);\n\t\t\treturn 1;\n\t\t}\n\t\t// With runtime extensibility, we can't\n\t\t// hard-error things. They have to\n\t\t// return nil, like regular table types\n\t\treturn stack::push(L, lua_nil);\n\t}\n\n\tinline int index_target_fail(lua_State* L, void*) {\n\t\treturn index_fail(L);\n\t}\n\n\tinline int new_index_fail(lua_State* L) {\n\t\treturn luaL_error(L, \"sol: cannot set (new_index) into this object: no defined new_index operation on usertype\");\n\t}\n\n\tinline int new_index_target_fail(lua_State* L, void*) {\n\t\treturn new_index_fail(L);\n\t}\n\n\tstruct string_for_each_metatable_func {\n\t\tbool is_destruction = false;\n\t\tbool is_index = false;\n\t\tbool is_new_index = false;\n\t\tbool is_static_index = false;\n\t\tbool is_static_new_index = false;\n\t\tbool poison_indexing = false;\n\t\tbool is_unqualified_lua_CFunction = false;\n\t\tbool is_unqualified_lua_reference = false;\n\t\tstd::string* p_key = nullptr;\n\t\treference* p_binding_ref = nullptr;\n\t\tlua_CFunction call_func = nullptr;\n\t\tindex_call_storage* p_ics = nullptr;\n\t\tusertype_storage_base* p_usb = nullptr;\n\t\tvoid* p_derived_usb = nullptr;\n\t\tlua_CFunction idx_call = nullptr, new_idx_call = nullptr, meta_idx_call = nullptr, meta_new_idx_call = nullptr;\n\t\tchange_indexing_mem_func change_indexing;\n\n\t\tvoid operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {\n\t\t\tstd::string& key = *p_key;\n\t\t\tusertype_storage_base& usb = *p_usb;\n\t\t\tindex_call_storage& ics = *p_ics;\n\n\t\t\tif (smt == submetatable_type::named) {\n\t\t\t\t// do not override __call or\n\t\t\t\t// other specific meta functions on named metatable:\n\t\t\t\t// we need that for call construction\n\t\t\t\t// and other amenities\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tint fast_index_table_push = fast_index_table.push();\n\t\t\tstack_reference t(L, -fast_index_table_push);\n\t\t\tif (poison_indexing) {\n\t\t\t\t(usb.*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call);\n\t\t\t}\n\t\t\tif (is_destruction\n\t\t\t\t&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named\n\t\t\t\t     || smt == submetatable_type::unique)) {\n\t\t\t\t// gc does not apply to us here\n\t\t\t\t// for reference types (raw T*, std::ref)\n\t\t\t\t// for the named metatable itself,\n\t\t\t\t// or for unique_usertypes, which do their own custom destruction\n\t\t\t\tt.pop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (is_index || is_new_index || is_static_index || is_static_new_index) {\n\t\t\t\t// do not serialize the new_index and index functions here directly\n\t\t\t\t// we control those...\n\t\t\t\tt.pop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (is_unqualified_lua_CFunction) {\n\t\t\t\tstack::set_field<false, true>(L, key, call_func, t.stack_index());\n\t\t\t}\n\t\t\telse if (is_unqualified_lua_reference) {\n\t\t\t\treference& binding_ref = *p_binding_ref;\n\t\t\t\tstack::set_field<false, true>(L, key, binding_ref, t.stack_index());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstack::set_field<false, true>(L, key, make_closure(call_func, nullptr, ics.binding_data), t.stack_index());\n\t\t\t}\n\t\t\tt.pop();\n\t\t}\n\t};\n\n\tstruct lua_reference_func {\n\t\treference key;\n\t\treference value;\n\n\t\tvoid operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {\n\t\t\tif (smt == submetatable_type::named) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tint fast_index_table_push = fast_index_table.push();\n\t\t\tstack_reference t(L, -fast_index_table_push);\n\t\t\tstack::set_field<false, true>(L, key, value, t.stack_index());\n\t\t\tt.pop();\n\t\t}\n\t};\n\n\tstruct update_bases_func {\n\t\tdetail::inheritance_check_function base_class_check_func;\n\t\tdetail::inheritance_cast_function base_class_cast_func;\n\t\tlua_CFunction idx_call, new_idx_call, meta_idx_call, meta_new_idx_call;\n\t\tusertype_storage_base* p_usb;\n\t\tvoid* p_derived_usb;\n\t\tchange_indexing_mem_func change_indexing;\n\n\t\tvoid operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {\n\t\t\tint fast_index_table_push = fast_index_table.push();\n\t\t\tstack_reference t(L, -fast_index_table_push);\n\t\t\tstack::set_field(L, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index());\n\t\t\tstack::set_field(L, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index());\n\t\t\t// change indexing, forcefully\n\t\t\t(p_usb->*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call);\n\t\t\tt.pop();\n\t\t}\n\t};\n\n\tstruct binding_data_equals {\n\t\tvoid* binding_data;\n\n\t\tbinding_data_equals(void* b) : binding_data(b) {\n\t\t}\n\n\t\tbool operator()(const std::unique_ptr<binding_base>& ptr) const {\n\t\t\treturn binding_data == ptr->data();\n\t\t}\n\t};\n\n\tstruct usertype_storage_base {\n\tpublic:\n\t\tstd::vector<std::unique_ptr<binding_base>> storage;\n\t\tstd::vector<std::unique_ptr<char[]>> string_keys_storage;\n\t\tstd::unordered_map<string_view, index_call_storage> string_keys;\n\t\tstd::unordered_map<reference, reference, reference_hash, reference_equals> auxiliary_keys;\n\t\treference value_index_table;\n\t\treference reference_index_table;\n\t\treference unique_index_table;\n\t\treference const_reference_index_table;\n\t\treference const_value_index_table;\n\t\treference named_index_table;\n\t\treference type_table;\n\t\treference gc_names_table;\n\t\treference named_metatable;\n\t\tnew_index_call_storage base_index;\n\t\tnew_index_call_storage static_base_index;\n\t\tbool is_using_index;\n\t\tbool is_using_new_index;\n\t\tstd::bitset<64> properties;\n\n\t\tusertype_storage_base(lua_State* L)\n\t\t: storage()\n\t\t, string_keys()\n\t\t, auxiliary_keys()\n\t\t, value_index_table()\n\t\t, reference_index_table()\n\t\t, unique_index_table()\n\t\t, const_reference_index_table()\n\t\t, type_table(make_reference(L, create))\n\t\t, gc_names_table(make_reference(L, create))\n\t\t, named_metatable(make_reference(L, create))\n\t\t, base_index()\n\t\t, static_base_index()\n\t\t, is_using_index(false)\n\t\t, is_using_new_index(false)\n\t\t, properties() {\n\t\t\tbase_index.binding_data = nullptr;\n\t\t\tbase_index.index = index_target_fail;\n\t\t\tbase_index.new_index = new_index_target_fail;\n\t\t\tbase_index.new_binding_data = nullptr;\n\t\t\tstatic_base_index.binding_data = nullptr;\n\t\t\tstatic_base_index.index = index_target_fail;\n\t\t\tstatic_base_index.new_binding_data = this;\n\t\t\tstatic_base_index.new_index = new_index_target_set;\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tvoid for_each_table(lua_State* L, Fx&& fx) {\n\t\t\tfor (int i = 0; i < 6; ++i) {\n\t\t\t\tsubmetatable_type smt = static_cast<submetatable_type>(i);\n\t\t\t\treference* p_fast_index_table = nullptr;\n\t\t\t\tswitch (smt) {\n\t\t\t\tcase submetatable_type::const_value:\n\t\t\t\t\tp_fast_index_table = &this->const_value_index_table;\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::reference:\n\t\t\t\t\tp_fast_index_table = &this->reference_index_table;\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::unique:\n\t\t\t\t\tp_fast_index_table = &this->unique_index_table;\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::const_reference:\n\t\t\t\t\tp_fast_index_table = &this->const_reference_index_table;\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::named:\n\t\t\t\t\tp_fast_index_table = &this->named_index_table;\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::value:\n\t\t\t\tdefault:\n\t\t\t\t\tp_fast_index_table = &this->value_index_table;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfx(L, smt, *p_fast_index_table);\n\t\t\t}\n\t\t}\n\n\t\tvoid add_entry(string_view sv, index_call_storage ics) {\n\t\t\tstring_keys_storage.emplace_back(new char[sv.size()]);\n\t\t\tstd::unique_ptr<char[]>& sv_storage = string_keys_storage.back();\n\t\t\tstd::memcpy(sv_storage.get(), sv.data(), sv.size());\n\t\t\tstring_view stored_sv(sv_storage.get(), sv.size());\n\t\t\tstring_keys.insert_or_assign(std::move(stored_sv), std::move(ics));\n\t\t}\n\n\t\ttemplate <typename T, typename... Bases>\n\t\tvoid update_bases(lua_State* L, bases<Bases...>) {\n\t\t\tstatic_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function),\n\t\t\t\t\"The size of this data pointer is too small to fit the inheritance checking function: Please file \"\n\t\t\t\t\"a bug report.\");\n\t\t\tstatic_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function),\n\t\t\t\t\"The size of this data pointer is too small to fit the inheritance checking function: Please file \"\n\t\t\t\t\"a bug report.\");\n\t\t\tstatic_assert(!meta::any_same<T, Bases...>::value, \"base classes cannot list the original class as part of the bases\");\n\t\t\tif constexpr (sizeof...(Bases) < 1) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t(void)detail::swallow { 0, ((weak_derive<Bases>::value = true), 0)... };\n\n\t\t\tvoid* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this));\n\n\t\t\tupdate_bases_func for_each_fx;\n\t\t\tfor_each_fx.base_class_check_func = &detail::inheritance<T>::template type_check_with<Bases...>;\n\t\t\tfor_each_fx.base_class_cast_func = &detail::inheritance<T>::template type_cast_with<Bases...>;\n\t\t\tfor_each_fx.idx_call = &usertype_storage<T>::template index_call_with_bases<false, Bases...>;\n\t\t\tfor_each_fx.new_idx_call = &usertype_storage<T>::template index_call_with_bases<true, Bases...>;\n\t\t\tfor_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<false, Bases...>;\n\t\t\tfor_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<true, Bases...>;\n\t\t\tfor_each_fx.p_usb = this;\n\t\t\tfor_each_fx.p_derived_usb = derived_this;\n\t\t\tfor_each_fx.change_indexing = &usertype_storage_base::change_indexing;\n\t\t\tfor_each_fx.p_derived_usb = derived_this;\n\t\t\tthis->for_each_table(L, for_each_fx);\n\t\t}\n\n\t\tvoid clear() {\n\t\t\tif (value_index_table.valid()) {\n\t\t\t\tstack::clear(value_index_table);\n\t\t\t}\n\t\t\tif (reference_index_table.valid()) {\n\t\t\t\tstack::clear(reference_index_table);\n\t\t\t}\n\t\t\tif (unique_index_table.valid()) {\n\t\t\t\tstack::clear(unique_index_table);\n\t\t\t}\n\t\t\tif (const_reference_index_table.valid()) {\n\t\t\t\tstack::clear(const_reference_index_table);\n\t\t\t}\n\t\t\tif (const_value_index_table.valid()) {\n\t\t\t\tstack::clear(const_value_index_table);\n\t\t\t}\n\t\t\tif (named_index_table.valid()) {\n\t\t\t\tstack::clear(named_index_table);\n\t\t\t}\n\t\t\tif (type_table.valid()) {\n\t\t\t\tstack::clear(type_table);\n\t\t\t}\n\t\t\tif (gc_names_table.valid()) {\n\t\t\t\tstack::clear(gc_names_table);\n\t\t\t}\n\t\t\tif (named_metatable.valid()) {\n\t\t\t\tlua_State* L = named_metatable.lua_state();\n\t\t\t\tauto pp = stack::push_pop(named_metatable);\n\t\t\t\tint named_metatable_index = pp.index_of(named_metatable);\n\t\t\t\tif (lua_getmetatable(L, named_metatable_index) == 1) {\n\t\t\t\t\tstack::clear(L, absolute_index(L, -1));\n\t\t\t\t}\n\t\t\t\tstack::clear(named_metatable);\n\t\t\t}\n\n\t\t\tvalue_index_table = lua_nil;\n\t\t\treference_index_table = lua_nil;\n\t\t\tunique_index_table = lua_nil;\n\t\t\tconst_reference_index_table = lua_nil;\n\t\t\tconst_value_index_table = lua_nil;\n\t\t\tnamed_index_table = lua_nil;\n\t\t\ttype_table = lua_nil;\n\t\t\tgc_names_table = lua_nil;\n\t\t\tnamed_metatable = lua_nil;\n\n\t\t\tstorage.clear();\n\t\t\tstring_keys.clear();\n\t\t\tauxiliary_keys.clear();\n\t\t}\n\n\t\ttemplate <bool is_new_index, typename Base>\n\t\tstatic void base_walk_index(lua_State* L, usertype_storage_base& self, bool& keep_going, int& base_result) {\n\t\t\tusing bases = typename base<Base>::type;\n\t\t\tif (!keep_going) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t(void)L;\n\t\t\t(void)self;\n#if SOL_IS_ON(SOL_USE_UNSAFE_BASE_LOOKUP_I_)\n\t\t\tusertype_storage_base& base_storage = get_usertype_storage<Base>(L);\n\t\t\tbase_result = self_index_call<is_new_index, true>(bases(), L, base_storage);\n#else\n\t\t\toptional<usertype_storage<Base>&> maybe_base_storage = maybe_get_usertype_storage<Base>(L);\n\t\t\tif (static_cast<bool>(maybe_base_storage)) {\n\t\t\t\tbase_result = self_index_call<is_new_index, true>(bases(), L, *maybe_base_storage);\n\t\t\t\tkeep_going = base_result == base_walking_failed_index;\n\t\t\t}\n#endif // Fast versus slow, safe base lookup\n\t\t}\n\n\t\ttemplate <bool is_new_index = false, bool base_walking = false, bool from_named_metatable = false, typename... Bases>\n\t\tstatic inline int self_index_call(types<Bases...>, lua_State* L, usertype_storage_base& self) {\n\t\t\ttype k_type = stack::get<type>(L, 2);\n\t\t\tif (k_type == type::string) {\n\t\t\t\tindex_call_storage* target = nullptr;\n\t\t\t\t{\n\t\t\t\t\tstring_view k = stack::get<string_view>(L, 2);\n\t\t\t\t\tauto it = self.string_keys.find(k);\n\t\t\t\t\tif (it != self.string_keys.cend()) {\n\t\t\t\t\t\ttarget = &it->second;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (target != nullptr) {\n\t\t\t\t\t// let the target decide what to do\n\t\t\t\t\tif constexpr (is_new_index) {\n\t\t\t\t\t\treturn (target->new_index)(L, target->binding_data);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn (target->index)(L, target->binding_data);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (k_type != type::lua_nil && k_type != type::none) {\n\t\t\t\treference* target = nullptr;\n\t\t\t\t{\n\t\t\t\t\tstack_reference k = stack::get<stack_reference>(L, 2);\n\t\t\t\t\tauto it = self.auxiliary_keys.find(k);\n\t\t\t\t\tif (it != self.auxiliary_keys.cend()) {\n\t\t\t\t\t\ttarget = &it->second;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (target != nullptr) {\n\t\t\t\t\tif constexpr (is_new_index) {\n\t\t\t\t\t\t// set value and return\n\t\t\t\t\t\t*target = reference(L, 3);\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// push target to return\n\t\t\t\t\t\t// what we found\n\t\t\t\t\t\treturn stack::push(L, *target);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// retrieve bases and walk through them.\n\t\t\tbool keep_going = true;\n\t\t\tint base_result;\n\t\t\t(void)keep_going;\n\t\t\t(void)base_result;\n\t\t\t(void)detail::swallow { 1, (base_walk_index<is_new_index, Bases>(L, self, keep_going, base_result), 1)... };\n\t\t\tif constexpr (sizeof...(Bases) > 0) {\n\t\t\t\tif (!keep_going) {\n\t\t\t\t\treturn base_result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif constexpr (base_walking) {\n\t\t\t\t// if we're JUST base-walking then don't index-fail, just\n\t\t\t\t// return the false bits\n\t\t\t\treturn base_walking_failed_index;\n\t\t\t}\n\t\t\telse if constexpr (from_named_metatable) {\n\t\t\t\tif constexpr (is_new_index) {\n\t\t\t\t\treturn self.static_base_index.new_index(L, self.static_base_index.new_binding_data);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn self.static_base_index.index(L, self.static_base_index.binding_data);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif constexpr (is_new_index) {\n\t\t\t\t\treturn self.base_index.new_index(L, self.base_index.new_binding_data);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn self.base_index.index(L, self.base_index.binding_data);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid change_indexing(lua_State* L, submetatable_type submetatable, void* derived_this, stack_reference& t, lua_CFunction index,\n\t\t\tlua_CFunction new_index, lua_CFunction meta_index, lua_CFunction meta_new_index) {\n\t\t\tusertype_storage_base& this_base = *this;\n\t\t\tvoid* base_this = static_cast<void*>(&this_base);\n\n\t\t\tthis->is_using_index |= true;\n\t\t\tthis->is_using_new_index |= true;\n\t\t\tif (submetatable == submetatable_type::named) {\n\t\t\t\tstack::set_field(L, metatable_key, named_index_table, t.stack_index());\n\t\t\t\tstack_reference stack_metametatable(L, -named_metatable.push());\n\t\t\t\tstack::set_field<false, true>(L,\n\t\t\t\t\tmeta_function::index,\n\t\t\t\t\tmake_closure(meta_index, nullptr, derived_this, base_this, nullptr, toplevel_magic),\n\t\t\t\t\tstack_metametatable.stack_index());\n\t\t\t\tstack::set_field<false, true>(L,\n\t\t\t\t\tmeta_function::new_index,\n\t\t\t\t\tmake_closure(meta_new_index, nullptr, derived_this, base_this, nullptr, toplevel_magic),\n\t\t\t\t\tstack_metametatable.stack_index());\n\t\t\t\tstack_metametatable.pop();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstack::set_field<false, true>(\n\t\t\t\t\tL, meta_function::index, make_closure(index, nullptr, derived_this, base_this, nullptr, toplevel_magic), t.stack_index());\n\t\t\t\tstack::set_field<false, true>(\n\t\t\t\t\tL, meta_function::new_index, make_closure(new_index, nullptr, derived_this, base_this, nullptr, toplevel_magic), t.stack_index());\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T = void, typename Key, typename Value>\n\t\tvoid set(lua_State* L, Key&& key, Value&& value);\n\n\t\tstatic int new_index_target_set(lua_State* L, void* target) {\n\t\t\tusertype_storage_base& self = *static_cast<usertype_storage_base*>(target);\n\t\t\tself.set(L, reference(L, raw_index(2)), reference(L, raw_index(3)));\n\t\t\treturn 0;\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct usertype_storage : usertype_storage_base {\n\n\t\tusing usertype_storage_base::usertype_storage_base;\n\n\t\ttemplate <bool is_new_index, bool from_named_metatable>\n\t\tstatic inline int index_call_(lua_State* L) {\n\t\t\tusing bases = typename base<T>::type;\n\t\t\tusertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index));\n\t\t\treturn self_index_call<is_new_index, false, from_named_metatable>(bases(), L, self);\n\t\t}\n\n\t\ttemplate <bool is_new_index, bool from_named_metatable, typename... Bases>\n\t\tstatic inline int index_call_with_bases_(lua_State* L) {\n\t\t\tusing bases = types<Bases...>;\n\t\t\tusertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index));\n\t\t\treturn self_index_call<is_new_index, false, from_named_metatable>(bases(), L, self);\n\t\t}\n\n\t\ttemplate <bool is_new_index>\n\t\tstatic inline int index_call(lua_State* L) {\n\t\t\treturn detail::static_trampoline<&index_call_<is_new_index, false>>(L);\n\t\t}\n\n\t\ttemplate <bool is_new_index, typename... Bases>\n\t\tstatic inline int index_call_with_bases(lua_State* L) {\n\t\t\treturn detail::static_trampoline<&index_call_with_bases_<is_new_index, false, Bases...>>(L);\n\t\t}\n\n\t\ttemplate <bool is_new_index>\n\t\tstatic inline int meta_index_call(lua_State* L) {\n\t\t\treturn detail::static_trampoline<&index_call_<is_new_index, true>>(L);\n\t\t}\n\n\t\ttemplate <bool is_new_index, typename... Bases>\n\t\tstatic inline int meta_index_call_with_bases(lua_State* L) {\n\t\t\treturn detail::static_trampoline<&index_call_with_bases_<is_new_index, true, Bases...>>(L);\n\t\t}\n\n\t\ttemplate <typename Key, typename Value>\n\t\tinline void set(lua_State* L, Key&& key, Value&& value);\n\t};\n\n\ttemplate <typename T>\n\tinline int destruct_usertype_storage(lua_State* L) {\n\t\treturn detail::user_alloc_destruct<usertype_storage<T>>(L);\n\t}\n\n\ttemplate <typename T, typename Key, typename Value>\n\tvoid usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) {\n\t\tusing ValueU = meta::unwrap_unqualified_t<Value>;\n\t\tusing KeyU = meta::unwrap_unqualified_t<Key>;\n\t\tusing Binding = binding<KeyU, ValueU, T>;\n\t\tusing is_var_bind = is_variable_binding<ValueU>;\n\t\tif constexpr (std::is_same_v<KeyU, call_construction>) {\n\t\t\t(void)key;\n\t\t\tstd::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value));\n\t\t\tBinding& b = *p_binding;\n\t\t\tthis->storage.push_back(std::move(p_binding));\n\n\t\t\tthis->named_index_table.push();\n\t\t\tabsolute_index metametatable_index(L, -1);\n\t\t\tstack::push(L, nullptr);\n\t\t\tstack::push(L, b.data());\n\t\t\tlua_CFunction target_func = &b.template call<false, false>;\n\t\t\tlua_pushcclosure(L, target_func, 2);\n\t\t\tlua_setfield(L, metametatable_index, to_string(meta_function::call).c_str());\n\t\t\tthis->named_index_table.pop();\n\t\t}\n\t\telse if constexpr (std::is_same_v<KeyU, base_classes_tag>) {\n\t\t\t(void)key;\n\t\t\tthis->update_bases<T>(L, std::forward<Value>(value));\n\t\t}\n\t\telse if constexpr ((meta::is_string_like_or_constructible<KeyU>::value || std::is_same_v<KeyU, meta_function>)) {\n\t\t\tstd::string s = u_detail::make_string(std::forward<Key>(key));\n\t\t\tauto storage_it = this->storage.end();\n\t\t\tauto string_it = this->string_keys.find(s);\n\t\t\tif (string_it != this->string_keys.cend()) {\n\t\t\t\tconst auto& binding_data = string_it->second.binding_data;\n\t\t\t\tstorage_it = std::find_if(this->storage.begin(), this->storage.end(), binding_data_equals(binding_data));\n\t\t\t\tthis->string_keys.erase(string_it);\n\t\t\t}\n\n\t\t\tstd::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value));\n\t\t\tBinding& b = *p_binding;\n\t\t\tif (storage_it != this->storage.cend()) {\n\t\t\t\t*storage_it = std::move(p_binding);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis->storage.push_back(std::move(p_binding));\n\t\t\t}\n\n\t\t\tbool is_index = (s == to_string(meta_function::index));\n\t\t\tbool is_new_index = (s == to_string(meta_function::new_index));\n\t\t\tbool is_static_index = (s == to_string(meta_function::static_index));\n\t\t\tbool is_static_new_index = (s == to_string(meta_function::static_new_index));\n\t\t\tbool is_destruction = s == to_string(meta_function::garbage_collect);\n\t\t\tbool poison_indexing = (!is_using_index || !is_using_new_index) && (is_var_bind::value || is_index || is_new_index);\n\t\t\tvoid* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this));\n\t\t\tindex_call_storage ics;\n\t\t\tics.binding_data = b.data();\n\t\t\tics.index = is_index || is_static_index ? &Binding::template call_with_<true, is_var_bind::value>\n\t\t\t\t                                   : &Binding::template index_call_with_<true, is_var_bind::value>;\n\t\t\tics.new_index = is_new_index || is_static_new_index ? &Binding::template call_with_<false, is_var_bind::value>\n\t\t\t\t                                               : &Binding::template index_call_with_<false, is_var_bind::value>;\n\n\t\t\tstring_for_each_metatable_func for_each_fx;\n\t\t\tfor_each_fx.is_destruction = is_destruction;\n\t\t\tfor_each_fx.is_index = is_index;\n\t\t\tfor_each_fx.is_new_index = is_new_index;\n\t\t\tfor_each_fx.is_static_index = is_static_index;\n\t\t\tfor_each_fx.is_static_new_index = is_static_new_index;\n\t\t\tfor_each_fx.poison_indexing = poison_indexing;\n\t\t\tfor_each_fx.p_key = &s;\n\t\t\tfor_each_fx.p_ics = &ics;\n\t\t\tif constexpr (is_lua_c_function_v<ValueU>) {\n\t\t\t\tfor_each_fx.is_unqualified_lua_CFunction = true;\n\t\t\t\tfor_each_fx.call_func = *static_cast<lua_CFunction*>(ics.binding_data);\n\t\t\t}\n\t\t\telse if constexpr (is_lua_reference_or_proxy_v<ValueU>) {\n\t\t\t\tfor_each_fx.is_unqualified_lua_reference = true;\n\t\t\t\tfor_each_fx.p_binding_ref = static_cast<reference*>(ics.binding_data);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor_each_fx.call_func = &b.template call<false, is_var_bind::value>;\n\t\t\t}\n\t\t\tfor_each_fx.p_usb = this;\n\t\t\tfor_each_fx.p_derived_usb = derived_this;\n\t\t\tfor_each_fx.idx_call = &usertype_storage<T>::template index_call<false>;\n\t\t\tfor_each_fx.new_idx_call = &usertype_storage<T>::template index_call<true>;\n\t\t\tfor_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call<false>;\n\t\t\tfor_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call<true>;\n\t\t\tfor_each_fx.change_indexing = &usertype_storage_base::change_indexing;\n\t\t\t// set base index and base new_index\n\t\t\t// functions here\n\t\t\tif (is_index) {\n\t\t\t\tthis->base_index.index = ics.index;\n\t\t\t\tthis->base_index.binding_data = ics.binding_data;\n\t\t\t}\n\t\t\tif (is_new_index) {\n\t\t\t\tthis->base_index.new_index = ics.new_index;\n\t\t\t\tthis->base_index.new_binding_data = ics.binding_data;\n\t\t\t}\n\t\t\tif (is_static_index) {\n\t\t\t\tthis->static_base_index.index = ics.index;\n\t\t\t\tthis->static_base_index.binding_data = ics.binding_data;\n\t\t\t}\n\t\t\tif (is_static_new_index) {\n\t\t\t\tthis->static_base_index.new_index = ics.new_index;\n\t\t\t\tthis->static_base_index.new_binding_data = ics.binding_data;\n\t\t\t}\n\t\t\tthis->for_each_table(L, for_each_fx);\n\t\t\tthis->add_entry(s, std::move(ics));\n\t\t}\n\t\telse {\n\t\t\t// the reference-based implementation might compare poorly and hash\n\t\t\t// poorly in some cases...\n\t\t\tif constexpr (is_lua_reference_v<KeyU> && is_lua_reference_v<ValueU>) {\n\t\t\t\tif (key.get_type() == type::string) {\n\t\t\t\t\tstack::push(L, key);\n\t\t\t\t\tstd::string string_key = stack::pop<std::string>(L);\n\t\t\t\t\tthis->set<T>(L, string_key, std::forward<Value>(value));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlua_reference_func ref_additions_fx { key, value };\n\n\t\t\t\t\tthis->for_each_table(L, ref_additions_fx);\n\t\t\t\t\tthis->auxiliary_keys.insert_or_assign(std::forward<Key>(key), std::forward<Value>(value));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\treference ref_key = make_reference(L, std::forward<Key>(key));\n\t\t\t\treference ref_value = make_reference(L, std::forward<Value>(value));\n\t\t\t\tlua_reference_func ref_additions_fx { key, value };\n\n\t\t\t\tthis->for_each_table(L, ref_additions_fx);\n\t\t\t\tthis->auxiliary_keys.insert_or_assign(std::move(ref_key), std::move(ref_value));\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate <typename T>\n\ttemplate <typename Key, typename Value>\n\tvoid usertype_storage<T>::set(lua_State* L, Key&& key, Value&& value) {\n\t\tstatic_cast<usertype_storage_base&>(*this).set<T>(L, std::forward<Key>(key), std::forward<Value>(value));\n\t}\n\n\ttemplate <typename T>\n\tinline usertype_storage<T>& create_usertype_storage(lua_State* L) {\n\t\tconst char* gcmetakey = &usertype_traits<T>::gc_table()[0];\n\n\t\t// Make sure userdata's memory is properly in lua first,\n\t\t// otherwise all the light userdata we make later will become invalid\n\t\tint usertype_storage_push_count = stack::push<user<usertype_storage<T>>>(L, no_metatable, L);\n\t\tstack_reference usertype_storage_ref(L, -usertype_storage_push_count);\n\n\t\t// create and push onto the stack a table to use as metatable for this GC\n\t\t// we create a metatable to attach to the regular gc_table\n\t\t// so that the destructor is called for the usertype storage\n\t\tint usertype_storage_metatabe_count = stack::push(L, new_table(0, 1));\n\t\tstack_reference usertype_storage_metatable(L, -usertype_storage_metatabe_count);\n\t\t// set the destruction routine on the metatable\n\t\tstack::set_field(L, meta_function::garbage_collect, &destruct_usertype_storage<T>, usertype_storage_metatable.stack_index());\n\t\t// set the metatable on the usertype storage userdata\n\t\tstack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index());\n\t\tusertype_storage_metatable.pop();\n\n\t\t// set the usertype storage and its metatable\n\t\t// into the global table...\n\t\tstack::set_field<true>(L, gcmetakey, usertype_storage_ref);\n\t\tusertype_storage_ref.pop();\n\n\t\t// then retrieve the lua-stored version so we have a well-pinned\n\t\t// reference that does not die\n\t\tstack::get_field<true>(L, gcmetakey);\n\t\tusertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L);\n\t\treturn target_umt;\n\t}\n\n\tinline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index) {\n\t\tstack::record tracking;\n\t\tif (!stack::check<user<usertype_storage_base>>(L, index)) {\n\t\t\treturn nullopt;\n\t\t}\n\t\tusertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking);\n\t\treturn target_umt;\n\t}\n\n\tinline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) {\n\t\tstack::get_field<true>(L, gcmetakey);\n\t\tauto maybe_storage = maybe_get_usertype_storage_base(L, lua_gettop(L));\n\t\tlua_pop(L, 1);\n\t\treturn maybe_storage;\n\t}\n\n\tinline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) {\n\t\tstack::get_field<true>(L, gcmetakey);\n\t\tstack::record tracking;\n\t\tusertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking);\n\t\tlua_pop(L, 1);\n\t\treturn target_umt;\n\t}\n\n\ttemplate <typename T>\n\tinline optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L) {\n\t\tconst char* gcmetakey = &usertype_traits<T>::gc_table()[0];\n\t\tstack::get_field<true>(L, gcmetakey);\n\t\tint target = lua_gettop(L);\n\t\tif (!stack::check<user<usertype_storage<T>>>(L, target)) {\n\t\t\treturn nullopt;\n\t\t}\n\t\tusertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L);\n\t\treturn target_umt;\n\t}\n\n\ttemplate <typename T>\n\tinline usertype_storage<T>& get_usertype_storage(lua_State* L) {\n\t\tconst char* gcmetakey = &usertype_traits<T>::gc_table()[0];\n\t\tstack::get_field<true>(L, gcmetakey);\n\t\tusertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L);\n\t\treturn target_umt;\n\t}\n\n\ttemplate <typename T>\n\tinline void delete_usertype_storage(lua_State* L) {\n\t\tusing u_traits = usertype_traits<T>;\n#if 0\n\t\tusing u_const_traits = usertype_traits<const T>;\n\t\tusing u_unique_traits = usertype_traits<detail::unique_usertype<T>>;\n\t\tusing u_ref_traits = usertype_traits<T*>;\n\t\tusing u_const_ref_traits = usertype_traits<T const*>;\n#endif\n\t\tusing uts = usertype_storage<T>;\n\n\t\tconst char* gcmetakey = &u_traits::gc_table()[0];\n\t\tstack::get_field<true>(L, gcmetakey);\n\t\tif (!stack::check<user<uts>>(L)) {\n\t\t\tlua_pop(L, 1);\n\t\t\treturn;\n\t\t}\n\t\tusertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L);\n\t\ttarget_umt.clear();\n\n\t\t// get the registry\n#if 0\n\t\tstack_reference registry(L, raw_index(LUA_REGISTRYINDEX));\n\t\tregistry.push();\n\t\t// eliminate all named entries for this usertype\n\t\t// in the registry (luaL_newmetatable does\n\t\t// [name] = new table\n\t\t// in registry upon creation\n\t\tstack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index());\n\t\tstack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index());\n\t\tstack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index());\n\t\tstack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index());\n\t\tstack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index());\n\t\tregistry.pop();\n#endif // Registry Cleanout\n\n\t\tstack::set_field<true>(L, gcmetakey, lua_nil);\n\t}\n\n\ttemplate <typename T>\n\tinline int register_usertype(lua_State* L, automagic_enrollments enrollments = {}) {\n\t\tusing u_traits = usertype_traits<T>;\n\t\tusing u_const_traits = usertype_traits<const T>;\n\t\tusing u_unique_traits = usertype_traits<detail::unique_usertype<T>>;\n\t\tusing u_ref_traits = usertype_traits<T*>;\n\t\tusing u_const_ref_traits = usertype_traits<T const*>;\n\t\tusing uts = usertype_storage<T>;\n\n\t\t// always have __new_index point to usertype_storage method\n\t\t// have __index always point to regular fast-lookup\n\t\t// meta_method table\n\t\t// if __new_index is invoked, runtime-swap\n\t\t// to slow __index if necessary\n\t\t// (no speed penalty because function calls\n\t\t// are all read-only -- only depend on __index\n\t\t// to retrieve function and then call happens VIA Lua)\n\n\t\t// __type entry:\n\t\t// table contains key -> value lookup,\n\t\t// where key is entry in metatable\n\t\t// and value is type information as a string as\n\t\t// best as we can give it\n\n\t\t// name entry:\n\t\t// string that contains raw class name,\n\t\t// as defined from C++\n\n\t\t// is entry:\n\t\t// checks if argument supplied is of type T\n\n\t\t// __storage entry:\n\t\t// a light userdata pointing to the storage\n\t\t// mostly to enable this new abstraction\n\t\t// to not require the type name `T`\n\t\t// to get at the C++ usertype storage within\n\n\t\t// we then let typical definitions potentially override these intrinsics\n\t\t// it's the user's fault if they override things or screw them up:\n\t\t// these names have been reserved and documented since sol3\n\n\t\t// STEP 0: tell the old usertype (if it exists)\n\t\t// to fuck off\n\t\tdelete_usertype_storage<T>(L);\n\n\t\t// STEP 1: Create backing store for usertype storage\n\t\t// Pretty much the most important step.\n\t\t// STEP 2: Create Lua tables used for fast method indexing.\n\t\t// This is done inside of the storage table's constructor\n\t\tusertype_storage<T>& storage = create_usertype_storage<T>(L);\n\t\tusertype_storage_base& base_storage = storage;\n\t\tvoid* light_storage = static_cast<void*>(&storage);\n\t\tvoid* light_base_storage = static_cast<void*>(&base_storage);\n\n\t\t// STEP 3: set up GC escape hatch table entirely\n\t\tstorage.gc_names_table.push();\n\t\tstack_reference gnt(L, -1);\n\t\tstack::set_field(L, submetatable_type::named, &u_traits::gc_table()[0], gnt.stack_index());\n\t\tstack::set_field(L, submetatable_type::const_value, &u_const_traits::metatable()[0], gnt.stack_index());\n\t\tstack::set_field(L, submetatable_type::const_reference, &u_const_ref_traits::metatable()[0], gnt.stack_index());\n\t\tstack::set_field(L, submetatable_type::reference, &u_ref_traits::metatable()[0], gnt.stack_index());\n\t\tstack::set_field(L, submetatable_type::unique, &u_unique_traits::metatable()[0], gnt.stack_index());\n\t\tstack::set_field(L, submetatable_type::value, &u_traits::metatable()[0], gnt.stack_index());\n\t\tgnt.pop();\n\n\t\t// STEP 4: add some useful information to the type table\n\t\tstack_reference stacked_type_table(L, -storage.type_table.push());\n\t\tstack::set_field(L, \"name\", detail::demangle<T>(), stacked_type_table.stack_index());\n\t\tstack::set_field(L, \"is\", &detail::is_check<T>, stacked_type_table.stack_index());\n\t\tstacked_type_table.pop();\n\n\t\t// STEP 5: create and hook up metatable,\n\t\t// add intrinsics\n\t\t// this one is the actual meta-handling table,\n\t\t// the next one will be the one for\n\t\tint for_each_backing_metatable_calls = 0;\n\t\tauto for_each_backing_metatable = [&](lua_State* L, submetatable_type smt, reference& fast_index_table) {\n\t\t\t// Pointer types, AKA \"references\" from C++\n\t\t\tconst char* metakey = nullptr;\n\t\t\tswitch (smt) {\n\t\t\tcase submetatable_type::const_value:\n\t\t\t\tmetakey = &u_const_traits::metatable()[0];\n\t\t\t\tbreak;\n\t\t\tcase submetatable_type::reference:\n\t\t\t\tmetakey = &u_ref_traits::metatable()[0];\n\t\t\t\tbreak;\n\t\t\tcase submetatable_type::unique:\n\t\t\t\tmetakey = &u_unique_traits::metatable()[0];\n\t\t\t\tbreak;\n\t\t\tcase submetatable_type::const_reference:\n\t\t\t\tmetakey = &u_const_ref_traits::metatable()[0];\n\t\t\t\tbreak;\n\t\t\tcase submetatable_type::named:\n\t\t\t\tmetakey = &u_traits::user_metatable()[0];\n\t\t\t\tbreak;\n\t\t\tcase submetatable_type::value:\n\t\t\tdefault:\n\t\t\t\tmetakey = &u_traits::metatable()[0];\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tluaL_newmetatable(L, metakey);\n\t\t\tif (smt == submetatable_type::named) {\n\t\t\t\t// the named table itself\n\t\t\t\t// gets the associated name value\n\t\t\t\tstorage.named_metatable = reference(L, -1);\n\t\t\t\tlua_pop(L, 1);\n\t\t\t\t// but the thing we perform the methods on\n\t\t\t\t// is still the metatable of the named\n\t\t\t\t// table\n\t\t\t\tlua_createtable(L, 0, 6);\n\t\t\t}\n\t\t\tstack_reference t(L, -1);\n\t\t\tfast_index_table = reference(t);\n\t\t\tstack::set_field<false, true>(L, meta_function::type, storage.type_table, t.stack_index());\n\t\t\tif constexpr (std::is_destructible_v<T>) {\n\t\t\t\t// destructible: serialize default\n\t\t\t\t// destructor here\n\t\t\t\tswitch (smt) {\n\t\t\t\tcase submetatable_type::const_reference:\n\t\t\t\tcase submetatable_type::reference:\n\t\t\t\tcase submetatable_type::named:\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::unique:\n\t\t\t\t\tstack::set_field<false, true>(L, meta_function::garbage_collect, &detail::unique_destruct<T>, t.stack_index());\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::value:\n\t\t\t\tcase submetatable_type::const_value:\n\t\t\t\tdefault:\n\t\t\t\t\tstack::set_field<false, true>(L, meta_function::garbage_collect, detail::make_destructor<T>(), t.stack_index());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// not destructible: serialize a\n\t\t\t\t// \"hey you messed up\"\n\t\t\t\t// destructor\n\t\t\t\tswitch (smt) {\n\t\t\t\tcase submetatable_type::const_reference:\n\t\t\t\tcase submetatable_type::reference:\n\t\t\t\tcase submetatable_type::named:\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::unique:\n\t\t\t\t\tstack::set_field<false, true>(L, meta_function::garbage_collect, &detail::cannot_destruct<T>, t.stack_index());\n\t\t\t\t\tbreak;\n\t\t\t\tcase submetatable_type::value:\n\t\t\t\tcase submetatable_type::const_value:\n\t\t\t\tdefault:\n\t\t\t\t\tstack::set_field<false, true>(L, meta_function::garbage_collect, &detail::cannot_destruct<T>, t.stack_index());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function),\n\t\t\t\t\"The size of this data pointer is too small to fit the inheritance checking function: file a bug \"\n\t\t\t\t\"report.\");\n\t\t\tstatic_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function),\n\t\t\t\t\"The size of this data pointer is too small to fit the inheritance checking function: file a bug \"\n\t\t\t\t\"report.\");\n\t\t\tstack::set_field<false, true>(L, detail::base_class_check_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_check), t.stack_index());\n\t\t\tstack::set_field<false, true>(L, detail::base_class_cast_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_cast), t.stack_index());\n\n\t\t\tauto prop_fx = detail::properties_enrollment_allowed(for_each_backing_metatable_calls, storage.properties, enrollments);\n\t\t\tauto insert_fx = [&L, &t, &storage](meta_function mf, lua_CFunction reg) {\n\t\t\t\tstack::set_field<false, true>(L, mf, reg, t.stack_index());\n\t\t\t\tstorage.properties[static_cast<int>(mf)] = true;\n\t\t\t};\n\t\t\tdetail::insert_default_registrations<T>(insert_fx, prop_fx);\n\n\t\t\t// There are no variables, so serialize the fast function stuff\n\t\t\t// be sure to reset the index stuff to the non-fast version\n\t\t\t// if the user ever adds something later!\n\t\t\tif (smt == submetatable_type::named) {\n\t\t\t\t// add escape hatch storage pointer and gc names\n\t\t\t\tstack::set_field<false, true>(L, meta_function::storage, light_base_storage, t.stack_index());\n\t\t\t\tstack::set_field<false, true>(L, meta_function::gc_names, storage.gc_names_table, t.stack_index());\n\n\t\t\t\t// fancy new_indexing when using the named table\n\t\t\t\t{\n\t\t\t\t\tabsolute_index named_metatable_index(L, -storage.named_metatable.push());\n\t\t\t\t\tstack::set_field<false, true>(L, metatable_key, t, named_metatable_index);\n\t\t\t\t\tstorage.named_metatable.pop();\n\t\t\t\t}\n\t\t\t\tstack_reference stack_metametatable(L, -storage.named_index_table.push());\n\t\t\t\tstack::set_field<false, true>(L,\n\t\t\t\t\tmeta_function::index,\n\t\t\t\t\tmake_closure(uts::template meta_index_call<false>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),\n\t\t\t\t\tstack_metametatable.stack_index());\n\t\t\t\tstack::set_field<false, true>(L,\n\t\t\t\t\tmeta_function::new_index,\n\t\t\t\t\tmake_closure(uts::template meta_index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),\n\t\t\t\t\tstack_metametatable.stack_index());\n\t\t\t\tstack_metametatable.pop();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// otherwise just plain for index,\n\t\t\t\t// and elaborated for new_index\n\t\t\t\tstack::set_field<false, true>(L, meta_function::index, t, t.stack_index());\n\t\t\t\tstack::set_field<false, true>(L,\n\t\t\t\t\tmeta_function::new_index,\n\t\t\t\t\tmake_closure(uts::template index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),\n\t\t\t\t\tt.stack_index());\n\t\t\t\tstorage.is_using_new_index = true;\n\t\t\t}\n\n\t\t\t++for_each_backing_metatable_calls;\n\t\t\tfast_index_table = reference(L, t);\n\t\t\tt.pop();\n\t\t};\n\n\t\tstorage.for_each_table(L, for_each_backing_metatable);\n\n\t\t// can only use set AFTER we initialize all the metatables\n\t\tif constexpr (std::is_default_constructible_v<T>) {\n\t\t\tif (enrollments.default_constructor) {\n\t\t\t\tstorage.set(L, meta_function::construct, constructors<T()>());\n\t\t\t}\n\t\t}\n\n\t\t// return the named metatable we want names linked into\n\t\tstorage.named_metatable.push();\n\t\treturn 1;\n\t}\n}} // namespace sol::u_detail\n\n// end of sol/usertype_storage.hpp\n\n// beginning of sol/usertype_proxy.hpp\n\nnamespace sol {\n\ttemplate <typename Table, typename Key>\n\tstruct usertype_proxy : public proxy_base<usertype_proxy<Table, Key>> {\n\tprivate:\n\t\tusing key_type = detail::proxy_key_t<Key>;\n\n\t\ttemplate <typename T, std::size_t... I>\n\t\tdecltype(auto) tuple_get(std::index_sequence<I...>) const & {\n\t\t\treturn tbl.template traverse_get<T>(std::get<I>(key)...);\n\t\t}\n\n\t\ttemplate <typename T, std::size_t... I>\n\t\tdecltype(auto) tuple_get(std::index_sequence<I...>) && {\n\t\t\treturn tbl.template traverse_get<T>(std::get<I>(std::move(key))...);\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename T>\n\t\tvoid tuple_set(std::index_sequence<I...>, T&& value) & {\n\t\t\tif constexpr (sizeof...(I) > 1) {\n\t\t\t\ttbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttbl.set(std::get<I>(key)..., std::forward<T>(value));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename T>\n\t\tvoid tuple_set(std::index_sequence<I...>, T&& value) && {\n\t\t\tif constexpr (sizeof...(I) > 1) {\n\t\t\t\ttbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttbl.set(std::get<I>(std::move(key))..., std::forward<T>(value));\n\t\t\t}\n\t\t}\n\n\tpublic:\n\t\tTable tbl;\n\t\tkey_type key;\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy(Table table, T&& k)\n\t\t: tbl(table), key(std::forward<T>(k)) {\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy& set(T&& item) & {\n\t\t\tusing idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;\n\t\t\ttuple_set(idx_seq(), std::forward<T>(item));\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy&& set(T&& item) && {\n\t\t\tusing idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;\n\t\t\tstd::move(*this).tuple_set(idx_seq(), std::forward<T>(item));\n\t\t\treturn std::move(*this);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy& operator=(T&& other) & {\n\t\t\treturn set(std::forward<T>(other));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy&& operator=(T&& other) && {\n\t\t\treturn std::move(*this).set(std::forward<T>(other));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy& operator=(std::initializer_list<T> other) & {\n\t\t\treturn set(std::move(other));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tusertype_proxy&& operator=(std::initializer_list<T> other) && {\n\t\t\treturn std::move(*this).set(std::move(other));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get() const& {\n\t\t\tusing idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;\n\t\t\treturn tuple_get<T>(idx_seq());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get() && {\n\t\t\tusing idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;\n\t\t\treturn std::move(*this).template tuple_get<T>(idx_seq());\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tdecltype(auto) operator[](K&& k) const& {\n\t\t\tauto keys = meta::tuplefy(key, std::forward<K>(k));\n\t\t\treturn usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tdecltype(auto) operator[](K&& k) & {\n\t\t\tauto keys = meta::tuplefy(key, std::forward<K>(k));\n\t\t\treturn usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tdecltype(auto) operator[](K&& k) && {\n\t\t\tauto keys = meta::tuplefy(std::move(key), std::forward<K>(k));\n\t\t\treturn usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args) {\n#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000\n\t\t\t// MSVC is ass sometimes\n\t\t\treturn get<function>().call<Ret...>(std::forward<Args>(args)...);\n#else\n\t\t\treturn get<function>().template call<Ret...>(std::forward<Args>(args)...);\n#endif\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tdecltype(auto) operator()(Args&&... args) {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\n\t\tbool valid() const {\n\t\t\tauto pp = stack::push_pop(tbl);\n\t\t\tauto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));\n\t\t\tlua_pop(lua_state(), p.levels);\n\t\t\treturn p;\n\t\t}\n\n\t\tint push() const noexcept {\n\t\t\treturn push(this->lua_state());\n\t\t}\n\n\t\tint push(lua_State* L) const noexcept {\n\t\t\treturn get<reference>().push(L);\n\t\t}\n\n\t\ttype get_type() const {\n\t\t\ttype t = type::none;\n\t\t\tauto pp = stack::push_pop(tbl);\n\t\t\tauto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));\n\t\t\tif (p) {\n\t\t\t\tt = type_of(lua_state(), -1);\n\t\t\t}\n\t\t\tlua_pop(lua_state(), p.levels);\n\t\t\treturn t;\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\treturn tbl.lua_state();\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/usertype_proxy.hpp\n\n// beginning of sol/metatable.hpp\n\n// beginning of sol/table_core.hpp\n\n// beginning of sol/table_proxy.hpp\n\nnamespace sol {\n\n\ttemplate <typename Table, typename Key>\n\tstruct table_proxy : public proxy_base<table_proxy<Table, Key>> {\n\tprivate:\n\t\tusing key_type = detail::proxy_key_t<Key>;\n\n\t\ttemplate <typename T, std::size_t... I>\n\t\tdecltype(auto) tuple_get(std::index_sequence<I...>) const& {\n\t\t\treturn tbl.template traverse_get<T>(std::get<I>(key)...);\n\t\t}\n\n\t\ttemplate <typename T, std::size_t... I>\n\t\tdecltype(auto) tuple_get(std::index_sequence<I...>) && {\n\t\t\treturn tbl.template traverse_get<T>(std::get<I>(std::move(key))...);\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename T>\n\t\tvoid tuple_set(std::index_sequence<I...>, T&& value) & {\n\t\t\ttbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename T>\n\t\tvoid tuple_set(std::index_sequence<I...>, T&& value) && {\n\t\t\ttbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));\n\t\t}\n\n\t\tauto setup_table(std::true_type) {\n\t\t\tauto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index());\n\t\t\tlua_pop(lua_state(), p.levels);\n\t\t\treturn p;\n\t\t}\n\n\t\tbool is_valid(std::false_type) {\n\t\t\tauto pp = stack::push_pop(tbl);\n\t\t\tauto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, lua_gettop(lua_state()));\n\t\t\tlua_pop(lua_state(), p.levels);\n\t\t\treturn p;\n\t\t}\n\n\tpublic:\n\t\tTable tbl;\n\t\tkey_type key;\n\n\t\ttemplate <typename T>\n\t\ttable_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) {\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy& set(T&& item) & {\n\t\t\ttuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy&& set(T&& item) && {\n\t\t\ttuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));\n\t\t\treturn std::move(*this);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\ttable_proxy& set_function(Args&&... args) & {\n\t\t\ttbl.set_function(key, std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\ttable_proxy&& set_function(Args&&... args) && {\n\t\t\ttbl.set_function(std::move(key), std::forward<Args>(args)...);\n\t\t\treturn std::move(*this);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy& operator=(T&& other) & {\n\t\t\tusing Tu = meta::unwrap_unqualified_t<T>;\n\t\t\tif constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {\n\t\t\t\treturn set_function(std::forward<T>(other));\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn set(std::forward<T>(other));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy&& operator=(T&& other) && {\n\t\t\tusing Tu = meta::unwrap_unqualified_t<T>;\n\t\t\tif constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {\n\t\t\t\treturn std::move(*this).set_function(std::forward<T>(other));\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn std::move(*this).set(std::forward<T>(other));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy& operator=(std::initializer_list<T> other) & {\n\t\t\treturn set(std::move(other));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy&& operator=(std::initializer_list<T> other) && {\n\t\t\treturn std::move(*this).set(std::move(other));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get() const& {\n\t\t\tusing idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;\n\t\t\treturn tuple_get<T>(idx_seq());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get() && {\n\t\t\tusing idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;\n\t\t\treturn std::move(*this).template tuple_get<T>(idx_seq());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_or(T&& otherwise) const {\n\t\t\ttypedef decltype(get<T>()) U;\n\t\t\toptional<U> option = get<optional<U>>();\n\t\t\tif (option) {\n\t\t\t\treturn static_cast<U>(option.value());\n\t\t\t}\n\t\t\treturn static_cast<U>(std::forward<T>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T, typename D>\n\t\tdecltype(auto) get_or(D&& otherwise) const {\n\t\t\toptional<T> option = get<optional<T>>();\n\t\t\tif (option) {\n\t\t\t\treturn static_cast<T>(option.value());\n\t\t\t}\n\t\t\treturn static_cast<T>(std::forward<D>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get_or_create() {\n\t\t\treturn get_or_create<T>(new_table());\n\t\t}\n\n\t\ttemplate <typename T, typename Otherwise>\n\t\tdecltype(auto) get_or_create(Otherwise&& other) {\n\t\t\tif (!this->valid()) {\n\t\t\t\tthis->set(std::forward<Otherwise>(other));\n\t\t\t}\n\t\t\treturn get<T>();\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tdecltype(auto) operator[](K&& k) const& {\n\t\t\tauto keys = meta::tuplefy(key, std::forward<K>(k));\n\t\t\treturn table_proxy<Table, decltype(keys)>(tbl, std::move(keys));\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tdecltype(auto) operator[](K&& k) & {\n\t\t\tauto keys = meta::tuplefy(key, std::forward<K>(k));\n\t\t\treturn table_proxy<Table, decltype(keys)>(tbl, std::move(keys));\n\t\t}\n\n\t\ttemplate <typename K>\n\t\tdecltype(auto) operator[](K&& k) && {\n\t\t\tauto keys = meta::tuplefy(std::move(key), std::forward<K>(k));\n\t\t\treturn table_proxy<Table, decltype(keys)>(tbl, std::move(keys));\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args) {\n\t\t\tlua_State* L = this->lua_state();\n\t\t\tpush(L);\n\t\t\tint idx = lua_gettop(L);\n\t\t\tstack_aligned_function func(L, idx);\n\t\t\treturn func.call<Ret...>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tdecltype(auto) operator()(Args&&... args) {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\n\t\tbool valid() const {\n\t\t\tauto pp = stack::push_pop(tbl);\n\t\t\tauto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));\n\t\t\tlua_pop(lua_state(), p.levels);\n\t\t\treturn p;\n\t\t}\n\n\t\tint push() const noexcept {\n\t\t\treturn push(this->lua_state());\n\t\t}\n\n\t\tint push(lua_State* L) const noexcept {\n\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Table>, global_table> || is_stack_table_v<meta::unqualified_t<Table>>) {\n\t\t\t\tauto pp = stack::push_pop<true>(tbl);\n\t\t\t\tint tableindex = pp.index_of(tbl);\n\t\t\t\tint top_index = lua_gettop(L);\n\t\t\t\tstack::get_field<true>(lua_state(), key, tableindex);\n\t\t\t\tlua_replace(L, top_index + 1);\n\t\t\t\tlua_settop(L, top_index + 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto pp = stack::push_pop<false>(tbl);\n\t\t\t\tint tableindex = pp.index_of(tbl);\n\t\t\t\tint aftertableindex = lua_gettop(L);\n\t\t\t\tstack::get_field<false>(lua_state(), key, tableindex);\n\t\t\t\tlua_replace(L, tableindex);\n\t\t\t\tlua_settop(L, aftertableindex + 1);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\ttype get_type() const {\n\t\t\ttype t = type::none;\n\t\t\tauto pp = stack::push_pop(tbl);\n\t\t\tauto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));\n\t\t\tif (p) {\n\t\t\t\tt = type_of(lua_state(), -1);\n\t\t\t}\n\t\t\tlua_pop(lua_state(), p.levels);\n\t\t\treturn t;\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\treturn tbl.lua_state();\n\t\t}\n\n\t\ttable_proxy& force() {\n\t\t\tif (!this->valid()) {\n\t\t\t\tthis->set(new_table());\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\t};\n\n\ttemplate <typename Table, typename Key, typename T>\n\tinline bool operator==(T&& left, const table_proxy<Table, Key>& right) {\n\t\tusing G = decltype(stack::get<T>(nullptr, 0));\n\t\treturn right.template get<optional<G>>() == left;\n\t}\n\n\ttemplate <typename Table, typename Key, typename T>\n\tinline bool operator==(const table_proxy<Table, Key>& right, T&& left) {\n\t\tusing G = decltype(stack::get<T>(nullptr, 0));\n\t\treturn right.template get<optional<G>>() == left;\n\t}\n\n\ttemplate <typename Table, typename Key, typename T>\n\tinline bool operator!=(T&& left, const table_proxy<Table, Key>& right) {\n\t\tusing G = decltype(stack::get<T>(nullptr, 0));\n\t\treturn right.template get<optional<G>>() != left;\n\t}\n\n\ttemplate <typename Table, typename Key, typename T>\n\tinline bool operator!=(const table_proxy<Table, Key>& right, T&& left) {\n\t\tusing G = decltype(stack::get<T>(nullptr, 0));\n\t\treturn right.template get<optional<G>>() != left;\n\t}\n\n\ttemplate <typename Table, typename Key>\n\tinline bool operator==(lua_nil_t, const table_proxy<Table, Key>& right) {\n\t\treturn !right.valid();\n\t}\n\n\ttemplate <typename Table, typename Key>\n\tinline bool operator==(const table_proxy<Table, Key>& right, lua_nil_t) {\n\t\treturn !right.valid();\n\t}\n\n\ttemplate <typename Table, typename Key>\n\tinline bool operator!=(lua_nil_t, const table_proxy<Table, Key>& right) {\n\t\treturn right.valid();\n\t}\n\n\ttemplate <typename Table, typename Key>\n\tinline bool operator!=(const table_proxy<Table, Key>& right, lua_nil_t) {\n\t\treturn right.valid();\n\t}\n\n\ttemplate <bool b>\n\ttemplate <typename Super>\n\tbasic_reference<b>& basic_reference<b>::operator=(proxy_base<Super>&& r) {\n\t\tbasic_reference<b> v = r;\n\t\tthis->operator=(std::move(v));\n\t\treturn *this;\n\t}\n\n\ttemplate <bool b>\n\ttemplate <typename Super>\n\tbasic_reference<b>& basic_reference<b>::operator=(const proxy_base<Super>& r) {\n\t\tbasic_reference<b> v = r;\n\t\tthis->operator=(std::move(v));\n\t\treturn *this;\n\t}\n\n\tnamespace stack {\n\t\ttemplate <typename Table, typename Key>\n\t\tstruct unqualified_pusher<table_proxy<Table, Key>> {\n\t\t\tstatic int push(lua_State* L, const table_proxy<Table, Key>& p) {\n\t\t\t\treturn p.push(L);\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/table_proxy.hpp\n\n// beginning of sol/table_iterator.hpp\n\n#include <iterator>\n\nnamespace sol {\n\n\ttemplate <typename reference_type>\n\tclass basic_table_iterator {\n\tpublic:\n\t\ttypedef object key_type;\n\t\ttypedef object mapped_type;\n\t\ttypedef std::pair<object, object> value_type;\n\t\ttypedef std::input_iterator_tag iterator_category;\n\t\ttypedef std::ptrdiff_t difference_type;\n\t\ttypedef value_type* pointer;\n\t\ttypedef value_type& reference;\n\t\ttypedef const value_type& const_reference;\n\n\tprivate:\n\t\tstd::pair<object, object> kvp;\n\t\treference_type ref;\n\t\tint tableidx = 0;\n\t\tint keyidx = 0;\n\t\tstd::ptrdiff_t idx = 0;\n\n\tpublic:\n\t\tbasic_table_iterator() : keyidx(-1), idx(-1) {\n\t\t}\n\n\t\tbasic_table_iterator(reference_type x) : ref(std::move(x)) {\n\t\t\tref.push();\n\t\t\ttableidx = lua_gettop(ref.lua_state());\n\t\t\tstack::push(ref.lua_state(), lua_nil);\n\t\t\tthis->operator++();\n\t\t\tif (idx == -1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t--idx;\n\t\t}\n\n\t\tbasic_table_iterator& operator++() {\n\t\t\tif (idx == -1)\n\t\t\t\treturn *this;\n\n\t\t\tif (lua_next(ref.lua_state(), tableidx) == 0) {\n\t\t\t\tidx = -1;\n\t\t\t\tkeyidx = -1;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t++idx;\n\t\t\tkvp.first = object(ref.lua_state(), -2);\n\t\t\tkvp.second = object(ref.lua_state(), -1);\n\t\t\tlua_pop(ref.lua_state(), 1);\n\t\t\t// leave key on the stack\n\t\t\tkeyidx = lua_gettop(ref.lua_state());\n\t\t\treturn *this;\n\t\t}\n\n\t\tbasic_table_iterator operator++(int) {\n\t\t\tauto saved = *this;\n\t\t\tthis->operator++();\n\t\t\treturn saved;\n\t\t}\n\n\t\treference operator*() {\n\t\t\treturn kvp;\n\t\t}\n\n\t\tconst_reference operator*() const {\n\t\t\treturn kvp;\n\t\t}\n\n\t\tbool operator==(const basic_table_iterator& right) const {\n\t\t\treturn idx == right.idx;\n\t\t}\n\n\t\tbool operator!=(const basic_table_iterator& right) const {\n\t\t\treturn idx != right.idx;\n\t\t}\n\n\t\t~basic_table_iterator() {\n\t\t\tif (keyidx != -1) {\n\t\t\t\tstack::remove(ref.lua_state(), keyidx, 1);\n\t\t\t}\n\t\t\tif (ref.lua_state() != nullptr && ref.valid()) {\n\t\t\t\tstack::remove(ref.lua_state(), tableidx, 1);\n\t\t\t}\n\t\t}\n\t};\n\n} // namespace sol\n\n// end of sol/table_iterator.hpp\n\nnamespace sol {\n\tnamespace detail {\n\t\ttemplate <std::size_t n>\n\t\tstruct clean {\n\t\t\tlua_State* L;\n\t\t\tclean(lua_State* luastate) : L(luastate) {\n\t\t\t}\n\t\t\t~clean() {\n\t\t\t\tlua_pop(L, static_cast<int>(n));\n\t\t\t}\n\t\t};\n\n\t\tstruct ref_clean {\n\t\t\tlua_State* L;\n\t\t\tint& n;\n\t\t\tref_clean(lua_State* luastate, int& n) : L(luastate), n(n) {\n\t\t\t}\n\t\t\t~ref_clean() {\n\t\t\t\tlua_pop(L, static_cast<int>(n));\n\t\t\t}\n\t\t};\n\n\t\tinline int fail_on_newindex(lua_State* L) {\n\t\t\treturn luaL_error(L, \"sol: cannot modify the elements of an enumeration table\");\n\t\t}\n\n\t} // namespace detail\n\n\ttemplate <bool top_level, typename ref_t>\n\tclass basic_table_core : public basic_object<ref_t> {\n\tprivate:\n\t\tusing base_t = basic_object<ref_t>;\n\n\t\tfriend class state;\n\t\tfriend class state_view;\n\t\ttemplate <typename, typename>\n\t\tfriend class basic_usertype;\n\t\ttemplate <typename>\n\t\tfriend class basic_metatable;\n\n\t\ttemplate <bool raw, typename... Ret, typename... Keys>\n\t\tdecltype(auto) tuple_get(int table_index, Keys&&... keys) const {\n\t\t\tif constexpr (sizeof...(Ret) < 2) {\n\t\t\t\treturn traverse_get_single_maybe_tuple<raw, Ret...>(table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tusing multi_ret = decltype(stack::pop<std::tuple<Ret...>>(nullptr));\n\t\t\t\treturn multi_ret(traverse_get_single_maybe_tuple<raw, Ret>(table_index, std::forward<Keys>(keys))...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool raw, typename Ret, size_t... I, typename Key>\n\t\tdecltype(auto) traverse_get_single_tuple(int table_index, std::index_sequence<I...>, Key&& key) const {\n\t\t\treturn traverse_get_single<raw, Ret>(table_index, std::get<I>(std::forward<Key>(key))...);\n\t\t}\n\n\t\ttemplate <bool raw, typename Ret, typename Key>\n\t\tdecltype(auto) traverse_get_single_maybe_tuple(int table_index, Key&& key) const {\n\t\t\tif constexpr (meta::is_tuple_v<meta::unqualified_t<Key>>) {\n\t\t\t\treturn traverse_get_single_tuple<raw, Ret>(\n\t\t\t\t     table_index, std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<Key>>>(), std::forward<Key>(key));\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn traverse_get_single<raw, Ret>(table_index, std::forward<Key>(key));\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool raw, typename Ret, typename... Keys>\n\t\tdecltype(auto) traverse_get_single(int table_index, Keys&&... keys) const {\n\t\t\tconstexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);\n\t\t\tif constexpr (meta::is_optional_v<meta::unqualified_t<Ret>>) {\n\t\t\t\tint popcount = 0;\n\t\t\t\tdetail::ref_clean c(base_t::lua_state(), popcount);\n\t\t\t\treturn traverse_get_deep_optional<global, raw, detail::insert_mode::none, Ret>(popcount, table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdetail::clean<sizeof...(Keys) - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>> c(base_t::lua_state());\n\t\t\t\treturn traverse_get_deep<global, raw, detail::insert_mode::none, Ret>(table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool raw, typename Pairs, std::size_t... I>\n\t\tvoid tuple_set(std::index_sequence<I...>, Pairs&& pairs) {\n\t\t\tconstexpr static bool global = top_level\n\t\t\t     && (meta::count_even_for_pack_v<meta::is_c_str, meta::unqualified_t<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>...> > 0);\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tlua_State* L = base_t::lua_state();\n\t\t\t(void)table_index;\n\t\t\t(void)L;\n\t\t\tvoid(detail::swallow { (stack::set_field<(top_level), raw>(\n\t\t\t                             L, std::get<I * 2>(std::forward<Pairs>(pairs)), std::get<I * 2 + 1>(std::forward<Pairs>(pairs)), table_index),\n\t\t\t     0)... });\n\t\t}\n\n\t\ttemplate <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys>\n\t\tdecltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const {\n\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) {\n\t\t\t\t(void)key;\n\t\t\t\treturn traverse_get_deep<false, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil), T>(\n\t\t\t\t     table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlua_State* L = base_t::lua_state();\n\t\t\t\tstack::get_field<global, raw>(L, std::forward<Key>(key), table_index);\n\t\t\t\tif constexpr (sizeof...(Keys) > 0) {\n\t\t\t\t\tif constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {\n\t\t\t\t\t\ttype t = type_of(L, -1);\n\t\t\t\t\t\tif (t == type::lua_nil || t == type::none) {\n\t\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\t\tstack::push(L, new_table(0, 0));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn traverse_get_deep<false, raw, mode, T>(lua_gettop(L), std::forward<Keys>(keys)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {\n\t\t\t\t\t\ttype t = type_of(L, -1);\n\t\t\t\t\t\tif ((t == type::lua_nil || t == type::none) && (is_table_like_v<T>)) {\n\t\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\t\tstack::push(L, new_table(0, 0));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn stack::get<T>(L);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys>\n\t\tdecltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const {\n\t\t\tif constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) {\n\t\t\t\tconstexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil);\n\t\t\t\t(void)key;\n\t\t\t\treturn traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<meta::unqualified_t<Key>, update_if_empty_t>) {\n\t\t\t\tconstexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty);\n\t\t\t\t(void)key;\n\t\t\t\treturn traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<meta::unqualified_t<Key>, override_value_t>) {\n\t\t\t\tconstexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value);\n\t\t\t\t(void)key;\n\t\t\t\treturn traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif constexpr (sizeof...(Keys) > 0) {\n\t\t\t\t\tlua_State* L = base_t::lua_state();\n\t\t\t\t\tauto p = stack::probe_get_field<global, raw>(L, std::forward<Key>(key), table_index);\n\t\t\t\t\tpopcount += p.levels;\n\t\t\t\t\tif (!p.success) {\n\t\t\t\t\t\tif constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {\n\t\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\t\tconstexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;\n\t\t\t\t\t\t\tstack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));\n\t\t\t\t\t\t\tstack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn T(nullopt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn traverse_get_deep_optional<false, raw, mode, T>(popcount, lua_gettop(L), std::forward<Keys>(keys)...);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tusing R = decltype(stack::get<T>(nullptr));\n\t\t\t\t\tusing value_type = typename meta::unqualified_t<R>::value_type;\n\t\t\t\t\tlua_State* L = base_t::lua_state();\n\t\t\t\t\tauto p = stack::probe_get_field<global, raw, value_type>(L, key, table_index);\n\t\t\t\t\tpopcount += p.levels;\n\t\t\t\t\tif (!p.success) {\n\t\t\t\t\t\tif constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {\n\t\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\t\tstack::push(L, new_table(0, 0));\n\t\t\t\t\t\t\tstack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);\n\t\t\t\t\t\t\tif (stack::check<value_type>(L, lua_gettop(L), no_panic)) {\n\t\t\t\t\t\t\t\treturn stack::get<T>(L);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn R(nullopt);\n\t\t\t\t\t}\n\t\t\t\t\treturn stack::get<T>(L);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <bool global, bool raw, detail::insert_mode mode, typename Key, typename... Keys>\n\t\tvoid traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const {\n\t\t\tusing KeyU = meta::unqualified_t<Key>;\n\t\t\tif constexpr (std::is_same_v<KeyU, update_if_empty_t>) {\n\t\t\t\t(void)key;\n\t\t\t\ttraverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty)>(\n\t\t\t\t     table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<KeyU, create_if_nil_t>) {\n\t\t\t\t(void)key;\n\t\t\t\ttraverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil)>(\n\t\t\t\t     table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<KeyU, override_value_t>) {\n\t\t\t\t(void)key;\n\t\t\t\ttraverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value)>(\n\t\t\t\t     table_index, std::forward<Keys>(keys)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlua_State* L = base_t::lua_state();\n\t\t\t\tif constexpr (sizeof...(Keys) == 1) {\n\t\t\t\t\tif constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {\n\t\t\t\t\t\tauto p = stack::probe_get_field<global, raw>(L, key, table_index);\n\t\t\t\t\t\tlua_pop(L, p.levels);\n\t\t\t\t\t\tif (!p.success) {\n\t\t\t\t\t\t\tstack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tstack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif constexpr (mode != detail::insert_mode::none) {\n\t\t\t\t\t\tstack::get_field<global, raw>(L, key, table_index);\n\t\t\t\t\t\ttype vt = type_of(L, -1);\n\t\t\t\t\t\tif constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty\n\t\t\t\t\t\t     || (mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {\n\t\t\t\t\t\t\tif (vt == type::lua_nil || vt == type::none) {\n\t\t\t\t\t\t\t\tconstexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;\n\t\t\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\t\t\tstack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));\n\t\t\t\t\t\t\t\tstack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif (vt != type::table) {\n\t\t\t\t\t\t\t\tconstexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;\n\t\t\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\t\t\tstack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));\n\t\t\t\t\t\t\t\tstack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tstack::get_field<global, raw>(L, std::forward<Key>(key), table_index);\n\t\t\t\t\t}\n\t\t\t\t\ttraverse_set_deep<false, raw, mode>(lua_gettop(L), std::forward<Keys>(keys)...);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbasic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) {\n\t\t}\n\n\tprotected:\n\t\tbasic_table_core(detail::no_safety_tag, lua_nil_t n) : base_t(n) {\n\t\t}\n\t\tbasic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {\n\t\t}\n\t\tbasic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_table_core(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) {\n\t\t}\n\n\tpublic:\n\t\tusing iterator = basic_table_iterator<ref_t>;\n\t\tusing const_iterator = iterator;\n\n\t\tusing base_t::lua_state;\n\n\t\tbasic_table_core() noexcept = default;\n\t\tbasic_table_core(const basic_table_core&) = default;\n\t\tbasic_table_core(basic_table_core&&) = default;\n\t\tbasic_table_core& operator=(const basic_table_core&) = default;\n\t\tbasic_table_core& operator=(basic_table_core&&) = default;\n\t\tbasic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_table_core(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_table_core>(lua_state(), table_index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_table_core(lua_State* L, const new_table& nt) : base_t(L, -stack::push(L, nt)) {\n\t\t\tif (!is_stack_based<meta::unqualified_t<ref_t>>::value) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t}\n\t\t}\n\t\tbasic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_table_core>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_table_core>(lua_state(), table_index, handler);\n#endif // Safety\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_table<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tint table_index = pp.index_of(*this);\n\t\t\t\tconstructor_handler handler {};\n\t\t\t\tstack::check<basic_table_core>(lua_state(), table_index, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_table_core(lua_nil_t r) noexcept : basic_table_core(detail::no_safety, r) {\n\t\t}\n\n\t\titerator begin() const {\n\t\t\tif (this->get_type() == type::table) {\n\t\t\t\treturn iterator(*this);\n\t\t\t}\n\t\t\treturn iterator();\n\t\t}\n\n\t\titerator end() const {\n\t\t\treturn iterator();\n\t\t}\n\n\t\tconst_iterator cbegin() const {\n\t\t\treturn begin();\n\t\t}\n\n\t\tconst_iterator cend() const {\n\t\t\treturn end();\n\t\t}\n\n\t\tvoid clear() {\n\t\t\tauto pp = stack::push_pop<false>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tstack::clear(lua_state(), table_index);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Keys>\n\t\tdecltype(auto) get(Keys&&... keys) const {\n\t\t\tstatic_assert(sizeof...(Keys) == sizeof...(Ret), \"number of keys and number of return types do not match\");\n\t\t\tconstexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\treturn tuple_get<false, Ret...>(table_index, std::forward<Keys>(keys)...);\n\t\t}\n\n\t\ttemplate <typename T, typename Key>\n\t\tdecltype(auto) get_or(Key&& key, T&& otherwise) const {\n\t\t\ttypedef decltype(get<T>(\"\")) U;\n\t\t\toptional<U> option = get<optional<U>>(std::forward<Key>(key));\n\t\t\tif (option) {\n\t\t\t\treturn static_cast<U>(option.value());\n\t\t\t}\n\t\t\treturn static_cast<U>(std::forward<T>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T, typename Key, typename D>\n\t\tdecltype(auto) get_or(Key&& key, D&& otherwise) const {\n\t\t\toptional<T> option = get<optional<T>>(std::forward<Key>(key));\n\t\t\tif (option) {\n\t\t\t\treturn static_cast<T>(option.value());\n\t\t\t}\n\t\t\treturn static_cast<T>(std::forward<D>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T, typename... Keys>\n\t\tdecltype(auto) traverse_get(Keys&&... keys) const {\n\t\t\tstatic_assert(sizeof...(Keys) > 0, \"must pass at least 1 key to get\");\n\t\t\tconstexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\treturn traverse_get_single<false, T>(table_index, std::forward<Keys>(keys)...);\n\t\t}\n\n\t\ttemplate <typename... Keys>\n\t\tbasic_table_core& traverse_set(Keys&&... keys) {\n\t\t\tstatic_assert(sizeof...(Keys) > 1, \"must pass at least 1 key and 1 value to set\");\n\t\t\tconstexpr static bool global\n\t\t\t     = top_level && (meta::count_when_for_to_pack_v<detail::is_not_insert_mode, 1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tlua_State* L = base_t::lua_state();\n\t\t\tauto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>));\n\t\t\ttraverse_set_deep<top_level, false, detail::insert_mode::none>(table_index, std::forward<Keys>(keys)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tbasic_table_core& set(Args&&... args) {\n\t\t\tif constexpr (sizeof...(Args) == 2) {\n\t\t\t\ttraverse_set(std::forward<Args>(args)...);\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttuple_set<false>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Keys>\n\t\tdecltype(auto) raw_get(Keys&&... keys) const {\n\t\t\tstatic_assert(sizeof...(Keys) == sizeof...(Ret), \"number of keys and number of return types do not match\");\n\t\t\tconstexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\treturn tuple_get<true, Ret...>(table_index, std::forward<Keys>(keys)...);\n\t\t}\n\n\t\ttemplate <typename T, typename Key>\n\t\tdecltype(auto) raw_get_or(Key&& key, T&& otherwise) const {\n\t\t\ttypedef decltype(raw_get<T>(\"\")) U;\n\t\t\toptional<U> option = raw_get<optional<U>>(std::forward<Key>(key));\n\t\t\tif (option) {\n\t\t\t\treturn static_cast<U>(option.value());\n\t\t\t}\n\t\t\treturn static_cast<U>(std::forward<T>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T, typename Key, typename D>\n\t\tdecltype(auto) raw_get_or(Key&& key, D&& otherwise) const {\n\t\t\toptional<T> option = raw_get<optional<T>>(std::forward<Key>(key));\n\t\t\tif (option) {\n\t\t\t\treturn static_cast<T>(option.value());\n\t\t\t}\n\t\t\treturn static_cast<T>(std::forward<D>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T, typename... Keys>\n\t\tdecltype(auto) traverse_raw_get(Keys&&... keys) const {\n\t\t\tconstexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\treturn traverse_get_single<true, T>(table_index, std::forward<Keys>(keys)...);\n\t\t}\n\n\t\ttemplate <typename... Keys>\n\t\tbasic_table_core& traverse_raw_set(Keys&&... keys) {\n\t\t\tconstexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);\n\t\t\tauto pp = stack::push_pop<global>(*this);\n\t\t\tlua_State* L = base_t::lua_state();\n\t\t\tauto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>));\n\t\t\ttraverse_set_deep<top_level, true, false>(std::forward<Keys>(keys)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tbasic_table_core& raw_set(Args&&... args) {\n\t\t\ttuple_set<true>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename Class, typename Key>\n\t\tusertype<Class> new_usertype(Key&& key);\n\n\t\ttemplate <typename Class, typename Key>\n\t\tusertype<Class> new_usertype(Key&& key, automagic_enrollments enrollment);\n\n\t\ttemplate <typename Class, typename Key, typename Arg, typename... Args,\n\t\t     typename = std::enable_if_t<!std::is_same_v<meta::unqualified_t<Arg>, automagic_enrollments>>>\n\t\tusertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args);\n\n\t\ttemplate <bool read_only = true, typename... Args>\n\t\ttable new_enum(const string_view& name, Args&&... args) {\n\t\t\ttable target = create_with(std::forward<Args>(args)...);\n\t\t\tif (read_only) {\n\t\t\t\ttable x = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target);\n\t\t\t\ttable shim = create_named(name, metatable_key, x);\n\t\t\t\treturn shim;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tset(name, target);\n\t\t\t\treturn target;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename T, bool read_only = true>\n\t\ttable new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) {\n\t\t\ttable target = create(static_cast<int>(items.size()), static_cast<int>(0));\n\t\t\tfor (const auto& kvp : items) {\n\t\t\t\ttarget.set(kvp.first, kvp.second);\n\t\t\t}\n\t\t\tif constexpr (read_only) {\n\t\t\t\ttable x = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target);\n\t\t\t\ttable shim = create_named(name, metatable_key, x);\n\t\t\t\treturn shim;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tset(name, target);\n\t\t\t\treturn target;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Key = object, typename Value = object, typename Fx>\n\t\tvoid for_each(Fx&& fx) const {\n\t\t\tlua_State* L = base_t::lua_state();\n\t\t\tif constexpr (std::is_invocable_v<Fx, Key, Value>) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tint table_index = pp.index_of(*this);\n\t\t\t\tstack::push(L, lua_nil);\n\t\t\t\twhile (lua_next(L, table_index)) {\n\t\t\t\t\tKey key(L, -2);\n\t\t\t\t\tValue value(L, -1);\n\t\t\t\t\tauto pn = stack::pop_n(L, 1);\n\t\t\t\t\tfx(key, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tint table_index = pp.index_of(*this);\n\t\t\t\tstack::push(L, lua_nil);\n\t\t\t\twhile (lua_next(L, table_index)) {\n\t\t\t\t\tKey key(L, -2);\n\t\t\t\t\tValue value(L, -1);\n\t\t\t\t\tauto pn = stack::pop_n(L, 1);\n\t\t\t\t\tstd::pair<Key&, Value&> keyvalue(key, value);\n\t\t\t\t\tfx(keyvalue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t size() const {\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tlua_State* L = base_t::lua_state();\n\t\t\tlua_len(L, table_index);\n\t\t\treturn stack::pop<size_t>(L);\n\t\t}\n\n\t\tbool empty() const {\n\t\t\treturn cbegin() == cend();\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tauto operator[](T&& key) & {\n\t\t\treturn table_proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tauto operator[](T&& key) const& {\n\t\t\treturn table_proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tauto operator[](T&& key) && {\n\t\t\treturn table_proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key));\n\t\t}\n\n\t\ttemplate <typename Sig, typename Key, typename... Args>\n\t\tbasic_table_core& set_function(Key&& key, Args&&... args) {\n\t\t\tset_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename Key, typename... Args>\n\t\tbasic_table_core& set_function(Key&& key, Args&&... args) {\n\t\t\tset_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tbasic_table_core& add(Args&&... args) {\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tint table_index = pp.index_of(*this);\n\t\t\tlua_State* L = base_t::lua_state();\n\t\t\t(void)detail::swallow { 0, (stack::set_ref(L, std::forward<Args>(args), table_index), 0)... };\n\t\t\treturn *this;\n\t\t}\n\n\tprivate:\n\t\ttemplate <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>>\n\t\tvoid set_fx(types<R(Args...)>, Key&& key, Fx&& fx) {\n\t\t\tset_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx));\n\t\t}\n\n\t\ttemplate <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler>\n\t\tvoid set_fx(types<>, Key&& key, Fx&& fx) {\n\t\t\tset(std::forward<Key>(key), std::forward<Fx>(fx));\n\t\t}\n\n\t\ttemplate <typename Fx, typename Key, typename... Args,\n\t\t     meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler>\n\t\tvoid set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) {\n\t\t\tset(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...));\n\t\t}\n\n\t\ttemplate <typename... Sig, typename... Args, typename Key>\n\t\tvoid set_resolved_function(Key&& key, Args&&... args) {\n\t\t\tset(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...));\n\t\t}\n\n\tpublic:\n\t\tstatic inline table create(lua_State* L, int narr = 0, int nrec = 0) {\n\t\t\tlua_createtable(L, narr, nrec);\n\t\t\ttable result(L);\n\t\t\tlua_pop(L, 1);\n\t\t\treturn result;\n\t\t}\n\n\t\ttemplate <typename Key, typename Value, typename... Args>\n\t\tstatic inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {\n\t\t\tlua_createtable(L, narr, nrec);\n\t\t\ttable result(L);\n\t\t\tresult.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);\n\t\t\tlua_pop(L, 1);\n\t\t\treturn result;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tstatic inline table create_with(lua_State* L, Args&&... args) {\n\t\t\tstatic_assert(sizeof...(Args) % 2 == 0, \"You must have an even number of arguments for a key, value ... list.\");\n\t\t\tconstexpr int narr = static_cast<int>(meta::count_odd_for_pack_v<std::is_integral, Args...>);\n\t\t\treturn create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttable create(int narr = 0, int nrec = 0) {\n\t\t\treturn create(base_t::lua_state(), narr, nrec);\n\t\t}\n\n\t\ttemplate <typename Key, typename Value, typename... Args>\n\t\ttable create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) {\n\t\t\treturn create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename Name>\n\t\ttable create(Name&& name, int narr = 0, int nrec = 0) {\n\t\t\ttable x = create(base_t::lua_state(), narr, nrec);\n\t\t\tthis->set(std::forward<Name>(name), x);\n\t\t\treturn x;\n\t\t}\n\n\t\ttemplate <typename Name, typename Key, typename Value, typename... Args>\n\t\ttable create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {\n\t\t\ttable x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);\n\t\t\tthis->set(std::forward<Name>(name), x);\n\t\t\treturn x;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\ttable create_with(Args&&... args) {\n\t\t\treturn create_with(base_t::lua_state(), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename Name, typename... Args>\n\t\ttable create_named(Name&& name, Args&&... args) {\n\t\t\tstatic const int narr = static_cast<int>(meta::count_even_for_pack_v<std::is_integral, Args...>);\n\t\t\treturn create(std::forward<Name>(name), narr, (sizeof...(Args) / 2) - narr, std::forward<Args>(args)...);\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/table_core.hpp\n\nnamespace sol {\n\n\ttemplate <typename base_type>\n\tclass basic_metatable : public basic_table<base_type> {\n\t\ttypedef basic_table<base_type> base_t;\n\t\tfriend class state;\n\t\tfriend class state_view;\n\n\tprotected:\n\t\tbasic_metatable(detail::no_safety_tag, lua_nil_t n) : base_t(n) {\n\t\t}\n\t\tbasic_metatable(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {\n\t\t}\n\t\tbasic_metatable(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_metatable(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_metatable(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) {\n\t\t}\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_metatable() noexcept = default;\n\t\tbasic_metatable(const basic_metatable&) = default;\n\t\tbasic_metatable(basic_metatable&&) = default;\n\t\tbasic_metatable& operator=(const basic_metatable&) = default;\n\t\tbasic_metatable& operator=(basic_metatable&&) = default;\n\t\tbasic_metatable(const stack_reference& r) : basic_metatable(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_metatable(stack_reference&& r) : basic_metatable(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_metatable(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_metatable>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_metatable(lua_State* L, int index = -1) : basic_metatable(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_metatable>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_metatable(lua_State* L, ref_index index) : basic_metatable(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_metatable>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_metatable(T&& r) noexcept : basic_metatable(detail::no_safety, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_table<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler{};\n\t\t\t\tstack::check<basic_metatable>(base_t::lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_metatable(lua_nil_t r) noexcept : basic_metatable(detail::no_safety, r) {\n\t\t}\n\n\t\ttemplate <typename Key, typename Value>\n\t\tvoid set(Key&& key, Value&& value);\n\n\t\tvoid unregister() {\n\t\t\tusing ustorage_base = u_detail::usertype_storage_base;\n\n\t\t\tlua_State* L = this->lua_state();\n\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tint top = lua_gettop(L);\n\n\t\t\tstack_reference mt(L, -1);\n\t\t\tstack::get_field(L, meta_function::gc_names, mt.stack_index());\n\t\t\tif (type_of(L, -1) != type::table) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstack_reference gc_names_table(L, -1);\n\t\t\tstack::get_field(L, meta_function::storage, mt.stack_index());\n\t\t\tif (type_of(L, -1) != type::lightuserdata) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tustorage_base& base_storage = *static_cast<ustorage_base*>(stack::get<void*>(L, -1));\n\t\t\tstd::array<string_view, 6> registry_traits;\n\t\t\tfor (std::size_t i = 0; i < registry_traits.size(); ++i) {\n\t\t\t\tu_detail::submetatable_type smt = static_cast<u_detail::submetatable_type>(i);\n\t\t\t\tstack::get_field<false, true>(L, smt, gc_names_table.stack_index());\n\t\t\t\tregistry_traits[i] = stack::get<string_view>(L, -1);\n\t\t\t}\n\n\t\t\t// get the registry\n\t\t\tstack_reference registry(L, raw_index(LUA_REGISTRYINDEX));\n\t\t\tregistry.push();\n\t\t\t// eliminate all named entries for this usertype\n\t\t\t// in the registry (luaL_newmetatable does\n\t\t\t// [name] = new table\n\t\t\t// in registry upon creation)\n\t\t\tfor (std::size_t i = 0; i < registry_traits.size(); ++i) {\n\t\t\t\tu_detail::submetatable_type smt = static_cast<u_detail::submetatable_type>(i);\n\t\t\t\tconst string_view& gcmetakey = registry_traits[i];\n\t\t\t\tif (smt == u_detail::submetatable_type::named) {\n\t\t\t\t\t// use .data() to make it treat it like a c string,\n\t\t\t\t\t// which it is...\n\t\t\t\t\tstack::set_field<true>(L, gcmetakey.data(), lua_nil);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// do not change the values in the registry: they need to be present\n\t\t\t\t\t// no matter what, for safety's sake\n\t\t\t\t\t//stack::set_field(L, gcmetakey, lua_nil, registry.stack_index());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// destroy all storage and tables\n\t\t\tbase_storage.clear();\n\n\t\t\t// 6 strings from gc_names table,\n\t\t\t// + 1 registry,\n\t\t\t// + 1 gc_names table\n\t\t\t// + 1 light userdata of storage\n\t\t\t// + 1 registry\n\t\t\t// 10 total, 4 left since popping off 6 gc_names tables\n\t\t\tlua_settop(L, top);\n\t\t}\n\t};\n\n} // namespace sol\n\n// end of sol/metatable.hpp\n\nnamespace sol {\n\n\ttemplate <typename T, typename base_type>\n\tclass basic_usertype : private basic_metatable<base_type> {\n\tprivate:\n\t\tusing base_t = basic_metatable<base_type>;\n\t\tusing table_base_t = basic_table<base_type>;\n\n\t\ttemplate <typename>\n\t\tfriend class basic_metatable;\n\n\t\ttemplate <bool, typename>\n\t\tfriend class basic_table_core;\n\n\t\ttemplate <std::size_t... I, typename... Args>\n\t\tvoid tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) {\n\t\t\t(void)args;\n\t\t\t(void)detail::swallow{ 0,\n\t\t\t\t(this->set(std::get<I * 2>(std::move(args)), std::get<I * 2 + 1>(std::move(args))), 0)... };\n\t\t}\n\n\tpublic:\n\t\tusing base_t::base_t;\n\n\t\tusing base_t::pop;\n\t\tusing base_t::push;\n\t\tusing base_t::lua_state;\n\t\tusing base_t::get;\n\t\tusing base_t::set_function;\n\t\tusing base_t::traverse_set;\n\t\tusing base_t::traverse_get;\n\t\tusing base_t::unregister;\n\n\t\ttemplate <typename Key, typename Value>\n\t\tvoid set(Key&& key, Value&& value) {\n\t\t\toptional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state());\n\t\t\tif (maybe_uts) {\n\t\t\t\tu_detail::usertype_storage<T>& uts = *maybe_uts;\n\t\t\t\tuts.set(this->lua_state(), std::forward<Key>(key), std::forward<Value>(value));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tusing ValueU = meta::unqualified_t<Value>;\n\t\t\t\t// cannot get metatable: try regular table set?\n\t\t\t\tif constexpr (detail::is_non_factory_constructor_v<ValueU> || detail::is_policy_v<ValueU>) {\n\t\t\t\t\t// tag constructors so we don't get destroyed by lack of info\n\t\t\t\t\ttable_base_t::set(std::forward<Key>(key), detail::tagged<T, Value>(std::forward<Value>(value)));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttable_base_t::set(std::forward<Key>(key), std::forward<Value>(value));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Key>\n\t\tusertype_proxy<basic_usertype&, std::decay_t<Key>> operator[](Key&& key) {\n\t\t\treturn usertype_proxy<basic_usertype&, std::decay_t<Key>>(*this, std::forward<Key>(key));\n\t\t}\n\n\t\ttemplate <typename Key>\n\t\tusertype_proxy<const basic_usertype&, std::decay_t<Key>> operator[](Key&& key) const {\n\t\t\treturn usertype_proxy<const basic_usertype&, std::decay_t<Key>>(*this, std::forward<Key>(key));\n\t\t}\n\t};\n\n} // namespace sol\n\n// end of sol/usertype.hpp\n\n// beginning of sol/table.hpp\n\n// beginning of sol/lua_table.hpp\n\nnamespace sol {\n\n\ttemplate <typename ref_t>\n\tstruct basic_lua_table : basic_table_core<false, ref_t> {\n\tprivate:\n\t\tusing base_t = basic_table_core<false, ref_t>;\n\n\t\tfriend class state;\n\t\tfriend class state_view;\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_lua_table() noexcept = default;\n\t\tbasic_lua_table(const basic_lua_table&) = default;\n\t\tbasic_lua_table(basic_lua_table&&) = default;\n\t\tbasic_lua_table& operator=(const basic_lua_table&) = default;\n\t\tbasic_lua_table& operator=(basic_lua_table&&) = default;\n\t\tbasic_lua_table(const stack_reference& r) : basic_lua_table(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_lua_table(stack_reference&& r) : basic_lua_table(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_lua_table(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_lua_table>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_lua_table(lua_State* L, const new_table& nt) : base_t(L, nt) {\n\t\t\tif (!is_stack_based<meta::unqualified_t<ref_t>>::value) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t}\n\t\t}\n\t\tbasic_lua_table(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_lua_table>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_lua_table(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_lua_table>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_lua_table>>, meta::neg<std::is_same<ref_t, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_lua_table(T&& r) noexcept : basic_lua_table(detail::no_safety, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_table<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler{};\n\t\t\t\tstack::check<basic_lua_table>(lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_lua_table(lua_nil_t r) noexcept : basic_lua_table(detail::no_safety, r) {\n\t\t}\n\t};\n\n}\n\n// end of sol/lua_table.hpp\n\nnamespace sol {\n\ttypedef table_core<false> table;\n\n\ttemplate <bool is_global, typename base_type>\n\ttemplate <typename Class, typename Key>\n\tusertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key) {\n\t\tautomagic_enrollments enrollments;\n\t\treturn this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments));\n\t}\n\n\ttemplate <bool is_global, typename base_type>\n\ttemplate <typename Class, typename Key>\n\tusertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, automagic_enrollments enrollments) {\n\t\tint mt_index = u_detail::register_usertype<Class>(this->lua_state(), std::move(enrollments));\n\t\tusertype<Class> mt(this->lua_state(), -mt_index);\n\t\tlua_pop(this->lua_state(), 1);\n\t\tset(std::forward<Key>(key), mt);\n\t\treturn mt;\n\t}\n\n\ttemplate <bool is_global, typename base_type>\n\ttemplate <typename Class, typename Key, typename Arg, typename... Args, typename>\n\tusertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, Arg&& arg, Args&&... args) {\n\t\tautomagic_enrollments enrollments;\n\t\tenrollments.default_constructor = !detail::any_is_constructor_v<Arg, Args...>;\n\t\tenrollments.destructor = !detail::any_is_destructor_v<Arg, Args...>;\n\t\tusertype<Class> ut = this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments));\n\t\tstatic_assert(sizeof...(Args) % 2 == static_cast<std::size_t>(!detail::any_is_constructor_v<Arg>), \n\t\t\t\"you must pass an even number of arguments to new_usertype after first passing a constructor\");\n\t\tif constexpr (detail::any_is_constructor_v<Arg>) {\n\t\t\tut.set(meta_function::construct, std::forward<Arg>(arg));\n\t\t\tut.tuple_set(std::make_index_sequence<(sizeof...(Args)) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));\n\t\t}\n\t\telse {\n\t\t\tut.tuple_set(std::make_index_sequence<(sizeof...(Args) + 1) / 2>(), std::forward_as_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...));\n\t\t}\n\t\treturn ut;\n\t}\n\n\ttemplate <typename base_type>\n\ttemplate <typename Key, typename Value>\n\tvoid basic_metatable<base_type>::set(Key&& key, Value&& value) {\n\t\tthis->push();\n\t\tlua_State* L = this->lua_state();\n\t\tint target = lua_gettop(L);\n\t\toptional<u_detail::usertype_storage_base&> maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target);\n\t\tlua_pop(L, 1);\n\t\tif (maybe_uts) {\n\t\t\tu_detail::usertype_storage_base& uts = *maybe_uts;\n\t\t\tuts.set(L, std::forward<Key>(key), std::forward<Value>(value));\n\t\t}\n\t\telse {\n\t\t\tbase_t::set(std::forward<Key>(key), std::forward<Value>(value));\n\t\t}\n\t}\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_getter<metatable_key_t> {\n\t\t\tstatic table get(lua_State* L, int index = -1) {\n\t\t\t\tif (lua_getmetatable(L, index) == 0) {\n\t\t\t\t\treturn table(L, ref_index(LUA_REFNIL));\n\t\t\t\t}\n\t\t\t\treturn table(L, -1);\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/table.hpp\n\n// beginning of sol/state.hpp\n\n// beginning of sol/state_view.hpp\n\n// beginning of sol/environment.hpp\n\nnamespace sol {\n\n\ttemplate <typename base_type>\n\tstruct basic_environment : basic_table<base_type> {\n\tprivate:\n\t\ttypedef basic_table<base_type> base_t;\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_environment() noexcept = default;\n\t\tbasic_environment(const basic_environment&) = default;\n\t\tbasic_environment(basic_environment&&) = default;\n\t\tbasic_environment& operator=(const basic_environment&) = default;\n\t\tbasic_environment& operator=(basic_environment&&) = default;\n\t\tbasic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {\n\t\t}\n\n\t\tbasic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {\n\t\t}\n\t\ttemplate <bool b>\n\t\tbasic_environment(lua_State* L, new_table t, const basic_reference<b>& fallback) : basic_environment(L, std::move(t)) {\n\t\t\tstack_table mt(L, new_table(0, 1));\n\t\t\tmt.set(meta_function::index, fallback);\n\t\t\tthis->set(metatable_key, mt);\n\t\t\tmt.pop();\n\t\t}\n\n\t\tbasic_environment(env_key_t, const stack_reference& extraction_target)\n\t\t: base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<env_key_t>(this->lua_state(), -1, handler);\n#endif // Safety\n\t\t\tlua_pop(this->lua_state(), 2);\n\t\t}\n\t\ttemplate <bool b>\n\t\tbasic_environment(env_key_t, const basic_reference<b>& extraction_target)\n\t\t: base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<env_key_t>(this->lua_state(), -1, handler);\n#endif // Safety\n\t\t\tlua_pop(this->lua_state(), 2);\n\t\t}\n\t\tbasic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_environment>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_environment>(L, -1, handler);\n#endif // Safety\n\t\t}\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_environment<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler {};\n\t\t\t\tstack::check<basic_environment>(lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_environment(lua_nil_t r) noexcept : base_t(detail::no_safety, r) {\n\t\t}\n\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_environment(lua_State* L, T&& r) noexcept : base_t(detail::no_safety, L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_environment<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler {};\n\t\t\t\tstack::check<basic_environment>(lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tvoid set_on(const T& target) const {\n\t\t\tlua_State* L = target.lua_state();\n\t\t\tauto pp = stack::push_pop(target);\n#if SOL_LUA_VESION_I_ < 502\n\t\t\t// Use lua_setfenv\n\t\t\tthis->push();\n\t\t\tlua_setfenv(L, -2);\n#else\n\t\t\t// Use upvalues as explained in Lua 5.2 and beyond's manual\n\t\t\tthis->push();\n\t\t\tconst char* name = lua_setupvalue(L, -2, 1);\n\t\t\tif (name == nullptr) {\n\t\t\t\tthis->pop();\n\t\t\t}\n#endif\n\t\t}\n\t};\n\n\ttemplate <typename T, typename E>\n\tvoid set_environment(const basic_environment<E>& env, const T& target) {\n\t\tenv.set_on(target);\n\t}\n\n\ttemplate <typename E = reference, typename T>\n\tbasic_environment<E> get_environment(const T& target) {\n\t\tlua_State* L = target.lua_state();\n\t\tauto pp = stack::pop_n(L, stack::push_environment_of(target));\n\t\treturn basic_environment<E>(L, -1);\n\t}\n\n\tstruct this_environment {\n\t\toptional<environment> env;\n\n\t\tthis_environment() : env(nullopt) {\n\t\t}\n\t\tthis_environment(environment e) : env(std::move(e)) {\n\t\t}\n\t\tthis_environment(const this_environment&) = default;\n\t\tthis_environment(this_environment&&) = default;\n\t\tthis_environment& operator=(const this_environment&) = default;\n\t\tthis_environment& operator=(this_environment&&) = default;\n\n\t\texplicit operator bool() const {\n\t\t\treturn static_cast<bool>(env);\n\t\t}\n\n\t\toperator optional<environment> &() {\n\t\t\treturn env;\n\t\t}\n\n\t\toperator const optional<environment> &() const {\n\t\t\treturn env;\n\t\t}\n\n\t\toperator environment&() {\n\t\t\treturn env.value();\n\t\t}\n\n\t\toperator const environment&() const {\n\t\t\treturn env.value();\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_getter<env_key_t> {\n\t\t\tstatic environment get(lua_State* L, int index, record& tracking) {\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn get_environment(stack_reference(L, raw_index(index)));\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_getter<this_environment> {\n\t\t\tstatic this_environment get(lua_State* L, int, record& tracking) {\n\t\t\t\ttracking.use(0);\n\t\t\t\tlua_Debug info;\n\t\t\t\t// Level 0 means current function (this C function, which may or may not be useful for us?)\n\t\t\t\t// Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call)\n\t\t\t\tint pre_stack_size = lua_gettop(L);\n\t\t\t\tif (lua_getstack(L, 1, &info) != 1) {\n\t\t\t\t\tif (lua_getstack(L, 0, &info) != 1) {\n\t\t\t\t\t\tlua_settop(L, pre_stack_size);\n\t\t\t\t\t\treturn this_environment();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (lua_getinfo(L, \"f\", &info) == 0) {\n\t\t\t\t\tlua_settop(L, pre_stack_size);\n\t\t\t\t\treturn this_environment();\n\t\t\t\t}\n\n\t\t\t\tstack_reference f(L, -1);\n\t\t\t\tenvironment env(env_key, f);\n\t\t\t\tif (!env.valid()) {\n\t\t\t\t\tlua_settop(L, pre_stack_size);\n\t\t\t\t\treturn this_environment();\n\t\t\t\t}\n\t\t\t\treturn this_environment(std::move(env));\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/environment.hpp\n\n// beginning of sol/load_result.hpp\n\n#include <cstdint>\n\nnamespace sol {\n\tstruct load_result : public proxy_base<load_result> {\n\tprivate:\n\t\tlua_State* L;\n\t\tint index;\n\t\tint returncount;\n\t\tint popcount;\n\t\tload_status err;\n\n\tpublic:\n\t\tload_result() noexcept = default;\n\t\tload_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept\n\t\t: L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) {\n\t\t}\n\n\t\t// We do not want anyone to copy these around willy-nilly\n\t\t// Will likely break people, but also will probably get rid of quiet bugs that have\n\t\t// been lurking. (E.g., Vanilla Lua will just quietly discard over-pops and under-pops:\n\t\t// LuaJIT and other Lua engines will implode and segfault at random later times.)\n\t\tload_result(const load_result&) = delete;\n\t\tload_result& operator=(const load_result&) = delete;\n\n\t\tload_result(load_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) {\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but we will be thorough\n\t\t\to.L = nullptr;\n\t\t\to.index = 0;\n\t\t\to.returncount = 0;\n\t\t\to.popcount = 0;\n\t\t\to.err = load_status::syntax;\n\t\t}\n\t\tload_result& operator=(load_result&& o) noexcept {\n\t\t\tL = o.L;\n\t\t\tindex = o.index;\n\t\t\treturncount = o.returncount;\n\t\t\tpopcount = o.popcount;\n\t\t\terr = o.err;\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but we will be thorough\n\t\t\to.L = nullptr;\n\t\t\to.index = 0;\n\t\t\to.returncount = 0;\n\t\t\to.popcount = 0;\n\t\t\to.err = load_status::syntax;\n\t\t\treturn *this;\n\t\t}\n\n\t\tload_status status() const noexcept {\n\t\t\treturn err;\n\t\t}\n\n\t\tbool valid() const noexcept {\n\t\t\treturn status() == load_status::ok;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tT get() const {\n\t\t\tusing UT = meta::unqualified_t<T>;\n\t\t\tif constexpr (meta::is_optional_v<UT>) {\n\t\t\t\tusing ValueType = typename UT::value_type;\n\t\t\t\tif constexpr (std::is_same_v<ValueType, error>) {\n\t\t\t\t\tif (valid()) {\n\t\t\t\t\t\treturn UT(nullopt);\n\t\t\t\t\t}\n\t\t\t\t\treturn error(detail::direct_error, stack::get<std::string>(L, index));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!valid()) {\n\t\t\t\t\t\treturn UT(nullopt);\n\t\t\t\t\t}\n\t\t\t\t\treturn stack::get<UT>(L, index);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif constexpr (std::is_same_v<T, error>) {\n#if SOL_IS_ON(SOL_SAFE_PROXIES_I_)\n\t\t\t\t\tif (valid()) {\n\t\t\t\t\t\ttype_panic_c_str(L, index, type_of(L, index), type::none, \"expecting an error type (a string, from Lua)\");\n\t\t\t\t\t}\n#endif // Check proxy type's safety\n\t\t\t\t\treturn error(detail::direct_error, stack::get<std::string>(L, index));\n\t\t\t\t}\n\t\t\t\telse {\n#if SOL_IS_ON(SOL_SAFE_PROXIES_I_)\n\t\t\t\t\tif (!valid()) {\n\t\t\t\t\t\ttype_panic_c_str(L, index, type_of(L, index), type::none);\n\t\t\t\t\t}\n#endif // Check proxy type's safety\n\t\t\t\t\treturn stack::get<T>(L, index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args) {\n#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000\n\t\t\t// MSVC is ass sometimes\n\t\t\treturn get<protected_function>().call<Ret...>(std::forward<Args>(args)...);\n#else\n\t\t\treturn get<protected_function>().template call<Ret...>(std::forward<Args>(args)...);\n#endif\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tdecltype(auto) operator()(Args&&... args) {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn L;\n\t\t};\n\t\tint stack_index() const noexcept {\n\t\t\treturn index;\n\t\t};\n\n\t\t~load_result() {\n\t\t\tstack::remove(L, index, popcount);\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/load_result.hpp\n\n// beginning of sol/state_handling.hpp\n\n// beginning of sol/lua_value.hpp\n\nnamespace sol {\n\tstruct lua_value {\n\tpublic:\n\t\tstruct arr : detail::ebco<std::initializer_list<lua_value>> {\n\t\tprivate:\n\t\t\tusing base_t = detail::ebco<std::initializer_list<lua_value>>;\n\n\t\tpublic:\n\t\t\tusing base_t::base_t;\n\t\t};\n\n\tprivate:\n\t\ttemplate <typename T>\n\t\tusing is_reference_or_lua_value_init_list\n\t\t     = meta::any<meta::is_specialization_of<T, std::initializer_list>, std::is_same<T, reference>, std::is_same<T, arr>>;\n\n\t\ttemplate <typename T>\n\t\tusing is_lua_value_single_constructible = meta::any<std::is_same<T, lua_value>, is_reference_or_lua_value_init_list<T>>;\n\n\t\tstatic lua_State*& thread_local_lua_state() {\n#if SOL_IS_ON(SOL_USE_THREAD_LOCAL_I_)\n\t\t\tstatic thread_local lua_State* L = nullptr;\n#else\n\t\t\tstatic lua_State* L = nullptr;\n#endif\n\t\t\treturn L;\n\t\t}\n\n\t\treference ref_value;\n\n\tpublic:\n\t\tstatic void set_lua_state(lua_State* L) {\n\t\t\tthread_local_lua_state() = L;\n\t\t}\n\n\t\ttemplate <typename T, meta::disable<is_reference_or_lua_value_init_list<meta::unqualified_t<T>>> = meta::enabler>\n\t\tlua_value(lua_State* L_, T&& value) : lua_value(((set_lua_state(L_)), std::forward<T>(value))) {\n\t\t}\n\n\t\ttemplate <typename T, meta::disable<is_lua_value_single_constructible<meta::unqualified_t<T>>> = meta::enabler>\n\t\tlua_value(T&& value) : ref_value(make_reference(thread_local_lua_state(), std::forward<T>(value))) {\n\t\t}\n\n\t\tlua_value(lua_State* L_, std::initializer_list<std::pair<lua_value, lua_value>> il)\n\t\t: lua_value([&L_, &il]() {\n\t\t\tset_lua_state(L_);\n\t\t\treturn std::move(il);\n\t\t}()) {\n\t\t}\n\n\t\tlua_value(std::initializer_list<std::pair<lua_value, lua_value>> il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) {\n\t\t}\n\n\t\tlua_value(lua_State* L_, arr il)\n\t\t: lua_value([&L_, &il]() {\n\t\t\tset_lua_state(L_);\n\t\t\treturn std::move(il);\n\t\t}()) {\n\t\t}\n\n\t\tlua_value(arr il) : ref_value(make_reference(thread_local_lua_state(), std::move(il.value()))) {\n\t\t}\n\n\t\tlua_value(lua_State* L_, reference r)\n\t\t: lua_value([&L_, &r]() {\n\t\t\tset_lua_state(L_);\n\t\t\treturn std::move(r);\n\t\t}()) {\n\t\t}\n\n\t\tlua_value(reference r) : ref_value(std::move(r)) {\n\t\t}\n\n\t\tlua_value(const lua_value&) noexcept = default;\n\t\tlua_value(lua_value&&) = default;\n\t\tlua_value& operator=(const lua_value&) = default;\n\t\tlua_value& operator=(lua_value&&) = default;\n\n\t\tconst reference& value() const& {\n\t\t\treturn ref_value;\n\t\t}\n\n\t\treference& value() & {\n\t\t\treturn ref_value;\n\t\t}\n\n\t\treference&& value() && {\n\t\t\treturn std::move(ref_value);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) as() const {\n\t\t\tref_value.push();\n\t\t\treturn stack::pop<T>(ref_value.lua_state());\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tbool is() const {\n\t\t\tint r = ref_value.registry_index();\n\t\t\tif (r == LUA_REFNIL)\n\t\t\t\treturn meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false;\n\t\t\tif (r == LUA_NOREF)\n\t\t\t\treturn false;\n\t\t\tauto pp = stack::push_pop(ref_value);\n\t\t\treturn stack::check<T>(ref_value.lua_state(), -1, no_panic);\n\t\t}\n\t};\n\n\tusing array_value = typename lua_value::arr;\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<lua_value> {\n\t\t\tstatic int push(lua_State* L, const lua_value& lv) {\n\t\t\t\treturn stack::push(L, lv.value());\n\t\t\t}\n\n\t\t\tstatic int push(lua_State* L, lua_value&& lv) {\n\t\t\t\treturn stack::push(L, std::move(lv).value());\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_getter<lua_value> {\n\t\t\tstatic lua_value get(lua_State* L, int index, record& tracking) {\n\t\t\t\treturn lua_value(L, stack::get<reference>(L, index, tracking));\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/lua_value.hpp\n\n#if SOL_IS_ON(SOL_PRINT_ERRORS_I_)\n#include <iostream>\n#endif\n\nnamespace sol {\n\tinline void register_main_thread(lua_State* L) {\n#if SOL_LUA_VESION_I_ < 502\n\t\tif (L == nullptr) {\n\t\t\tlua_pushnil(L);\n\t\t\tlua_setglobal(L, detail::default_main_thread_name());\n\t\t\treturn;\n\t\t}\n\t\tlua_pushthread(L);\n\t\tlua_setglobal(L, detail::default_main_thread_name());\n#else\n\t\t(void)L;\n#endif\n\t}\n\n\tinline int default_at_panic(lua_State* L) {\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\t(void)L;\n\t\treturn -1;\n#else\n\t\tsize_t messagesize;\n\t\tconst char* message = lua_tolstring(L, -1, &messagesize);\n\t\tif (message) {\n\t\t\tstd::string err(message, messagesize);\n\t\t\tlua_settop(L, 0);\n#if SOL_IS_ON(SOL_PRINT_ERRORS_I_)\n\t\t\tstd::cerr << \"[sol3] An error occurred and panic has been invoked: \";\n\t\t\tstd::cerr << err;\n\t\t\tstd::cerr << std::endl;\n#endif\n\t\t\tthrow error(err);\n\t\t}\n\t\tlua_settop(L, 0);\n\t\tthrow error(std::string(\"An unexpected error occurred and panic has been invoked\"));\n#endif // Printing Errors\n\t}\n\n\tinline int default_traceback_error_handler(lua_State* L) {\n\t\tstd::string msg = \"An unknown error has triggered the default error handler\";\n\t\toptional<string_view> maybetopmsg = stack::unqualified_check_get<string_view>(L, 1, no_panic);\n\t\tif (maybetopmsg) {\n\t\t\tconst string_view& topmsg = maybetopmsg.value();\n\t\t\tmsg.assign(topmsg.data(), topmsg.size());\n\t\t}\n\t\tluaL_traceback(L, L, msg.c_str(), 1);\n\t\toptional<string_view> maybetraceback = stack::unqualified_check_get<string_view>(L, -1, no_panic);\n\t\tif (maybetraceback) {\n\t\t\tconst string_view& traceback = maybetraceback.value();\n\t\t\tmsg.assign(traceback.data(), traceback.size());\n\t\t}\n#if SOL_IS_ON(SOL_PRINT_ERRORS_I_)\n\t\t// std::cerr << \"[sol3] An error occurred and was caught in traceback: \";\n\t\t// std::cerr << msg;\n\t\t// std::cerr << std::endl;\n#endif // Printing\n\t\treturn stack::push(L, msg);\n\t}\n\n\tinline void set_default_state(lua_State* L, lua_CFunction panic_function = &default_at_panic,\n\t     lua_CFunction traceback_function = c_call<decltype(&default_traceback_error_handler), &default_traceback_error_handler>,\n\t     exception_handler_function exf = detail::default_exception_handler) {\n\t\tlua_atpanic(L, panic_function);\n\t\tprotected_function::set_default_handler(object(L, in_place, traceback_function));\n\t\tset_default_exception_handler(L, exf);\n\t\tregister_main_thread(L);\n\t\tstack::luajit_exception_handler(L);\n\t\tlua_value::set_lua_state(L);\n\t}\n\n\tinline std::size_t total_memory_used(lua_State* L) {\n\t\tstd::size_t kb = lua_gc(L, LUA_GCCOUNT, 0);\n\t\tkb *= 1024;\n\t\tkb += lua_gc(L, LUA_GCCOUNTB, 0);\n\t\treturn kb;\n\t}\n\n\tinline protected_function_result script_pass_on_error(lua_State*, protected_function_result result) {\n\t\treturn result;\n\t}\n\n\tinline protected_function_result script_throw_on_error(lua_State* L, protected_function_result result) {\n\t\ttype t = type_of(L, result.stack_index());\n\t\tstd::string err = \"sol: \";\n\t\terr += to_string(result.status());\n\t\terr += \" error\";\n#if SOL_IS_ON(SOL_EXCEPTIONS_I_)\n\t\tstd::exception_ptr eptr = std::current_exception();\n\t\tif (eptr) {\n\t\t\terr += \" with a \";\n\t\t\ttry {\n\t\t\t\tstd::rethrow_exception(eptr);\n\t\t\t}\n\t\t\tcatch (const std::exception& ex) {\n\t\t\t\terr += \"std::exception -- \";\n\t\t\t\terr.append(ex.what());\n\t\t\t}\n\t\t\tcatch (const std::string& message) {\n\t\t\t\terr += \"thrown message -- \";\n\t\t\t\terr.append(message);\n\t\t\t}\n\t\t\tcatch (const char* message) {\n\t\t\t\terr += \"thrown message -- \";\n\t\t\t\terr.append(message);\n\t\t\t}\n\t\t\tcatch (...) {\n\t\t\t\terr.append(\"thrown but unknown type, cannot serialize into error message\");\n\t\t\t}\n\t\t}\n#endif // serialize exception information if possible\n\t\tif (t == type::string) {\n\t\t\terr += \": \";\n\t\t\tstring_view serr = stack::unqualified_get<string_view>(L, result.stack_index());\n\t\t\terr.append(serr.data(), serr.size());\n\t\t}\n#if SOL_IS_ON(SOL_PRINT_ERRORS_I_)\n\t\tstd::cerr << \"[sol3] An error occurred and has been passed to an error handler: \";\n\t\tstd::cerr << err;\n\t\tstd::cerr << std::endl;\n#endif\n\t\t// replacing information of stack error into pfr\n\t\tint target = result.stack_index();\n\t\tif (result.pop_count() > 0) {\n\t\t\tstack::remove(L, target, result.pop_count());\n\t\t}\n\t\tstack::push(L, err);\n\t\tint top = lua_gettop(L);\n\t\tint towards = top - target;\n\t\tif (towards != 0) {\n\t\t\tlua_rotate(L, top, towards);\n\t\t}\n#if SOL_IS_OFF(SOL_EXCEPTIONS_I_)\n\t\treturn result;\n#else\n\t\t// just throw our error\n\t\tthrow error(detail::direct_error, err);\n#endif // If exceptions are allowed\n\t}\n\n\tinline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) {\n#if SOL_IS_ON(SOL_DEFAULT_PASS_ON_ERROR_I_)\n\t\treturn script_pass_on_error(L, std::move(pfr));\n#else\n\t\treturn script_throw_on_error(L, std::move(pfr));\n#endif\n\t}\n\n\tnamespace stack {\n\t\tinline error get_traceback_or_errors(lua_State* L) {\n\t\t\tint p = default_traceback_error_handler(L);\n\t\t\tsol::error err = stack::get<sol::error>(L, -p);\n\t\t\tlua_pop(L, p);\n\t\t\treturn err;\n\t\t}\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/state_handling.hpp\n\n#include <memory>\n#include <cstddef>\n\nnamespace sol {\n\n\tclass state_view {\n\tprivate:\n\t\tlua_State* L;\n\t\ttable reg;\n\t\tglobal_table global;\n\n\t\toptional<object> is_loaded_package(const std::string& key) {\n\t\t\tauto loaded = reg.traverse_get<optional<object>>(\"_LOADED\", key);\n\t\t\tbool is53mod = loaded && !(loaded->is<bool>() && !loaded->as<bool>());\n\t\t\tif (is53mod)\n\t\t\t\treturn loaded;\n#if SOL_LUA_VESION_I_ <= 501\n\t\t\tauto loaded51 = global.traverse_get<optional<object>>(\"package\", \"loaded\", key);\n\t\t\tbool is51mod = loaded51 && !(loaded51->is<bool>() && !loaded51->as<bool>());\n\t\t\tif (is51mod)\n\t\t\t\treturn loaded51;\n#endif\n\t\t\treturn nullopt;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tvoid ensure_package(const std::string& key, T&& sr) {\n#if SOL_LUA_VESION_I_ <= 501\n\t\t\tauto pkg = global[\"package\"];\n\t\t\tif (!pkg.valid()) {\n\t\t\t\tpkg = create_table_with(\"loaded\", create_table_with(key, sr));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto ld = pkg[\"loaded\"];\n\t\t\t\tif (!ld.valid()) {\n\t\t\t\t\tld = create_table_with(key, sr);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tld[key] = sr;\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\tauto loaded = reg[\"_LOADED\"];\n\t\t\tif (!loaded.valid()) {\n\t\t\t\tloaded = create_table_with(key, sr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloaded[key] = sr;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tobject require_core(const std::string& key, Fx&& action, bool create_global = true) {\n\t\t\toptional<object> loaded = is_loaded_package(key);\n\t\t\tif (loaded && loaded->valid())\n\t\t\t\treturn std::move(*loaded);\n\t\t\taction();\n\t\t\tstack_reference sr(L, -1);\n\t\t\tif (create_global)\n\t\t\t\tset(key, sr);\n\t\t\tensure_package(key, sr);\n\t\t\treturn stack::pop<object>(L);\n\t\t}\n\n\tpublic:\n\t\tusing iterator = typename global_table::iterator;\n\t\tusing const_iterator = typename global_table::const_iterator;\n\n\t\tstate_view(lua_State* Ls) : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, detail::global_) {\n\t\t}\n\n\t\tstate_view(this_state Ls) : state_view(Ls.L) {\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\treturn L;\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tvoid open_libraries(Args&&... args) {\n\t\t\tstatic_assert(meta::all_same<lib, meta::unqualified_t<Args>...>::value, \"all types must be libraries\");\n\t\t\tif constexpr (sizeof...(args) == 0) {\n\t\t\t\tluaL_openlibs(L);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlib libraries[1 + sizeof...(args)] = { lib::count, std::forward<Args>(args)... };\n\n\t\t\t\tfor (auto&& library : libraries) {\n\t\t\t\t\tswitch (library) {\n#if SOL_LUA_VESION_I_ <= 501 && defined(SOL_LUAJIT)\n\t\t\t\t\tcase lib::coroutine:\n#endif // luajit opens coroutine base stuff\n\t\t\t\t\tcase lib::base:\n\t\t\t\t\t\tluaL_requiref(L, \"base\", luaopen_base, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::package:\n\t\t\t\t\t\tluaL_requiref(L, \"package\", luaopen_package, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n#if !defined(SOL_LUAJIT)\n\t\t\t\t\tcase lib::coroutine:\n#if SOL_LUA_VESION_I_ > 501\n\t\t\t\t\t\tluaL_requiref(L, \"coroutine\", luaopen_coroutine, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n#endif // Lua 5.2+ only\n\t\t\t\t\t\tbreak;\n#endif // Not LuaJIT - comes builtin\n\t\t\t\t\tcase lib::string:\n\t\t\t\t\t\tluaL_requiref(L, \"string\", luaopen_string, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::table:\n\t\t\t\t\t\tluaL_requiref(L, \"table\", luaopen_table, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::math:\n\t\t\t\t\t\tluaL_requiref(L, \"math\", luaopen_math, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::bit32:\n#ifdef SOL_LUAJIT\n\t\t\t\t\t\tluaL_requiref(L, \"bit32\", luaopen_bit, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n#elif (SOL_LUA_VESION_I_ == 502) || defined(LUA_COMPAT_BITLIB) || defined(LUA_COMPAT_5_2)\n\t\t\t\t\t\tluaL_requiref(L, \"bit32\", luaopen_bit32, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n#else\n#endif // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::io:\n\t\t\t\t\t\tluaL_requiref(L, \"io\", luaopen_io, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::os:\n\t\t\t\t\t\tluaL_requiref(L, \"os\", luaopen_os, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::debug:\n\t\t\t\t\t\tluaL_requiref(L, \"debug\", luaopen_debug, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::utf8:\n#if SOL_LUA_VESION_I_ > 502 && !defined(SOL_LUAJIT)\n\t\t\t\t\t\tluaL_requiref(L, \"utf8\", luaopen_utf8, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n#endif // Lua 5.3+ only\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::ffi:\n#ifdef SOL_LUAJIT\n\t\t\t\t\t\tluaL_requiref(L, \"ffi\", luaopen_ffi, 1);\n\t\t\t\t\t\tlua_pop(L, 1);\n#endif // LuaJIT only\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::jit:\n#ifdef SOL_LUAJIT\n\t\t\t\t\t\tluaL_requiref(L, \"jit\", luaopen_jit, 0);\n\t\t\t\t\t\tlua_pop(L, 1);\n#endif // LuaJIT Only\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase lib::count:\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tobject require(const std::string& key, lua_CFunction open_function, bool create_global = true) {\n\t\t\tluaL_requiref(L, key.c_str(), open_function, create_global ? 1 : 0);\n\t\t\treturn stack::pop<object>(L);\n\t\t}\n\n\t\tobject require_script(const std::string& key, const string_view& code, bool create_global = true,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tauto action = [this, &code, &chunkname, &mode]() { stack::script(L, code, chunkname, mode); };\n\t\t\treturn require_core(key, action, create_global);\n\t\t}\n\n\t\tobject require_file(const std::string& key, const std::string& filename, bool create_global = true, load_mode mode = load_mode::any) {\n\t\t\tauto action = [this, &filename, &mode]() { stack::script_file(L, filename, mode); };\n\t\t\treturn require_core(key, action, create_global);\n\t\t}\n\n\t\tvoid clear_package_loaders() {\n\t\t\toptional<table> maybe_package = this->global[\"package\"];\n\t\t\tif (!maybe_package) {\n\t\t\t\t// package lib wasn't opened\n\t\t\t\t// open package lib\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttable& package = *maybe_package;\n\t\t\t// yay for version differences...\n\t\t\t// one day Lua 5.1 will die a peaceful death\n\t\t\t// and its old bones will find blissful rest\n\t\t\tauto loaders_proxy = package\n#if SOL_LUA_VESION_I_ < 502\n\t\t\t     [\"loaders\"]\n#else\n\t\t\t     [\"searchers\"]\n#endif\n\t\t\t     ;\n\t\t\tif (!loaders_proxy.valid()) {\n\t\t\t\t// nothing to clear\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// we need to create the table for loaders\n\t\t\t// table does not exist, so create and move forward\n\t\t\tloaders_proxy = new_table(1, 0);\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tvoid add_package_loader(Fx&& fx, bool clear_all_package_loaders = false) {\n\t\t\toptional<table> maybe_package = this->global[\"package\"];\n\t\t\tif (!maybe_package) {\n\t\t\t\t// package lib wasn't opened\n\t\t\t\t// open package lib\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttable& package = *maybe_package;\n\t\t\t// yay for version differences...\n\t\t\t// one day Lua 5.1 will die a peaceful death\n\t\t\t// and its old bones will find blissful rest\n\t\t\tauto loaders_proxy = package\n#if SOL_LUA_VESION_I_ < 502\n\t\t\t     [\"loaders\"]\n#else\n\t\t\t     [\"searchers\"]\n#endif\n\t\t\t     ;\n\t\t\tbool make_new_table = clear_all_package_loaders || !loaders_proxy.valid();\n\t\t\tif (make_new_table) {\n\t\t\t\t// we need to create the table for loaders\n\t\t\t\t// table does not exist, so create and move forward\n\t\t\t\tloaders_proxy = new_table(1, 0);\n\t\t\t}\n\t\t\toptional<table> maybe_loaders = loaders_proxy;\n\t\t\tif (!maybe_loaders) {\n\t\t\t\t// loaders/searches\n\t\t\t\t// thing exists in package, but it\n\t\t\t\t// ain't a table or a table-alike...!\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttable loaders = loaders_proxy;\n\t\t\tloaders.add(std::forward<Fx>(fx));\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tprotected_function_result do_reader(lua_Reader reader, void* data, const basic_environment<E>& env,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(\"lua_Reader\", chunkname, basechunkname);\n\t\t\tload_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));\n\t\t\tif (x != load_status::ok) {\n\t\t\t\treturn protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));\n\t\t\t}\n\t\t\tstack_aligned_protected_function pf(L, -1);\n\t\t\tset_environment(env, pf);\n\t\t\treturn pf();\n\t\t}\n\n\t\tprotected_function_result do_reader(\n\t\t     lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(\"lua_Reader\", chunkname, basechunkname);\n\t\t\tload_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));\n\t\t\tif (x != load_status::ok) {\n\t\t\t\treturn protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));\n\t\t\t}\n\t\t\tstack_aligned_protected_function pf(L, -1);\n\t\t\treturn pf();\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tprotected_function_result do_string(const string_view& code, const basic_environment<E>& env,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);\n\t\t\tload_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()));\n\t\t\tif (x != load_status::ok) {\n\t\t\t\treturn protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));\n\t\t\t}\n\t\t\tstack_aligned_protected_function pf(L, -1);\n\t\t\tset_environment(env, pf);\n\t\t\treturn pf();\n\t\t}\n\n\t\tprotected_function_result do_string(\n\t\t     const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);\n\t\t\tload_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()));\n\t\t\tif (x != load_status::ok) {\n\t\t\t\treturn protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));\n\t\t\t}\n\t\t\tstack_aligned_protected_function pf(L, -1);\n\t\t\treturn pf();\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tprotected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {\n\t\t\tload_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));\n\t\t\tif (x != load_status::ok) {\n\t\t\t\treturn protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));\n\t\t\t}\n\t\t\tstack_aligned_protected_function pf(L, -1);\n\t\t\tset_environment(env, pf);\n\t\t\treturn pf();\n\t\t}\n\n\t\tprotected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\tload_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));\n\t\t\tif (x != load_status::ok) {\n\t\t\t\treturn protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));\n\t\t\t}\n\t\t\tstack_aligned_protected_function pf(L, -1);\n\t\t\treturn pf();\n\t\t}\n\n\t\ttemplate <typename Fx,\n\t\t     meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>,\n\t\t          meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>\n\t\tprotected_function_result safe_script(\n\t\t     lua_Reader reader, void* data, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tprotected_function_result pfr = do_reader(reader, data, chunkname, mode);\n\t\t\tif (!pfr.valid()) {\n\t\t\t\treturn on_error(L, std::move(pfr));\n\t\t\t}\n\t\t\treturn pfr;\n\t\t}\n\n\t\tprotected_function_result safe_script(\n\t\t     lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(reader, data, script_default_on_error, chunkname, mode);\n\t\t}\n\n\t\ttemplate <typename Fx,\n\t\t     meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>,\n\t\t          meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>\n\t\tprotected_function_result safe_script(\n\t\t     const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tprotected_function_result pfr = do_string(code, chunkname, mode);\n\t\t\tif (!pfr.valid()) {\n\t\t\t\treturn on_error(L, std::move(pfr));\n\t\t\t}\n\t\t\treturn pfr;\n\t\t}\n\n\t\ttemplate <typename Fx, typename E>\n\t\tprotected_function_result safe_script(const string_view& code, const basic_environment<E>& env, Fx&& on_error,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tprotected_function_result pfr = do_string(code, env, chunkname, mode);\n\t\t\tif (!pfr.valid()) {\n\t\t\t\treturn on_error(L, std::move(pfr));\n\t\t\t}\n\t\t\treturn pfr;\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tprotected_function_result safe_script(const string_view& code, const basic_environment<E>& env,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(code, env, script_default_on_error, chunkname, mode);\n\t\t}\n\n\t\tprotected_function_result safe_script(\n\t\t     const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(code, script_default_on_error, chunkname, mode);\n\t\t}\n\n\t\ttemplate <typename Fx,\n\t\t     meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>,\n\t\t          meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>\n\t\tprotected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {\n\t\t\tprotected_function_result pfr = do_file(filename, mode);\n\t\t\tif (!pfr.valid()) {\n\t\t\t\treturn on_error(L, std::move(pfr));\n\t\t\t}\n\t\t\treturn pfr;\n\t\t}\n\n\t\ttemplate <typename Fx, typename E>\n\t\tprotected_function_result safe_script_file(\n\t\t     const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) {\n\t\t\tprotected_function_result pfr = do_file(filename, env, mode);\n\t\t\tif (!pfr.valid()) {\n\t\t\t\treturn on_error(L, std::move(pfr));\n\t\t\t}\n\t\t\treturn pfr;\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tprotected_function_result safe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {\n\t\t\treturn safe_script_file(filename, env, script_default_on_error, mode);\n\t\t}\n\n\t\tprotected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\treturn safe_script_file(filename, script_default_on_error, mode);\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tunsafe_function_result unsafe_script(lua_Reader reader, void* data, const basic_environment<E>& env,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(\"lua_Reader\", chunkname, basechunkname);\n\t\t\tint index = lua_gettop(L);\n\t\t\tif (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t\tset_environment(env, stack_reference(L, raw_index(index + 1)));\n\t\t\tif (lua_pcall(L, 0, LUA_MULTRET, 0)) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t\tint postindex = lua_gettop(L);\n\t\t\tint returns = postindex - index;\n\t\t\treturn unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);\n\t\t}\n\n\t\tunsafe_function_result unsafe_script(\n\t\t     lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tint index = lua_gettop(L);\n\t\t\tstack::script(L, reader, data, chunkname, mode);\n\t\t\tint postindex = lua_gettop(L);\n\t\t\tint returns = postindex - index;\n\t\t\treturn unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tunsafe_function_result unsafe_script(const string_view& code, const basic_environment<E>& env,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);\n\t\t\tint index = lua_gettop(L);\n\t\t\tif (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t\tset_environment(env, stack_reference(L, raw_index(index + 1)));\n\t\t\tif (lua_pcall(L, 0, LUA_MULTRET, 0)) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t\tint postindex = lua_gettop(L);\n\t\t\tint returns = postindex - index;\n\t\t\treturn unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);\n\t\t}\n\n\t\tunsafe_function_result unsafe_script(\n\t\t     const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tint index = lua_gettop(L);\n\t\t\tstack::script(L, code, chunkname, mode);\n\t\t\tint postindex = lua_gettop(L);\n\t\t\tint returns = postindex - index;\n\t\t\treturn unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);\n\t\t}\n\n\t\ttemplate <typename E>\n\t\tunsafe_function_result unsafe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {\n\t\t\tint index = lua_gettop(L);\n\t\t\tif (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t\tset_environment(env, stack_reference(L, raw_index(index + 1)));\n\t\t\tif (lua_pcall(L, 0, LUA_MULTRET, 0)) {\n\t\t\t\tlua_error(L);\n\t\t\t}\n\t\t\tint postindex = lua_gettop(L);\n\t\t\tint returns = postindex - index;\n\t\t\treturn unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);\n\t\t}\n\n\t\tunsafe_function_result unsafe_script_file(const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\tint index = lua_gettop(L);\n\t\t\tstack::script_file(L, filename, mode);\n\t\t\tint postindex = lua_gettop(L);\n\t\t\tint returns = postindex - index;\n\t\t\treturn unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);\n\t\t}\n\n\t\ttemplate <typename Fx,\n\t\t     meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>,\n\t\t          meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>\n\t\tprotected_function_result script(\n\t\t     const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(code, std::forward<Fx>(on_error), chunkname, mode);\n\t\t}\n\n\t\ttemplate <typename Fx,\n\t\t     meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>,\n\t\t          meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>\n\t\tprotected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {\n\t\t\treturn safe_script_file(filename, std::forward<Fx>(on_error), mode);\n\t\t}\n\n\t\ttemplate <typename Fx, typename E>\n\t\tprotected_function_result script(const string_view& code, const basic_environment<E>& env, Fx&& on_error,\n\t\t     const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(code, env, std::forward<Fx>(on_error), chunkname, mode);\n\t\t}\n\n\t\ttemplate <typename Fx, typename E>\n\t\tprotected_function_result script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) {\n\t\t\treturn safe_script_file(filename, env, std::forward<Fx>(on_error), mode);\n\t\t}\n\n\t\tprotected_function_result script(\n\t\t     const string_view& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(code, env, script_default_on_error, chunkname, mode);\n\t\t}\n\n\t\tprotected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) {\n\t\t\treturn safe_script_file(filename, env, script_default_on_error, mode);\n\t\t}\n\n#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)\n\t\tprotected_function_result script(\n\t\t     lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(reader, data, chunkname, mode);\n\t\t}\n\n\t\tprotected_function_result script(\n\t\t     const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn safe_script(code, chunkname, mode);\n\t\t}\n\n\t\tprotected_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\treturn safe_script_file(filename, mode);\n\t\t}\n#else\n\t\tunsafe_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn unsafe_script(code, chunkname, mode);\n\t\t}\n\n\t\tunsafe_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\treturn unsafe_script_file(filename, mode);\n\t\t}\n#endif\n\t\tload_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);\n\t\t\tload_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()));\n\t\t\treturn load_result(L, absolute_index(L, -1), 1, 1, x);\n\t\t}\n\n\t\tload_result load_buffer(const char* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn load(string_view(buff, size), chunkname, mode);\n\t\t}\n\n\t\tload_result load_buffer(\n\t\t     const std::byte* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\treturn load(string_view(reinterpret_cast<const char*>(buff), size), chunkname, mode);\n\t\t}\n\n\t\tload_result load_file(const std::string& filename, load_mode mode = load_mode::any) {\n\t\t\tload_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));\n\t\t\treturn load_result(L, absolute_index(L, -1), 1, 1, x);\n\t\t}\n\n\t\tload_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {\n\t\t\tdetail::typical_chunk_name_t basechunkname = {};\n\t\t\tconst char* chunknametarget = detail::make_chunk_name(\"lua_Reader\", chunkname, basechunkname);\n\t\t\tload_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));\n\t\t\treturn load_result(L, absolute_index(L, -1), 1, 1, x);\n\t\t}\n\n\t\titerator begin() const {\n\t\t\treturn global.begin();\n\t\t}\n\n\t\titerator end() const {\n\t\t\treturn global.end();\n\t\t}\n\n\t\tconst_iterator cbegin() const {\n\t\t\treturn global.cbegin();\n\t\t}\n\n\t\tconst_iterator cend() const {\n\t\t\treturn global.cend();\n\t\t}\n\n\t\tglobal_table globals() const {\n\t\t\t// if we return a reference\n\t\t\t// we'll be screwed a bit\n\t\t\treturn global;\n\t\t}\n\n\t\tglobal_table& globals() {\n\t\t\treturn global;\n\t\t}\n\n\t\ttable registry() const {\n\t\t\treturn reg;\n\t\t}\n\n\t\tstd::size_t memory_used() const {\n\t\t\treturn total_memory_used(lua_state());\n\t\t}\n\n\t\tint stack_top() const {\n\t\t\treturn stack::top(L);\n\t\t}\n\n\t\tint stack_clear() {\n\t\t\tint s = stack_top();\n\t\t\tlua_pop(L, s);\n\t\t\treturn s;\n\t\t}\n\n\t\tbool supports_gc_mode(gc_mode mode) const noexcept {\n#if SOL_LUA_VESION_I_ >= 504\n\t\t\t// supports all modes\n\t\t\t(void)mode;\n\t\t\treturn true;\n#endif\n\t\t\treturn mode == gc_mode::default_value;\n\t\t}\n\n\t\tbool is_gc_on() const {\n#if SOL_LUA_VESION_I_ >= 502\n\t\t\treturn lua_gc(lua_state(), LUA_GCISRUNNING, 0) == 1;\n#else\n\t\t\t// You cannot turn it off in Lua 5.1\n\t\t\treturn true;\n#endif\n\t\t}\n\n\t\tvoid collect_garbage() {\n\t\t\tlua_gc(lua_state(), LUA_GCCOLLECT, 0);\n\t\t}\n\n\t\tvoid collect_gc() {\n\t\t\tcollect_garbage();\n\t\t}\n\n\t\tbool step_gc(int step_size_kilobytes) {\n\t\t\t// THOUGHT: std::chrono-alikes to map \"kilobyte size\" here...?\n\t\t\t// Make it harder to give MB or KB to a B parameter...?\n\t\t\t// Probably overkill for now.\n#if SOL_LUA_VESION_I_ >= 504\n\t\t\t// The manual implies that this function is almost always successful...\n\t\t\t// is it?? It could depend on the GC mode...\n\t\t\treturn lua_gc(lua_state(), LUA_GCSTEP, step_size_kilobytes) != 0;\n#else\n\t\t\treturn lua_gc(lua_state(), LUA_GCSTEP, step_size_kilobytes) == 1;\n#endif\n\t\t}\n\n\t\tvoid restart_gc() {\n\t\t\tlua_gc(lua_state(), LUA_GCRESTART, 0);\n\t\t}\n\n\t\tvoid stop_gc() {\n\t\t\tlua_gc(lua_state(), LUA_GCSTOP, 0);\n\t\t}\n\n\t\t// Returns the old GC mode. Check support using the supports_gc_mode function.\n\t\tgc_mode change_gc_mode_incremental(int pause, int step_multiplier, int step_byte_size) {\n\t\t\t// \"What the fuck does any of this mean??\"\n\t\t\t// http://www.lua.org/manual/5.4/manual.html#2.5.1\n\n\t\t\t// THOUGHT: std::chrono-alikes to map \"byte size\" here...?\n\t\t\t// Make it harder to give MB or KB to a B parameter...?\n\t\t\t// Probably overkill for now.\n#if SOL_LUA_VESION_I_ >= 504\n\t\t\tint old_mode = lua_gc(lua_state(), LUA_GCINC, pause, step_multiplier, step_byte_size);\n\t\t\tif (old_mode == LUA_GCGEN) {\n\t\t\t\treturn gc_mode::generational;\n\t\t\t}\n\t\t\telse if (old_mode == LUA_GCINC) {\n\t\t\t\treturn gc_mode::incremental;\n\t\t\t}\n#else\n\t\t\tlua_gc(lua_state(), LUA_GCSETPAUSE, pause);\n\t\t\tlua_gc(lua_state(), LUA_GCSETSTEPMUL, step_multiplier);\n\t\t\t(void)step_byte_size; // means nothing in older versions\n#endif\n\t\t\treturn gc_mode::default_value;\n\t\t}\n\n\t\t// Returns the old GC mode. Check support using the supports_gc_mode function.\n\t\tgc_mode change_gc_mode_generational(int minor_multiplier, int major_multiplier) {\n#if SOL_LUA_VESION_I_ >= 504\n\t\t\t// \"What does this shit mean?\"\n\t\t\t// http://www.lua.org/manual/5.4/manual.html#2.5.2\n\t\t\tint old_mode = lua_gc(lua_state(), LUA_GCGEN, minor_multiplier, major_multiplier);\n\t\t\tif (old_mode == LUA_GCGEN) {\n\t\t\t\treturn gc_mode::generational;\n\t\t\t}\n\t\t\telse if (old_mode == LUA_GCINC) {\n\t\t\t\treturn gc_mode::incremental;\n\t\t\t}\n#endif\n\t\t\treturn gc_mode::default_value;\n\t\t}\n\n\t\toperator lua_State*() const {\n\t\t\treturn lua_state();\n\t\t}\n\n\t\tvoid set_panic(lua_CFunction panic) {\n\t\t\tlua_atpanic(lua_state(), panic);\n\t\t}\n\n\t\tvoid set_exception_handler(exception_handler_function handler) {\n\t\t\tset_default_exception_handler(lua_state(), handler);\n\t\t}\n\n\t\ttemplate <typename... Args, typename... Keys>\n\t\tdecltype(auto) get(Keys&&... keys) const {\n\t\t\treturn global.get<Args...>(std::forward<Keys>(keys)...);\n\t\t}\n\n\t\ttemplate <typename T, typename Key>\n\t\tdecltype(auto) get_or(Key&& key, T&& otherwise) const {\n\t\t\treturn global.get_or(std::forward<Key>(key), std::forward<T>(otherwise));\n\t\t}\n\n\t\ttemplate <typename T, typename Key, typename D>\n\t\tdecltype(auto) get_or(Key&& key, D&& otherwise) const {\n\t\t\treturn global.get_or<T>(std::forward<Key>(key), std::forward<D>(otherwise));\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tstate_view& set(Args&&... args) {\n\t\t\tglobal.set(std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename T, typename... Keys>\n\t\tdecltype(auto) traverse_get(Keys&&... keys) const {\n\t\t\treturn global.traverse_get<T>(std::forward<Keys>(keys)...);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tstate_view& traverse_set(Args&&... args) {\n\t\t\tglobal.traverse_set(std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename Class, typename... Args>\n\t\tusertype<Class> new_usertype(const std::string& name, Args&&... args) {\n\t\t\treturn global.new_usertype<Class>(name, std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <bool read_only = true, typename... Args>\n\t\tstate_view& new_enum(const string_view& name, Args&&... args) {\n\t\t\tglobal.new_enum<read_only>(name, std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename T, bool read_only = true>\n\t\tstate_view& new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) {\n\t\t\tglobal.new_enum<T, read_only>(name, std::move(items));\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename Fx>\n\t\tvoid for_each(Fx&& fx) {\n\t\t\tglobal.for_each(std::forward<Fx>(fx));\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy<global_table&, detail::proxy_key_t<T>> operator[](T&& key) {\n\t\t\treturn global[std::forward<T>(key)];\n\t\t}\n\n\t\ttemplate <typename T>\n\t\ttable_proxy<const global_table&, detail::proxy_key_t<T>> operator[](T&& key) const {\n\t\t\treturn global[std::forward<T>(key)];\n\t\t}\n\n\t\ttemplate <typename Sig, typename... Args, typename Key>\n\t\tstate_view& set_function(Key&& key, Args&&... args) {\n\t\t\tglobal.set_function<Sig>(std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename... Args, typename Key>\n\t\tstate_view& set_function(Key&& key, Args&&... args) {\n\t\t\tglobal.set_function(std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\treturn *this;\n\t\t}\n\n\t\ttemplate <typename Name>\n\t\ttable create_table(Name&& name, int narr = 0, int nrec = 0) {\n\t\t\treturn global.create(std::forward<Name>(name), narr, nrec);\n\t\t}\n\n\t\ttemplate <typename Name, typename Key, typename Value, typename... Args>\n\t\ttable create_table(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {\n\t\t\treturn global.create(std::forward<Name>(name), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename Name, typename... Args>\n\t\ttable create_named_table(Name&& name, Args&&... args) {\n\t\t\ttable x = global.create_with(std::forward<Args>(args)...);\n\t\t\tglobal.set(std::forward<Name>(name), x);\n\t\t\treturn x;\n\t\t}\n\n\t\ttable create_table(int narr = 0, int nrec = 0) {\n\t\t\treturn create_table(lua_state(), narr, nrec);\n\t\t}\n\n\t\ttemplate <typename Key, typename Value, typename... Args>\n\t\ttable create_table(int narr, int nrec, Key&& key, Value&& value, Args&&... args) {\n\t\t\treturn create_table(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\ttable create_table_with(Args&&... args) {\n\t\t\treturn create_table_with(lua_state(), std::forward<Args>(args)...);\n\t\t}\n\n\t\tstatic inline table create_table(lua_State* L, int narr = 0, int nrec = 0) {\n\t\t\treturn global_table::create(L, narr, nrec);\n\t\t}\n\n\t\ttemplate <typename Key, typename Value, typename... Args>\n\t\tstatic inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {\n\t\t\treturn global_table::create(L, narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tstatic inline table create_table_with(lua_State* L, Args&&... args) {\n\t\t\treturn global_table::create_with(L, std::forward<Args>(args)...);\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/state_view.hpp\n\n// beginning of sol/thread.hpp\n\nnamespace sol {\n\tstruct lua_thread_state {\n\t\tlua_State* L;\n\n\t\tlua_thread_state(lua_State* Ls)\n\t\t: L(Ls) {\n\t\t}\n\n\t\tlua_State* lua_state() const noexcept {\n\t\t\treturn L;\n\t\t}\n\t\toperator lua_State*() const noexcept {\n\t\t\treturn lua_state();\n\t\t}\n\t\tlua_State* operator->() const noexcept {\n\t\t\treturn lua_state();\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<lua_thread_state> {\n\t\t\tint push(lua_State*, lua_thread_state lts) {\n\t\t\t\tlua_pushthread(lts.L);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_getter<lua_thread_state> {\n\t\t\tlua_thread_state get(lua_State* L, int index, record& tracking) {\n\t\t\t\ttracking.use(1);\n\t\t\t\tlua_thread_state lts( lua_tothread(L, index) );\n\t\t\t\treturn lts;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_check_getter<lua_thread_state> {\n\t\t\ttemplate <typename Handler>\n\t\t\toptional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) {\n\t\t\t\tlua_thread_state lts( lua_tothread(L, index) );\n\t\t\t\tif (lts.lua_state() == nullptr) {\n\t\t\t\t\thandler(L, index, type::thread, type_of(L, index), \"value is not a valid thread type\");\n\t\t\t\t\treturn nullopt;\n\t\t\t\t}\n\t\t\t\ttracking.use(1);\n\t\t\t\treturn lts;\n\t\t\t}\n\t\t};\n\t} // namespace stack\n\n\ttemplate <typename ref_t>\n\tclass basic_thread : public basic_object<ref_t> {\n\tprivate:\n\t\tusing base_t = basic_object<ref_t>;\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_thread() noexcept = default;\n\t\tbasic_thread(const basic_thread&) = default;\n\t\tbasic_thread(basic_thread&&) = default;\n\t\ttemplate <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_thread>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_thread(T&& r)\n\t\t: base_t(std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_thread>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_thread(const stack_reference& r)\n\t\t: basic_thread(r.lua_state(), r.stack_index()){};\n\t\tbasic_thread(stack_reference&& r)\n\t\t: basic_thread(r.lua_state(), r.stack_index()){};\n\t\tbasic_thread& operator=(const basic_thread&) = default;\n\t\tbasic_thread& operator=(basic_thread&&) = default;\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_thread(lua_State* L, T&& r)\n\t\t: base_t(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_thread>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_thread(lua_State* L, int index = -1)\n\t\t: base_t(L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_thread>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_thread(lua_State* L, ref_index index)\n\t\t: base_t(L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_thread>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_thread(lua_State* L, lua_State* actualthread)\n\t\t: basic_thread(L, lua_thread_state{ actualthread }) {\n\t\t}\n\t\tbasic_thread(lua_State* L, this_state actualthread)\n\t\t: basic_thread(L, lua_thread_state{ actualthread.L }) {\n\t\t}\n\t\tbasic_thread(lua_State* L, lua_thread_state actualthread)\n\t\t: base_t(L, -stack::push(L, actualthread)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_thread>(lua_state(), -1, handler);\n#endif // Safety\n\t\t\tif (!is_stack_based<base_t>::value) {\n\t\t\t\tlua_pop(lua_state(), 1);\n\t\t\t}\n\t\t}\n\n\t\tstate_view state() const {\n\t\t\treturn state_view(this->thread_state());\n\t\t}\n\n\t\tbool is_main_thread() const {\n\t\t\treturn stack::is_main_thread(this->thread_state());\n\t\t}\n\n\t\tlua_State* thread_state() const {\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tlua_State* lthread = lua_tothread(lua_state(), -1);\n\t\t\treturn lthread;\n\t\t}\n\n\t\tthread_status status() const {\n\t\t\tlua_State* lthread = thread_state();\n\t\t\tauto lstat = static_cast<thread_status>(lua_status(lthread));\n\t\t\tif (lstat == thread_status::ok) {\n\t\t\t\tlua_Debug ar;\n\t\t\t\tif (lua_getstack(lthread, 0, &ar) > 0)\n\t\t\t\t\treturn thread_status::ok;\n\t\t\t\telse if (lua_gettop(lthread) == 0)\n\t\t\t\t\treturn thread_status::dead;\n\t\t\t\telse\n\t\t\t\t\treturn thread_status::yielded;\n\t\t\t}\n\t\t\treturn lstat;\n\t\t}\n\n\t\tbasic_thread create() {\n\t\t\treturn create(lua_state());\n\t\t}\n\n\t\tstatic basic_thread create(lua_State* L) {\n\t\t\tlua_newthread(L);\n\t\t\tbasic_thread result(L);\n\t\t\tif (!is_stack_based<base_t>::value) {\n\t\t\t\tlua_pop(L, 1);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttypedef basic_thread<reference> thread;\n\ttypedef basic_thread<stack_reference> stack_thread;\n} // namespace sol\n\n// end of sol/thread.hpp\n\nnamespace sol {\n\n\tclass state : private std::unique_ptr<lua_State, detail::state_deleter>, public state_view {\n\tprivate:\n\t\ttypedef std::unique_ptr<lua_State, detail::state_deleter> unique_base;\n\n\tpublic:\n\t\tstate(lua_CFunction panic = default_at_panic)\n\t\t: unique_base(luaL_newstate()), state_view(unique_base::get()) {\n\t\t\tset_default_state(unique_base::get(), panic);\n\t\t}\n\n\t\tstate(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr)\n\t\t: unique_base(lua_newstate(alfunc, alpointer)), state_view(unique_base::get()) {\n\t\t\tset_default_state(unique_base::get(), panic);\n\t\t}\n\n\t\tstate(const state&) = delete;\n\t\tstate(state&&) = default;\n\t\tstate& operator=(const state&) = delete;\n\t\tstate& operator=(state&& that) {\n\t\t\tstate_view::operator=(std::move(that));\n\t\t\tunique_base::operator=(std::move(that));\n\t\t\treturn *this;\n\t\t}\n\n\t\tusing state_view::get;\n\n\t\t~state() {\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/state.hpp\n\n// beginning of sol/coroutine.hpp\n\nnamespace sol {\n\ttemplate <typename ref_t>\n\tclass basic_coroutine : public basic_object<ref_t> {\n\tprivate:\n\t\tusing base_t = basic_object<ref_t>;\n\n\tpublic:\n\t\ttypedef reference handler_t;\n\t\thandler_t error_handler;\n\n\tprivate:\n\t\tcall_status stats = call_status::yielded;\n\n\t\tvoid luacall(std::ptrdiff_t argcount, std::ptrdiff_t) {\n#if SOL_LUA_VESION_I_ >= 504\n\t\t\tint nresults;\n\t\t\tstats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount), &nresults));\n#else\n\t\t\tstats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount)));\n#endif\n\t\t}\n\n\t\ttemplate <std::size_t... I, typename... Ret>\n\t\tauto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) {\n\t\t\tluacall(n, sizeof...(Ret));\n\t\t\treturn stack::pop<std::tuple<Ret...>>(lua_state());\n\t\t}\n\n\t\ttemplate <std::size_t I, typename Ret>\n\t\tRet invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) {\n\t\t\tluacall(n, 1);\n\t\t\treturn stack::pop<Ret>(lua_state());\n\t\t}\n\n\t\ttemplate <std::size_t I>\n\t\tvoid invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) {\n\t\t\tluacall(n, 0);\n\t\t}\n\n\t\tprotected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {\n\t\t\tint firstreturn = 1;\n\t\t\tluacall(n, LUA_MULTRET);\n\t\t\tint poststacksize = lua_gettop(this->lua_state());\n\t\t\tint returncount = poststacksize - (firstreturn - 1);\n\t\t\tif (error()) {\n\t\t\t\tif (error_handler.valid()) {\n\t\t\t\t\tstring_view err = stack::get<string_view>(this->lua_state(), poststacksize);\n\t\t\t\t\terror_handler.push();\n\t\t\t\t\tstack::push(this->lua_state(), err);\n\t\t\t\t\tlua_call(lua_state(), 1, 1);\n\t\t\t\t}\n\t\t\t\treturn protected_function_result(this->lua_state(), lua_absindex(this->lua_state(), -1), 1, returncount, status());\n\t\t\t}\n\t\t\treturn protected_function_result(this->lua_state(), firstreturn, returncount, returncount, status());\n\t\t}\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_coroutine() = default;\n\t\ttemplate <typename T,\n\t\t     meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_coroutine>>,\n\t\t          meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>,\n\t\t          meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_coroutine(T&& r) noexcept\n\t\t: base_t(std::forward<T>(r)), error_handler(detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_function<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\tconstructor_handler handler {};\n\t\t\t\tstack::check<basic_coroutine>(lua_state(), -1, handler);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_coroutine(const basic_coroutine&) = default;\n\t\tbasic_coroutine& operator=(const basic_coroutine&) = default;\n\t\tbasic_coroutine(basic_coroutine&&) = default;\n\t\tbasic_coroutine& operator=(basic_coroutine&&) = default;\n\t\tbasic_coroutine(const basic_function<base_t>& b)\n\t\t: basic_coroutine(b, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) {\n\t\t}\n\t\tbasic_coroutine(basic_function<base_t>&& b)\n\t\t: basic_coroutine(std::move(b), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) {\n\t\t}\n\t\tbasic_coroutine(const basic_function<base_t>& b, handler_t eh) : base_t(b), error_handler(std::move(eh)) {\n\t\t}\n\t\tbasic_coroutine(basic_function<base_t>&& b, handler_t eh) : base_t(std::move(b)), error_handler(std::move(eh)) {\n\t\t}\n\t\tbasic_coroutine(const stack_reference& r)\n\t\t: basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) {\n\t\t}\n\t\tbasic_coroutine(stack_reference&& r)\n\t\t: basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) {\n\t\t}\n\t\tbasic_coroutine(const stack_reference& r, handler_t eh) : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) {\n\t\t}\n\t\tbasic_coroutine(stack_reference&& r, handler_t eh) : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) {\n\t\t}\n\n\t\ttemplate <typename Super>\n\t\tbasic_coroutine(const proxy_base<Super>& p)\n\t\t: basic_coroutine(p, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) {\n\t\t}\n\t\ttemplate <typename Super>\n\t\tbasic_coroutine(proxy_base<Super>&& p)\n\t\t: basic_coroutine(std::move(p), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) {\n\t\t}\n\t\ttemplate <typename Proxy, typename Handler,\n\t\t     meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler>\n\t\tbasic_coroutine(Proxy&& p, Handler&& eh) : basic_coroutine(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) {\n\t\t}\n\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_coroutine(lua_State* L, T&& r)\n\t\t: basic_coroutine(L, std::forward<T>(r), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_coroutine(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_coroutine>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\n\t\tbasic_coroutine(lua_nil_t n) : base_t(n), error_handler(n) {\n\t\t}\n\n\t\tbasic_coroutine(lua_State* L, int index = -1)\n\t\t: basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {\n\t\t}\n\t\tbasic_coroutine(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {\n#ifdef SOL_SAFE_REFERENCES\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_coroutine>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_coroutine(lua_State* L, absolute_index index)\n\t\t: basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {\n\t\t}\n\t\tbasic_coroutine(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_coroutine>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_coroutine(lua_State* L, raw_index index)\n\t\t: basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {\n\t\t}\n\t\tbasic_coroutine(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_coroutine>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_coroutine(lua_State* L, ref_index index)\n\t\t: basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {\n\t\t}\n\t\tbasic_coroutine(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler {};\n\t\t\tstack::check<basic_coroutine>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\n\t\tcall_status status() const noexcept {\n\t\t\treturn stats;\n\t\t}\n\n\t\tbool error() const noexcept {\n\t\t\tcall_status cs = status();\n\t\t\treturn cs != call_status::ok && cs != call_status::yielded;\n\t\t}\n\n\t\tbool runnable() const noexcept {\n\t\t\treturn base_t::valid() && (status() == call_status::yielded);\n\t\t}\n\n\t\texplicit operator bool() const noexcept {\n\t\t\treturn runnable();\n\t\t}\n\n\t\ttemplate <typename... Args>\n\t\tprotected_function_result operator()(Args&&... args) {\n\t\t\treturn call<>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) operator()(types<Ret...>, Args&&... args) {\n\t\t\treturn call<Ret...>(std::forward<Args>(args)...);\n\t\t}\n\n\t\ttemplate <typename... Ret, typename... Args>\n\t\tdecltype(auto) call(Args&&... args) {\n\t\t\t// some users screw up coroutine.create\n\t\t\t// and try to use it with sol::coroutine without ever calling the first resume in Lua\n\t\t\t// this makes the stack incompatible with other kinds of stacks: protect against this\n\t\t\t// make sure coroutines don't screw us over\n\t\t\tbase_t::push();\n\t\t\tint pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);\n\t\t\treturn invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);\n\t\t}\n\t};\n} // namespace sol\n\n// end of sol/coroutine.hpp\n\n// beginning of sol/userdata.hpp\n\nnamespace sol {\n\ttemplate <typename base_type>\n\tclass basic_userdata : public basic_table<base_type> {\n\tprivate:\n\t\tusing base_t = basic_table<base_type>;\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_userdata() noexcept = default;\n\t\ttemplate <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_userdata(T&& r) noexcept\n\t\t: base_t(std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_userdata<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\ttype_assert(lua_state(), -1, type::userdata);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_userdata(const basic_userdata&) = default;\n\t\tbasic_userdata(basic_userdata&&) = default;\n\t\tbasic_userdata& operator=(const basic_userdata&) = default;\n\t\tbasic_userdata& operator=(basic_userdata&&) = default;\n\t\tbasic_userdata(const stack_reference& r)\n\t\t: basic_userdata(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_userdata(stack_reference&& r)\n\t\t: basic_userdata(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_userdata(lua_State* L, T&& r)\n\t\t: base_t(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_userdata>(L, -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_userdata(lua_State* L, int index = -1)\n\t\t: base_t(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_userdata>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_userdata(lua_State* L, ref_index index)\n\t\t: base_t(detail::no_safety, L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_userdata>(L, -1, handler);\n#endif // Safety\n\t\t}\n\t};\n\n\ttemplate <typename base_type>\n\tclass basic_lightuserdata : public basic_object_base<base_type> {\n\t\ttypedef basic_object_base<base_type> base_t;\n\n\tpublic:\n\t\tusing base_t::lua_state;\n\n\t\tbasic_lightuserdata() noexcept = default;\n\t\ttemplate <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_lightuserdata(T&& r) noexcept\n\t\t: base_t(std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tif (!is_lightuserdata<meta::unqualified_t<T>>::value) {\n\t\t\t\tauto pp = stack::push_pop(*this);\n\t\t\t\ttype_assert(lua_state(), -1, type::lightuserdata);\n\t\t\t}\n#endif // Safety\n\t\t}\n\t\tbasic_lightuserdata(const basic_lightuserdata&) = default;\n\t\tbasic_lightuserdata(basic_lightuserdata&&) = default;\n\t\tbasic_lightuserdata& operator=(const basic_lightuserdata&) = default;\n\t\tbasic_lightuserdata& operator=(basic_lightuserdata&&) = default;\n\t\tbasic_lightuserdata(const stack_reference& r)\n\t\t: basic_lightuserdata(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\tbasic_lightuserdata(stack_reference&& r)\n\t\t: basic_lightuserdata(r.lua_state(), r.stack_index()) {\n\t\t}\n\t\ttemplate <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>\n\t\tbasic_lightuserdata(lua_State* L, T&& r)\n\t\t: basic_lightuserdata(L, std::forward<T>(r)) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_lightuserdata>(lua_state(), -1, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_lightuserdata(lua_State* L, int index = -1)\n\t\t: base_t(L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_lightuserdata>(L, index, handler);\n#endif // Safety\n\t\t}\n\t\tbasic_lightuserdata(lua_State* L, ref_index index)\n\t\t: base_t(L, index) {\n#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_)\n\t\t\tauto pp = stack::push_pop(*this);\n\t\t\tconstructor_handler handler{};\n\t\t\tstack::check<basic_lightuserdata>(lua_state(), index, handler);\n#endif // Safety\n\t\t}\n\t};\n\n} // namespace sol\n\n// end of sol/userdata.hpp\n\n// beginning of sol/as_args.hpp\n\nnamespace sol {\n\ttemplate <typename T>\n\tstruct as_args_t {\n\t\tT src;\n\t};\n\n\ttemplate <typename Source>\n\tauto as_args(Source&& source) {\n\t\treturn as_args_t<Source> { std::forward<Source>(source) };\n\t}\n\n\tnamespace stack {\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<as_args_t<T>> {\n\t\t\tint push(lua_State* L, const as_args_t<T>& e) {\n\t\t\t\tint p = 0;\n\t\t\t\tfor (const auto& i : e.src) {\n\t\t\t\t\tp += stack::push(L, i);\n\t\t\t\t}\n\t\t\t\treturn p;\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/as_args.hpp\n\n// beginning of sol/variadic_args.hpp\n\n#include <limits>\n#include <iterator>\n\nnamespace sol {\n\tstruct variadic_args {\n\tprivate:\n\t\tlua_State* L;\n\t\tint index;\n\t\tint stacktop;\n\n\tpublic:\n\t\ttypedef stack_proxy reference_type;\n\t\ttypedef stack_proxy value_type;\n\t\ttypedef stack_proxy* pointer;\n\t\ttypedef std::ptrdiff_t difference_type;\n\t\ttypedef std::size_t size_type;\n\t\ttypedef stack_iterator<stack_proxy, false> iterator;\n\t\ttypedef stack_iterator<stack_proxy, true> const_iterator;\n\t\ttypedef std::reverse_iterator<iterator> reverse_iterator;\n\t\ttypedef std::reverse_iterator<const_iterator> const_reverse_iterator;\n\n\t\tvariadic_args() = default;\n\t\tvariadic_args(lua_State* luastate, int stackindex = -1)\n\t\t\t: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {\n\t\t}\n\t\tvariadic_args(lua_State* luastate, int stackindex, int lastindex)\n\t\t\t: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) {\n\t\t}\n\t\tvariadic_args(const variadic_args&) = default;\n\t\tvariadic_args& operator=(const variadic_args&) = default;\n\t\tvariadic_args(variadic_args&& o)\n\t\t\t: L(o.L), index(o.index), stacktop(o.stacktop) {\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but will be thorough\n\t\t\to.L = nullptr;\n\t\t\to.index = 0;\n\t\t\to.stacktop = 0;\n\t\t}\n\t\tvariadic_args& operator=(variadic_args&& o) {\n\t\t\tL = o.L;\n\t\t\tindex = o.index;\n\t\t\tstacktop = o.stacktop;\n\t\t\t// Must be manual, otherwise destructor will screw us\n\t\t\t// return count being 0 is enough to keep things clean\n\t\t\t// but will be thorough\n\t\t\to.L = nullptr;\n\t\t\to.index = 0;\n\t\t\to.stacktop = 0;\n\t\t\treturn *this;\n\t\t}\n\n\t\titerator begin() {\n\t\t\treturn iterator(L, index, stacktop + 1);\n\t\t}\n\t\titerator end() {\n\t\t\treturn iterator(L, stacktop + 1, stacktop + 1);\n\t\t}\n\t\tconst_iterator begin() const {\n\t\t\treturn const_iterator(L, index, stacktop + 1);\n\t\t}\n\t\tconst_iterator end() const {\n\t\t\treturn const_iterator(L, stacktop + 1, stacktop + 1);\n\t\t}\n\t\tconst_iterator cbegin() const {\n\t\t\treturn begin();\n\t\t}\n\t\tconst_iterator cend() const {\n\t\t\treturn end();\n\t\t}\n\n\t\treverse_iterator rbegin() {\n\t\t\treturn std::reverse_iterator<iterator>(begin());\n\t\t}\n\t\treverse_iterator rend() {\n\t\t\treturn std::reverse_iterator<iterator>(end());\n\t\t}\n\t\tconst_reverse_iterator rbegin() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(begin());\n\t\t}\n\t\tconst_reverse_iterator rend() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(end());\n\t\t}\n\t\tconst_reverse_iterator crbegin() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(cbegin());\n\t\t}\n\t\tconst_reverse_iterator crend() const {\n\t\t\treturn std::reverse_iterator<const_iterator>(cend());\n\t\t}\n\n\t\tint push() const {\n\t\t\treturn push(L);\n\t\t}\n\n\t\tint push(lua_State* target) const {\n\t\t\tint pushcount = 0;\n\t\t\tfor (int i = index; i <= stacktop; ++i) {\n\t\t\t\tlua_pushvalue(L, i);\n\t\t\t\tpushcount += 1;\n\t\t\t}\n\t\t\tif (target != L) {\n\t\t\t\tlua_xmove(L, target, pushcount);\n\t\t\t}\n\t\t\treturn pushcount;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tdecltype(auto) get(difference_type index_offset = 0) const {\n\t\t\treturn stack::get<T>(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\ttype get_type(difference_type index_offset = 0) const noexcept {\n\t\t\treturn type_of(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\tstack_proxy operator[](difference_type index_offset) const {\n\t\t\treturn stack_proxy(L, index + static_cast<int>(index_offset));\n\t\t}\n\n\t\tlua_State* lua_state() const {\n\t\t\treturn L;\n\t\t};\n\t\tint stack_index() const {\n\t\t\treturn index;\n\t\t};\n\t\tint leftover_count() const {\n\t\t\treturn stacktop - (index - 1);\n\t\t}\n\t\tstd::size_t size() const {\n\t\t\treturn static_cast<std::size_t>(leftover_count());\n\t\t}\n\t\tint top() const {\n\t\t\treturn stacktop;\n\t\t}\n\t};\n\n\tnamespace stack {\n\t\ttemplate <>\n\t\tstruct unqualified_getter<variadic_args> {\n\t\t\tstatic variadic_args get(lua_State* L, int index, record& tracking) {\n\t\t\t\ttracking.last = 0;\n\t\t\t\treturn variadic_args(L, index);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<variadic_args> {\n\t\t\tstatic int push(lua_State* L, const variadic_args& ref) {\n\t\t\t\treturn ref.push(L);\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/variadic_args.hpp\n\n// beginning of sol/variadic_results.hpp\n\n// beginning of sol/as_returns.hpp\n\nnamespace sol {\n\ttemplate <typename T>\n\tstruct as_returns_t {\n\t\tT src;\n\t};\n\n\ttemplate <typename Source>\n\tauto as_returns(Source&& source) {\n\t\treturn as_returns_t<std::decay_t<Source>>{ std::forward<Source>(source) };\n\t}\n\n\tnamespace stack {\n\t\ttemplate <typename T>\n\t\tstruct unqualified_pusher<as_returns_t<T>> {\n\t\t\tint push(lua_State* L, const as_returns_t<T>& e) {\n\t\t\t\tauto& src = detail::unwrap(e.src);\n\t\t\t\tint p = 0;\n\t\t\t\tfor (const auto& i : src) {\n\t\t\t\t\tp += stack::push(L, i);\n\t\t\t\t}\n\t\t\t\treturn p;\n\t\t\t}\n\t\t};\n\t} // namespace stack\n} // namespace sol\n\n// end of sol/as_returns.hpp\n\n#include <vector>\n\nnamespace sol {\n\n\ttemplate <typename Al = typename std::allocator<object>>\n\tstruct basic_variadic_results : public std::vector<object, Al> {\n\tprivate:\n\t\tusing base_t = std::vector<object, Al>;\n\n\tpublic:\n\t\tbasic_variadic_results() : base_t() {\n\t\t}\n\n\t\tbasic_variadic_results(unsafe_function_result fr) : base_t() {\n\t\t\tthis->reserve(fr.return_count());\n\t\t\tthis->insert(this->cend(), fr.begin(), fr.end());\n\t\t}\n\n\t\tbasic_variadic_results(protected_function_result fr) : base_t() {\n\t\t\tthis->reserve(fr.return_count());\n\t\t\tthis->insert(this->cend(), fr.begin(), fr.end());\n\t\t}\n\n\t\ttemplate <typename Arg0, typename... Args,\n\t\t     meta::disable_any<std::is_same<meta::unqualified_t<Arg0>, basic_variadic_results>, std::is_same<meta::unqualified_t<Arg0>, function_result>,\n\t\t          std::is_same<meta::unqualified_t<Arg0>, protected_function_result>> = meta::enabler>\n\t\tbasic_variadic_results(Arg0&& arg0, Args&&... args) : base_t(std::forward<Arg0>(arg0), std::forward<Args>(args)...) {\n\t\t}\n\n\t\tbasic_variadic_results(const basic_variadic_results&) = default;\n\t\tbasic_variadic_results(basic_variadic_results&&) = default;\n\t};\n\n\tstruct variadic_results : public basic_variadic_results<> {\n\tprivate:\n\t\tusing base_t = basic_variadic_results<>;\n\n\tpublic:\n\t\tusing base_t::base_t;\n\t};\n\n\ttemplate <typename Al>\n\tstruct is_container<basic_variadic_results<Al>> : std::false_type { };\n\n\ttemplate <>\n\tstruct is_container<variadic_results> : std::false_type { };\n\n\tnamespace stack {\n\t\ttemplate <typename Al>\n\t\tstruct unqualified_pusher<basic_variadic_results<Al>> {\n\t\t\tint push(lua_State* L, const basic_variadic_results<Al>& e) {\n\t\t\t\tint p = 0;\n\t\t\t\tfor (const auto& i : e) {\n\t\t\t\t\tp += stack::push(L, i);\n\t\t\t\t}\n\t\t\t\treturn p;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <>\n\t\tstruct unqualified_pusher<variadic_results> {\n\t\t\tint push(lua_State* L, const variadic_results& r) {\n\t\t\t\tusing base_t = basic_variadic_results<>;\n\t\t\t\treturn stack::push(L, static_cast<const base_t&>(r));\n\t\t\t}\n\t\t};\n\t} // namespace stack\n\n} // namespace sol\n\n// end of sol/variadic_results.hpp\n\n#if SOL_IS_ON(SOL_COMPILER_GCC_I_)\n#pragma GCC diagnostic pop\n#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)\n#pragma warning(pop)\n#endif // g++\n\n#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE_I_)\n#undef check\n#pragma pop_macro(\"check\")\n#endif // Unreal Engine 4 Bullshit\n\n#endif // SOL_HPP\n// end of sol/sol.hpp\n\n#endif // SOL_SINGLE_INCLUDE_HPP\n"
  },
  {
    "path": "deps/stb/CMakeLists.txt",
    "content": "add_library(stb INTERFACE EXCLUDE_FROM_ALL)\ntarget_include_directories(stb INTERFACE .)\n\n"
  },
  {
    "path": "deps/stb/stb_rect_pack.h",
    "content": "// stb_rect_pack.h - v1.01 - public domain - rectangle packing\n// Sean Barrett 2014\n//\n// Useful for e.g. packing rectangular textures into an atlas.\n// Does not do rotation.\n//\n// Before #including,\n//\n//    #define STB_RECT_PACK_IMPLEMENTATION\n//\n// in the file that you want to have the implementation.\n//\n// Not necessarily the awesomest packing method, but better than\n// the totally naive one in stb_truetype (which is primarily what\n// this is meant to replace).\n//\n// Has only had a few tests run, may have issues.\n//\n// More docs to come.\n//\n// No memory allocations; uses qsort() and assert() from stdlib.\n// Can override those by defining STBRP_SORT and STBRP_ASSERT.\n//\n// This library currently uses the Skyline Bottom-Left algorithm.\n//\n// Please note: better rectangle packers are welcome! Please\n// implement them to the same API, but with a different init\n// function.\n//\n// Credits\n//\n//  Library\n//    Sean Barrett\n//  Minor features\n//    Martins Mozeiko\n//    github:IntellectualKitty\n//\n//  Bugfixes / warning fixes\n//    Jeremy Jaussaud\n//    Fabian Giesen\n//\n// Version history:\n//\n//     1.01  (2021-07-11)  always use large rect mode, expose STBRP__MAXVAL in public section\n//     1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles\n//     0.99  (2019-02-07)  warning fixes\n//     0.11  (2017-03-03)  return packing success/fail result\n//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings\n//     0.09  (2016-08-27)  fix compiler warnings\n//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)\n//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)\n//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort\n//     0.05:  added STBRP_ASSERT to allow replacing assert\n//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support\n//     0.01:  initial release\n//\n// LICENSE\n//\n//   See end of file for license information.\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//       INCLUDE SECTION\n//\n\n#ifndef STB_INCLUDE_STB_RECT_PACK_H\n#define STB_INCLUDE_STB_RECT_PACK_H\n\n#define STB_RECT_PACK_VERSION  1\n\n#ifdef STBRP_STATIC\n#define STBRP_DEF static\n#else\n#define STBRP_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct stbrp_context stbrp_context;\ntypedef struct stbrp_node    stbrp_node;\ntypedef struct stbrp_rect    stbrp_rect;\n\ntypedef int            stbrp_coord;\n\n#define STBRP__MAXVAL  0x7fffffff\n// Mostly for internal use, but this is the maximum supported coordinate value.\n\nSTBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);\n// Assign packed locations to rectangles. The rectangles are of type\n// 'stbrp_rect' defined below, stored in the array 'rects', and there\n// are 'num_rects' many of them.\n//\n// Rectangles which are successfully packed have the 'was_packed' flag\n// set to a non-zero value and 'x' and 'y' store the minimum location\n// on each axis (i.e. bottom-left in cartesian coordinates, top-left\n// if you imagine y increasing downwards). Rectangles which do not fit\n// have the 'was_packed' flag set to 0.\n//\n// You should not try to access the 'rects' array from another thread\n// while this function is running, as the function temporarily reorders\n// the array while it executes.\n//\n// To pack into another rectangle, you need to call stbrp_init_target\n// again. To continue packing into the same rectangle, you can call\n// this function again. Calling this multiple times with multiple rect\n// arrays will probably produce worse packing results than calling it\n// a single time with the full rectangle array, but the option is\n// available.\n//\n// The function returns 1 if all of the rectangles were successfully\n// packed and 0 otherwise.\n\nstruct stbrp_rect\n{\n   // reserved for your use:\n   int            id;\n\n   // input:\n   stbrp_coord    w, h;\n\n   // output:\n   stbrp_coord    x, y;\n   int            was_packed;  // non-zero if valid packing\n\n}; // 16 bytes, nominally\n\n\nSTBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);\n// Initialize a rectangle packer to:\n//    pack a rectangle that is 'width' by 'height' in dimensions\n//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long\n//\n// You must call this function every time you start packing into a new target.\n//\n// There is no \"shutdown\" function. The 'nodes' memory must stay valid for\n// the following stbrp_pack_rects() call (or calls), but can be freed after\n// the call (or calls) finish.\n//\n// Note: to guarantee best results, either:\n//       1. make sure 'num_nodes' >= 'width'\n//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'\n//\n// If you don't do either of the above things, widths will be quantized to multiples\n// of small integers to guarantee the algorithm doesn't run out of temporary storage.\n//\n// If you do #2, then the non-quantized algorithm will be used, but the algorithm\n// may run out of temporary storage and be unable to pack some rectangles.\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);\n// Optionally call this function after init but before doing any packing to\n// change the handling of the out-of-temp-memory scenario, described above.\n// If you call init again, this will be reset to the default (false).\n\n\nSTBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);\n// Optionally select which packing heuristic the library should use. Different\n// heuristics will produce better/worse results for different data sets.\n// If you call init again, this will be reset to the default.\n\nenum\n{\n   STBRP_HEURISTIC_Skyline_default=0,\n   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,\n   STBRP_HEURISTIC_Skyline_BF_sortHeight\n};\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// the details of the following structures don't matter to you, but they must\n// be visible so you can handle the memory allocations for them\n\nstruct stbrp_node\n{\n   stbrp_coord  x,y;\n   stbrp_node  *next;\n};\n\nstruct stbrp_context\n{\n   int width;\n   int height;\n   int align;\n   int init_mode;\n   int heuristic;\n   int num_nodes;\n   stbrp_node *active_head;\n   stbrp_node *free_head;\n   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//     IMPLEMENTATION SECTION\n//\n\n#ifdef STB_RECT_PACK_IMPLEMENTATION\n#ifndef STBRP_SORT\n#include <stdlib.h>\n#define STBRP_SORT qsort\n#endif\n\n#ifndef STBRP_ASSERT\n#include <assert.h>\n#define STBRP_ASSERT assert\n#endif\n\n#ifdef _MSC_VER\n#define STBRP__NOTUSED(v)  (void)(v)\n#define STBRP__CDECL       __cdecl\n#else\n#define STBRP__NOTUSED(v)  (void)sizeof(v)\n#define STBRP__CDECL\n#endif\n\nenum\n{\n   STBRP__INIT_skyline = 1\n};\n\nSTBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)\n{\n   switch (context->init_mode) {\n      case STBRP__INIT_skyline:\n         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);\n         context->heuristic = heuristic;\n         break;\n      default:\n         STBRP_ASSERT(0);\n   }\n}\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)\n{\n   if (allow_out_of_mem)\n      // if it's ok to run out of memory, then don't bother aligning them;\n      // this gives better packing, but may fail due to OOM (even though\n      // the rectangles easily fit). @TODO a smarter approach would be to only\n      // quantize once we've hit OOM, then we could get rid of this parameter.\n      context->align = 1;\n   else {\n      // if it's not ok to run out of memory, then quantize the widths\n      // so that num_nodes is always enough nodes.\n      //\n      // I.e. num_nodes * align >= width\n      //                  align >= width / num_nodes\n      //                  align = ceil(width/num_nodes)\n\n      context->align = (context->width + context->num_nodes-1) / context->num_nodes;\n   }\n}\n\nSTBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)\n{\n   int i;\n\n   for (i=0; i < num_nodes-1; ++i)\n      nodes[i].next = &nodes[i+1];\n   nodes[i].next = NULL;\n   context->init_mode = STBRP__INIT_skyline;\n   context->heuristic = STBRP_HEURISTIC_Skyline_default;\n   context->free_head = &nodes[0];\n   context->active_head = &context->extra[0];\n   context->width = width;\n   context->height = height;\n   context->num_nodes = num_nodes;\n   stbrp_setup_allow_out_of_mem(context, 0);\n\n   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)\n   context->extra[0].x = 0;\n   context->extra[0].y = 0;\n   context->extra[0].next = &context->extra[1];\n   context->extra[1].x = (stbrp_coord) width;\n   context->extra[1].y = (1<<30);\n   context->extra[1].next = NULL;\n}\n\n// find minimum y position if it starts at x1\nstatic int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)\n{\n   stbrp_node *node = first;\n   int x1 = x0 + width;\n   int min_y, visited_width, waste_area;\n\n   STBRP__NOTUSED(c);\n\n   STBRP_ASSERT(first->x <= x0);\n\n   #if 0\n   // skip in case we're past the node\n   while (node->next->x <= x0)\n      ++node;\n   #else\n   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency\n   #endif\n\n   STBRP_ASSERT(node->x <= x0);\n\n   min_y = 0;\n   waste_area = 0;\n   visited_width = 0;\n   while (node->x < x1) {\n      if (node->y > min_y) {\n         // raise min_y higher.\n         // we've accounted for all waste up to min_y,\n         // but we'll now add more waste for everything we've visted\n         waste_area += visited_width * (node->y - min_y);\n         min_y = node->y;\n         // the first time through, visited_width might be reduced\n         if (node->x < x0)\n            visited_width += node->next->x - x0;\n         else\n            visited_width += node->next->x - node->x;\n      } else {\n         // add waste area\n         int under_width = node->next->x - node->x;\n         if (under_width + visited_width > width)\n            under_width = width - visited_width;\n         waste_area += under_width * (min_y - node->y);\n         visited_width += under_width;\n      }\n      node = node->next;\n   }\n\n   *pwaste = waste_area;\n   return min_y;\n}\n\ntypedef struct\n{\n   int x,y;\n   stbrp_node **prev_link;\n} stbrp__findresult;\n\nstatic stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)\n{\n   int best_waste = (1<<30), best_x, best_y = (1 << 30);\n   stbrp__findresult fr;\n   stbrp_node **prev, *node, *tail, **best = NULL;\n\n   // align to multiple of c->align\n   width = (width + c->align - 1);\n   width -= width % c->align;\n   STBRP_ASSERT(width % c->align == 0);\n\n   // if it can't possibly fit, bail immediately\n   if (width > c->width || height > c->height) {\n      fr.prev_link = NULL;\n      fr.x = fr.y = 0;\n      return fr;\n   }\n\n   node = c->active_head;\n   prev = &c->active_head;\n   while (node->x + width <= c->width) {\n      int y,waste;\n      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);\n      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL\n         // bottom left\n         if (y < best_y) {\n            best_y = y;\n            best = prev;\n         }\n      } else {\n         // best-fit\n         if (y + height <= c->height) {\n            // can only use it if it first vertically\n            if (y < best_y || (y == best_y && waste < best_waste)) {\n               best_y = y;\n               best_waste = waste;\n               best = prev;\n            }\n         }\n      }\n      prev = &node->next;\n      node = node->next;\n   }\n\n   best_x = (best == NULL) ? 0 : (*best)->x;\n\n   // if doing best-fit (BF), we also have to try aligning right edge to each node position\n   //\n   // e.g, if fitting\n   //\n   //     ____________________\n   //    |____________________|\n   //\n   //            into\n   //\n   //   |                         |\n   //   |             ____________|\n   //   |____________|\n   //\n   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned\n   //\n   // This makes BF take about 2x the time\n\n   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {\n      tail = c->active_head;\n      node = c->active_head;\n      prev = &c->active_head;\n      // find first node that's admissible\n      while (tail->x < width)\n         tail = tail->next;\n      while (tail) {\n         int xpos = tail->x - width;\n         int y,waste;\n         STBRP_ASSERT(xpos >= 0);\n         // find the left position that matches this\n         while (node->next->x <= xpos) {\n            prev = &node->next;\n            node = node->next;\n         }\n         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);\n         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);\n         if (y + height <= c->height) {\n            if (y <= best_y) {\n               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {\n                  best_x = xpos;\n                  STBRP_ASSERT(y <= best_y);\n                  best_y = y;\n                  best_waste = waste;\n                  best = prev;\n               }\n            }\n         }\n         tail = tail->next;\n      }\n   }\n\n   fr.prev_link = best;\n   fr.x = best_x;\n   fr.y = best_y;\n   return fr;\n}\n\nstatic stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)\n{\n   // find best position according to heuristic\n   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);\n   stbrp_node *node, *cur;\n\n   // bail if:\n   //    1. it failed\n   //    2. the best node doesn't fit (we don't always check this)\n   //    3. we're out of memory\n   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {\n      res.prev_link = NULL;\n      return res;\n   }\n\n   // on success, create new node\n   node = context->free_head;\n   node->x = (stbrp_coord) res.x;\n   node->y = (stbrp_coord) (res.y + height);\n\n   context->free_head = node->next;\n\n   // insert the new node into the right starting point, and\n   // let 'cur' point to the remaining nodes needing to be\n   // stiched back in\n\n   cur = *res.prev_link;\n   if (cur->x < res.x) {\n      // preserve the existing one, so start testing with the next one\n      stbrp_node *next = cur->next;\n      cur->next = node;\n      cur = next;\n   } else {\n      *res.prev_link = node;\n   }\n\n   // from here, traverse cur and free the nodes, until we get to one\n   // that shouldn't be freed\n   while (cur->next && cur->next->x <= res.x + width) {\n      stbrp_node *next = cur->next;\n      // move the current node to the free list\n      cur->next = context->free_head;\n      context->free_head = cur;\n      cur = next;\n   }\n\n   // stitch the list back in\n   node->next = cur;\n\n   if (cur->x < res.x + width)\n      cur->x = (stbrp_coord) (res.x + width);\n\n#ifdef _DEBUG\n   cur = context->active_head;\n   while (cur->x < context->width) {\n      STBRP_ASSERT(cur->x < cur->next->x);\n      cur = cur->next;\n   }\n   STBRP_ASSERT(cur->next == NULL);\n\n   {\n      int count=0;\n      cur = context->active_head;\n      while (cur) {\n         cur = cur->next;\n         ++count;\n      }\n      cur = context->free_head;\n      while (cur) {\n         cur = cur->next;\n         ++count;\n      }\n      STBRP_ASSERT(count == context->num_nodes+2);\n   }\n#endif\n\n   return res;\n}\n\nstatic int STBRP__CDECL rect_height_compare(const void *a, const void *b)\n{\n   const stbrp_rect *p = (const stbrp_rect *) a;\n   const stbrp_rect *q = (const stbrp_rect *) b;\n   if (p->h > q->h)\n      return -1;\n   if (p->h < q->h)\n      return  1;\n   return (p->w > q->w) ? -1 : (p->w < q->w);\n}\n\nstatic int STBRP__CDECL rect_original_order(const void *a, const void *b)\n{\n   const stbrp_rect *p = (const stbrp_rect *) a;\n   const stbrp_rect *q = (const stbrp_rect *) b;\n   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);\n}\n\nSTBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)\n{\n   int i, all_rects_packed = 1;\n\n   // we use the 'was_packed' field internally to allow sorting/unsorting\n   for (i=0; i < num_rects; ++i) {\n      rects[i].was_packed = i;\n   }\n\n   // sort according to heuristic\n   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);\n\n   for (i=0; i < num_rects; ++i) {\n      if (rects[i].w == 0 || rects[i].h == 0) {\n         rects[i].x = rects[i].y = 0;  // empty rect needs no space\n      } else {\n         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);\n         if (fr.prev_link) {\n            rects[i].x = (stbrp_coord) fr.x;\n            rects[i].y = (stbrp_coord) fr.y;\n         } else {\n            rects[i].x = rects[i].y = STBRP__MAXVAL;\n         }\n      }\n   }\n\n   // unsort\n   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);\n\n   // set was_packed flags and all_rects_packed status\n   for (i=0; i < num_rects; ++i) {\n      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);\n      if (!rects[i].was_packed)\n         all_rects_packed = 0;\n   }\n\n   // return the all_rects_packed status\n   return all_rects_packed;\n}\n#endif\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "deps/stb/stb_truetype.h",
    "content": "// stb_truetype.h - v1.26 - public domain\n// authored from 2009-2021 by Sean Barrett / RAD Game Tools\n//\n// =======================================================================\n//\n//    NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES\n//\n// This library does no range checking of the offsets found in the file,\n// meaning an attacker can use it to read arbitrary memory.\n//\n// =======================================================================\n//\n//   This library processes TrueType files:\n//        parse files\n//        extract glyph metrics\n//        extract glyph shapes\n//        render glyphs to one-channel bitmaps with antialiasing (box filter)\n//        render glyphs to one-channel SDF bitmaps (signed-distance field/function)\n//\n//   Todo:\n//        non-MS cmaps\n//        crashproof on bad data\n//        hinting? (no longer patented)\n//        cleartype-style AA?\n//        optimize: use simple memory allocator for intermediates\n//        optimize: build edge-list directly from curves\n//        optimize: rasterize directly from curves?\n//\n// ADDITIONAL CONTRIBUTORS\n//\n//   Mikko Mononen: compound shape support, more cmap formats\n//   Tor Andersson: kerning, subpixel rendering\n//   Dougall Johnson: OpenType / Type 2 font handling\n//   Daniel Ribeiro Maciel: basic GPOS-based kerning\n//\n//   Misc other:\n//       Ryan Gordon\n//       Simon Glass\n//       github:IntellectualKitty\n//       Imanol Celaya\n//       Daniel Ribeiro Maciel\n//\n//   Bug/warning reports/fixes:\n//       \"Zer\" on mollyrocket       Fabian \"ryg\" Giesen   github:NiLuJe\n//       Cass Everitt               Martins Mozeiko       github:aloucks\n//       stoiko (Haemimont Games)   Cap Petschulat        github:oyvindjam\n//       Brian Hook                 Omar Cornut           github:vassvik\n//       Walter van Niftrik         Ryan Griege\n//       David Gow                  Peter LaValle\n//       David Given                Sergey Popov\n//       Ivan-Assen Ivanov          Giumo X. Clanjor\n//       Anthony Pesch              Higor Euripedes\n//       Johan Duparc               Thomas Fields\n//       Hou Qiming                 Derek Vinyard\n//       Rob Loach                  Cort Stratton\n//       Kenney Phillis Jr.         Brian Costabile\n//       Ken Voskuil (kaesve)\n//\n// VERSION HISTORY\n//\n//   1.26 (2021-08-28) fix broken rasterizer\n//   1.25 (2021-07-11) many fixes\n//   1.24 (2020-02-05) fix warning\n//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)\n//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined\n//   1.21 (2019-02-25) fix warning\n//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()\n//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod\n//   1.18 (2018-01-29) add missing function\n//   1.17 (2017-07-23) make more arguments const; doc fix\n//   1.16 (2017-07-12) SDF support\n//   1.15 (2017-03-03) make more arguments const\n//   1.14 (2017-01-16) num-fonts-in-TTC function\n//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts\n//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual\n//   1.11 (2016-04-02) fix unused-variable warning\n//   1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef\n//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly\n//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges\n//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;\n//                     variant PackFontRanges to pack and render in separate phases;\n//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);\n//                     fixed an assert() bug in the new rasterizer\n//                     replace assert() with STBTT_assert() in new rasterizer\n//\n//   Full history can be found at the end of this file.\n//\n// LICENSE\n//\n//   See end of file for license information.\n//\n// USAGE\n//\n//   Include this file in whatever places need to refer to it. In ONE C/C++\n//   file, write:\n//      #define STB_TRUETYPE_IMPLEMENTATION\n//   before the #include of this file. This expands out the actual\n//   implementation into that C/C++ file.\n//\n//   To make the implementation private to the file that generates the implementation,\n//      #define STBTT_STATIC\n//\n//   Simple 3D API (don't ship this, but it's fine for tools and quick start)\n//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture\n//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char\n//\n//   Improved 3D API (more shippable):\n//           #include \"stb_rect_pack.h\"           -- optional, but you really want it\n//           stbtt_PackBegin()\n//           stbtt_PackSetOversampling()          -- for improved quality on small fonts\n//           stbtt_PackFontRanges()               -- pack and renders\n//           stbtt_PackEnd()\n//           stbtt_GetPackedQuad()\n//\n//   \"Load\" a font file from a memory buffer (you have to keep the buffer loaded)\n//           stbtt_InitFont()\n//           stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections\n//           stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections\n//\n//   Render a unicode codepoint to a bitmap\n//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap\n//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide\n//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be\n//\n//   Character advance/positioning\n//           stbtt_GetCodepointHMetrics()\n//           stbtt_GetFontVMetrics()\n//           stbtt_GetFontVMetricsOS2()\n//           stbtt_GetCodepointKernAdvance()\n//\n//   Starting with version 1.06, the rasterizer was replaced with a new,\n//   faster and generally-more-precise rasterizer. The new rasterizer more\n//   accurately measures pixel coverage for anti-aliasing, except in the case\n//   where multiple shapes overlap, in which case it overestimates the AA pixel\n//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If\n//   this turns out to be a problem, you can re-enable the old rasterizer with\n//        #define STBTT_RASTERIZER_VERSION 1\n//   which will incur about a 15% speed hit.\n//\n// ADDITIONAL DOCUMENTATION\n//\n//   Immediately after this block comment are a series of sample programs.\n//\n//   After the sample programs is the \"header file\" section. This section\n//   includes documentation for each API function.\n//\n//   Some important concepts to understand to use this library:\n//\n//      Codepoint\n//         Characters are defined by unicode codepoints, e.g. 65 is\n//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is\n//         the hiragana for \"ma\".\n//\n//      Glyph\n//         A visual character shape (every codepoint is rendered as\n//         some glyph)\n//\n//      Glyph index\n//         A font-specific integer ID representing a glyph\n//\n//      Baseline\n//         Glyph shapes are defined relative to a baseline, which is the\n//         bottom of uppercase characters. Characters extend both above\n//         and below the baseline.\n//\n//      Current Point\n//         As you draw text to the screen, you keep track of a \"current point\"\n//         which is the origin of each character. The current point's vertical\n//         position is the baseline. Even \"baked fonts\" use this model.\n//\n//      Vertical Font Metrics\n//         The vertical qualities of the font, used to vertically position\n//         and space the characters. See docs for stbtt_GetFontVMetrics.\n//\n//      Font Size in Pixels or Points\n//         The preferred interface for specifying font sizes in stb_truetype\n//         is to specify how tall the font's vertical extent should be in pixels.\n//         If that sounds good enough, skip the next paragraph.\n//\n//         Most font APIs instead use \"points\", which are a common typographic\n//         measurement for describing font size, defined as 72 points per inch.\n//         stb_truetype provides a point API for compatibility. However, true\n//         \"per inch\" conventions don't make much sense on computer displays\n//         since different monitors have different number of pixels per\n//         inch. For example, Windows traditionally uses a convention that\n//         there are 96 pixels per inch, thus making 'inch' measurements have\n//         nothing to do with inches, and thus effectively defining a point to\n//         be 1.333 pixels. Additionally, the TrueType font data provides\n//         an explicit scale factor to scale a given font's glyphs to points,\n//         but the author has observed that this scale factor is often wrong\n//         for non-commercial fonts, thus making fonts scaled in points\n//         according to the TrueType spec incoherently sized in practice.\n//\n// DETAILED USAGE:\n//\n//  Scale:\n//    Select how high you want the font to be, in points or pixels.\n//    Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute\n//    a scale factor SF that will be used by all other functions.\n//\n//  Baseline:\n//    You need to select a y-coordinate that is the baseline of where\n//    your text will appear. Call GetFontBoundingBox to get the baseline-relative\n//    bounding box for all characters. SF*-y0 will be the distance in pixels\n//    that the worst-case character could extend above the baseline, so if\n//    you want the top edge of characters to appear at the top of the\n//    screen where y=0, then you would set the baseline to SF*-y0.\n//\n//  Current point:\n//    Set the current point where the first character will appear. The\n//    first character could extend left of the current point; this is font\n//    dependent. You can either choose a current point that is the leftmost\n//    point and hope, or add some padding, or check the bounding box or\n//    left-side-bearing of the first character to be displayed and set\n//    the current point based on that.\n//\n//  Displaying a character:\n//    Compute the bounding box of the character. It will contain signed values\n//    relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,\n//    then the character should be displayed in the rectangle from\n//    <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).\n//\n//  Advancing for the next character:\n//    Call GlyphHMetrics, and compute 'current_point += SF * advance'.\n//\n//\n// ADVANCED USAGE\n//\n//   Quality:\n//\n//    - Use the functions with Subpixel at the end to allow your characters\n//      to have subpixel positioning. Since the font is anti-aliased, not\n//      hinted, this is very import for quality. (This is not possible with\n//      baked fonts.)\n//\n//    - Kerning is now supported, and if you're supporting subpixel rendering\n//      then kerning is worth using to give your text a polished look.\n//\n//   Performance:\n//\n//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;\n//      if you don't do this, stb_truetype is forced to do the conversion on\n//      every call.\n//\n//    - There are a lot of memory allocations. We should modify it to take\n//      a temp buffer and allocate from the temp buffer (without freeing),\n//      should help performance a lot.\n//\n// NOTES\n//\n//   The system uses the raw data found in the .ttf file without changing it\n//   and without building auxiliary data structures. This is a bit inefficient\n//   on little-endian systems (the data is big-endian), but assuming you're\n//   caching the bitmaps or glyph shapes this shouldn't be a big deal.\n//\n//   It appears to be very hard to programmatically determine what font a\n//   given file is in a general way. I provide an API for this, but I don't\n//   recommend it.\n//\n//\n// PERFORMANCE MEASUREMENTS FOR 1.06:\n//\n//                      32-bit     64-bit\n//   Previous release:  8.83 s     7.68 s\n//   Pool allocations:  7.72 s     6.34 s\n//   Inline sort     :  6.54 s     5.65 s\n//   New rasterizer  :  5.63 s     5.00 s\n\n//////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////\n////\n////  SAMPLE PROGRAMS\n////\n//\n//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.\n//  See \"tests/truetype_demo_win32.c\" for a complete version.\n#if 0\n#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation\n#include \"stb_truetype.h\"\n\nunsigned char ttf_buffer[1<<20];\nunsigned char temp_bitmap[512*512];\n\nstbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs\nGLuint ftex;\n\nvoid my_stbtt_initfont(void)\n{\n   fread(ttf_buffer, 1, 1<<20, fopen(\"c:/windows/fonts/times.ttf\", \"rb\"));\n   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!\n   // can free ttf_buffer at this point\n   glGenTextures(1, &ftex);\n   glBindTexture(GL_TEXTURE_2D, ftex);\n   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);\n   // can free temp_bitmap at this point\n   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n}\n\nvoid my_stbtt_print(float x, float y, char *text)\n{\n   // assume orthographic projection with units = screen pixels, origin at top left\n   glEnable(GL_BLEND);\n   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n   glEnable(GL_TEXTURE_2D);\n   glBindTexture(GL_TEXTURE_2D, ftex);\n   glBegin(GL_QUADS);\n   while (*text) {\n      if (*text >= 32 && *text < 128) {\n         stbtt_aligned_quad q;\n         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9\n         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);\n         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);\n         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);\n         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);\n      }\n      ++text;\n   }\n   glEnd();\n}\n#endif\n//\n//\n//////////////////////////////////////////////////////////////////////////////\n//\n// Complete program (this compiles): get a single bitmap, print as ASCII art\n//\n#if 0\n#include <stdio.h>\n#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation\n#include \"stb_truetype.h\"\n\nchar ttf_buffer[1<<25];\n\nint main(int argc, char **argv)\n{\n   stbtt_fontinfo font;\n   unsigned char *bitmap;\n   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);\n\n   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : \"c:/windows/fonts/arialbd.ttf\", \"rb\"));\n\n   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));\n   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);\n\n   for (j=0; j < h; ++j) {\n      for (i=0; i < w; ++i)\n         putchar(\" .:ioVM@\"[bitmap[j*w+i]>>5]);\n      putchar('\\n');\n   }\n   return 0;\n}\n#endif\n//\n// Output:\n//\n//     .ii.\n//    @@@@@@.\n//   V@Mio@@o\n//   :i.  V@V\n//     :oM@@M\n//   :@@@MM@M\n//   @@o  o@M\n//  :@@.  M@M\n//   @@@o@@@@\n//   :M@@V:@@.\n//\n//////////////////////////////////////////////////////////////////////////////\n//\n// Complete program: print \"Hello World!\" banner, with bugs\n//\n#if 0\nchar buffer[24<<20];\nunsigned char screen[20][79];\n\nint main(int arg, char **argv)\n{\n   stbtt_fontinfo font;\n   int i,j,ascent,baseline,ch=0;\n   float scale, xpos=2; // leave a little padding in case the character extends left\n   char *text = \"Heljo World!\"; // intentionally misspelled to show 'lj' brokenness\n\n   fread(buffer, 1, 1000000, fopen(\"c:/windows/fonts/arialbd.ttf\", \"rb\"));\n   stbtt_InitFont(&font, buffer, 0);\n\n   scale = stbtt_ScaleForPixelHeight(&font, 15);\n   stbtt_GetFontVMetrics(&font, &ascent,0,0);\n   baseline = (int) (ascent*scale);\n\n   while (text[ch]) {\n      int advance,lsb,x0,y0,x1,y1;\n      float x_shift = xpos - (float) floor(xpos);\n      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);\n      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);\n      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);\n      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong\n      // because this API is really for baking character bitmaps into textures. if you want to render\n      // a sequence of characters, you really need to render each bitmap to a temp buffer, then\n      // \"alpha blend\" that into the working buffer\n      xpos += (advance * scale);\n      if (text[ch+1])\n         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);\n      ++ch;\n   }\n\n   for (j=0; j < 20; ++j) {\n      for (i=0; i < 78; ++i)\n         putchar(\" .:ioVM@\"[screen[j][i]>>5]);\n      putchar('\\n');\n   }\n\n   return 0;\n}\n#endif\n\n\n//////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////\n////\n////   INTEGRATION WITH YOUR CODEBASE\n////\n////   The following sections allow you to supply alternate definitions\n////   of C library functions used by stb_truetype, e.g. if you don't\n////   link with the C runtime library.\n\n#ifdef STB_TRUETYPE_IMPLEMENTATION\n   // #define your own (u)stbtt_int8/16/32 before including to override this\n   #ifndef stbtt_uint8\n   typedef unsigned char   stbtt_uint8;\n   typedef signed   char   stbtt_int8;\n   typedef unsigned short  stbtt_uint16;\n   typedef signed   short  stbtt_int16;\n   typedef unsigned int    stbtt_uint32;\n   typedef signed   int    stbtt_int32;\n   #endif\n\n   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];\n   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];\n\n   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h\n   #ifndef STBTT_ifloor\n   #include <math.h>\n   #define STBTT_ifloor(x)   ((int) floor(x))\n   #define STBTT_iceil(x)    ((int) ceil(x))\n   #endif\n\n   #ifndef STBTT_sqrt\n   #include <math.h>\n   #define STBTT_sqrt(x)      sqrt(x)\n   #define STBTT_pow(x,y)     pow(x,y)\n   #endif\n\n   #ifndef STBTT_fmod\n   #include <math.h>\n   #define STBTT_fmod(x,y)    fmod(x,y)\n   #endif\n\n   #ifndef STBTT_cos\n   #include <math.h>\n   #define STBTT_cos(x)       cos(x)\n   #define STBTT_acos(x)      acos(x)\n   #endif\n\n   #ifndef STBTT_fabs\n   #include <math.h>\n   #define STBTT_fabs(x)      fabs(x)\n   #endif\n\n   // #define your own functions \"STBTT_malloc\" / \"STBTT_free\" to avoid malloc.h\n   #ifndef STBTT_malloc\n   #include <stdlib.h>\n   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))\n   #define STBTT_free(x,u)    ((void)(u),free(x))\n   #endif\n\n   #ifndef STBTT_assert\n   #include <assert.h>\n   #define STBTT_assert(x)    assert(x)\n   #endif\n\n   #ifndef STBTT_strlen\n   #include <string.h>\n   #define STBTT_strlen(x)    strlen(x)\n   #endif\n\n   #ifndef STBTT_memcpy\n   #include <string.h>\n   #define STBTT_memcpy       memcpy\n   #define STBTT_memset       memset\n   #endif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n////\n////   INTERFACE\n////\n////\n\n#ifndef __STB_INCLUDE_STB_TRUETYPE_H__\n#define __STB_INCLUDE_STB_TRUETYPE_H__\n\n#ifdef STBTT_STATIC\n#define STBTT_DEF static\n#else\n#define STBTT_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// private structure\ntypedef struct\n{\n   unsigned char *data;\n   int cursor;\n   int size;\n} stbtt__buf;\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// TEXTURE BAKING API\n//\n// If you use this API, you only have to call two functions ever.\n//\n\ntypedef struct\n{\n   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap\n   float xoff,yoff,xadvance;\n} stbtt_bakedchar;\n\nSTBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)\n                                float pixel_height,                     // height of font in pixels\n                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in\n                                int first_char, int num_chars,          // characters to bake\n                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long\n// if return is positive, the first unused row of the bitmap\n// if return is negative, returns the negative of the number of characters that fit\n// if return is 0, no characters fit and no rows were used\n// This uses a very crappy packing.\n\ntypedef struct\n{\n   float x0,y0,s0,t0; // top-left\n   float x1,y1,s1,t1; // bottom-right\n} stbtt_aligned_quad;\n\nSTBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above\n                               int char_index,             // character to display\n                               float *xpos, float *ypos,   // pointers to current position in screen pixel space\n                               stbtt_aligned_quad *q,      // output: quad to draw\n                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier\n// Call GetBakedQuad with char_index = 'character - first_char', and it\n// creates the quad you need to draw and advances the current position.\n//\n// The coordinate system used assumes y increases downwards.\n//\n// Characters will extend both above and below the current position;\n// see discussion of \"BASELINE\" above.\n//\n// It's inefficient; you might want to c&p it and optimize it.\n\nSTBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);\n// Query the font vertical metrics without having to create a font first.\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// NEW TEXTURE BAKING API\n//\n// This provides options for packing multiple fonts into one atlas, not\n// perfectly but better than nothing.\n\ntypedef struct\n{\n   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap\n   float xoff,yoff,xadvance;\n   float xoff2,yoff2;\n} stbtt_packedchar;\n\ntypedef struct stbtt_pack_context stbtt_pack_context;\ntypedef struct stbtt_fontinfo stbtt_fontinfo;\n#ifndef STB_RECT_PACK_VERSION\ntypedef struct stbrp_rect stbrp_rect;\n#endif\n\nSTBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);\n// Initializes a packing context stored in the passed-in stbtt_pack_context.\n// Future calls using this context will pack characters into the bitmap passed\n// in here: a 1-channel bitmap that is width * height. stride_in_bytes is\n// the distance from one row to the next (or 0 to mean they are packed tightly\n// together). \"padding\" is the amount of padding to leave between each\n// character (normally you want '1' for bitmaps you'll use as textures with\n// bilinear filtering).\n//\n// Returns 0 on failure, 1 on success.\n\nSTBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);\n// Cleans up the packing context and frees all memory.\n\n#define STBTT_POINT_SIZE(x)   (-(x))\n\nSTBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,\n                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);\n// Creates character bitmaps from the font_index'th font found in fontdata (use\n// font_index=0 if you don't know what that is). It creates num_chars_in_range\n// bitmaps for characters with unicode values starting at first_unicode_char_in_range\n// and increasing. Data for how to render them is stored in chardata_for_range;\n// pass these to stbtt_GetPackedQuad to get back renderable quads.\n//\n// font_size is the full height of the character from ascender to descender,\n// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed\n// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()\n// and pass that result as 'font_size':\n//       ...,                  20 , ... // font max minus min y is 20 pixels tall\n//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall\n\ntypedef struct\n{\n   float font_size;\n   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint\n   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints\n   int num_chars;\n   stbtt_packedchar *chardata_for_range; // output\n   unsigned char h_oversample, v_oversample; // don't set these, they're used internally\n} stbtt_pack_range;\n\nSTBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);\n// Creates character bitmaps from multiple ranges of characters stored in\n// ranges. This will usually create a better-packed bitmap than multiple\n// calls to stbtt_PackFontRange. Note that you can call this multiple\n// times within a single PackBegin/PackEnd.\n\nSTBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);\n// Oversampling a font increases the quality by allowing higher-quality subpixel\n// positioning, and is especially valuable at smaller text sizes.\n//\n// This function sets the amount of oversampling for all following calls to\n// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given\n// pack context. The default (no oversampling) is achieved by h_oversample=1\n// and v_oversample=1. The total number of pixels required is\n// h_oversample*v_oversample larger than the default; for example, 2x2\n// oversampling requires 4x the storage of 1x1. For best results, render\n// oversampled textures with bilinear filtering. Look at the readme in\n// stb/tests/oversample for information about oversampled fonts\n//\n// To use with PackFontRangesGather etc., you must set it before calls\n// call to PackFontRangesGatherRects.\n\nSTBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);\n// If skip != 0, this tells stb_truetype to skip any codepoints for which\n// there is no corresponding glyph. If skip=0, which is the default, then\n// codepoints without a glyph recived the font's \"missing character\" glyph,\n// typically an empty box by convention.\n\nSTBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above\n                               int char_index,             // character to display\n                               float *xpos, float *ypos,   // pointers to current position in screen pixel space\n                               stbtt_aligned_quad *q,      // output: quad to draw\n                               int align_to_integer);\n\nSTBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);\nSTBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);\nSTBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);\n// Calling these functions in sequence is roughly equivalent to calling\n// stbtt_PackFontRanges(). If you more control over the packing of multiple\n// fonts, or if you want to pack custom data into a font texture, take a look\n// at the source to of stbtt_PackFontRanges() and create a custom version\n// using these functions, e.g. call GatherRects multiple times,\n// building up a single array of rects, then call PackRects once,\n// then call RenderIntoRects repeatedly. This may result in a\n// better packing than calling PackFontRanges multiple times\n// (or it may not).\n\n// this is an opaque structure that you shouldn't mess with which holds\n// all the context needed from PackBegin to PackEnd.\nstruct stbtt_pack_context {\n   void *user_allocator_context;\n   void *pack_info;\n   int   width;\n   int   height;\n   int   stride_in_bytes;\n   int   padding;\n   int   skip_missing;\n   unsigned int   h_oversample, v_oversample;\n   unsigned char *pixels;\n   void  *nodes;\n};\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// FONT LOADING\n//\n//\n\nSTBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);\n// This function will determine the number of fonts in a font file.  TrueType\n// collection (.ttc) files may contain multiple fonts, while TrueType font\n// (.ttf) files only contain one font. The number of fonts can be used for\n// indexing with the previous function where the index is between zero and one\n// less than the total fonts. If an error occurs, -1 is returned.\n\nSTBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);\n// Each .ttf/.ttc file may have more than one font. Each font has a sequential\n// index number starting from 0. Call this function to get the font offset for\n// a given index; it returns -1 if the index is out of range. A regular .ttf\n// file will only define one font and it always be at offset 0, so it will\n// return '0' for index 0, and -1 for all other indices.\n\n// The following structure is defined publicly so you can declare one on\n// the stack or as a global or etc, but you should treat it as opaque.\nstruct stbtt_fontinfo\n{\n   void           * userdata;\n   unsigned char  * data;              // pointer to .ttf file\n   int              fontstart;         // offset of start of font\n\n   int numGlyphs;                     // number of glyphs, needed for range checking\n\n   int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf\n   int index_map;                     // a cmap mapping for our chosen character encoding\n   int indexToLocFormat;              // format needed to map from glyph index to glyph\n\n   stbtt__buf cff;                    // cff font data\n   stbtt__buf charstrings;            // the charstring index\n   stbtt__buf gsubrs;                 // global charstring subroutines index\n   stbtt__buf subrs;                  // private charstring subroutines index\n   stbtt__buf fontdicts;              // array of font dicts\n   stbtt__buf fdselect;               // map from glyph to fontdict\n};\n\nSTBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);\n// Given an offset into the file that defines a font, this function builds\n// the necessary cached info for the rest of the system. You must allocate\n// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't\n// need to do anything special to free it, because the contents are pure\n// value data with no additional data structures. Returns 0 on failure.\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// CHARACTER TO GLYPH-INDEX CONVERSIOn\n\nSTBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);\n// If you're going to perform multiple operations on the same character\n// and you want a speed-up, call this function with the character you're\n// going to process, then use glyph-based functions instead of the\n// codepoint-based functions.\n// Returns 0 if the character codepoint is not defined in the font.\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// CHARACTER PROPERTIES\n//\n\nSTBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);\n// computes a scale factor to produce a font whose \"height\" is 'pixels' tall.\n// Height is measured as the distance from the highest ascender to the lowest\n// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics\n// and computing:\n//       scale = pixels / (ascent - descent)\n// so if you prefer to measure height by the ascent only, use a similar calculation.\n\nSTBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);\n// computes a scale factor to produce a font whose EM size is mapped to\n// 'pixels' tall. This is probably what traditional APIs compute, but\n// I'm not positive.\n\nSTBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);\n// ascent is the coordinate above the baseline the font extends; descent\n// is the coordinate below the baseline the font extends (i.e. it is typically negative)\n// lineGap is the spacing between one row's descent and the next row's ascent...\n// so you should advance the vertical position by \"*ascent - *descent + *lineGap\"\n//   these are expressed in unscaled coordinates, so you must multiply by\n//   the scale factor for a given size\n\nSTBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);\n// analogous to GetFontVMetrics, but returns the \"typographic\" values from the OS/2\n// table (specific to MS/Windows TTF files).\n//\n// Returns 1 on success (table present), 0 on failure.\n\nSTBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);\n// the bounding box around all possible characters\n\nSTBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);\n// leftSideBearing is the offset from the current horizontal position to the left edge of the character\n// advanceWidth is the offset from the current horizontal position to the next horizontal position\n//   these are expressed in unscaled coordinates\n\nSTBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);\n// an additional amount to add to the 'advance' value between ch1 and ch2\n\nSTBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);\n// Gets the bounding box of the visible part of the glyph, in unscaled coordinates\n\nSTBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);\nSTBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);\nSTBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);\n// as above, but takes one or more glyph indices for greater efficiency\n\ntypedef struct stbtt_kerningentry\n{\n   int glyph1; // use stbtt_FindGlyphIndex\n   int glyph2;\n   int advance;\n} stbtt_kerningentry;\n\nSTBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info);\nSTBTT_DEF int  stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);\n// Retrieves a complete list of all of the kerning pairs provided by the font\n// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.\n// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// GLYPH SHAPES (you probably don't need these, but they have to go before\n// the bitmaps for C declaration-order reasons)\n//\n\n#ifndef STBTT_vmove // you can predefine these to use different values (but why?)\n   enum {\n      STBTT_vmove=1,\n      STBTT_vline,\n      STBTT_vcurve,\n      STBTT_vcubic\n   };\n#endif\n\n#ifndef stbtt_vertex // you can predefine this to use different values\n                   // (we share this with other code at RAD)\n   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file\n   typedef struct\n   {\n      stbtt_vertex_type x,y,cx,cy,cx1,cy1;\n      unsigned char type,padding;\n   } stbtt_vertex;\n#endif\n\nSTBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);\n// returns non-zero if nothing is drawn for this glyph\n\nSTBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);\nSTBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);\n// returns # of vertices and fills *vertices with the pointer to them\n//   these are expressed in \"unscaled\" coordinates\n//\n// The shape is a series of contours. Each one starts with\n// a STBTT_moveto, then consists of a series of mixed\n// STBTT_lineto and STBTT_curveto segments. A lineto\n// draws a line from previous endpoint to its x,y; a curveto\n// draws a quadratic bezier from previous endpoint to\n// its x,y, using cx,cy as the bezier control point.\n\nSTBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);\n// frees the data allocated above\n\nSTBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);\nSTBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);\nSTBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);\n// fills svg with the character's SVG data.\n// returns data size or 0 if SVG not found.\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// BITMAP RENDERING\n//\n\nSTBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);\n// frees the bitmap allocated below\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);\n// allocates a large-enough single-channel 8bpp bitmap and renders the\n// specified character/glyph at the specified scale into it, with\n// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).\n// *width & *height are filled out with the width & height of the bitmap,\n// which is stored left-to-right, top-to-bottom.\n//\n// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);\n// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel\n// shift for the character\n\nSTBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);\n// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap\n// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap\n// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the\n// width and height and positioning info for it first.\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);\n// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel\n// shift for the character\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);\n// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering\n// is performed (see stbtt_PackSetOversampling)\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);\n// get the bbox of the bitmap centered around the glyph origin; so the\n// bitmap width is ix1-ix0, height is iy1-iy0, and location to place\n// the bitmap top left is (leftSideBearing*scale,iy0).\n// (Note that the bitmap uses y-increases-down, but the shape uses\n// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);\n// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel\n// shift for the character\n\n// the following functions are equivalent to the above functions, but operate\n// on glyph indices instead of Unicode codepoints (for efficiency)\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);\nSTBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);\nSTBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);\n\n\n// @TODO: don't expose this structure\ntypedef struct\n{\n   int w,h,stride;\n   unsigned char *pixels;\n} stbtt__bitmap;\n\n// rasterize a shape with quadratic beziers into a bitmap\nSTBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into\n                               float flatness_in_pixels,     // allowable error of curve in pixels\n                               stbtt_vertex *vertices,       // array of vertices defining shape\n                               int num_verts,                // number of vertices in above array\n                               float scale_x, float scale_y, // scale applied to input vertices\n                               float shift_x, float shift_y, // translation applied to input vertices\n                               int x_off, int y_off,         // another translation applied to input\n                               int invert,                   // if non-zero, vertically flip shape\n                               void *userdata);              // context for to STBTT_MALLOC\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Signed Distance Function (or Field) rendering\n\nSTBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);\n// frees the SDF bitmap allocated below\n\nSTBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);\n// These functions compute a discretized SDF field for a single character, suitable for storing\n// in a single-channel texture, sampling with bilinear filtering, and testing against\n// larger than some threshold to produce scalable fonts.\n//        info              --  the font\n//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap\n//        glyph/codepoint   --  the character to generate the SDF for\n//        padding           --  extra \"pixels\" around the character which are filled with the distance to the character (not 0),\n//                                 which allows effects like bit outlines\n//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)\n//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF \"pixel\" away from the edge (on the 0..255 scale)\n//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside\n//        width,height      --  output height & width of the SDF bitmap (including padding)\n//        xoff,yoff         --  output origin of the character\n//        return value      --  a 2D array of bytes 0..255, width*height in size\n//\n// pixel_dist_scale & onedge_value are a scale & bias that allows you to make\n// optimal use of the limited 0..255 for your application, trading off precision\n// and special effects. SDF values outside the range 0..255 are clamped to 0..255.\n//\n// Example:\n//      scale = stbtt_ScaleForPixelHeight(22)\n//      padding = 5\n//      onedge_value = 180\n//      pixel_dist_scale = 180/5.0 = 36.0\n//\n//      This will create an SDF bitmap in which the character is about 22 pixels\n//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled\n//      shape, sample the SDF at each pixel and fill the pixel if the SDF value\n//      is greater than or equal to 180/255. (You'll actually want to antialias,\n//      which is beyond the scope of this example.) Additionally, you can compute\n//      offset outlines (e.g. to stroke the character border inside & outside,\n//      or only outside). For example, to fill outside the character up to 3 SDF\n//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above\n//      choice of variables maps a range from 5 pixels outside the shape to\n//      2 pixels inside the shape to 0..255; this is intended primarily for apply\n//      outside effects only (the interior range is needed to allow proper\n//      antialiasing of the font at *smaller* sizes)\n//\n// The function computes the SDF analytically at each SDF pixel, not by e.g.\n// building a higher-res bitmap and approximating it. In theory the quality\n// should be as high as possible for an SDF of this size & representation, but\n// unclear if this is true in practice (perhaps building a higher-res bitmap\n// and computing from that can allow drop-out prevention).\n//\n// The algorithm has not been optimized at all, so expect it to be slow\n// if computing lots of characters or very large sizes.\n\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Finding the right font...\n//\n// You should really just solve this offline, keep your own tables\n// of what font is what, and don't try to get it out of the .ttf file.\n// That's because getting it out of the .ttf file is really hard, because\n// the names in the file can appear in many possible encodings, in many\n// possible languages, and e.g. if you need a case-insensitive comparison,\n// the details of that depend on the encoding & language in a complex way\n// (actually underspecified in truetype, but also gigantic).\n//\n// But you can use the provided functions in two possible ways:\n//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on\n//             unicode-encoded names to try to find the font you want;\n//             you can run this before calling stbtt_InitFont()\n//\n//     stbtt_GetFontNameString() lets you get any of the various strings\n//             from the file yourself and do your own comparisons on them.\n//             You have to have called stbtt_InitFont() first.\n\n\nSTBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);\n// returns the offset (not index) of the font that matches, or -1 if none\n//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like \"Arial Bold\".\n//   if you use any other flag, use a font name like \"Arial\"; this checks\n//     the 'macStyle' header field; i don't know if fonts set this consistently\n#define STBTT_MACSTYLE_DONTCARE     0\n#define STBTT_MACSTYLE_BOLD         1\n#define STBTT_MACSTYLE_ITALIC       2\n#define STBTT_MACSTYLE_UNDERSCORE   4\n#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0\n\nSTBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);\n// returns 1/0 whether the first string interpreted as utf8 is identical to\n// the second string interpreted as big-endian utf16... useful for strings from next func\n\nSTBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);\n// returns the string (which may be big-endian double byte, e.g. for unicode)\n// and puts the length in bytes in *length.\n//\n// some of the values for the IDs are below; for more see the truetype spec:\n//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html\n//     http://www.microsoft.com/typography/otspec/name.htm\n\nenum { // platformID\n   STBTT_PLATFORM_ID_UNICODE   =0,\n   STBTT_PLATFORM_ID_MAC       =1,\n   STBTT_PLATFORM_ID_ISO       =2,\n   STBTT_PLATFORM_ID_MICROSOFT =3\n};\n\nenum { // encodingID for STBTT_PLATFORM_ID_UNICODE\n   STBTT_UNICODE_EID_UNICODE_1_0    =0,\n   STBTT_UNICODE_EID_UNICODE_1_1    =1,\n   STBTT_UNICODE_EID_ISO_10646      =2,\n   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,\n   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4\n};\n\nenum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT\n   STBTT_MS_EID_SYMBOL        =0,\n   STBTT_MS_EID_UNICODE_BMP   =1,\n   STBTT_MS_EID_SHIFTJIS      =2,\n   STBTT_MS_EID_UNICODE_FULL  =10\n};\n\nenum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes\n   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,\n   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,\n   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,\n   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7\n};\n\nenum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...\n       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs\n   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,\n   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,\n   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,\n   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,\n   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,\n   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D\n};\n\nenum { // languageID for STBTT_PLATFORM_ID_MAC\n   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,\n   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,\n   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,\n   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,\n   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,\n   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,\n   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // __STB_INCLUDE_STB_TRUETYPE_H__\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n////\n////   IMPLEMENTATION\n////\n////\n\n#ifdef STB_TRUETYPE_IMPLEMENTATION\n\n#ifndef STBTT_MAX_OVERSAMPLE\n#define STBTT_MAX_OVERSAMPLE   8\n#endif\n\n#if STBTT_MAX_OVERSAMPLE > 255\n#error \"STBTT_MAX_OVERSAMPLE cannot be > 255\"\n#endif\n\ntypedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];\n\n#ifndef STBTT_RASTERIZER_VERSION\n#define STBTT_RASTERIZER_VERSION 2\n#endif\n\n#ifdef _MSC_VER\n#define STBTT__NOTUSED(v)  (void)(v)\n#else\n#define STBTT__NOTUSED(v)  (void)sizeof(v)\n#endif\n\n//////////////////////////////////////////////////////////////////////////\n//\n// stbtt__buf helpers to parse data from file\n//\n\nstatic stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)\n{\n   if (b->cursor >= b->size)\n      return 0;\n   return b->data[b->cursor++];\n}\n\nstatic stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)\n{\n   if (b->cursor >= b->size)\n      return 0;\n   return b->data[b->cursor];\n}\n\nstatic void stbtt__buf_seek(stbtt__buf *b, int o)\n{\n   STBTT_assert(!(o > b->size || o < 0));\n   b->cursor = (o > b->size || o < 0) ? b->size : o;\n}\n\nstatic void stbtt__buf_skip(stbtt__buf *b, int o)\n{\n   stbtt__buf_seek(b, b->cursor + o);\n}\n\nstatic stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)\n{\n   stbtt_uint32 v = 0;\n   int i;\n   STBTT_assert(n >= 1 && n <= 4);\n   for (i = 0; i < n; i++)\n      v = (v << 8) | stbtt__buf_get8(b);\n   return v;\n}\n\nstatic stbtt__buf stbtt__new_buf(const void *p, size_t size)\n{\n   stbtt__buf r;\n   STBTT_assert(size < 0x40000000);\n   r.data = (stbtt_uint8*) p;\n   r.size = (int) size;\n   r.cursor = 0;\n   return r;\n}\n\n#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)\n#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)\n\nstatic stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)\n{\n   stbtt__buf r = stbtt__new_buf(NULL, 0);\n   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;\n   r.data = b->data + o;\n   r.size = s;\n   return r;\n}\n\nstatic stbtt__buf stbtt__cff_get_index(stbtt__buf *b)\n{\n   int count, start, offsize;\n   start = b->cursor;\n   count = stbtt__buf_get16(b);\n   if (count) {\n      offsize = stbtt__buf_get8(b);\n      STBTT_assert(offsize >= 1 && offsize <= 4);\n      stbtt__buf_skip(b, offsize * count);\n      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);\n   }\n   return stbtt__buf_range(b, start, b->cursor - start);\n}\n\nstatic stbtt_uint32 stbtt__cff_int(stbtt__buf *b)\n{\n   int b0 = stbtt__buf_get8(b);\n   if (b0 >= 32 && b0 <= 246)       return b0 - 139;\n   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;\n   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;\n   else if (b0 == 28)               return stbtt__buf_get16(b);\n   else if (b0 == 29)               return stbtt__buf_get32(b);\n   STBTT_assert(0);\n   return 0;\n}\n\nstatic void stbtt__cff_skip_operand(stbtt__buf *b) {\n   int v, b0 = stbtt__buf_peek8(b);\n   STBTT_assert(b0 >= 28);\n   if (b0 == 30) {\n      stbtt__buf_skip(b, 1);\n      while (b->cursor < b->size) {\n         v = stbtt__buf_get8(b);\n         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)\n            break;\n      }\n   } else {\n      stbtt__cff_int(b);\n   }\n}\n\nstatic stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)\n{\n   stbtt__buf_seek(b, 0);\n   while (b->cursor < b->size) {\n      int start = b->cursor, end, op;\n      while (stbtt__buf_peek8(b) >= 28)\n         stbtt__cff_skip_operand(b);\n      end = b->cursor;\n      op = stbtt__buf_get8(b);\n      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;\n      if (op == key) return stbtt__buf_range(b, start, end-start);\n   }\n   return stbtt__buf_range(b, 0, 0);\n}\n\nstatic void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)\n{\n   int i;\n   stbtt__buf operands = stbtt__dict_get(b, key);\n   for (i = 0; i < outcount && operands.cursor < operands.size; i++)\n      out[i] = stbtt__cff_int(&operands);\n}\n\nstatic int stbtt__cff_index_count(stbtt__buf *b)\n{\n   stbtt__buf_seek(b, 0);\n   return stbtt__buf_get16(b);\n}\n\nstatic stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)\n{\n   int count, offsize, start, end;\n   stbtt__buf_seek(&b, 0);\n   count = stbtt__buf_get16(&b);\n   offsize = stbtt__buf_get8(&b);\n   STBTT_assert(i >= 0 && i < count);\n   STBTT_assert(offsize >= 1 && offsize <= 4);\n   stbtt__buf_skip(&b, i*offsize);\n   start = stbtt__buf_get(&b, offsize);\n   end = stbtt__buf_get(&b, offsize);\n   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// accessors to parse data from file\n//\n\n// on platforms that don't allow misaligned reads, if we want to allow\n// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE\n\n#define ttBYTE(p)     (* (stbtt_uint8 *) (p))\n#define ttCHAR(p)     (* (stbtt_int8 *) (p))\n#define ttFixed(p)    ttLONG(p)\n\nstatic stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }\nstatic stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }\nstatic stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }\nstatic stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }\n\n#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))\n#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])\n\nstatic int stbtt__isfont(stbtt_uint8 *font)\n{\n   // check the version number\n   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1\n   if (stbtt_tag(font, \"typ1\"))   return 1; // TrueType with type 1 font -- we don't support this!\n   if (stbtt_tag(font, \"OTTO\"))   return 1; // OpenType with CFF\n   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0\n   if (stbtt_tag(font, \"true\"))   return 1; // Apple specification for TrueType fonts\n   return 0;\n}\n\n// @OPTIMIZE: binary search\nstatic stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)\n{\n   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);\n   stbtt_uint32 tabledir = fontstart + 12;\n   stbtt_int32 i;\n   for (i=0; i < num_tables; ++i) {\n      stbtt_uint32 loc = tabledir + 16*i;\n      if (stbtt_tag(data+loc+0, tag))\n         return ttULONG(data+loc+8);\n   }\n   return 0;\n}\n\nstatic int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)\n{\n   // if it's just a font, there's only one valid index\n   if (stbtt__isfont(font_collection))\n      return index == 0 ? 0 : -1;\n\n   // check if it's a TTC\n   if (stbtt_tag(font_collection, \"ttcf\")) {\n      // version 1?\n      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {\n         stbtt_int32 n = ttLONG(font_collection+8);\n         if (index >= n)\n            return -1;\n         return ttULONG(font_collection+12+index*4);\n      }\n   }\n   return -1;\n}\n\nstatic int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)\n{\n   // if it's just a font, there's only one valid font\n   if (stbtt__isfont(font_collection))\n      return 1;\n\n   // check if it's a TTC\n   if (stbtt_tag(font_collection, \"ttcf\")) {\n      // version 1?\n      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {\n         return ttLONG(font_collection+8);\n      }\n   }\n   return 0;\n}\n\nstatic stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)\n{\n   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };\n   stbtt__buf pdict;\n   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);\n   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);\n   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);\n   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);\n   if (!subrsoff) return stbtt__new_buf(NULL, 0);\n   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);\n   return stbtt__cff_get_index(&cff);\n}\n\n// since most people won't use this, find this table the first time it's needed\nstatic int stbtt__get_svg(stbtt_fontinfo *info)\n{\n   stbtt_uint32 t;\n   if (info->svg < 0) {\n      t = stbtt__find_table(info->data, info->fontstart, \"SVG \");\n      if (t) {\n         stbtt_uint32 offset = ttULONG(info->data + t + 2);\n         info->svg = t + offset;\n      } else {\n         info->svg = 0;\n      }\n   }\n   return info->svg;\n}\n\nstatic int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)\n{\n   stbtt_uint32 cmap, t;\n   stbtt_int32 i,numTables;\n\n   info->data = data;\n   info->fontstart = fontstart;\n   info->cff = stbtt__new_buf(NULL, 0);\n\n   cmap = stbtt__find_table(data, fontstart, \"cmap\");       // required\n   info->loca = stbtt__find_table(data, fontstart, \"loca\"); // required\n   info->head = stbtt__find_table(data, fontstart, \"head\"); // required\n   info->glyf = stbtt__find_table(data, fontstart, \"glyf\"); // required\n   info->hhea = stbtt__find_table(data, fontstart, \"hhea\"); // required\n   info->hmtx = stbtt__find_table(data, fontstart, \"hmtx\"); // required\n   info->kern = stbtt__find_table(data, fontstart, \"kern\"); // not required\n   info->gpos = stbtt__find_table(data, fontstart, \"GPOS\"); // not required\n\n   if (!cmap || !info->head || !info->hhea || !info->hmtx)\n      return 0;\n   if (info->glyf) {\n      // required for truetype\n      if (!info->loca) return 0;\n   } else {\n      // initialization for CFF / Type2 fonts (OTF)\n      stbtt__buf b, topdict, topdictidx;\n      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;\n      stbtt_uint32 cff;\n\n      cff = stbtt__find_table(data, fontstart, \"CFF \");\n      if (!cff) return 0;\n\n      info->fontdicts = stbtt__new_buf(NULL, 0);\n      info->fdselect = stbtt__new_buf(NULL, 0);\n\n      // @TODO this should use size from table (not 512MB)\n      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);\n      b = info->cff;\n\n      // read the header\n      stbtt__buf_skip(&b, 2);\n      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize\n\n      // @TODO the name INDEX could list multiple fonts,\n      // but we just use the first one.\n      stbtt__cff_get_index(&b);  // name INDEX\n      topdictidx = stbtt__cff_get_index(&b);\n      topdict = stbtt__cff_index_get(topdictidx, 0);\n      stbtt__cff_get_index(&b);  // string INDEX\n      info->gsubrs = stbtt__cff_get_index(&b);\n\n      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);\n      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);\n      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);\n      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);\n      info->subrs = stbtt__get_subrs(b, topdict);\n\n      // we only support Type 2 charstrings\n      if (cstype != 2) return 0;\n      if (charstrings == 0) return 0;\n\n      if (fdarrayoff) {\n         // looks like a CID font\n         if (!fdselectoff) return 0;\n         stbtt__buf_seek(&b, fdarrayoff);\n         info->fontdicts = stbtt__cff_get_index(&b);\n         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);\n      }\n\n      stbtt__buf_seek(&b, charstrings);\n      info->charstrings = stbtt__cff_get_index(&b);\n   }\n\n   t = stbtt__find_table(data, fontstart, \"maxp\");\n   if (t)\n      info->numGlyphs = ttUSHORT(data+t+4);\n   else\n      info->numGlyphs = 0xffff;\n\n   info->svg = -1;\n\n   // find a cmap encoding table we understand *now* to avoid searching\n   // later. (todo: could make this installable)\n   // the same regardless of glyph.\n   numTables = ttUSHORT(data + cmap + 2);\n   info->index_map = 0;\n   for (i=0; i < numTables; ++i) {\n      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;\n      // find an encoding we understand:\n      switch(ttUSHORT(data+encoding_record)) {\n         case STBTT_PLATFORM_ID_MICROSOFT:\n            switch (ttUSHORT(data+encoding_record+2)) {\n               case STBTT_MS_EID_UNICODE_BMP:\n               case STBTT_MS_EID_UNICODE_FULL:\n                  // MS/Unicode\n                  info->index_map = cmap + ttULONG(data+encoding_record+4);\n                  break;\n            }\n            break;\n        case STBTT_PLATFORM_ID_UNICODE:\n            // Mac/iOS has these\n            // all the encodingIDs are unicode, so we don't bother to check it\n            info->index_map = cmap + ttULONG(data+encoding_record+4);\n            break;\n      }\n   }\n   if (info->index_map == 0)\n      return 0;\n\n   info->indexToLocFormat = ttUSHORT(data+info->head + 50);\n   return 1;\n}\n\nSTBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)\n{\n   stbtt_uint8 *data = info->data;\n   stbtt_uint32 index_map = info->index_map;\n\n   stbtt_uint16 format = ttUSHORT(data + index_map + 0);\n   if (format == 0) { // apple byte encoding\n      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);\n      if (unicode_codepoint < bytes-6)\n         return ttBYTE(data + index_map + 6 + unicode_codepoint);\n      return 0;\n   } else if (format == 6) {\n      stbtt_uint32 first = ttUSHORT(data + index_map + 6);\n      stbtt_uint32 count = ttUSHORT(data + index_map + 8);\n      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)\n         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);\n      return 0;\n   } else if (format == 2) {\n      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean\n      return 0;\n   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges\n      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;\n      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;\n      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);\n      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;\n\n      // do a binary search of the segments\n      stbtt_uint32 endCount = index_map + 14;\n      stbtt_uint32 search = endCount;\n\n      if (unicode_codepoint > 0xffff)\n         return 0;\n\n      // they lie from endCount .. endCount + segCount\n      // but searchRange is the nearest power of two, so...\n      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))\n         search += rangeShift*2;\n\n      // now decrement to bias correctly to find smallest\n      search -= 2;\n      while (entrySelector) {\n         stbtt_uint16 end;\n         searchRange >>= 1;\n         end = ttUSHORT(data + search + searchRange*2);\n         if (unicode_codepoint > end)\n            search += searchRange*2;\n         --entrySelector;\n      }\n      search += 2;\n\n      {\n         stbtt_uint16 offset, start, last;\n         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);\n\n         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);\n         last = ttUSHORT(data + endCount + 2*item);\n         if (unicode_codepoint < start || unicode_codepoint > last)\n            return 0;\n\n         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);\n         if (offset == 0)\n            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));\n\n         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);\n      }\n   } else if (format == 12 || format == 13) {\n      stbtt_uint32 ngroups = ttULONG(data+index_map+12);\n      stbtt_int32 low,high;\n      low = 0; high = (stbtt_int32)ngroups;\n      // Binary search the right group.\n      while (low < high) {\n         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high\n         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);\n         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);\n         if ((stbtt_uint32) unicode_codepoint < start_char)\n            high = mid;\n         else if ((stbtt_uint32) unicode_codepoint > end_char)\n            low = mid+1;\n         else {\n            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);\n            if (format == 12)\n               return start_glyph + unicode_codepoint-start_char;\n            else // format == 13\n               return start_glyph;\n         }\n      }\n      return 0; // not found\n   }\n   // @TODO\n   STBTT_assert(0);\n   return 0;\n}\n\nSTBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)\n{\n   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);\n}\n\nstatic void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)\n{\n   v->type = type;\n   v->x = (stbtt_int16) x;\n   v->y = (stbtt_int16) y;\n   v->cx = (stbtt_int16) cx;\n   v->cy = (stbtt_int16) cy;\n}\n\nstatic int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)\n{\n   int g1,g2;\n\n   STBTT_assert(!info->cff.size);\n\n   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range\n   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format\n\n   if (info->indexToLocFormat == 0) {\n      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;\n      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;\n   } else {\n      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);\n      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);\n   }\n\n   return g1==g2 ? -1 : g1; // if length is 0, return -1\n}\n\nstatic int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);\n\nSTBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)\n{\n   if (info->cff.size) {\n      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);\n   } else {\n      int g = stbtt__GetGlyfOffset(info, glyph_index);\n      if (g < 0) return 0;\n\n      if (x0) *x0 = ttSHORT(info->data + g + 2);\n      if (y0) *y0 = ttSHORT(info->data + g + 4);\n      if (x1) *x1 = ttSHORT(info->data + g + 6);\n      if (y1) *y1 = ttSHORT(info->data + g + 8);\n   }\n   return 1;\n}\n\nSTBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)\n{\n   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);\n}\n\nSTBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)\n{\n   stbtt_int16 numberOfContours;\n   int g;\n   if (info->cff.size)\n      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;\n   g = stbtt__GetGlyfOffset(info, glyph_index);\n   if (g < 0) return 1;\n   numberOfContours = ttSHORT(info->data + g);\n   return numberOfContours == 0;\n}\n\nstatic int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,\n    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)\n{\n   if (start_off) {\n      if (was_off)\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);\n      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);\n   } else {\n      if (was_off)\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);\n      else\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);\n   }\n   return num_vertices;\n}\n\nstatic int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   stbtt_int16 numberOfContours;\n   stbtt_uint8 *endPtsOfContours;\n   stbtt_uint8 *data = info->data;\n   stbtt_vertex *vertices=0;\n   int num_vertices=0;\n   int g = stbtt__GetGlyfOffset(info, glyph_index);\n\n   *pvertices = NULL;\n\n   if (g < 0) return 0;\n\n   numberOfContours = ttSHORT(data + g);\n\n   if (numberOfContours > 0) {\n      stbtt_uint8 flags=0,flagcount;\n      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;\n      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;\n      stbtt_uint8 *points;\n      endPtsOfContours = (data + g + 10);\n      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);\n      points = data + g + 10 + numberOfContours * 2 + 2 + ins;\n\n      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);\n\n      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need\n      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);\n      if (vertices == 0)\n         return 0;\n\n      next_move = 0;\n      flagcount=0;\n\n      // in first pass, we load uninterpreted data into the allocated array\n      // above, shifted to the end of the array so we won't overwrite it when\n      // we create our final data starting from the front\n\n      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated\n\n      // first load flags\n\n      for (i=0; i < n; ++i) {\n         if (flagcount == 0) {\n            flags = *points++;\n            if (flags & 8)\n               flagcount = *points++;\n         } else\n            --flagcount;\n         vertices[off+i].type = flags;\n      }\n\n      // now load x coordinates\n      x=0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         if (flags & 2) {\n            stbtt_int16 dx = *points++;\n            x += (flags & 16) ? dx : -dx; // ???\n         } else {\n            if (!(flags & 16)) {\n               x = x + (stbtt_int16) (points[0]*256 + points[1]);\n               points += 2;\n            }\n         }\n         vertices[off+i].x = (stbtt_int16) x;\n      }\n\n      // now load y coordinates\n      y=0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         if (flags & 4) {\n            stbtt_int16 dy = *points++;\n            y += (flags & 32) ? dy : -dy; // ???\n         } else {\n            if (!(flags & 32)) {\n               y = y + (stbtt_int16) (points[0]*256 + points[1]);\n               points += 2;\n            }\n         }\n         vertices[off+i].y = (stbtt_int16) y;\n      }\n\n      // now convert them to our format\n      num_vertices=0;\n      sx = sy = cx = cy = scx = scy = 0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         x     = (stbtt_int16) vertices[off+i].x;\n         y     = (stbtt_int16) vertices[off+i].y;\n\n         if (next_move == i) {\n            if (i != 0)\n               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);\n\n            // now start the new one\n            start_off = !(flags & 1);\n            if (start_off) {\n               // if we start off with an off-curve point, then when we need to find a point on the curve\n               // where we can start, and we need to save some state for when we wraparound.\n               scx = x;\n               scy = y;\n               if (!(vertices[off+i+1].type & 1)) {\n                  // next point is also a curve point, so interpolate an on-point curve\n                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;\n                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;\n               } else {\n                  // otherwise just use the next point as our start point\n                  sx = (stbtt_int32) vertices[off+i+1].x;\n                  sy = (stbtt_int32) vertices[off+i+1].y;\n                  ++i; // we're using point i+1 as the starting point, so skip it\n               }\n            } else {\n               sx = x;\n               sy = y;\n            }\n            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);\n            was_off = 0;\n            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);\n            ++j;\n         } else {\n            if (!(flags & 1)) { // if it's a curve\n               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);\n               cx = x;\n               cy = y;\n               was_off = 1;\n            } else {\n               if (was_off)\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);\n               else\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);\n               was_off = 0;\n            }\n         }\n      }\n      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);\n   } else if (numberOfContours < 0) {\n      // Compound shapes.\n      int more = 1;\n      stbtt_uint8 *comp = data + g + 10;\n      num_vertices = 0;\n      vertices = 0;\n      while (more) {\n         stbtt_uint16 flags, gidx;\n         int comp_num_verts = 0, i;\n         stbtt_vertex *comp_verts = 0, *tmp = 0;\n         float mtx[6] = {1,0,0,1,0,0}, m, n;\n\n         flags = ttSHORT(comp); comp+=2;\n         gidx = ttSHORT(comp); comp+=2;\n\n         if (flags & 2) { // XY values\n            if (flags & 1) { // shorts\n               mtx[4] = ttSHORT(comp); comp+=2;\n               mtx[5] = ttSHORT(comp); comp+=2;\n            } else {\n               mtx[4] = ttCHAR(comp); comp+=1;\n               mtx[5] = ttCHAR(comp); comp+=1;\n            }\n         }\n         else {\n            // @TODO handle matching point\n            STBTT_assert(0);\n         }\n         if (flags & (1<<3)) { // WE_HAVE_A_SCALE\n            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = mtx[2] = 0;\n         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE\n            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = mtx[2] = 0;\n            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO\n            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n         }\n\n         // Find transformation scales.\n         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);\n         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);\n\n         // Get indexed glyph.\n         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);\n         if (comp_num_verts > 0) {\n            // Transform vertices.\n            for (i = 0; i < comp_num_verts; ++i) {\n               stbtt_vertex* v = &comp_verts[i];\n               stbtt_vertex_type x,y;\n               x=v->x; y=v->y;\n               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));\n               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));\n               x=v->cx; y=v->cy;\n               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));\n               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));\n            }\n            // Append vertices.\n            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);\n            if (!tmp) {\n               if (vertices) STBTT_free(vertices, info->userdata);\n               if (comp_verts) STBTT_free(comp_verts, info->userdata);\n               return 0;\n            }\n            if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));\n            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));\n            if (vertices) STBTT_free(vertices, info->userdata);\n            vertices = tmp;\n            STBTT_free(comp_verts, info->userdata);\n            num_vertices += comp_num_verts;\n         }\n         // More components ?\n         more = flags & (1<<5);\n      }\n   } else {\n      // numberOfCounters == 0, do nothing\n   }\n\n   *pvertices = vertices;\n   return num_vertices;\n}\n\ntypedef struct\n{\n   int bounds;\n   int started;\n   float first_x, first_y;\n   float x, y;\n   stbtt_int32 min_x, max_x, min_y, max_y;\n\n   stbtt_vertex *pvertices;\n   int num_vertices;\n} stbtt__csctx;\n\n#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}\n\nstatic void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)\n{\n   if (x > c->max_x || !c->started) c->max_x = x;\n   if (y > c->max_y || !c->started) c->max_y = y;\n   if (x < c->min_x || !c->started) c->min_x = x;\n   if (y < c->min_y || !c->started) c->min_y = y;\n   c->started = 1;\n}\n\nstatic void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)\n{\n   if (c->bounds) {\n      stbtt__track_vertex(c, x, y);\n      if (type == STBTT_vcubic) {\n         stbtt__track_vertex(c, cx, cy);\n         stbtt__track_vertex(c, cx1, cy1);\n      }\n   } else {\n      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);\n      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;\n      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;\n   }\n   c->num_vertices++;\n}\n\nstatic void stbtt__csctx_close_shape(stbtt__csctx *ctx)\n{\n   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)\n      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)\n{\n   stbtt__csctx_close_shape(ctx);\n   ctx->first_x = ctx->x = ctx->x + dx;\n   ctx->first_y = ctx->y = ctx->y + dy;\n   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)\n{\n   ctx->x += dx;\n   ctx->y += dy;\n   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)\n{\n   float cx1 = ctx->x + dx1;\n   float cy1 = ctx->y + dy1;\n   float cx2 = cx1 + dx2;\n   float cy2 = cy1 + dy2;\n   ctx->x = cx2 + dx3;\n   ctx->y = cy2 + dy3;\n   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);\n}\n\nstatic stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)\n{\n   int count = stbtt__cff_index_count(&idx);\n   int bias = 107;\n   if (count >= 33900)\n      bias = 32768;\n   else if (count >= 1240)\n      bias = 1131;\n   n += bias;\n   if (n < 0 || n >= count)\n      return stbtt__new_buf(NULL, 0);\n   return stbtt__cff_index_get(idx, n);\n}\n\nstatic stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)\n{\n   stbtt__buf fdselect = info->fdselect;\n   int nranges, start, end, v, fmt, fdselector = -1, i;\n\n   stbtt__buf_seek(&fdselect, 0);\n   fmt = stbtt__buf_get8(&fdselect);\n   if (fmt == 0) {\n      // untested\n      stbtt__buf_skip(&fdselect, glyph_index);\n      fdselector = stbtt__buf_get8(&fdselect);\n   } else if (fmt == 3) {\n      nranges = stbtt__buf_get16(&fdselect);\n      start = stbtt__buf_get16(&fdselect);\n      for (i = 0; i < nranges; i++) {\n         v = stbtt__buf_get8(&fdselect);\n         end = stbtt__buf_get16(&fdselect);\n         if (glyph_index >= start && glyph_index < end) {\n            fdselector = v;\n            break;\n         }\n         start = end;\n      }\n   }\n   if (fdselector == -1) stbtt__new_buf(NULL, 0);\n   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));\n}\n\nstatic int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)\n{\n   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;\n   int has_subrs = 0, clear_stack;\n   float s[48];\n   stbtt__buf subr_stack[10], subrs = info->subrs, b;\n   float f;\n\n#define STBTT__CSERR(s) (0)\n\n   // this currently ignores the initial width value, which isn't needed if we have hmtx\n   b = stbtt__cff_index_get(info->charstrings, glyph_index);\n   while (b.cursor < b.size) {\n      i = 0;\n      clear_stack = 1;\n      b0 = stbtt__buf_get8(&b);\n      switch (b0) {\n      // @TODO implement hinting\n      case 0x13: // hintmask\n      case 0x14: // cntrmask\n         if (in_header)\n            maskbits += (sp / 2); // implicit \"vstem\"\n         in_header = 0;\n         stbtt__buf_skip(&b, (maskbits + 7) / 8);\n         break;\n\n      case 0x01: // hstem\n      case 0x03: // vstem\n      case 0x12: // hstemhm\n      case 0x17: // vstemhm\n         maskbits += (sp / 2);\n         break;\n\n      case 0x15: // rmoveto\n         in_header = 0;\n         if (sp < 2) return STBTT__CSERR(\"rmoveto stack\");\n         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);\n         break;\n      case 0x04: // vmoveto\n         in_header = 0;\n         if (sp < 1) return STBTT__CSERR(\"vmoveto stack\");\n         stbtt__csctx_rmove_to(c, 0, s[sp-1]);\n         break;\n      case 0x16: // hmoveto\n         in_header = 0;\n         if (sp < 1) return STBTT__CSERR(\"hmoveto stack\");\n         stbtt__csctx_rmove_to(c, s[sp-1], 0);\n         break;\n\n      case 0x05: // rlineto\n         if (sp < 2) return STBTT__CSERR(\"rlineto stack\");\n         for (; i + 1 < sp; i += 2)\n            stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         break;\n\n      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical\n      // starting from a different place.\n\n      case 0x07: // vlineto\n         if (sp < 1) return STBTT__CSERR(\"vlineto stack\");\n         goto vlineto;\n      case 0x06: // hlineto\n         if (sp < 1) return STBTT__CSERR(\"hlineto stack\");\n         for (;;) {\n            if (i >= sp) break;\n            stbtt__csctx_rline_to(c, s[i], 0);\n            i++;\n      vlineto:\n            if (i >= sp) break;\n            stbtt__csctx_rline_to(c, 0, s[i]);\n            i++;\n         }\n         break;\n\n      case 0x1F: // hvcurveto\n         if (sp < 4) return STBTT__CSERR(\"hvcurveto stack\");\n         goto hvcurveto;\n      case 0x1E: // vhcurveto\n         if (sp < 4) return STBTT__CSERR(\"vhcurveto stack\");\n         for (;;) {\n            if (i + 3 >= sp) break;\n            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);\n            i += 4;\n      hvcurveto:\n            if (i + 3 >= sp) break;\n            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);\n            i += 4;\n         }\n         break;\n\n      case 0x08: // rrcurveto\n         if (sp < 6) return STBTT__CSERR(\"rcurveline stack\");\n         for (; i + 5 < sp; i += 6)\n            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         break;\n\n      case 0x18: // rcurveline\n         if (sp < 8) return STBTT__CSERR(\"rcurveline stack\");\n         for (; i + 5 < sp - 2; i += 6)\n            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         if (i + 1 >= sp) return STBTT__CSERR(\"rcurveline stack\");\n         stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         break;\n\n      case 0x19: // rlinecurve\n         if (sp < 8) return STBTT__CSERR(\"rlinecurve stack\");\n         for (; i + 1 < sp - 6; i += 2)\n            stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         if (i + 5 >= sp) return STBTT__CSERR(\"rlinecurve stack\");\n         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         break;\n\n      case 0x1A: // vvcurveto\n      case 0x1B: // hhcurveto\n         if (sp < 4) return STBTT__CSERR(\"(vv|hh)curveto stack\");\n         f = 0.0;\n         if (sp & 1) { f = s[i]; i++; }\n         for (; i + 3 < sp; i += 4) {\n            if (b0 == 0x1B)\n               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);\n            else\n               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);\n            f = 0.0;\n         }\n         break;\n\n      case 0x0A: // callsubr\n         if (!has_subrs) {\n            if (info->fdselect.size)\n               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);\n            has_subrs = 1;\n         }\n         // FALLTHROUGH\n      case 0x1D: // callgsubr\n         if (sp < 1) return STBTT__CSERR(\"call(g|)subr stack\");\n         v = (int) s[--sp];\n         if (subr_stack_height >= 10) return STBTT__CSERR(\"recursion limit\");\n         subr_stack[subr_stack_height++] = b;\n         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);\n         if (b.size == 0) return STBTT__CSERR(\"subr not found\");\n         b.cursor = 0;\n         clear_stack = 0;\n         break;\n\n      case 0x0B: // return\n         if (subr_stack_height <= 0) return STBTT__CSERR(\"return outside subr\");\n         b = subr_stack[--subr_stack_height];\n         clear_stack = 0;\n         break;\n\n      case 0x0E: // endchar\n         stbtt__csctx_close_shape(c);\n         return 1;\n\n      case 0x0C: { // two-byte escape\n         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;\n         float dx, dy;\n         int b1 = stbtt__buf_get8(&b);\n         switch (b1) {\n         // @TODO These \"flex\" implementations ignore the flex-depth and resolution,\n         // and always draw beziers.\n         case 0x22: // hflex\n            if (sp < 7) return STBTT__CSERR(\"hflex stack\");\n            dx1 = s[0];\n            dx2 = s[1];\n            dy2 = s[2];\n            dx3 = s[3];\n            dx4 = s[4];\n            dx5 = s[5];\n            dx6 = s[6];\n            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);\n            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);\n            break;\n\n         case 0x23: // flex\n            if (sp < 13) return STBTT__CSERR(\"flex stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dy3 = s[5];\n            dx4 = s[6];\n            dy4 = s[7];\n            dx5 = s[8];\n            dy5 = s[9];\n            dx6 = s[10];\n            dy6 = s[11];\n            //fd is s[12]\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);\n            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);\n            break;\n\n         case 0x24: // hflex1\n            if (sp < 9) return STBTT__CSERR(\"hflex1 stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dx4 = s[5];\n            dx5 = s[6];\n            dy5 = s[7];\n            dx6 = s[8];\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);\n            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));\n            break;\n\n         case 0x25: // flex1\n            if (sp < 11) return STBTT__CSERR(\"flex1 stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dy3 = s[5];\n            dx4 = s[6];\n            dy4 = s[7];\n            dx5 = s[8];\n            dy5 = s[9];\n            dx6 = dy6 = s[10];\n            dx = dx1+dx2+dx3+dx4+dx5;\n            dy = dy1+dy2+dy3+dy4+dy5;\n            if (STBTT_fabs(dx) > STBTT_fabs(dy))\n               dy6 = -dy;\n            else\n               dx6 = -dx;\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);\n            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);\n            break;\n\n         default:\n            return STBTT__CSERR(\"unimplemented\");\n         }\n      } break;\n\n      default:\n         if (b0 != 255 && b0 != 28 && b0 < 32)\n            return STBTT__CSERR(\"reserved operator\");\n\n         // push immediate\n         if (b0 == 255) {\n            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;\n         } else {\n            stbtt__buf_skip(&b, -1);\n            f = (float)(stbtt_int16)stbtt__cff_int(&b);\n         }\n         if (sp >= 48) return STBTT__CSERR(\"push stack overflow\");\n         s[sp++] = f;\n         clear_stack = 0;\n         break;\n      }\n      if (clear_stack) sp = 0;\n   }\n   return STBTT__CSERR(\"no endchar\");\n\n#undef STBTT__CSERR\n}\n\nstatic int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   // runs the charstring twice, once to count and once to output (to avoid realloc)\n   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);\n   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);\n   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {\n      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);\n      output_ctx.pvertices = *pvertices;\n      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {\n         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);\n         return output_ctx.num_vertices;\n      }\n   }\n   *pvertices = NULL;\n   return 0;\n}\n\nstatic int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)\n{\n   stbtt__csctx c = STBTT__CSCTX_INIT(1);\n   int r = stbtt__run_charstring(info, glyph_index, &c);\n   if (x0)  *x0 = r ? c.min_x : 0;\n   if (y0)  *y0 = r ? c.min_y : 0;\n   if (x1)  *x1 = r ? c.max_x : 0;\n   if (y1)  *y1 = r ? c.max_y : 0;\n   return r ? c.num_vertices : 0;\n}\n\nSTBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   if (!info->cff.size)\n      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);\n   else\n      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);\n}\n\nSTBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)\n{\n   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);\n   if (glyph_index < numOfLongHorMetrics) {\n      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);\n      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);\n   } else {\n      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));\n      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));\n   }\n}\n\nSTBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n\n   // we only look at the first table. it must be 'horizontal' and format 0.\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1\n      return 0;\n   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format\n      return 0;\n\n   return ttUSHORT(data+10);\n}\n\nSTBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n   int k, length;\n\n   // we only look at the first table. it must be 'horizontal' and format 0.\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1\n      return 0;\n   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format\n      return 0;\n\n   length = ttUSHORT(data+10);\n   if (table_length < length)\n      length = table_length;\n\n   for (k = 0; k < length; k++)\n   {\n      table[k].glyph1 = ttUSHORT(data+18+(k*6));\n      table[k].glyph2 = ttUSHORT(data+20+(k*6));\n      table[k].advance = ttSHORT(data+22+(k*6));\n   }\n\n   return length;\n}\n\nstatic int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n   stbtt_uint32 needle, straw;\n   int l, r, m;\n\n   // we only look at the first table. it must be 'horizontal' and format 0.\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1\n      return 0;\n   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format\n      return 0;\n\n   l = 0;\n   r = ttUSHORT(data+10) - 1;\n   needle = glyph1 << 16 | glyph2;\n   while (l <= r) {\n      m = (l + r) >> 1;\n      straw = ttULONG(data+18+(m*6)); // note: unaligned read\n      if (needle < straw)\n         r = m - 1;\n      else if (needle > straw)\n         l = m + 1;\n      else\n         return ttSHORT(data+22+(m*6));\n   }\n   return 0;\n}\n\nstatic stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)\n{\n   stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);\n   switch (coverageFormat) {\n      case 1: {\n         stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);\n\n         // Binary search.\n         stbtt_int32 l=0, r=glyphCount-1, m;\n         int straw, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *glyphArray = coverageTable + 4;\n            stbtt_uint16 glyphID;\n            m = (l + r) >> 1;\n            glyphID = ttUSHORT(glyphArray + 2 * m);\n            straw = glyphID;\n            if (needle < straw)\n               r = m - 1;\n            else if (needle > straw)\n               l = m + 1;\n            else {\n               return m;\n            }\n         }\n         break;\n      }\n\n      case 2: {\n         stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);\n         stbtt_uint8 *rangeArray = coverageTable + 4;\n\n         // Binary search.\n         stbtt_int32 l=0, r=rangeCount-1, m;\n         int strawStart, strawEnd, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *rangeRecord;\n            m = (l + r) >> 1;\n            rangeRecord = rangeArray + 6 * m;\n            strawStart = ttUSHORT(rangeRecord);\n            strawEnd = ttUSHORT(rangeRecord + 2);\n            if (needle < strawStart)\n               r = m - 1;\n            else if (needle > strawEnd)\n               l = m + 1;\n            else {\n               stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);\n               return startCoverageIndex + glyph - strawStart;\n            }\n         }\n         break;\n      }\n\n      default: return -1; // unsupported\n   }\n\n   return -1;\n}\n\nstatic stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)\n{\n   stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);\n   switch (classDefFormat)\n   {\n      case 1: {\n         stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);\n         stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);\n         stbtt_uint8 *classDef1ValueArray = classDefTable + 6;\n\n         if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)\n            return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));\n         break;\n      }\n\n      case 2: {\n         stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);\n         stbtt_uint8 *classRangeRecords = classDefTable + 4;\n\n         // Binary search.\n         stbtt_int32 l=0, r=classRangeCount-1, m;\n         int strawStart, strawEnd, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *classRangeRecord;\n            m = (l + r) >> 1;\n            classRangeRecord = classRangeRecords + 6 * m;\n            strawStart = ttUSHORT(classRangeRecord);\n            strawEnd = ttUSHORT(classRangeRecord + 2);\n            if (needle < strawStart)\n               r = m - 1;\n            else if (needle > strawEnd)\n               l = m + 1;\n            else\n               return (stbtt_int32)ttUSHORT(classRangeRecord + 4);\n         }\n         break;\n      }\n\n      default:\n         return -1; // Unsupported definition type, return an error.\n   }\n\n   // \"All glyphs not assigned to a class fall into class 0\". (OpenType spec)\n   return 0;\n}\n\n// Define to STBTT_assert(x) if you want to break on unimplemented formats.\n#define STBTT_GPOS_TODO_assert(x)\n\nstatic stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)\n{\n   stbtt_uint16 lookupListOffset;\n   stbtt_uint8 *lookupList;\n   stbtt_uint16 lookupCount;\n   stbtt_uint8 *data;\n   stbtt_int32 i, sti;\n\n   if (!info->gpos) return 0;\n\n   data = info->data + info->gpos;\n\n   if (ttUSHORT(data+0) != 1) return 0; // Major version 1\n   if (ttUSHORT(data+2) != 0) return 0; // Minor version 0\n\n   lookupListOffset = ttUSHORT(data+8);\n   lookupList = data + lookupListOffset;\n   lookupCount = ttUSHORT(lookupList);\n\n   for (i=0; i<lookupCount; ++i) {\n      stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);\n      stbtt_uint8 *lookupTable = lookupList + lookupOffset;\n\n      stbtt_uint16 lookupType = ttUSHORT(lookupTable);\n      stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);\n      stbtt_uint8 *subTableOffsets = lookupTable + 6;\n      if (lookupType != 2) // Pair Adjustment Positioning Subtable\n         continue;\n\n      for (sti=0; sti<subTableCount; sti++) {\n         stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);\n         stbtt_uint8 *table = lookupTable + subtableOffset;\n         stbtt_uint16 posFormat = ttUSHORT(table);\n         stbtt_uint16 coverageOffset = ttUSHORT(table + 2);\n         stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);\n         if (coverageIndex == -1) continue;\n\n         switch (posFormat) {\n            case 1: {\n               stbtt_int32 l, r, m;\n               int straw, needle;\n               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);\n               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);\n               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?\n                  stbtt_int32 valueRecordPairSizeInBytes = 2;\n                  stbtt_uint16 pairSetCount = ttUSHORT(table + 8);\n                  stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);\n                  stbtt_uint8 *pairValueTable = table + pairPosOffset;\n                  stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);\n                  stbtt_uint8 *pairValueArray = pairValueTable + 2;\n\n                  if (coverageIndex >= pairSetCount) return 0;\n\n                  needle=glyph2;\n                  r=pairValueCount-1;\n                  l=0;\n\n                  // Binary search.\n                  while (l <= r) {\n                     stbtt_uint16 secondGlyph;\n                     stbtt_uint8 *pairValue;\n                     m = (l + r) >> 1;\n                     pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;\n                     secondGlyph = ttUSHORT(pairValue);\n                     straw = secondGlyph;\n                     if (needle < straw)\n                        r = m - 1;\n                     else if (needle > straw)\n                        l = m + 1;\n                     else {\n                        stbtt_int16 xAdvance = ttSHORT(pairValue + 2);\n                        return xAdvance;\n                     }\n                  }\n               } else\n                  return 0;\n               break;\n            }\n\n            case 2: {\n               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);\n               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);\n               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?\n                  stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);\n                  stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);\n                  int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);\n                  int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);\n\n                  stbtt_uint16 class1Count = ttUSHORT(table + 12);\n                  stbtt_uint16 class2Count = ttUSHORT(table + 14);\n                  stbtt_uint8 *class1Records, *class2Records;\n                  stbtt_int16 xAdvance;\n\n                  if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed\n                  if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed\n\n                  class1Records = table + 16;\n                  class2Records = class1Records + 2 * (glyph1class * class2Count);\n                  xAdvance = ttSHORT(class2Records + 2 * glyph2class);\n                  return xAdvance;\n               } else\n                  return 0;\n               break;\n            }\n\n            default:\n               return 0; // Unsupported position format\n         }\n      }\n   }\n\n   return 0;\n}\n\nSTBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)\n{\n   int xAdvance = 0;\n\n   if (info->gpos)\n      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);\n   else if (info->kern)\n      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);\n\n   return xAdvance;\n}\n\nSTBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)\n{\n   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs\n      return 0;\n   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));\n}\n\nSTBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)\n{\n   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);\n}\n\nSTBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)\n{\n   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);\n   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);\n   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);\n}\n\nSTBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)\n{\n   int tab = stbtt__find_table(info->data, info->fontstart, \"OS/2\");\n   if (!tab)\n      return 0;\n   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);\n   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);\n   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);\n   return 1;\n}\n\nSTBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)\n{\n   *x0 = ttSHORT(info->data + info->head + 36);\n   *y0 = ttSHORT(info->data + info->head + 38);\n   *x1 = ttSHORT(info->data + info->head + 40);\n   *y1 = ttSHORT(info->data + info->head + 42);\n}\n\nSTBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)\n{\n   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);\n   return (float) height / fheight;\n}\n\nSTBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)\n{\n   int unitsPerEm = ttUSHORT(info->data + info->head + 18);\n   return pixels / unitsPerEm;\n}\n\nSTBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)\n{\n   STBTT_free(v, info->userdata);\n}\n\nSTBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)\n{\n   int i;\n   stbtt_uint8 *data = info->data;\n   stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);\n\n   int numEntries = ttUSHORT(svg_doc_list);\n   stbtt_uint8 *svg_docs = svg_doc_list + 2;\n\n   for(i=0; i<numEntries; i++) {\n      stbtt_uint8 *svg_doc = svg_docs + (12 * i);\n      if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))\n         return svg_doc;\n   }\n   return 0;\n}\n\nSTBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)\n{\n   stbtt_uint8 *data = info->data;\n   stbtt_uint8 *svg_doc;\n\n   if (info->svg == 0)\n      return 0;\n\n   svg_doc = stbtt_FindSVGDoc(info, gl);\n   if (svg_doc != NULL) {\n      *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);\n      return ttULONG(svg_doc + 8);\n   } else {\n      return 0;\n   }\n}\n\nSTBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)\n{\n   return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// antialiasing software rasterizer\n//\n\nSTBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning\n   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {\n      // e.g. space character\n      if (ix0) *ix0 = 0;\n      if (iy0) *iy0 = 0;\n      if (ix1) *ix1 = 0;\n      if (iy1) *iy1 = 0;\n   } else {\n      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?\n      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);\n      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);\n      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);\n      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);\n   }\n}\n\nSTBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);\n}\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);\n}\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  Rasterizer\n\ntypedef struct stbtt__hheap_chunk\n{\n   struct stbtt__hheap_chunk *next;\n} stbtt__hheap_chunk;\n\ntypedef struct stbtt__hheap\n{\n   struct stbtt__hheap_chunk *head;\n   void   *first_free;\n   int    num_remaining_in_head_chunk;\n} stbtt__hheap;\n\nstatic void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)\n{\n   if (hh->first_free) {\n      void *p = hh->first_free;\n      hh->first_free = * (void **) p;\n      return p;\n   } else {\n      if (hh->num_remaining_in_head_chunk == 0) {\n         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);\n         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);\n         if (c == NULL)\n            return NULL;\n         c->next = hh->head;\n         hh->head = c;\n         hh->num_remaining_in_head_chunk = count;\n      }\n      --hh->num_remaining_in_head_chunk;\n      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;\n   }\n}\n\nstatic void stbtt__hheap_free(stbtt__hheap *hh, void *p)\n{\n   *(void **) p = hh->first_free;\n   hh->first_free = p;\n}\n\nstatic void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)\n{\n   stbtt__hheap_chunk *c = hh->head;\n   while (c) {\n      stbtt__hheap_chunk *n = c->next;\n      STBTT_free(c, userdata);\n      c = n;\n   }\n}\n\ntypedef struct stbtt__edge {\n   float x0,y0, x1,y1;\n   int invert;\n} stbtt__edge;\n\n\ntypedef struct stbtt__active_edge\n{\n   struct stbtt__active_edge *next;\n   #if STBTT_RASTERIZER_VERSION==1\n   int x,dx;\n   float ey;\n   int direction;\n   #elif STBTT_RASTERIZER_VERSION==2\n   float fx,fdx,fdy;\n   float direction;\n   float sy;\n   float ey;\n   #else\n   #error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n   #endif\n} stbtt__active_edge;\n\n#if STBTT_RASTERIZER_VERSION == 1\n#define STBTT_FIXSHIFT   10\n#define STBTT_FIX        (1 << STBTT_FIXSHIFT)\n#define STBTT_FIXMASK    (STBTT_FIX-1)\n\nstatic stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)\n{\n   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);\n   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);\n   STBTT_assert(z != NULL);\n   if (!z) return z;\n\n   // round dx down to avoid overshooting\n   if (dxdy < 0)\n      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);\n   else\n      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);\n\n   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount\n   z->x -= off_x * STBTT_FIX;\n\n   z->ey = e->y1;\n   z->next = 0;\n   z->direction = e->invert ? 1 : -1;\n   return z;\n}\n#elif STBTT_RASTERIZER_VERSION == 2\nstatic stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)\n{\n   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);\n   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);\n   STBTT_assert(z != NULL);\n   //STBTT_assert(e->y0 <= start_point);\n   if (!z) return z;\n   z->fdx = dxdy;\n   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;\n   z->fx = e->x0 + dxdy * (start_point - e->y0);\n   z->fx -= off_x;\n   z->direction = e->invert ? 1.0f : -1.0f;\n   z->sy = e->y0;\n   z->ey = e->y1;\n   z->next = 0;\n   return z;\n}\n#else\n#error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n\n#if STBTT_RASTERIZER_VERSION == 1\n// note: this routine clips fills that extend off the edges... ideally this\n// wouldn't happen, but it could happen if the truetype glyph bounding boxes\n// are wrong, or if the user supplies a too-small bitmap\nstatic void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)\n{\n   // non-zero winding fill\n   int x0=0, w=0;\n\n   while (e) {\n      if (w == 0) {\n         // if we're currently at zero, we need to record the edge start point\n         x0 = e->x; w += e->direction;\n      } else {\n         int x1 = e->x; w += e->direction;\n         // if we went to zero, we need to draw\n         if (w == 0) {\n            int i = x0 >> STBTT_FIXSHIFT;\n            int j = x1 >> STBTT_FIXSHIFT;\n\n            if (i < len && j >= 0) {\n               if (i == j) {\n                  // x0,x1 are the same pixel, so compute combined coverage\n                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);\n               } else {\n                  if (i >= 0) // add antialiasing for x0\n                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);\n                  else\n                     i = -1; // clip\n\n                  if (j < len) // add antialiasing for x1\n                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);\n                  else\n                     j = len; // clip\n\n                  for (++i; i < j; ++i) // fill pixels between x0 and x1\n                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;\n               }\n            }\n         }\n      }\n\n      e = e->next;\n   }\n}\n\nstatic void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)\n{\n   stbtt__hheap hh = { 0, 0, 0 };\n   stbtt__active_edge *active = NULL;\n   int y,j=0;\n   int max_weight = (255 / vsubsample);  // weight per vertical scanline\n   int s; // vertical subsample index\n   unsigned char scanline_data[512], *scanline;\n\n   if (result->w > 512)\n      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);\n   else\n      scanline = scanline_data;\n\n   y = off_y * vsubsample;\n   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;\n\n   while (j < result->h) {\n      STBTT_memset(scanline, 0, result->w);\n      for (s=0; s < vsubsample; ++s) {\n         // find center of pixel for this scanline\n         float scan_y = y + 0.5f;\n         stbtt__active_edge **step = &active;\n\n         // update all active edges;\n         // remove all active edges that terminate before the center of this scanline\n         while (*step) {\n            stbtt__active_edge * z = *step;\n            if (z->ey <= scan_y) {\n               *step = z->next; // delete from list\n               STBTT_assert(z->direction);\n               z->direction = 0;\n               stbtt__hheap_free(&hh, z);\n            } else {\n               z->x += z->dx; // advance to position for current scanline\n               step = &((*step)->next); // advance through list\n            }\n         }\n\n         // resort the list if needed\n         for(;;) {\n            int changed=0;\n            step = &active;\n            while (*step && (*step)->next) {\n               if ((*step)->x > (*step)->next->x) {\n                  stbtt__active_edge *t = *step;\n                  stbtt__active_edge *q = t->next;\n\n                  t->next = q->next;\n                  q->next = t;\n                  *step = q;\n                  changed = 1;\n               }\n               step = &(*step)->next;\n            }\n            if (!changed) break;\n         }\n\n         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline\n         while (e->y0 <= scan_y) {\n            if (e->y1 > scan_y) {\n               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);\n               if (z != NULL) {\n                  // find insertion point\n                  if (active == NULL)\n                     active = z;\n                  else if (z->x < active->x) {\n                     // insert at front\n                     z->next = active;\n                     active = z;\n                  } else {\n                     // find thing to insert AFTER\n                     stbtt__active_edge *p = active;\n                     while (p->next && p->next->x < z->x)\n                        p = p->next;\n                     // at this point, p->next->x is NOT < z->x\n                     z->next = p->next;\n                     p->next = z;\n                  }\n               }\n            }\n            ++e;\n         }\n\n         // now process all active edges in XOR fashion\n         if (active)\n            stbtt__fill_active_edges(scanline, result->w, active, max_weight);\n\n         ++y;\n      }\n      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);\n      ++j;\n   }\n\n   stbtt__hheap_cleanup(&hh, userdata);\n\n   if (scanline != scanline_data)\n      STBTT_free(scanline, userdata);\n}\n\n#elif STBTT_RASTERIZER_VERSION == 2\n\n// the edge passed in here does not cross the vertical line at x or the vertical line at x+1\n// (i.e. it has already been clipped to those)\nstatic void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)\n{\n   if (y0 == y1) return;\n   STBTT_assert(y0 < y1);\n   STBTT_assert(e->sy <= e->ey);\n   if (y0 > e->ey) return;\n   if (y1 < e->sy) return;\n   if (y0 < e->sy) {\n      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);\n      y0 = e->sy;\n   }\n   if (y1 > e->ey) {\n      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);\n      y1 = e->ey;\n   }\n\n   if (x0 == x)\n      STBTT_assert(x1 <= x+1);\n   else if (x0 == x+1)\n      STBTT_assert(x1 >= x);\n   else if (x0 <= x)\n      STBTT_assert(x1 <= x);\n   else if (x0 >= x+1)\n      STBTT_assert(x1 >= x+1);\n   else\n      STBTT_assert(x1 >= x && x1 <= x+1);\n\n   if (x0 <= x && x1 <= x)\n      scanline[x] += e->direction * (y1-y0);\n   else if (x0 >= x+1 && x1 >= x+1)\n      ;\n   else {\n      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);\n      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position\n   }\n}\n\nstatic float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)\n{\n   STBTT_assert(top_width >= 0);\n   STBTT_assert(bottom_width >= 0);\n   return (top_width + bottom_width) / 2.0f * height;\n}\n\nstatic float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)\n{\n   return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);\n}\n\nstatic float stbtt__sized_triangle_area(float height, float width)\n{\n   return height * width / 2;\n}\n\nstatic void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)\n{\n   float y_bottom = y_top+1;\n\n   while (e) {\n      // brute force every pixel\n\n      // compute intersection points with top & bottom\n      STBTT_assert(e->ey >= y_top);\n\n      if (e->fdx == 0) {\n         float x0 = e->fx;\n         if (x0 < len) {\n            if (x0 >= 0) {\n               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);\n               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);\n            } else {\n               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);\n            }\n         }\n      } else {\n         float x0 = e->fx;\n         float dx = e->fdx;\n         float xb = x0 + dx;\n         float x_top, x_bottom;\n         float sy0,sy1;\n         float dy = e->fdy;\n         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);\n\n         // compute endpoints of line segment clipped to this scanline (if the\n         // line segment starts on this scanline. x0 is the intersection of the\n         // line with y_top, but that may be off the line segment.\n         if (e->sy > y_top) {\n            x_top = x0 + dx * (e->sy - y_top);\n            sy0 = e->sy;\n         } else {\n            x_top = x0;\n            sy0 = y_top;\n         }\n         if (e->ey < y_bottom) {\n            x_bottom = x0 + dx * (e->ey - y_top);\n            sy1 = e->ey;\n         } else {\n            x_bottom = xb;\n            sy1 = y_bottom;\n         }\n\n         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {\n            // from here on, we don't have to range check x values\n\n            if ((int) x_top == (int) x_bottom) {\n               float height;\n               // simple case, only spans one pixel\n               int x = (int) x_top;\n               height = (sy1 - sy0) * e->direction;\n               STBTT_assert(x >= 0 && x < len);\n               scanline[x]      += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);\n               scanline_fill[x] += height; // everything right of this pixel is filled\n            } else {\n               int x,x1,x2;\n               float y_crossing, y_final, step, sign, area;\n               // covers 2+ pixels\n               if (x_top > x_bottom) {\n                  // flip scanline vertically; signed area is the same\n                  float t;\n                  sy0 = y_bottom - (sy0 - y_top);\n                  sy1 = y_bottom - (sy1 - y_top);\n                  t = sy0, sy0 = sy1, sy1 = t;\n                  t = x_bottom, x_bottom = x_top, x_top = t;\n                  dx = -dx;\n                  dy = -dy;\n                  t = x0, x0 = xb, xb = t;\n               }\n               STBTT_assert(dy >= 0);\n               STBTT_assert(dx >= 0);\n\n               x1 = (int) x_top;\n               x2 = (int) x_bottom;\n               // compute intersection with y axis at x1+1\n               y_crossing = y_top + dy * (x1+1 - x0);\n\n               // compute intersection with y axis at x2\n               y_final = y_top + dy * (x2 - x0);\n\n               //           x1    x_top                            x2    x_bottom\n               //     y_top  +------|-----+------------+------------+--------|---+------------+\n               //            |            |            |            |            |            |\n               //            |            |            |            |            |            |\n               //       sy0  |      Txxxxx|............|............|............|............|\n               // y_crossing |            *xxxxx.......|............|............|............|\n               //            |            |     xxxxx..|............|............|............|\n               //            |            |     /-   xx*xxxx........|............|............|\n               //            |            | dy <       |    xxxxxx..|............|............|\n               //   y_final  |            |     \\-     |          xx*xxx.........|............|\n               //       sy1  |            |            |            |   xxxxxB...|............|\n               //            |            |            |            |            |            |\n               //            |            |            |            |            |            |\n               //  y_bottom  +------------+------------+------------+------------+------------+\n               //\n               // goal is to measure the area covered by '.' in each pixel\n\n               // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057\n               // @TODO: maybe test against sy1 rather than y_bottom?\n               if (y_crossing > y_bottom)\n                  y_crossing = y_bottom;\n\n               sign = e->direction;\n\n               // area of the rectangle covered from sy0..y_crossing\n               area = sign * (y_crossing-sy0);\n\n               // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)\n               scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);\n\n               // check if final y_crossing is blown up; no test case for this\n               if (y_final > y_bottom) {\n                  y_final = y_bottom;\n                  dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom\n               }\n\n               // in second pixel, area covered by line segment found in first pixel\n               // is always a rectangle 1 wide * the height of that line segment; this\n               // is exactly what the variable 'area' stores. it also gets a contribution\n               // from the line segment within it. the THIRD pixel will get the first\n               // pixel's rectangle contribution, the second pixel's rectangle contribution,\n               // and its own contribution. the 'own contribution' is the same in every pixel except\n               // the leftmost and rightmost, a trapezoid that slides down in each pixel.\n               // the second pixel's contribution to the third pixel will be the\n               // rectangle 1 wide times the height change in the second pixel, which is dy.\n\n               step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,\n               // which multiplied by 1-pixel-width is how much pixel area changes for each step in x\n               // so the area advances by 'step' every time\n\n               for (x = x1+1; x < x2; ++x) {\n                  scanline[x] += area + step/2; // area of trapezoid is 1*step/2\n                  area += step;\n               }\n               STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down\n               STBTT_assert(sy1 > y_final-0.01f);\n\n               // area covered in the last pixel is the rectangle from all the pixels to the left,\n               // plus the trapezoid filled by the line segment in this pixel all the way to the right edge\n               scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);\n\n               // the rest of the line is filled based on the total height of the line segment in this pixel\n               scanline_fill[x2] += sign * (sy1-sy0);\n            }\n         } else {\n            // if edge goes outside of box we're drawing, we require\n            // clipping logic. since this does not match the intended use\n            // of this library, we use a different, very slow brute\n            // force implementation\n            // note though that this does happen some of the time because\n            // x_top and x_bottom can be extrapolated at the top & bottom of\n            // the shape and actually lie outside the bounding box\n            int x;\n            for (x=0; x < len; ++x) {\n               // cases:\n               //\n               // there can be up to two intersections with the pixel. any intersection\n               // with left or right edges can be handled by splitting into two (or three)\n               // regions. intersections with top & bottom do not necessitate case-wise logic.\n               //\n               // the old way of doing this found the intersections with the left & right edges,\n               // then used some simple logic to produce up to three segments in sorted order\n               // from top-to-bottom. however, this had a problem: if an x edge was epsilon\n               // across the x border, then the corresponding y position might not be distinct\n               // from the other y segment, and it might ignored as an empty segment. to avoid\n               // that, we need to explicitly produce segments based on x positions.\n\n               // rename variables to clearly-defined pairs\n               float y0 = y_top;\n               float x1 = (float) (x);\n               float x2 = (float) (x+1);\n               float x3 = xb;\n               float y3 = y_bottom;\n\n               // x = e->x + e->dx * (y-y_top)\n               // (y-y_top) = (x - e->x) / e->dx\n               // y = (x - e->x) / e->dx + y_top\n               float y1 = (x - x0) / dx + y_top;\n               float y2 = (x+1 - x0) / dx + y_top;\n\n               if (x0 < x1 && x3 > x2) {         // three segments descending down-right\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else {  // one segment\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);\n               }\n            }\n         }\n      }\n      e = e->next;\n   }\n}\n\n// directly AA rasterize edges w/o supersampling\nstatic void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)\n{\n   stbtt__hheap hh = { 0, 0, 0 };\n   stbtt__active_edge *active = NULL;\n   int y,j=0, i;\n   float scanline_data[129], *scanline, *scanline2;\n\n   STBTT__NOTUSED(vsubsample);\n\n   if (result->w > 64)\n      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);\n   else\n      scanline = scanline_data;\n\n   scanline2 = scanline + result->w;\n\n   y = off_y;\n   e[n].y0 = (float) (off_y + result->h) + 1;\n\n   while (j < result->h) {\n      // find center of pixel for this scanline\n      float scan_y_top    = y + 0.0f;\n      float scan_y_bottom = y + 1.0f;\n      stbtt__active_edge **step = &active;\n\n      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));\n      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));\n\n      // update all active edges;\n      // remove all active edges that terminate before the top of this scanline\n      while (*step) {\n         stbtt__active_edge * z = *step;\n         if (z->ey <= scan_y_top) {\n            *step = z->next; // delete from list\n            STBTT_assert(z->direction);\n            z->direction = 0;\n            stbtt__hheap_free(&hh, z);\n         } else {\n            step = &((*step)->next); // advance through list\n         }\n      }\n\n      // insert all edges that start before the bottom of this scanline\n      while (e->y0 <= scan_y_bottom) {\n         if (e->y0 != e->y1) {\n            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);\n            if (z != NULL) {\n               if (j == 0 && off_y != 0) {\n                  if (z->ey < scan_y_top) {\n                     // this can happen due to subpixel positioning and some kind of fp rounding error i think\n                     z->ey = scan_y_top;\n                  }\n               }\n               STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds\n               // insert at front\n               z->next = active;\n               active = z;\n            }\n         }\n         ++e;\n      }\n\n      // now process all active edges\n      if (active)\n         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);\n\n      {\n         float sum = 0;\n         for (i=0; i < result->w; ++i) {\n            float k;\n            int m;\n            sum += scanline2[i];\n            k = scanline[i] + sum;\n            k = (float) STBTT_fabs(k)*255 + 0.5f;\n            m = (int) k;\n            if (m > 255) m = 255;\n            result->pixels[j*result->stride + i] = (unsigned char) m;\n         }\n      }\n      // advance all the edges\n      step = &active;\n      while (*step) {\n         stbtt__active_edge *z = *step;\n         z->fx += z->fdx; // advance to position for current scanline\n         step = &((*step)->next); // advance through list\n      }\n\n      ++y;\n      ++j;\n   }\n\n   stbtt__hheap_cleanup(&hh, userdata);\n\n   if (scanline != scanline_data)\n      STBTT_free(scanline, userdata);\n}\n#else\n#error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n\n#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)\n\nstatic void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)\n{\n   int i,j;\n   for (i=1; i < n; ++i) {\n      stbtt__edge t = p[i], *a = &t;\n      j = i;\n      while (j > 0) {\n         stbtt__edge *b = &p[j-1];\n         int c = STBTT__COMPARE(a,b);\n         if (!c) break;\n         p[j] = p[j-1];\n         --j;\n      }\n      if (i != j)\n         p[j] = t;\n   }\n}\n\nstatic void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)\n{\n   /* threshold for transitioning to insertion sort */\n   while (n > 12) {\n      stbtt__edge t;\n      int c01,c12,c,m,i,j;\n\n      /* compute median of three */\n      m = n >> 1;\n      c01 = STBTT__COMPARE(&p[0],&p[m]);\n      c12 = STBTT__COMPARE(&p[m],&p[n-1]);\n      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */\n      if (c01 != c12) {\n         /* otherwise, we'll need to swap something else to middle */\n         int z;\n         c = STBTT__COMPARE(&p[0],&p[n-1]);\n         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */\n         /* 0<mid && mid>n:  0>n => 0; 0<n => n */\n         z = (c == c12) ? 0 : n-1;\n         t = p[z];\n         p[z] = p[m];\n         p[m] = t;\n      }\n      /* now p[m] is the median-of-three */\n      /* swap it to the beginning so it won't move around */\n      t = p[0];\n      p[0] = p[m];\n      p[m] = t;\n\n      /* partition loop */\n      i=1;\n      j=n-1;\n      for(;;) {\n         /* handling of equality is crucial here */\n         /* for sentinels & efficiency with duplicates */\n         for (;;++i) {\n            if (!STBTT__COMPARE(&p[i], &p[0])) break;\n         }\n         for (;;--j) {\n            if (!STBTT__COMPARE(&p[0], &p[j])) break;\n         }\n         /* make sure we haven't crossed */\n         if (i >= j) break;\n         t = p[i];\n         p[i] = p[j];\n         p[j] = t;\n\n         ++i;\n         --j;\n      }\n      /* recurse on smaller side, iterate on larger */\n      if (j < (n-i)) {\n         stbtt__sort_edges_quicksort(p,j);\n         p = p+i;\n         n = n-i;\n      } else {\n         stbtt__sort_edges_quicksort(p+i, n-i);\n         n = j;\n      }\n   }\n}\n\nstatic void stbtt__sort_edges(stbtt__edge *p, int n)\n{\n   stbtt__sort_edges_quicksort(p, n);\n   stbtt__sort_edges_ins_sort(p, n);\n}\n\ntypedef struct\n{\n   float x,y;\n} stbtt__point;\n\nstatic void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)\n{\n   float y_scale_inv = invert ? -scale_y : scale_y;\n   stbtt__edge *e;\n   int n,i,j,k,m;\n#if STBTT_RASTERIZER_VERSION == 1\n   int vsubsample = result->h < 8 ? 15 : 5;\n#elif STBTT_RASTERIZER_VERSION == 2\n   int vsubsample = 1;\n#else\n   #error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity\n\n   // now we have to blow out the windings into explicit edge lists\n   n = 0;\n   for (i=0; i < windings; ++i)\n      n += wcount[i];\n\n   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel\n   if (e == 0) return;\n   n = 0;\n\n   m=0;\n   for (i=0; i < windings; ++i) {\n      stbtt__point *p = pts + m;\n      m += wcount[i];\n      j = wcount[i]-1;\n      for (k=0; k < wcount[i]; j=k++) {\n         int a=k,b=j;\n         // skip the edge if horizontal\n         if (p[j].y == p[k].y)\n            continue;\n         // add edge from j to k to the list\n         e[n].invert = 0;\n         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {\n            e[n].invert = 1;\n            a=j,b=k;\n         }\n         e[n].x0 = p[a].x * scale_x + shift_x;\n         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;\n         e[n].x1 = p[b].x * scale_x + shift_x;\n         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;\n         ++n;\n      }\n   }\n\n   // now sort the edges by their highest point (should snap to integer, and then by x)\n   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);\n   stbtt__sort_edges(e, n);\n\n   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule\n   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);\n\n   STBTT_free(e, userdata);\n}\n\nstatic void stbtt__add_point(stbtt__point *points, int n, float x, float y)\n{\n   if (!points) return; // during first pass, it's unallocated\n   points[n].x = x;\n   points[n].y = y;\n}\n\n// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching\nstatic int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)\n{\n   // midpoint\n   float mx = (x0 + 2*x1 + x2)/4;\n   float my = (y0 + 2*y1 + y2)/4;\n   // versus directly drawn line\n   float dx = (x0+x2)/2 - mx;\n   float dy = (y0+y2)/2 - my;\n   if (n > 16) // 65536 segments on one curve better be enough!\n      return 1;\n   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA\n      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);\n      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);\n   } else {\n      stbtt__add_point(points, *num_points,x2,y2);\n      *num_points = *num_points+1;\n   }\n   return 1;\n}\n\nstatic void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)\n{\n   // @TODO this \"flatness\" calculation is just made-up nonsense that seems to work well enough\n   float dx0 = x1-x0;\n   float dy0 = y1-y0;\n   float dx1 = x2-x1;\n   float dy1 = y2-y1;\n   float dx2 = x3-x2;\n   float dy2 = y3-y2;\n   float dx = x3-x0;\n   float dy = y3-y0;\n   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));\n   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);\n   float flatness_squared = longlen*longlen-shortlen*shortlen;\n\n   if (n > 16) // 65536 segments on one curve better be enough!\n      return;\n\n   if (flatness_squared > objspace_flatness_squared) {\n      float x01 = (x0+x1)/2;\n      float y01 = (y0+y1)/2;\n      float x12 = (x1+x2)/2;\n      float y12 = (y1+y2)/2;\n      float x23 = (x2+x3)/2;\n      float y23 = (y2+y3)/2;\n\n      float xa = (x01+x12)/2;\n      float ya = (y01+y12)/2;\n      float xb = (x12+x23)/2;\n      float yb = (y12+y23)/2;\n\n      float mx = (xa+xb)/2;\n      float my = (ya+yb)/2;\n\n      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);\n      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);\n   } else {\n      stbtt__add_point(points, *num_points,x3,y3);\n      *num_points = *num_points+1;\n   }\n}\n\n// returns number of contours\nstatic stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)\n{\n   stbtt__point *points=0;\n   int num_points=0;\n\n   float objspace_flatness_squared = objspace_flatness * objspace_flatness;\n   int i,n=0,start=0, pass;\n\n   // count how many \"moves\" there are to get the contour count\n   for (i=0; i < num_verts; ++i)\n      if (vertices[i].type == STBTT_vmove)\n         ++n;\n\n   *num_contours = n;\n   if (n == 0) return 0;\n\n   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);\n\n   if (*contour_lengths == 0) {\n      *num_contours = 0;\n      return 0;\n   }\n\n   // make two passes through the points so we don't need to realloc\n   for (pass=0; pass < 2; ++pass) {\n      float x=0,y=0;\n      if (pass == 1) {\n         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);\n         if (points == NULL) goto error;\n      }\n      num_points = 0;\n      n= -1;\n      for (i=0; i < num_verts; ++i) {\n         switch (vertices[i].type) {\n            case STBTT_vmove:\n               // start the next contour\n               if (n >= 0)\n                  (*contour_lengths)[n] = num_points - start;\n               ++n;\n               start = num_points;\n\n               x = vertices[i].x, y = vertices[i].y;\n               stbtt__add_point(points, num_points++, x,y);\n               break;\n            case STBTT_vline:\n               x = vertices[i].x, y = vertices[i].y;\n               stbtt__add_point(points, num_points++, x, y);\n               break;\n            case STBTT_vcurve:\n               stbtt__tesselate_curve(points, &num_points, x,y,\n                                        vertices[i].cx, vertices[i].cy,\n                                        vertices[i].x,  vertices[i].y,\n                                        objspace_flatness_squared, 0);\n               x = vertices[i].x, y = vertices[i].y;\n               break;\n            case STBTT_vcubic:\n               stbtt__tesselate_cubic(points, &num_points, x,y,\n                                        vertices[i].cx, vertices[i].cy,\n                                        vertices[i].cx1, vertices[i].cy1,\n                                        vertices[i].x,  vertices[i].y,\n                                        objspace_flatness_squared, 0);\n               x = vertices[i].x, y = vertices[i].y;\n               break;\n         }\n      }\n      (*contour_lengths)[n] = num_points - start;\n   }\n\n   return points;\nerror:\n   STBTT_free(points, userdata);\n   STBTT_free(*contour_lengths, userdata);\n   *contour_lengths = 0;\n   *num_contours = 0;\n   return NULL;\n}\n\nSTBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)\n{\n   float scale            = scale_x > scale_y ? scale_y : scale_x;\n   int winding_count      = 0;\n   int *winding_lengths   = NULL;\n   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);\n   if (windings) {\n      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);\n      STBTT_free(winding_lengths, userdata);\n      STBTT_free(windings, userdata);\n   }\n}\n\nSTBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)\n{\n   STBTT_free(bitmap, userdata);\n}\n\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)\n{\n   int ix0,iy0,ix1,iy1;\n   stbtt__bitmap gbm;\n   stbtt_vertex *vertices;\n   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);\n\n   if (scale_x == 0) scale_x = scale_y;\n   if (scale_y == 0) {\n      if (scale_x == 0) {\n         STBTT_free(vertices, info->userdata);\n         return NULL;\n      }\n      scale_y = scale_x;\n   }\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);\n\n   // now we get the size\n   gbm.w = (ix1 - ix0);\n   gbm.h = (iy1 - iy0);\n   gbm.pixels = NULL; // in case we error\n\n   if (width ) *width  = gbm.w;\n   if (height) *height = gbm.h;\n   if (xoff  ) *xoff   = ix0;\n   if (yoff  ) *yoff   = iy0;\n\n   if (gbm.w && gbm.h) {\n      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);\n      if (gbm.pixels) {\n         gbm.stride = gbm.w;\n\n         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);\n      }\n   }\n   STBTT_free(vertices, info->userdata);\n   return gbm.pixels;\n}\n\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)\n{\n   int ix0,iy0;\n   stbtt_vertex *vertices;\n   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);\n   stbtt__bitmap gbm;\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);\n   gbm.pixels = output;\n   gbm.w = out_w;\n   gbm.h = out_h;\n   gbm.stride = out_stride;\n\n   if (gbm.w && gbm.h)\n      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);\n\n   STBTT_free(vertices, info->userdata);\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);\n}\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)\n{\n   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));\n}\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)\n{\n   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// bitmap baking\n//\n// This is SUPER-CRAPPY packing to keep source code small\n\nstatic int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)\n                                float pixel_height,                     // height of font in pixels\n                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in\n                                int first_char, int num_chars,          // characters to bake\n                                stbtt_bakedchar *chardata)\n{\n   float scale;\n   int x,y,bottom_y, i;\n   stbtt_fontinfo f;\n   f.userdata = NULL;\n   if (!stbtt_InitFont(&f, data, offset))\n      return -1;\n   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels\n   x=y=1;\n   bottom_y = 1;\n\n   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);\n\n   for (i=0; i < num_chars; ++i) {\n      int advance, lsb, x0,y0,x1,y1,gw,gh;\n      int g = stbtt_FindGlyphIndex(&f, first_char + i);\n      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);\n      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);\n      gw = x1-x0;\n      gh = y1-y0;\n      if (x + gw + 1 >= pw)\n         y = bottom_y, x = 1; // advance to next row\n      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row\n         return -i;\n      STBTT_assert(x+gw < pw);\n      STBTT_assert(y+gh < ph);\n      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);\n      chardata[i].x0 = (stbtt_int16) x;\n      chardata[i].y0 = (stbtt_int16) y;\n      chardata[i].x1 = (stbtt_int16) (x + gw);\n      chardata[i].y1 = (stbtt_int16) (y + gh);\n      chardata[i].xadvance = scale * advance;\n      chardata[i].xoff     = (float) x0;\n      chardata[i].yoff     = (float) y0;\n      x = x + gw + 1;\n      if (y+gh+1 > bottom_y)\n         bottom_y = y+gh+1;\n   }\n   return bottom_y;\n}\n\nSTBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)\n{\n   float d3d_bias = opengl_fillrule ? 0 : -0.5f;\n   float ipw = 1.0f / pw, iph = 1.0f / ph;\n   const stbtt_bakedchar *b = chardata + char_index;\n   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);\n   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);\n\n   q->x0 = round_x + d3d_bias;\n   q->y0 = round_y + d3d_bias;\n   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;\n   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;\n\n   q->s0 = b->x0 * ipw;\n   q->t0 = b->y0 * iph;\n   q->s1 = b->x1 * ipw;\n   q->t1 = b->y1 * iph;\n\n   *xpos += b->xadvance;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// rectangle packing replacement routines if you don't have stb_rect_pack.h\n//\n\n#ifndef STB_RECT_PACK_VERSION\n\ntypedef int stbrp_coord;\n\n////////////////////////////////////////////////////////////////////////////////////\n//                                                                                //\n//                                                                                //\n// COMPILER WARNING ?!?!?                                                         //\n//                                                                                //\n//                                                                                //\n// if you get a compile warning due to these symbols being defined more than      //\n// once, move #include \"stb_rect_pack.h\" before #include \"stb_truetype.h\"         //\n//                                                                                //\n////////////////////////////////////////////////////////////////////////////////////\n\ntypedef struct\n{\n   int width,height;\n   int x,y,bottom_y;\n} stbrp_context;\n\ntypedef struct\n{\n   unsigned char x;\n} stbrp_node;\n\nstruct stbrp_rect\n{\n   stbrp_coord x,y;\n   int id,w,h,was_packed;\n};\n\nstatic void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)\n{\n   con->width  = pw;\n   con->height = ph;\n   con->x = 0;\n   con->y = 0;\n   con->bottom_y = 0;\n   STBTT__NOTUSED(nodes);\n   STBTT__NOTUSED(num_nodes);\n}\n\nstatic void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)\n{\n   int i;\n   for (i=0; i < num_rects; ++i) {\n      if (con->x + rects[i].w > con->width) {\n         con->x = 0;\n         con->y = con->bottom_y;\n      }\n      if (con->y + rects[i].h > con->height)\n         break;\n      rects[i].x = con->x;\n      rects[i].y = con->y;\n      rects[i].was_packed = 1;\n      con->x += rects[i].w;\n      if (con->y + rects[i].h > con->bottom_y)\n         con->bottom_y = con->y + rects[i].h;\n   }\n   for (   ; i < num_rects; ++i)\n      rects[i].was_packed = 0;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// bitmap baking\n//\n// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If\n// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.\n\nSTBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)\n{\n   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);\n   int            num_nodes = pw - padding;\n   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);\n\n   if (context == NULL || nodes == NULL) {\n      if (context != NULL) STBTT_free(context, alloc_context);\n      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);\n      return 0;\n   }\n\n   spc->user_allocator_context = alloc_context;\n   spc->width = pw;\n   spc->height = ph;\n   spc->pixels = pixels;\n   spc->pack_info = context;\n   spc->nodes = nodes;\n   spc->padding = padding;\n   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;\n   spc->h_oversample = 1;\n   spc->v_oversample = 1;\n   spc->skip_missing = 0;\n\n   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);\n\n   if (pixels)\n      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels\n\n   return 1;\n}\n\nSTBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)\n{\n   STBTT_free(spc->nodes    , spc->user_allocator_context);\n   STBTT_free(spc->pack_info, spc->user_allocator_context);\n}\n\nSTBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)\n{\n   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);\n   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);\n   if (h_oversample <= STBTT_MAX_OVERSAMPLE)\n      spc->h_oversample = h_oversample;\n   if (v_oversample <= STBTT_MAX_OVERSAMPLE)\n      spc->v_oversample = v_oversample;\n}\n\nSTBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)\n{\n   spc->skip_missing = skip;\n}\n\n#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)\n\nstatic void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)\n{\n   unsigned char buffer[STBTT_MAX_OVERSAMPLE];\n   int safe_w = w - kernel_width;\n   int j;\n   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze\n   for (j=0; j < h; ++j) {\n      int i;\n      unsigned int total;\n      STBTT_memset(buffer, 0, kernel_width);\n\n      total = 0;\n\n      // make kernel_width a constant in common cases so compiler can optimize out the divide\n      switch (kernel_width) {\n         case 2:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 2);\n            }\n            break;\n         case 3:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 3);\n            }\n            break;\n         case 4:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 4);\n            }\n            break;\n         case 5:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 5);\n            }\n            break;\n         default:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / kernel_width);\n            }\n            break;\n      }\n\n      for (; i < w; ++i) {\n         STBTT_assert(pixels[i] == 0);\n         total -= buffer[i & STBTT__OVER_MASK];\n         pixels[i] = (unsigned char) (total / kernel_width);\n      }\n\n      pixels += stride_in_bytes;\n   }\n}\n\nstatic void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)\n{\n   unsigned char buffer[STBTT_MAX_OVERSAMPLE];\n   int safe_h = h - kernel_width;\n   int j;\n   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze\n   for (j=0; j < w; ++j) {\n      int i;\n      unsigned int total;\n      STBTT_memset(buffer, 0, kernel_width);\n\n      total = 0;\n\n      // make kernel_width a constant in common cases so compiler can optimize out the divide\n      switch (kernel_width) {\n         case 2:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);\n            }\n            break;\n         case 3:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);\n            }\n            break;\n         case 4:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);\n            }\n            break;\n         case 5:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);\n            }\n            break;\n         default:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);\n            }\n            break;\n      }\n\n      for (; i < h; ++i) {\n         STBTT_assert(pixels[i*stride_in_bytes] == 0);\n         total -= buffer[i & STBTT__OVER_MASK];\n         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);\n      }\n\n      pixels += 1;\n   }\n}\n\nstatic float stbtt__oversample_shift(int oversample)\n{\n   if (!oversample)\n      return 0.0f;\n\n   // The prefilter is a box filter of width \"oversample\",\n   // which shifts phase by (oversample - 1)/2 pixels in\n   // oversampled space. We want to shift in the opposite\n   // direction to counter this.\n   return (float)-(oversample - 1) / (2.0f * (float)oversample);\n}\n\n// rects array must be big enough to accommodate all characters in the given ranges\nSTBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)\n{\n   int i,j,k;\n   int missing_glyph_added = 0;\n\n   k=0;\n   for (i=0; i < num_ranges; ++i) {\n      float fh = ranges[i].font_size;\n      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);\n      ranges[i].h_oversample = (unsigned char) spc->h_oversample;\n      ranges[i].v_oversample = (unsigned char) spc->v_oversample;\n      for (j=0; j < ranges[i].num_chars; ++j) {\n         int x0,y0,x1,y1;\n         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];\n         int glyph = stbtt_FindGlyphIndex(info, codepoint);\n         if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {\n            rects[k].w = rects[k].h = 0;\n         } else {\n            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,\n                                            scale * spc->h_oversample,\n                                            scale * spc->v_oversample,\n                                            0,0,\n                                            &x0,&y0,&x1,&y1);\n            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);\n            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);\n            if (glyph == 0)\n               missing_glyph_added = 1;\n         }\n         ++k;\n      }\n   }\n\n   return k;\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info,\n                                 output,\n                                 out_w - (prefilter_x - 1),\n                                 out_h - (prefilter_y - 1),\n                                 out_stride,\n                                 scale_x,\n                                 scale_y,\n                                 shift_x,\n                                 shift_y,\n                                 glyph);\n\n   if (prefilter_x > 1)\n      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);\n\n   if (prefilter_y > 1)\n      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);\n\n   *sub_x = stbtt__oversample_shift(prefilter_x);\n   *sub_y = stbtt__oversample_shift(prefilter_y);\n}\n\n// rects array must be big enough to accommodate all characters in the given ranges\nSTBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)\n{\n   int i,j,k, missing_glyph = -1, return_value = 1;\n\n   // save current values\n   int old_h_over = spc->h_oversample;\n   int old_v_over = spc->v_oversample;\n\n   k = 0;\n   for (i=0; i < num_ranges; ++i) {\n      float fh = ranges[i].font_size;\n      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);\n      float recip_h,recip_v,sub_x,sub_y;\n      spc->h_oversample = ranges[i].h_oversample;\n      spc->v_oversample = ranges[i].v_oversample;\n      recip_h = 1.0f / spc->h_oversample;\n      recip_v = 1.0f / spc->v_oversample;\n      sub_x = stbtt__oversample_shift(spc->h_oversample);\n      sub_y = stbtt__oversample_shift(spc->v_oversample);\n      for (j=0; j < ranges[i].num_chars; ++j) {\n         stbrp_rect *r = &rects[k];\n         if (r->was_packed && r->w != 0 && r->h != 0) {\n            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];\n            int advance, lsb, x0,y0,x1,y1;\n            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];\n            int glyph = stbtt_FindGlyphIndex(info, codepoint);\n            stbrp_coord pad = (stbrp_coord) spc->padding;\n\n            // pad on left and top\n            r->x += pad;\n            r->y += pad;\n            r->w -= pad;\n            r->h -= pad;\n            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);\n            stbtt_GetGlyphBitmapBox(info, glyph,\n                                    scale * spc->h_oversample,\n                                    scale * spc->v_oversample,\n                                    &x0,&y0,&x1,&y1);\n            stbtt_MakeGlyphBitmapSubpixel(info,\n                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                          r->w - spc->h_oversample+1,\n                                          r->h - spc->v_oversample+1,\n                                          spc->stride_in_bytes,\n                                          scale * spc->h_oversample,\n                                          scale * spc->v_oversample,\n                                          0,0,\n                                          glyph);\n\n            if (spc->h_oversample > 1)\n               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                  r->w, r->h, spc->stride_in_bytes,\n                                  spc->h_oversample);\n\n            if (spc->v_oversample > 1)\n               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                  r->w, r->h, spc->stride_in_bytes,\n                                  spc->v_oversample);\n\n            bc->x0       = (stbtt_int16)  r->x;\n            bc->y0       = (stbtt_int16)  r->y;\n            bc->x1       = (stbtt_int16) (r->x + r->w);\n            bc->y1       = (stbtt_int16) (r->y + r->h);\n            bc->xadvance =                scale * advance;\n            bc->xoff     =       (float)  x0 * recip_h + sub_x;\n            bc->yoff     =       (float)  y0 * recip_v + sub_y;\n            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;\n            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;\n\n            if (glyph == 0)\n               missing_glyph = j;\n         } else if (spc->skip_missing) {\n            return_value = 0;\n         } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {\n            ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];\n         } else {\n            return_value = 0; // if any fail, report failure\n         }\n\n         ++k;\n      }\n   }\n\n   // restore original values\n   spc->h_oversample = old_h_over;\n   spc->v_oversample = old_v_over;\n\n   return return_value;\n}\n\nSTBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)\n{\n   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);\n}\n\nSTBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)\n{\n   stbtt_fontinfo info;\n   int i,j,n, return_value = 1;\n   //stbrp_context *context = (stbrp_context *) spc->pack_info;\n   stbrp_rect    *rects;\n\n   // flag all characters as NOT packed\n   for (i=0; i < num_ranges; ++i)\n      for (j=0; j < ranges[i].num_chars; ++j)\n         ranges[i].chardata_for_range[j].x0 =\n         ranges[i].chardata_for_range[j].y0 =\n         ranges[i].chardata_for_range[j].x1 =\n         ranges[i].chardata_for_range[j].y1 = 0;\n\n   n = 0;\n   for (i=0; i < num_ranges; ++i)\n      n += ranges[i].num_chars;\n\n   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);\n   if (rects == NULL)\n      return 0;\n\n   info.userdata = spc->user_allocator_context;\n   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));\n\n   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);\n\n   stbtt_PackFontRangesPackRects(spc, rects, n);\n\n   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);\n\n   STBTT_free(rects, spc->user_allocator_context);\n   return return_value;\n}\n\nSTBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,\n            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)\n{\n   stbtt_pack_range range;\n   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;\n   range.array_of_unicode_codepoints = NULL;\n   range.num_chars                   = num_chars_in_range;\n   range.chardata_for_range          = chardata_for_range;\n   range.font_size                   = font_size;\n   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);\n}\n\nSTBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)\n{\n   int i_ascent, i_descent, i_lineGap;\n   float scale;\n   stbtt_fontinfo info;\n   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));\n   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);\n   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);\n   *ascent  = (float) i_ascent  * scale;\n   *descent = (float) i_descent * scale;\n   *lineGap = (float) i_lineGap * scale;\n}\n\nSTBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)\n{\n   float ipw = 1.0f / pw, iph = 1.0f / ph;\n   const stbtt_packedchar *b = chardata + char_index;\n\n   if (align_to_integer) {\n      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);\n      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);\n      q->x0 = x;\n      q->y0 = y;\n      q->x1 = x + b->xoff2 - b->xoff;\n      q->y1 = y + b->yoff2 - b->yoff;\n   } else {\n      q->x0 = *xpos + b->xoff;\n      q->y0 = *ypos + b->yoff;\n      q->x1 = *xpos + b->xoff2;\n      q->y1 = *ypos + b->yoff2;\n   }\n\n   q->s0 = b->x0 * ipw;\n   q->t0 = b->y0 * iph;\n   q->s1 = b->x1 * ipw;\n   q->t1 = b->y1 * iph;\n\n   *xpos += b->xadvance;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// sdf computation\n//\n\n#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))\n#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))\n\nstatic int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])\n{\n   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];\n   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];\n   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];\n   float roperp = orig[1]*ray[0] - orig[0]*ray[1];\n\n   float a = q0perp - 2*q1perp + q2perp;\n   float b = q1perp - q0perp;\n   float c = q0perp - roperp;\n\n   float s0 = 0., s1 = 0.;\n   int num_s = 0;\n\n   if (a != 0.0) {\n      float discr = b*b - a*c;\n      if (discr > 0.0) {\n         float rcpna = -1 / a;\n         float d = (float) STBTT_sqrt(discr);\n         s0 = (b+d) * rcpna;\n         s1 = (b-d) * rcpna;\n         if (s0 >= 0.0 && s0 <= 1.0)\n            num_s = 1;\n         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {\n            if (num_s == 0) s0 = s1;\n            ++num_s;\n         }\n      }\n   } else {\n      // 2*b*s + c = 0\n      // s = -c / (2*b)\n      s0 = c / (-2 * b);\n      if (s0 >= 0.0 && s0 <= 1.0)\n         num_s = 1;\n   }\n\n   if (num_s == 0)\n      return 0;\n   else {\n      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);\n      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;\n\n      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;\n      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;\n      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;\n      float rod = orig[0]*rayn_x + orig[1]*rayn_y;\n\n      float q10d = q1d - q0d;\n      float q20d = q2d - q0d;\n      float q0rd = q0d - rod;\n\n      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;\n      hits[0][1] = a*s0+b;\n\n      if (num_s > 1) {\n         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;\n         hits[1][1] = a*s1+b;\n         return 2;\n      } else {\n         return 1;\n      }\n   }\n}\n\nstatic int equal(float *a, float *b)\n{\n   return (a[0] == b[0] && a[1] == b[1]);\n}\n\nstatic int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)\n{\n   int i;\n   float orig[2], ray[2] = { 1, 0 };\n   float y_frac;\n   int winding = 0;\n\n   // make sure y never passes through a vertex of the shape\n   y_frac = (float) STBTT_fmod(y, 1.0f);\n   if (y_frac < 0.01f)\n      y += 0.01f;\n   else if (y_frac > 0.99f)\n      y -= 0.01f;\n\n   orig[0] = x;\n   orig[1] = y;\n\n   // test a ray from (-infinity,y) to (x,y)\n   for (i=0; i < nverts; ++i) {\n      if (verts[i].type == STBTT_vline) {\n         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;\n         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;\n         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {\n            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;\n            if (x_inter < x)\n               winding += (y0 < y1) ? 1 : -1;\n         }\n      }\n      if (verts[i].type == STBTT_vcurve) {\n         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;\n         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;\n         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;\n         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));\n         int by = STBTT_max(y0,STBTT_max(y1,y2));\n         if (y > ay && y < by && x > ax) {\n            float q0[2],q1[2],q2[2];\n            float hits[2][2];\n            q0[0] = (float)x0;\n            q0[1] = (float)y0;\n            q1[0] = (float)x1;\n            q1[1] = (float)y1;\n            q2[0] = (float)x2;\n            q2[1] = (float)y2;\n            if (equal(q0,q1) || equal(q1,q2)) {\n               x0 = (int)verts[i-1].x;\n               y0 = (int)verts[i-1].y;\n               x1 = (int)verts[i  ].x;\n               y1 = (int)verts[i  ].y;\n               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {\n                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;\n                  if (x_inter < x)\n                     winding += (y0 < y1) ? 1 : -1;\n               }\n            } else {\n               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);\n               if (num_hits >= 1)\n                  if (hits[0][0] < 0)\n                     winding += (hits[0][1] < 0 ? -1 : 1);\n               if (num_hits >= 2)\n                  if (hits[1][0] < 0)\n                     winding += (hits[1][1] < 0 ? -1 : 1);\n            }\n         }\n      }\n   }\n   return winding;\n}\n\nstatic float stbtt__cuberoot( float x )\n{\n   if (x<0)\n      return -(float) STBTT_pow(-x,1.0f/3.0f);\n   else\n      return  (float) STBTT_pow( x,1.0f/3.0f);\n}\n\n// x^3 + a*x^2 + b*x + c = 0\nstatic int stbtt__solve_cubic(float a, float b, float c, float* r)\n{\n   float s = -a / 3;\n   float p = b - a*a / 3;\n   float q = a * (2*a*a - 9*b) / 27 + c;\n   float p3 = p*p*p;\n   float d = q*q + 4*p3 / 27;\n   if (d >= 0) {\n      float z = (float) STBTT_sqrt(d);\n      float u = (-q + z) / 2;\n      float v = (-q - z) / 2;\n      u = stbtt__cuberoot(u);\n      v = stbtt__cuberoot(v);\n      r[0] = s + u + v;\n      return 1;\n   } else {\n      float u = (float) STBTT_sqrt(-p/3);\n      float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative\n      float m = (float) STBTT_cos(v);\n      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;\n      r[0] = s + u * 2 * m;\n      r[1] = s - u * (m + n);\n      r[2] = s - u * (m - n);\n\n      //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?\n      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);\n      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);\n      return 3;\n   }\n}\n\nSTBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)\n{\n   float scale_x = scale, scale_y = scale;\n   int ix0,iy0,ix1,iy1;\n   int w,h;\n   unsigned char *data;\n\n   if (scale == 0) return NULL;\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);\n\n   // if empty, return NULL\n   if (ix0 == ix1 || iy0 == iy1)\n      return NULL;\n\n   ix0 -= padding;\n   iy0 -= padding;\n   ix1 += padding;\n   iy1 += padding;\n\n   w = (ix1 - ix0);\n   h = (iy1 - iy0);\n\n   if (width ) *width  = w;\n   if (height) *height = h;\n   if (xoff  ) *xoff   = ix0;\n   if (yoff  ) *yoff   = iy0;\n\n   // invert for y-downwards bitmaps\n   scale_y = -scale_y;\n\n   {\n      int x,y,i,j;\n      float *precompute;\n      stbtt_vertex *verts;\n      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);\n      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);\n      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);\n\n      for (i=0,j=num_verts-1; i < num_verts; j=i++) {\n         if (verts[i].type == STBTT_vline) {\n            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;\n            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;\n            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));\n            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;\n         } else if (verts[i].type == STBTT_vcurve) {\n            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;\n            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;\n            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;\n            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;\n            float len2 = bx*bx + by*by;\n            if (len2 != 0.0f)\n               precompute[i] = 1.0f / (bx*bx + by*by);\n            else\n               precompute[i] = 0.0f;\n         } else\n            precompute[i] = 0.0f;\n      }\n\n      for (y=iy0; y < iy1; ++y) {\n         for (x=ix0; x < ix1; ++x) {\n            float val;\n            float min_dist = 999999.0f;\n            float sx = (float) x + 0.5f;\n            float sy = (float) y + 0.5f;\n            float x_gspace = (sx / scale_x);\n            float y_gspace = (sy / scale_y);\n\n            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path\n\n            for (i=0; i < num_verts; ++i) {\n               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;\n\n               if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {\n                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;\n\n                  float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);\n                  if (dist2 < min_dist*min_dist)\n                     min_dist = (float) STBTT_sqrt(dist2);\n\n                  // coarse culling against bbox\n                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&\n                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)\n                  dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];\n                  STBTT_assert(i != 0);\n                  if (dist < min_dist) {\n                     // check position along line\n                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)\n                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)\n                     float dx = x1-x0, dy = y1-y0;\n                     float px = x0-sx, py = y0-sy;\n                     // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy\n                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve\n                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);\n                     if (t >= 0.0f && t <= 1.0f)\n                        min_dist = dist;\n                  }\n               } else if (verts[i].type == STBTT_vcurve) {\n                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;\n                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;\n                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);\n                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);\n                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);\n                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);\n                  // coarse culling against bbox to avoid computing cubic unnecessarily\n                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {\n                     int num=0;\n                     float ax = x1-x0, ay = y1-y0;\n                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;\n                     float mx = x0 - sx, my = y0 - sy;\n                     float res[3] = {0.f,0.f,0.f};\n                     float px,py,t,it,dist2;\n                     float a_inv = precompute[i];\n                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula\n                        float a = 3*(ax*bx + ay*by);\n                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);\n                        float c = mx*ax+my*ay;\n                        if (a == 0.0) { // if a is 0, it's linear\n                           if (b != 0.0) {\n                              res[num++] = -c/b;\n                           }\n                        } else {\n                           float discriminant = b*b - 4*a*c;\n                           if (discriminant < 0)\n                              num = 0;\n                           else {\n                              float root = (float) STBTT_sqrt(discriminant);\n                              res[0] = (-b - root)/(2*a);\n                              res[1] = (-b + root)/(2*a);\n                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work\n                           }\n                        }\n                     } else {\n                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point\n                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;\n                        float d = (mx*ax+my*ay) * a_inv;\n                        num = stbtt__solve_cubic(b, c, d, res);\n                     }\n                     dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);\n                     if (dist2 < min_dist*min_dist)\n                        min_dist = (float) STBTT_sqrt(dist2);\n\n                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {\n                        t = res[0], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {\n                        t = res[1], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {\n                        t = res[2], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                  }\n               }\n            }\n            if (winding == 0)\n               min_dist = -min_dist;  // if outside the shape, value is negative\n            val = onedge_value + pixel_dist_scale * min_dist;\n            if (val < 0)\n               val = 0;\n            else if (val > 255)\n               val = 255;\n            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;\n         }\n      }\n      STBTT_free(precompute, info->userdata);\n      STBTT_free(verts, info->userdata);\n   }\n   return data;\n}\n\nSTBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);\n}\n\nSTBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)\n{\n   STBTT_free(bitmap, userdata);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// font name matching -- recommended not to use this\n//\n\n// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string\nstatic stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)\n{\n   stbtt_int32 i=0;\n\n   // convert utf16 to utf8 and compare the results while converting\n   while (len2) {\n      stbtt_uint16 ch = s2[0]*256 + s2[1];\n      if (ch < 0x80) {\n         if (i >= len1) return -1;\n         if (s1[i++] != ch) return -1;\n      } else if (ch < 0x800) {\n         if (i+1 >= len1) return -1;\n         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;\n         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;\n      } else if (ch >= 0xd800 && ch < 0xdc00) {\n         stbtt_uint32 c;\n         stbtt_uint16 ch2 = s2[2]*256 + s2[3];\n         if (i+3 >= len1) return -1;\n         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;\n         if (s1[i++] != 0xf0 + (c >> 18)) return -1;\n         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;\n         s2 += 2; // plus another 2 below\n         len2 -= 2;\n      } else if (ch >= 0xdc00 && ch < 0xe000) {\n         return -1;\n      } else {\n         if (i+2 >= len1) return -1;\n         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;\n         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;\n      }\n      s2 += 2;\n      len2 -= 2;\n   }\n   return i;\n}\n\nstatic int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)\n{\n   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);\n}\n\n// returns results in whatever encoding you request... but note that 2-byte encodings\n// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare\nSTBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)\n{\n   stbtt_int32 i,count,stringOffset;\n   stbtt_uint8 *fc = font->data;\n   stbtt_uint32 offset = font->fontstart;\n   stbtt_uint32 nm = stbtt__find_table(fc, offset, \"name\");\n   if (!nm) return NULL;\n\n   count = ttUSHORT(fc+nm+2);\n   stringOffset = nm + ttUSHORT(fc+nm+4);\n   for (i=0; i < count; ++i) {\n      stbtt_uint32 loc = nm + 6 + 12 * i;\n      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)\n          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {\n         *length = ttUSHORT(fc+loc+8);\n         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));\n      }\n   }\n   return NULL;\n}\n\nstatic int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)\n{\n   stbtt_int32 i;\n   stbtt_int32 count = ttUSHORT(fc+nm+2);\n   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);\n\n   for (i=0; i < count; ++i) {\n      stbtt_uint32 loc = nm + 6 + 12 * i;\n      stbtt_int32 id = ttUSHORT(fc+loc+6);\n      if (id == target_id) {\n         // find the encoding\n         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);\n\n         // is this a Unicode encoding?\n         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {\n            stbtt_int32 slen = ttUSHORT(fc+loc+8);\n            stbtt_int32 off = ttUSHORT(fc+loc+10);\n\n            // check if there's a prefix match\n            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);\n            if (matchlen >= 0) {\n               // check for target_id+1 immediately following, with same encoding & language\n               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {\n                  slen = ttUSHORT(fc+loc+12+8);\n                  off = ttUSHORT(fc+loc+12+10);\n                  if (slen == 0) {\n                     if (matchlen == nlen)\n                        return 1;\n                  } else if (matchlen < nlen && name[matchlen] == ' ') {\n                     ++matchlen;\n                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))\n                        return 1;\n                  }\n               } else {\n                  // if nothing immediately following\n                  if (matchlen == nlen)\n                     return 1;\n               }\n            }\n         }\n\n         // @TODO handle other encodings\n      }\n   }\n   return 0;\n}\n\nstatic int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)\n{\n   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);\n   stbtt_uint32 nm,hd;\n   if (!stbtt__isfont(fc+offset)) return 0;\n\n   // check italics/bold/underline flags in macStyle...\n   if (flags) {\n      hd = stbtt__find_table(fc, offset, \"head\");\n      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;\n   }\n\n   nm = stbtt__find_table(fc, offset, \"name\");\n   if (!nm) return 0;\n\n   if (flags) {\n      // if we checked the macStyle flags, then just check the family and ignore the subfamily\n      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;\n   } else {\n      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;\n   }\n\n   return 0;\n}\n\nstatic int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)\n{\n   stbtt_int32 i;\n   for (i=0;;++i) {\n      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);\n      if (off < 0) return off;\n      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))\n         return off;\n   }\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-qual\"\n#endif\n\nSTBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,\n                                float pixel_height, unsigned char *pixels, int pw, int ph,\n                                int first_char, int num_chars, stbtt_bakedchar *chardata)\n{\n   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);\n}\n\nSTBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)\n{\n   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);\n}\n\nSTBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)\n{\n   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);\n}\n\nSTBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)\n{\n   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);\n}\n\nSTBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)\n{\n   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);\n}\n\nSTBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)\n{\n   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n#endif // STB_TRUETYPE_IMPLEMENTATION\n\n\n// FULL VERSION HISTORY\n//\n//   1.25 (2021-07-11) many fixes\n//   1.24 (2020-02-05) fix warning\n//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)\n//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined\n//   1.21 (2019-02-25) fix warning\n//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()\n//   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod\n//   1.18 (2018-01-29) add missing function\n//   1.17 (2017-07-23) make more arguments const; doc fix\n//   1.16 (2017-07-12) SDF support\n//   1.15 (2017-03-03) make more arguments const\n//   1.14 (2017-01-16) num-fonts-in-TTC function\n//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts\n//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual\n//   1.11 (2016-04-02) fix unused-variable warning\n//   1.10 (2016-04-02) allow user-defined fabs() replacement\n//                     fix memory leak if fontsize=0.0\n//                     fix warning from duplicate typedef\n//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges\n//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges\n//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;\n//                     allow PackFontRanges to pack and render in separate phases;\n//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);\n//                     fixed an assert() bug in the new rasterizer\n//                     replace assert() with STBTT_assert() in new rasterizer\n//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)\n//                     also more precise AA rasterizer, except if shapes overlap\n//                     remove need for STBTT_sort\n//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC\n//   1.04 (2015-04-15) typo in example\n//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes\n//   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++\n//   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match\n//                        non-oversampled; STBTT_POINT_SIZE for packed case only\n//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling\n//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)\n//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID\n//   0.8b (2014-07-07) fix a warning\n//   0.8  (2014-05-25) fix a few more warnings\n//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back\n//   0.6c (2012-07-24) improve documentation\n//   0.6b (2012-07-20) fix a few more warnings\n//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,\n//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty\n//   0.5  (2011-12-09) bugfixes:\n//                        subpixel glyph renderer computed wrong bounding box\n//                        first vertex of shape can be off-curve (FreeSans)\n//   0.4b (2011-12-03) fixed an error in the font baking example\n//   0.4  (2011-12-01) kerning, subpixel rendering (tor)\n//                    bugfixes for:\n//                        codepoint-to-glyph conversion using table fmt=12\n//                        codepoint-to-glyph conversion using table fmt=4\n//                        stbtt_GetBakedQuad with non-square texture (Zer)\n//                    updated Hello World! sample to use kerning and subpixel\n//                    fixed some warnings\n//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)\n//                    userdata, malloc-from-userdata, non-zero fill (stb)\n//   0.2  (2009-03-11) Fix unsigned/signed char warnings\n//   0.1  (2009-03-09) First public release\n//\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "doc/ChangeLog.md",
    "content": "# v0.10.2\n* do not show names of dummy objects\n* fix localized string loading, to fix a bug that some objects are not shown\n* fix a bug that some guide-line config entries are not correctly read\n\n# v0.10.1\n* fix map display after party window opened in multiplayer games\n\n# v0.10.0\n* (#102,#105,#106) update codes to support v1.2.69324\n* (#84) add game room name/password, server region and season patterns to `text_panel_pattern`\n* (#97) don't draw other players not in same ACT\n* change `full_line` to `line_style` in D2RMH.ini, and you can set it to 2 for displaying walkable path to target through new path finding functions, please not this would increase CPU usage.\n* refactoring TTF rendering to fix glitches on text display\n* add `object_size_minimal` to D2RMH.ini for minimal size of object quads\n* add `draw_on_game_bar` to D2RMH.ini\n* load all data from D2R Casc Storage directly now, so `gendata` is removed\n* add support to read D2/D2R's TBL/DC6 font, as well as refactoring TTF rendering to suite fonts with fixed pixel size\n  * add support to load fonts from D2R Casc Storage, and is the default option now\n* read language of D2R from registry if `language` is left empty in D2RMH.ini\n* add keyboard/mouse input and delay functions to plugin system\n* hide overlay window while game is not running\n* (d2mapapi_mod) add support for D2Legacy client v1.11a\n* (d2mapapi_mod) add simple BFS path finding\n\n# v0.9.4\n* fix support for D2R 1.1.67554\n\n# v0.9.3\n* d2mapapi_mod: add support for Diablo II Legacy 1.11b, 1.12 and 1.13d, now there are 4 versions supported: 1.11b, 1.12, 1.13c and 1.13d\n* (#44) show players on map even out of sight\n* set default FPS value to 25, to reduce extra GPU consumption\n* (#86) fix edge detection when `walkable_color` is 0,0,0,0\n* plugin system:\n  * (#85) possible crash on reloading config or quitting later\n  * do not throw exception on lua script initialization, show a message box with error description instead\n  * (#88) town_portal_check: should not check portal during loading screen\n\n# v0.9.2\n* add hotkey functions to plugin system\n* chicken_life plugin: disable it by default and toggle by hotkey `Ctrl+/`\n* add a hotkey plugin: `-`/`+`/`\\` to do zoom-out/zoom-in/map-show-toggle\n\n# v0.9.1\n* finished basic lua plugin support, with plugins: chicken_life and town_portal_check\n* add skill selection popup(0x100) to panel masks\n* fix the bug that `fps` not working while set to positive value\n* fix wrong size fetched on fullscreen mode for multiple monitors\n* fix nearby map exits detection\n\n# v0.9.0 prerelease\n* new transparency mechanism, now you can set each color with alpha channel, and are stack with global `alpha` setting\n* separate d2mapapi out as a standalone project, and re-add by git-subrepo, with lots of tweaks\n* D2RMH main program can be built in 64bit now, while using `d2mapapi_piped` as a child process for querying map data\n\n# v0.8.1\n* fix lines for some quest targets\n* fix random color blocks outside of map area sometime\n\n# v0.8\n* (#38) multi-instance support\n* (#66) fix issue that map layer not shown for non-expansion characters\n* (#68) fix issue that other players not shown\n* search for memory offsets in order to get expansion flag address, offsets from [MapAssist](https://github.com/OneXDeveloper/MapAssist/blob/9b5658760efa8e8e243a4927d25abd2c796a41df/Helpers/ProcessContext.cs#L115-L167)\n* fix `panel_mask` entry in config is not correctly processed\n* add waypoint panel to `panel_mask`\n* show neighbour maps, with `neighbour_map_bounds` entry added to D2RMH.ini\n* dynamic loading functions from ntdll.dll and build release binaries with mingw32 now, to minify risks of virus detection\n\n# v0.7\n* (#47, #59, #63) add adaptive size for `map_area`, and is set as default value, kinda resolves confusion caused by new mechanism of `map_area`\n* (#50) add text panel support, with new entries `text_panel_pattern` and `text_panel_position` in D2RMH.ini\n* (#58) fix bug that monster immunities is not shown when disable `show_monster_enchants`\n* (#60) add simple function that play sound on item dropping\n* (#61) items sold to merchants are not detected now\n* (#62) neutral NPCs in town, mercenaries and summons are shown as NPC now\n* show real names of mercenaries now\n* much simpler and faster way to detect real TalTomb, and show TalTomb with Super Unique monster(Ancient Kaa the Soulless) now\n* set D2R process finding interval to 5 seconds, and remove WinMM from dependencies\n* restore tray icon on Windows Explorer restart\n* add `Reload Config` to tray menu for quick reloading D2RMH.ini\n\n# v0.6.2\n* add `panel_mask` to config ini, which can hide map layer when panels are opened\n* fix the way to test local player\n* fix a logic bug that causes map layer not shown once D2R is closed and reopen\n* use real size in objects.txt for drawing map objects and draw doors on map layer now\n* (#46) config entries are changed and fixed, now it is able to display names, enchants and immunities for normal monsters:\n  * remove `show_normal_monsters`, merged into `show_monsters`, which has 3 available values now\n  * `show_monster_name` => `show_monster_names` and has 3 available values now\n  * `show_monster_enchant` => `show_monster_enchants` and has 3 available values now\n  * `show_monster_immune` => `show_monster_immunities` and has 3 available values now\n  * old config entries are still accepted, but please migrate to new names if possible\n* (gendata) can read D2R installation path from registry now\n\n# v0.6.1\n* add `map_area` to config ini, to restrict map drawing area\n* `msg_position` is relative to the whole D2R window now\n* add missing items to `D2RMH_data.ini` to avoid crash on filtering certain items\n* hide overlay when D2R window is not foreground\n\n# v0.6\n* add edge line to map, and dim color for walkable area in default config\n* add dropped item filter, with `show_items`, `msg_font_size`, `msg_bg_color` added to config ini\n* add D2RMH_item.ini as item filter config, check comments inside for detail\n* add `monster_color`, `unique_monster_color`, `npc_color`, `show_npc_name` to config ini\n* add `msg_position` to config ini for message list position\n* try a new way to locate current player in multiplayer games\n* add reading installation path from registry as fallback\n* change default config values (better for common use):\n    * font_size: 12->14\n    * position: 1->2\n    * scale: 1.0->2.0\n    * map_centered: 0->1\n    * show_monster_name: 1->0\n* fix bug that running D2RMH before D2R(windowed) causes overlay window shown out of window\n* add an About dialog\n* refactoring some remote mem reading codes to make it more readable\n* refactoring string matching codes to improve performance\n\n# v0.5.4\n* show all players(including corpse) now\n* add show_player_names to config ini\n* show player's town portals and permanent portals now\n* support 67005\n* a potential crash and other bugs fix\n\n# v0.5.3\n* can detect monster aura type now\n* always show NPCs\n* add show_normal_monster to config ini\n* add enchants display text settings to config ini, uses text color list from d2hackmap\n* add FPS/VSync setting to config ini\n* fix bug that `show_monster_immune` was not processed\n\n# v0.5.2\n* add monster resist(immune) display\n* minor bug fixes and performance optimizations\n\n# v0.5.1\n* add nearby monsters(super-unique/boss/champion only) display\n* fix shrine text stack issue, and remove opened shrines' title\n* fix crash due to memory searching function changes\n\n# v0.5\n* support D2R 66878 update\n* totally rewritten rendering engine, removes several dependencies(sokol, fontstash)\n* add an exclusive-run check\n* add a tray icon and remove program from taskbar\n* optimize d2mapapi a bit\n* show nearby shrines (you can disable it by set `show_objects=0` in D2RMH.ini)\n* set default values for ini configurations so D2RMH can be run without D2RMH.ini (but you still need D2RMH_data.ini)\n* add Caged Barbarian Quest to useful objects\n\n# v0.4\n* (#2) add 397 to useful_objects\n* fixed path display between Rogue Encampment and Blood Moor, and similar paths\n* reduce memory use of vertex buffers\n* alpha and all color values can be set in configuration file now\n\n# v0.3\n* add various configurations in D2RMH.ini, check comments there\n* fix Gidbinn guide line\n\n# v0.2\n* add display for Unique Chest, Well, neighbour map path\n* fix display of correct taltomb entrance\n* shorter line pointed to target, similar to legacy d2hackmap\n* peformance tweaks to d2mapapi\n\n# v0.1\n* first release, with complete map revealing and quest/npc guides\n"
  },
  {
    "path": "doc/ItemDesc.md",
    "content": "﻿|  ID | code | enUS                             | zhTW      | deDE                               | esES                                 | frFR                                    | itIT                                  | koKR         | plPL                           | esMX                                  | jaJP           | ptBR                                | ruRU                              | zhCN      |\n|----:|------|----------------------------------|-----------|------------------------------------|--------------------------------------|-----------------------------------------|---------------------------------------|--------------|--------------------------------|---------------------------------------|----------------|-------------------------------------|-----------------------------------|-----------|\n|   0 | hax  | Hand Axe                         | 手斧        | [fs]Handaxt                        | [fs]Hacha de mano                    | [fs]Hache de poing                      | [fs]Mannaia                           | 핸드 액스        | [ms]Ręczny Toporek             | [fs]Hacha de mano                     | 片手斧            | [ms]Machado de Mão                  | [ms]одноручный топор              | 手斧        |\n|   1 | axe  | Axe                              | 斧         | [fs]Axt                            | [fs]Hacha                            | [fs]Hache                               | [fs]Ascia                             | 액스           | [ms]Topór                      | [fs]Hacha                             | 斧              | [ms]Machado                         | [ms]топор                         | 斧         |\n|   2 | 2ax  | Double Axe                       | 雙刃斧       | [fs]Doppelaxt                      | [fs]Hacha doble                      | [fs]Francisque                          | [fs]Ascia Bipenne                     | 더블 액스        | [ms]Podwójny Topór             | [fs]Hacha doble                       | 両刃斧            | [ms]Machado Duplo                   | [ms]обоюдоострый топор            | 双刃斧       |\n|   3 | mpi  | Military Pick                    | 軍用鎬       | [fs]Militärpicke                   | [ms]Pico militar                     | [ms]Épieu militaire                     | [fs]Picca                             | 밀리터리 픽       | [ms]Nadziak                    | [ms]Pico militar                      | ミリタリー・ピック      | [fs]Picareta Militar                | [ms]солдатский клевец             | 军镐        |\n|   4 | wax  | War Axe                          | 征戰斧       | [fs]Kriegsaxt                      | [fs]Hacha de guerra                  | [fs]Hache de guerre                     | [fs]Ascia da Guerra                   | 워 액스         | [ms]Bojowy Topór               | [fs]Hacha de guerra                   | ウォー・アックス       | [ms]Machado Bélico                  | [ms]воинский топор                | 战斧        |\n|   5 | lax  | Large Axe                        | 重斧        | [fs]große Axt                      | [fs]Hacha grande                     | [fs]Hache de combat                     | [fs]Ascia Grande                      | 라지 액스        | [ms]Duży Topór                 | [fs]Hacha grande                      | 大斧             | [ms]Machado Grande                  | [ms]большой топор                 | 大斧        |\n|   6 | bax  | Broad Axe                        | 闊斧        | [fs]Breitaxt                       | [fs]Hacha ancha                      | [fs]Large hache                         | [fs]Ascia Larga                       | 브로드 액스       | [ms]Szeroki Topór              | [fs]Hacha ancha                       | ブロード・アックス      | [ms]Machado Largo                   | [ms]широколезвийный топор         | 宽刃斧       |\n|   7 | btx  | Battle Axe                       | 戰斧        | [fs]Kampfaxt                       | [fs]Hacha de batalla                 | [fs]Hache de bataille                   | [fs]Ascia da Battaglia                | 배틀 액스        | [ms]Bitewny Topór              | [fs]Hacha de batalla                  | 戦斧             | [ms]Machado de Batalha              | [ms]боевой топор                  | 战斗斧       |\n|   8 | gax  | Great Axe                        | 巨斧        | [fs]schwere Axt                    | [fs]Gran hacha                       | [fs]Grande hache                        | [fs]Grande Ascia                      | 그레이트 액스      | [ms]Wielki Topór               | [fs]Gran hacha                        | グレート・アックス      | [ms]Grão-machado                    | [ms]огромный топор                | 重斧        |\n|   9 | gix  | Giant Axe                        | 巨人斧       | [fs]Riesenaxt                      | [fs]Hacha gigante                    | [fs]Hache géante                        | [fs]Ascia Gigante                     | 자이언트 액스      | [ms]Ogromny Topór              | [fs]Hacha gigante                     | ジャイアント・アックス    | [ms]Machado Gigante                 | [ms]гигантский топор              | 巨斧        |\n|  10 | wnd  | Wand                             | 魔杖        | [ms]Stab                           | [fs]Vara                             | [fs]Baguette                            | [fs]Verga                             | 원드           | [fs]Różdżka                    | [fs]Vara                              | ワンド            | [fs]Varinha                         | [ms]жезл                          | 魔杖        |\n|  11 | ywn  | Yew Wand                         | 紫杉魔杖      | [ms]Eibenstab                      | [fs]Vara de tejo                     | [fs]Baguette en if                      | [fs]Verga di Tasso                    | 유 원드         | [fs]Cisowa Różdżka             | [fs]Vara de tejo                      | イューワンド         | [fs]Varinha de Teixo                | [ms]тисовый жезл                  | 紫杉魔杖      |\n|  12 | bwn  | Bone Wand                        | 骸骨魔杖      | [ms]Knochenstab                    | [fs]Vara de hueso                    | [fs]Baguette en os                      | [fs]Verga d'Ossa                      | 본 원드         | [fs]Kościana Różdżka           | [fs]Vara ósea                         | ボーン・ワンド        | [fs]Varinha Óssea                   | [ms]костяной жезл                 | 白骨魔杖      |\n|  13 | gwn  | Grim Wand                        | 陰森魔杖      | [ms]Schlagstab                     | [fs]Vara lúgubre                     | [fs]Baguette macabre                    | [fs]Verga Arcigna                     | 그림 원드        | [fs]Złowroga Różdżka           | [fs]Vara lúgubre                      | グリム・ワンド        | [fs]Varinha Sinistra                | [ms]устрашающий жезл              | 恐怖魔杖      |\n|  14 | clb  | Club                             | 短棒        | [fs]Keule                          | [fs]Porra                            | [fs]Massue                              | [fs]Clava                             | 클럽           | [fs]Maczuga                    | [fs]Porra                             | クラブ            | [fs]Clava                           | [fs]дубина                        | 木棒        |\n|  15 | scp  | Scepter                          | 權杖        | [ns]Szepter                        | [ms]Cetro                            | [ms]Sceptre                             | [ms]Scettro                           | 셉터           | [nl]Berło                      | [ms]Cetro                             | セプター           | [ms]Cetro                           | [ms]скипетр                       | 权杖        |\n|  16 | gsc  | Grand Scepter                    | 莊嚴權杖      | [ns]großes Szepter                 | [ms]Gran cetro                       | [ms]Grand sceptre                       | [ms]Grande Scettro                    | 그랜드 셉터       | [nl]Wielkie Berło              | [ms]Gran cetro                        | グランド・セプター      | [ms]Grande Cetro                    | [ms]большой скипетр               | 大权杖       |\n|  17 | wsp  | War Scepter                      | 征戰權杖      | [ns]Kriegsszepter                  | [ms]Cetro de guerra                  | [ms]Sceptre de guerre                   | [ms]Scettro da Guerra                 | 워 셉터         | [nl]Bojowe Berło               | [ms]Cetro de guerra                   | ウォーセプター        | [ms]Cetro Bélico                    | [ms]воинский скипетр              | 战争权杖      |\n|  18 | spc  | Spiked Club                      | 狼牙棒       | [fs]Dornenkeule                    | [fs]Porra con pinchos                | [ms]Gourdin clouté                      | [fs]Clava Puntuta                     | 스파이크 클럽      | [fs]Kolczasta Maczuga          | [ms]Garrote con púas                  | スパイク・クラブ       | [fs]Clava com Espetos               | [fs]шипастая дубина               | 狼牙棒       |\n|  19 | mac  | Mace                             | 釘鎚        | [ms]Knüppel                        | [fs]Maza                             | [fs]Masse                               | [fs]Mazza                             | 메이스          | [fs]Buława                     | [fs]Maza                              | メイス            | [fs]Maça                            | [fs]булава                        | 钉锤        |\n|  20 | mst  | Morning Star                     | 釘頭鎚       | [ms]Morgenstern                    | [fs]Estrella del alba                | [ms]Morgenstern                         | [fs]Mazza Chiodata                    | 모닝스타         | [fs]Wekiera                    | [ms]Lucero del alba                   | モーニングスター       | [fs]Estrela da Manhã                | [ms]моргенштерн                   | 流星锤       |\n|  21 | fla  | Flail                            | 連枷        | [ms]Flegel                         | [ms]Mangual                          | [ms]Fléau                               | [ms]Mazzafrusto                       | 프레일          | [ms]Korbacz                    | [ms]Mangual                           | フレイル           | [ms]Mangual                         | [ms]кистень                       | 连枷        |\n|  22 | whm  | War Hammer                       | 戰鎚        | [ms]Kriegshammer                   | [ms]Martillo de guerra               | [ms]Marteau de guerre                   | [ms]Martello da Guerra                | 워 해머         | [ms]Bojowy Młot                | [ms]Martillo de guerra                | 戦鎚             | [ms]Martelo Bélico                  | [ms]воинский молот                | 战锤        |\n|  23 | mau  | Maul                             | 重鎚        | [ms]Holzhammer                     | [fs]Almádena                         | [ms]Merlin                              | [ms]Maglio                            | 마울           | [ms]Kafar                      | [ms]Mazo                              | モール            | [ms]Malho                           | [fs]кувалда                       | 大锤        |\n|  24 | gma  | Great Maul                       | 巨型重鎚      | [ms]großer Holzhammer              | [fs]Gran almádena                    | [ms]Merlin à deux mains                 | [ms]Grande Maglio                     | 그레이트 마울      | [ms]Wielki Kafar               | [ms]Gran mazo                         | グレート・モール       | [ms]Grande Malho                    | [fs]большая кувалда               | 重锤        |\n|  25 | ssd  | Short Sword                      | 短劍        | [ns]Kurzschwert                    | [fs]Espada corta                     | [fs]Épée courte                         | [fs]Spada Corta                       | 숏소드          | [ms]Krótki Miecz               | [fs]Espada corta                      | ショートソード        | [fs]Espada Curta                    | [ms]короткий меч                  | 短剑        |\n|  26 | scm  | Scimitar                         | 彎刀        | [ms]Krummsäbel                     | [fs]Cimitarra                        | [ms]Cimeterre                           | [fs]Scimitarra                        | 시미터          | [ms]Sejmitar                   | [fs]Cimitarra                         | シミター           | [fs]Cimitarra                       | [fs]кривая сабля                  | 弯刀        |\n|  27 | sbr  | Sabre                            | 軍刀        | [ms]Säbel                          | [ms]Sable                            | [ms]Sabre                               | [fs]Sciabola                          | 세이버          | [fs]Szabla                     | [ms]Sable                             | サーベル           | [ms]Sabre                           | [fs]сабля                         | 军刀        |\n|  28 | flc  | Falchion                         | 彎刃大刀      | [ns]Krummschwert                   | [ms]Chafarote                        | [ms]Fauchon                             | [ms]Falcione                          | 펄션           | [fs]Maczeta                    | [ms]Bracamante                        | ファルシオン         | [ms]Bracamante                      | [ms]фальшион                      | 弯刃剑       |\n|  29 | crs  | Crystal Sword                    | 水晶劍       | [ns]Kristallschwert                | [fs]Espada de cristal                | [fs]Épée de cristal                     | [fs]Spada di Cristallo                | 크리스탈 소드      | [ms]Kryształowy Miecz          | [fs]Espada de cristal                 | クリスタル・ソード      | [fs]Espada de Cristal               | [ms]кристаллический меч           | 水晶剑       |\n|  30 | bsd  | Broad Sword                      | 闊劍        | [ns]Breitschwert                   | [fs]Espada ancha                     | [fs]Épée large                          | [fs]Spada Larga                       | 브로드소드        | [ms]Pałasz                     | [fs]Espada ancha                      | ブロードソード        | [fs]Espada Larga                    | [ms]широкий меч                   | 阔剑        |\n|  31 | lsd  | Long Sword                       | 長劍        | [ns]Langschwert                    | [fs]Espada larga                     | [fs]Rapière                             | [fs]Spada Lunga                       | 롱소드          | [ms]Długi Miecz                | [fs]Espada larga                      | ロングソード         | [fs]Espada Longa                    | [ms]длинный меч                   | 长剑        |\n|  32 | wsd  | War Sword                        | 征戰劍       | [ns]Kriegsschwert                  | [fs]Espada de guerra                 | [fs]Épée de guerre                      | [fs]Spada da Guerra                   | 워 소드         | [ms]Bojowy Miecz               | [fs]Espada de guerra                  | ウォーソード         | [fs]Espada Bélica                   | [ms]воинский меч                  | 战争剑       |\n|  33 | 2hs  | Two-Handed Sword                 | 雙手劍       | [ns]Zweihänderschwert              | [ms]Mandoble                         | [fs]Épée à deux mains                   | [fs]Spada a Due Mani                  | 투핸드 소드       | [ms]Dwuręczny Miecz            | [fs]Espada de dos manos               | 両手剣            | [fs]Espada de Duas Mãos             | [ms]двуручный меч                 | 双手剑       |\n|  34 | clm  | Claymore                         | 闊刃大劍      | [ns]Schottenschwert                | [ms]Claymore                         | [fs]Claymore                            | [ms]Claymore                          | 클레이모어        | [ms]Claymore                   | [fs]Claymore                          | クレイモア          | [fs]Claymore                        | [ms]клеймор                       | 双手大剑      |\n|  35 | gis  | Giant Sword                      | 大劍        | [ns]Riesenschwert                  | [fs]Espada gigante                   | [fs]Épée géante                         | [fs]Spada Gigante                     | 자이언트 소드      | [ms]Ogromny Miecz              | [fs]Espada gigante                    | 大剣             | [fs]Espada Gigante                  | [ms]гигантский меч                | 巨剑        |\n|  36 | bsw  | Bastard Sword                    | 重劍        | [ns]Bastardschwert                 | [fs]Espada bastarda                  | [fs]Épée bâtarde                        | [fs]Spada Bastarda                    | 바스타드 소드      | [ms]Półtorak                   | [fs]Espada bastarda                   | バスタード・ソード      | [fs]Espada Bastarda                 | [ms]бастард                       | 手半剑       |\n|  37 | flb  | Flamberge                        | 焰形劍       | [ms]Flamberg                       | [ms]Flamberge                        | [fs]Flamberge                           | [fs]Flamberga                         | 플랑베르쥬        | [ms]Flamberg                   | [fs]Espada flamígera                  | フランベルジュ        | [fs]Flambérgia                      | [ms]фламберг                      | 焰刃剑       |\n|  38 | gsd  | Great Sword                      | 巨劍        | [ns]Großschwert                    | [fs]Gran espada                      | [fs]Grande épée                         | [ms]Spadone                           | 그레이트 소드      | [ms]Wielki Miecz               | [ms]Espadón                           | グレートソード        | [fs]Espada Montante                 | [ms]великий меч                   | 重剑        |\n|  39 | dgr  | Dagger                           | 匕首        | [ms]Dolch                          | [fs]Daga                             | [fs]Dague                               | [ms]Pugnale                           | 대거           | [ms]Sztylet                    | [fs]Daga                              | ダガー            | [fs]Adaga                           | [ms]кинжал                        | 匕首        |\n|  40 | dir  | Dirk                             | 長匕首       | [ns]Dolchmesser                    | [ms]Dirk                             | [ms]Surin                               | [ms]Dirk                              | 더크           | [ms]Kozik                      | [fs]Dirk                              | ダーク            | [fs]Dirk                            | [ms]кортик                        | 长匕首       |\n|  41 | kri  | Kris                             | 波刃匕首      | [ms]Kris                           | [ms]Kris                             | [ms]Kriss                               | [ms]Kris                              | 크리스          | [ms]Kris                       | [ms]Kris                              | クリス            | [fs]Kris                            | [ms]крис                          | 波刃剑       |\n|  42 | bld  | Blade                            | 利刃匕首      | [ns]messer                         | [fs]Navaja                           | [fs]Lame                                | [fs]Lama                              | 블레이드         | [fs]Klinga                     | [fs]Cuchilla                          | ブレイド           | [fs]Lâmina                          | [ms]клинок                        | 短刃        |\n|  43 | tkf  | Throwing Knife                   | 飛刀        | [ns]Wurfmesser                     | [ms]Cuchillo arrojadizo              | [ms]Couteau de lancer                   | [ms]Coltello da Lancio                | 스로잉 나이프      | [ms]Nóż do Rzucania            | [ms]Cuchillo arrojadizo               | 投げナイフ          | [fs]Faca de Arremesso               | [ms]метательный нож               | 投掷小刀      |\n|  44 | tax  | Throwing Axe                     | 飛斧        | [fs]Wurfaxt                        | [fs]Hacha arrojadiza                 | [fs]Hache de lancer                     | [fs]Ascia da Lancio                   | 스로잉 액스       | [ms]Topór do Rzucania          | [fs]Hacha arrojadiza                  | 投げ斧            | [ms]Machado de Arremesso            | [ms]метательный топорик           | 投掷斧       |\n|  45 | bkf  | Balanced Knife                   | 平衡飛刀      | [ns]Zwillingsmesser                | [ms]Cuchillo equilibrado             | [ms]Couteau équilibré                   | [ms]Coltello Bilanciato               | 밸런스드 나이프     | [ms]Wyważony Nóż               | [ms]Cuchillo equilibrado              | バランスド・ナイフ      | [fs]Faca Equilibrada                | [ms]сбалансированный нож          | 平衡飞刀      |\n|  46 | bal  | Balanced Axe                     | 平衡飛斧      | [fs]Zweifachaxt                    | [fs]Hacha equilibrada                | [fs]Hache équilibrée                    | [fs]Ascia Bilanciata                  | 밸런스드 액스      | [ms]Wyważony Topór             | [fs]Hacha equilibrada                 | バランスド・アックス     | [ms]Machado Equilibrado             | [ms]сбалансированный топор        | 平衡飞斧      |\n|  47 | jav  | Javelin                          | 標槍        | [ms]Wurfspieß                      | [fs]Jabalina                         | [ms]Javelot                             | [ms]Giavellotto                       | 재벌린          | [ms]Oszczep                    | [fs]Jabalina                          | ジャベリン          | [ms]Dardo                           | [ms]дротик                        | 标枪        |\n|  48 | pil  | Pilum                            | 長標槍       | [ms]Spieß                          | [ms]Pilum                            | [ms]Pilum                               | [ms]Pilum                             | 필럼           | [nl]Pilum                      | [ms]Pilum                             | ピルム            | [ms]Pilum                           | [ms]пилум                         | 长标枪       |\n|  49 | ssp  | Short Spear                      | 短矛        | [ms]Kurzspeer                      | [fs]Lanza corta                      | [fs]Lance courte                        | [fs]Lancia Corta                      | 숏스피어         | [fs]Krótka Włócznia            | [fs]Lanza corta                       | ショート・スピア       | [fs]Lança Curta                     | [ns]короткое копье                | 短矛        |\n|  50 | glv  | Glaive                           | 長刃槍       | [fs]Gleve                          | [fs]Guja                             | [ms]Couteau de brèche                   | [fs]Guisarma                          | 글레이브         | [fs]Glewia                     | [fs]Guja                              | グレイヴ           | [fs]Glaive                          | [fs]глефа                         | 梭镖        |\n|  51 | tsp  | Throwing Spear                   | 飛矛        | [ms]Wurfspeer                      | [fs]Lanza arrojadiza                 | [fs]Lance de jet                        | [fs]Lancia Veloce                     | 스로잉 스피어      | [fs]Włócznia do Rzucania       | [fs]Lanza arrojadiza                  | 投げスピア          | [fs]Lança de Arremesso              | [ns]метательное копье             | 投枪        |\n|  52 | spr  | Spear                            | 長矛        | [ms]Speer                          | [fs]Lanza                            | [fs]Lance                               | [fs]Lancia                            | 스피어          | [fs]Włócznia                   | [fs]Lanza                             | スピア            | [fs]Lança                           | [ns]копье                         | 矛         |\n|  53 | tri  | Trident                          | 三叉戟       | [ms]Dreizack                       | [ms]Tridente                         | [ms]Trident                             | [ms]Tridente                          | 트라이던트        | [ms]Trójząb                    | [ms]Tridente                          | トライデント         | [ms]Tridente                        | [ms]трезубец                      | 三叉戟       |\n|  54 | brn  | Brandistock                      | 三叉槍       | [fs]Forke                          | [fs]Roncona                          | [ms]Brandestoc                          | [ms]Brandistocco                      | 브랜디스탁        | [fs]Korseka                    | [fs]Corcesca                          | ブランディストック      | [fs]Brandistock                     | [fs]рунка                         | 羽剑杖       |\n|  55 | spt  | Spetum                           | 勾刃槍       | [ns]Spetum                         | [ms]Spetum                           | [ms]Spetum                              | [ms]Spetum                            | 스페텀          | [nl]Spetum                     | [fs]Roncona                           | スペタム           | [ms]Spetum                          | [ms]спетум                        | 镋钯        |\n|  56 | pik  | Pike                             | 步戰矛       | [fs]Pike                           | [fs]Pica                             | [fs]Pique                               | [fs]Picca                             | 파이크          | [fs]Pika                       | [fs]Pica                              | パイク            | [ms]Pique                           | [fs]пика                          | 尖枪        |\n|  57 | bar  | Bardiche                         | 月牙砍刀      | [fs]Bardike                        | [ms]Bardiche                         | [fs]Bardiche                            | [fs]Bardica                           | 바디쉬          | [ms]Berdysz                    | [ms]Bardiche                          | バルディッシュ        | [ms]Bardiche                        | [ms]бердыш                        | 大砍刀       |\n|  58 | vou  | Voulge                           | 槍斧        | [ms]Landsknechtsspieß              | [ms]Voulge                           | [ms]Vouge                               | [fs]Voulge                            | 불즈           | [ms]Voulge                     | [fs]Archa                             | ヴォウジェ          | [fs]Voulge                          | [ms]вуж                           | 斧戟        |\n|  59 | scy  | Scythe                           | 鐮刀        | [fs]Sense                          | [fs]Guadaña                          | [fs]Faux                                | [fs]Falce                             | 싸이드          | [fs]Kosa                       | [fs]Guadaña                           | サイス            | [fs]Foice                           | [fs]коса                          | 巨镰        |\n|  60 | pax  | Poleaxe                          | 長柄斧       | [ms]Schwengel                      | [fs]Hacha larga                      | [fs]Hache d’abordage                    | [fs]Ascia Inastata                    | 폴액스          | [fs]Gizarma                    | [fs]Hacha de petos                    | ポールアックス        | [fs]Acha                            | [ms]полэкс                        | 长柄斧       |\n|  61 | hal  | Halberd                          | 長戟        | [fs]Hellebarde                     | [fs]Alabarda                         | [fs]Hallebarde                          | [fs]Alabarda                          | 헬버드          | [fs]Halabarda                  | [fs]Alabarda                          | ハルバード          | [fs]Alabarda                        | [fs]алебарда                      | 斧枪        |\n|  62 | wsc  | War Scythe                       | 征戰鐮刀      | [fs]Kriegssense                    | [fs]Guadaña de guerra                | [fs]Faux de guerre                      | [fs]Falce da Guerra                   | 워 싸이드        | [fs]Bojowa Kosa                | [fs]Guadaña de guerra                 | ウォー・サイス        | [fs]Foice Bélica                    | [fs]воинская коса                 | 战争镰刀      |\n|  63 | sst  | Short Staff                      | 短杖        | [ms]Kurzstab                       | [ms]Bastón corto                     | [ms]Bâton court                         | [ms]Bastone Corto                     | 숏스태프         | [ms]Krótki Kostur              | [ms]Bastón corto                      | ショート・スタッフ      | [ms]Cajado Curto                    | [ms]короткий посох                | 短杖        |\n|  64 | lst  | Long Staff                       | 長杖        | [ms]Langstab                       | [ms]Bastón largo                     | [ms]Bâton long                          | [ms]Bastone Lungo                     | 롱스태프         | [ms]Długi Kostur               | [ms]Bastón largo                      | ロング・スタッフ       | [ms]Cajado Longo                    | [ms]длинный посох                 | 长杖        |\n|  65 | cst  | Gnarled Staff                    | 木節法杖      | [ms]Knorrenstab                    | [ms]Bastón nudoso                    | [ms]Bâton noueux                        | [ms]Bastone Nodoso                    | 나알드 스태프      | [ms]Sękaty Kostur              | [ms]Bastón nudoso                     | ナールド・スタッフ      | [ms]Cajado Nodoso                   | [ms]изогнутый посох               | 多节杖       |\n|  66 | bst  | Battle Staff                     | 戰鬥法杖      | [ms]Kriegsstab                     | [ms]Bastón de batalla                | [ms]Bâton de bataille                   | [ms]Bastone da Battaglia              | 배틀 스태프       | [ms]Bitewny Kostur             | [ms]Bastón de batalla                 | バトル・スタッフ       | [ms]Cajado de Batalha               | [ms]боевой посох                  | 战斗杖       |\n|  67 | wst  | War Staff                        | 征戰法杖      | [ms]Schlachtenstab                 | [ms]Bastón de guerra                 | [ms]Bâton de guerre                     | [ms]Bastone da Guerra                 | 워 스태프        | [ms]Bojowy Kostur              | [ms]Bastón de guerra                  | ウォー・スタッフ       | [ms]Cajado Bélico                   | [ms]воинский посох                | 战杖        |\n|  68 | sbw  | Short Bow                        | 短弓        | [ms]Kurzbogen                      | [ms]Arco corto                       | [ms]Arc court                           | [ms]Arco Corto                        | 숏보우          | [ms]Krótki Łuk                 | [ms]Arco corto                        | ショートボウ         | [ms]Arco Curto                      | [ms]короткий лук                  | 短弓        |\n|  69 | hbw  | Hunter's Bow                     | 獵弓        | [ms]Jagdbogen                      | [ms]Arco de cazador                  | [ms]Arc de chasseur                     | [ms]Arco da Caccia                    | 헌터보우         | [ms]Myśliwski Łuk              | [ms]Arco de cazador                   | ハンターズ・ボウ       | [ms]Arco de Caça                    | [ms]охотничий лук                 | 猎弓        |\n|  70 | lbw  | Long Bow                         | 長弓        | [ms]Langbogen                      | [ms]Arco largo                       | [ms]Arc long                            | [ms]Arco Lungo                        | 롱보우          | [ms]Długi Łuk                  | [ms]Arco largo                        | ロングボウ          | [ms]Arco Longo                      | [ms]длинный лук                   | 长弓        |\n|  71 | cbw  | Composite Bow                    | 複合弓       | [ms]Kompositbogen                  | [ms]Arco compuesto                   | [ms]Arc composite                       | [ms]Arco Composito                    | 컴포지트 보우      | [ms]Kompozytowy Łuk            | [ms]Arco compuesto                    | コンポジット・ボウ      | [ms]Arco Composto                   | [ms]составной лук                 | 复合弓       |\n|  72 | sbb  | Short Battle Bow                 | 戰鬥短弓      | [ms]kurzer Kampfbogen              | [ms]Arco corto de batalla            | [ms]Arc court de bataille               | [ms]Arco Corto da Battaglia           | 숏 배틀 보우      | [ms]Krótki Bitewny Łuk         | [ms]Arco corto de batalla             | ショート・バトルボウ     | [ms]Arco de Batalha Curto           | [ms]короткий боевой лук           | 短战弓       |\n|  73 | lbb  | Long Battle Bow                  | 戰鬥長弓      | [ms]langer Kampfbogen              | [ms]Arco largo de batalla            | [ms]Arc long de bataille                | [ms]Arco Lungo da Battaglia           | 롱 배틀 보우      | [ms]Długi Bitewny Łuk          | [ms]Arco largo de batalla             | ロング・バトルボウ      | [ms]Arco de Batalha Longo           | [ms]длинный боевой лук            | 长战弓       |\n|  74 | swb  | Short War Bow                    | 征戰短弓      | [ms]kurzer Kriegsbogen             | [ms]Arco corto de guerra             | [ms]Arc court de guerre                 | [ms]Arco Corto da Guerra              | 숏 워 보우       | [ms]Krótki Bojowy Łuk          | [ms]Arco corto de guerra              | ショート・ウォーボウ     | [ms]Arco Bélico Curto               | [ms]короткий воинский лук         | 短战争弓      |\n|  75 | lwb  | Long War Bow                     | 征戰長弓      | [ms]langer Kriegsbogen             | [ms]Arco largo de guerra             | [ms]Arc long de guerre                  | [ms]Arco Lungo da Guerra              | 롱 워 보우       | [ms]Długi Bojowy Łuk           | [ms]Arco largo de guerra              | ロング・ウォーボウ      | [ms]Arco Bélico Longo               | [ms]длинный воинский лук          | 长战争弓      |\n|  76 | lxb  | Light Crossbow                   | 輕弩        | [fs]leichte Armbrust               | [fs]Ballesta ligera                  | [fs]Arbalète légère                     | [fs]Balestra Leggera                  | 라이트 크로스보우    | [fs]Lekka Kusza                | [fs]Ballesta ligera                   | ライト・クロスボウ      | [fs]Besta Leve                      | [ms]легкий арбалет                | 轻弩        |\n|  77 | mxb  | Crossbow                         | 弩         | [fs]Armbrust                       | [fs]Ballesta                         | [fs]Arbalète                            | [fs]Balestra                          | 크로스보우        | [fs]Kusza                      | [fs]Ballesta                          | クロスボウ          | [fs]Besta                           | [ms]арбалет                       | 弩         |\n|  78 | hxb  | Heavy Crossbow                   | 重弩        | [fs]schwere Armbrust               | [fs]Ballesta pesada                  | [fs]Arbalète lourde                     | [fs]Balestra Pesante                  | 헤비 크로스보우     | [fs]Ciężka Kusza               | [fs]Ballesta pesada                   | ヘビー・クロスボウ      | [fs]Besta Pesada                    | [ms]тяжелый арбалет               | 重弩        |\n|  79 | rxb  | Repeating Crossbow               | 連弩        | [fs]Repetierarmbrust               | [fs]Ballesta de repetición           | [fs]Arbalète à répétition               | [fs]Balestra a Ripetizione            | 리피팅 크로스보우    | [fs]Powtarzalna Kusza          | [fs]Ballesta de repetición            | 連射クロスボウ        | [fs]Besta de Repetição              | [ms]многозарядный арбалет         | 连击弩       |\n|  80 | gps  | Rancid Gas Potion                | 腐臭毒氣藥水    | Stinkgaselixier                    | [fs]Poción de gas rancio             | [fs]Cartouche de gaz rance              | Pozione di Gas Rancido                | 부패 가스 물약     | Mikstura zjełczałego gazu      | Poción de gas ponzoñoso               | 腐食ガス・ポーション     | Poção de Gás Rançoso                | Едкий газ                         | 恶臭毒气药水    |\n|  81 | ops  | Oil Potion                       | 火油藥水      | Ölelixier                          | [fs]Poción de aceite                 | [fs]Huile                               | Pozione d'Olio                        | 기름 물약        | Olejowa mikstura               | Poción inflamable                     | オイル・ポーション      | Poção Inflamável                    | Масло                             | 火油药水      |\n|  82 | gpm  | Choking Gas Potion               | 窒息毒氣藥水    | Würgegaselixier                    | [fs]Poción de gas estrangulante      | [fs]Cartouche de gaz asphyxiant         | Pozione Soffocante                    | 질식 가스 물약     | Mikstura dławiącego gazu       | Poción de gas asfixiante              | 窒息ガス・ポーション     | Poção de Gás Sufocante              | Удушающий газ                     | 窒息毒气药水    |\n|  83 | opm  | Exploding Potion                 | 爆炸藥水      | Explosivelixier                    | [fs]Poción explosiva                 | [fs]Potion explosive                    | Pozione Esplosiva                     | 폭발 물약        | Eksplodująca mikstura          | Poción explosiva                      | 炸裂ポーション        | Poção Explosiva                     | Взрывчатое зелье                  | 爆炸药水      |\n|  84 | gpl  | Strangling Gas Potion            | 刺鼻毒氣藥水    | Erstickungsgaselixier              | [fs]Poción de gas sofocante          | [fs]Cartouche de gaz de strangulation   | Pozione Soffocante                    | 유독 가스 물약     | Mikstura duszącego gazu        | Poción de gas sofocante               | 有毒ガス・ポーション     | Poção de Gás Asfixiante             | Асфиксический газ                 | 呛息毒气药水    |\n|  85 | opl  | Fulminating Potion               | 烈性藥水      | Knallelixier                       | [fs]Poción fulminante                | [fs]Potion fulminante                   | Pozione Fulminante                    | 기폭 물약        | Wybuchowa mikstura             | Poción fulminante                     | 火炎ポーション        | Poção Fulminante                    | Гремучее зелье                    | 爆燃药水      |\n|  86 | d33  | Decoy Gidbinn                    | 吉德賓誘餌     | falscher Gidbinn                   | Gidbinn señuelo                      | Faux Gidbinn                            | Falso Gidbinn                         | 미끼 기드빈       | Atrapa Gidbinna                | Gidbinn señuelo                       | 偽物のギドビン        | Gidbinn Ilusória                    | Поддельный Гидбинн                | 赝品吉德宾     |\n|  87 | g33  | The Gidbinn                      | 吉德賓       | der Gidbinn                        | Gidbinn                              | Gidbinn                                 | Il Gidbinn                            | 기드빈          | Gidbinn                        | La Gidbinn                            | 真なるギドビン        | A Gidbinn                           | Гидбинн                           | 吉德宾       |\n|  88 | leg  | Wirt's Leg                       | 維特的腿      | [ns]Wirts Bein                     | [fs]Pierna de Wirt                   | [fs]Jambe de Wirt                       | Gamba di Wirt                         | 워트의 의족       | [fs]Noga Wirta                 | Pata de Wirt                          | ワートの脚          | Perna do Wirt                       | Нога Вирта                        | 怀特的腿      |\n|  89 | hdm  | Horadric Malus                   | 赫拉迪姆之鎚    | Horadrimmalus                      | [ms]Malaise horádrico                | [ms]Marteau d'Horadrim                  | Malleus Horadrico                     | 호라드림 망치      | Malleus Horadrimów             | Martillo horádrico                    | ホラドリムの片手鎚      | Malus Horádrico                     | Хорадримский молот                | 赫拉迪姆之锤    |\n|  90 | hfh  | Hell Forge Hammer                | 地獄熔爐之鎚    | Hammer der Höllenschmiede          | Martillo de la Fragua del Infierno   | Marteau de la forge des Enfers          | Martello della Fornace Infernale      | 지옥의 대장간 망치   | Młot z Piekielnej Kuźni        | Martillo de la Forja Infernal         | 業火で鍛えられし鎚      | Martelo da Forja Infernal           | Молот Адской кузни                | 地狱熔炉之锤    |\n|  91 | hst  | Horadric Staff                   | 赫拉迪姆之杖    | Horadrimstab                       | Bastón horádrico                     | Bâton horadrique                        | Verga Horadrica                       | 호라드림 지팡이     | Kostur Horadrimów              | Bastón horádrico                      | ホラドリムの杖        | Cajado Horádrico                    | Хорадримский посох                | 赫拉迪姆法杖    |\n|  92 | msf  | Shaft of the Horadric Staff      | 赫拉迪姆之杖的杖身 | Schaft des Horadrimstabes          | Vara del bastón horádrico            | Manche du bâton horadrique              | Asta della Verga Horadrica            | 호라드림 지팡이 자루  | Trzonek Kostura Horadrimów     | Vara del Bastón horádrico             | ホラドリムの杖の柄      | Haste do Cajado Horádrico           | Древко хорадримского посоха       | 赫拉迪姆法杖的杖身 |\n|  93 | 9ha  | Hatchet                          | 短斧        | [ns]Kriegsbeil                     | [fs]Hachuela                         | [fs]Hachette                            | [fs]Accetta                           | 해칫           | [ms]Toporek                    | [fs]Hachuela                          | ハチェット          | [fs]Machadinha                      | [ms]пальштаб                      | 小斧        |\n|  94 | 9ax  | Cleaver                          | 斬斧        | [fs]Spaltaxt                       | [fs]Tajadera                         | [ms]Couperet                            | [fs]Mannaia                           | 클리버          | [ms]Tasak                      | [fs]Hendedora                         | クリーバー          | [ms]Cutelo                          | [ms]колун                         | 剁肉斧       |\n|  95 | 92a  | Twin Axe                         | 雙面斧       | [fs]Zwillingsaxt                   | [fs]Hacha gemela                     | [fs]Hache jumelle                       | [fs]Ascia Doppia                      | 트윈 액스        | [ms]Bliźniaczy Topór           | [fs]Hacha gemela                      | ツイン・アックス       | [ms]Machado Gêmeo                   | [ms]двойной топор                 | 双锋斧       |\n|  96 | 9mp  | Crowbill                         | 鴉嘴鎬       | [fs]Bogenpicke                     | [ms]Pico de cuervo                   | [ms]Épieu                               | [fs]Picca d'Arme                      | 크로우빌         | [fs]Kruczy Nadziak             | [ms]Pico de cuervo                    | クロウビル          | [fs]Picareta                        | [ms]клевец                        | 鸦嘴锄       |\n|  97 | 9wa  | Naga                             | 那伽斧       | [fs]Dao                            | [fs]Naga                             | Naga                                    | [fs]Naga                              | 나가           | [fs]Naga                       | [fs]Naga                              | ナーガ            | [ms]Naga                            | [fs]нага                          | 蛇妖斧       |\n|  98 | 9la  | Military Axe                     | 軍斧        | [fs]Militäraxt                     | [fs]Hacha militar                    | [fs]Hache militaire                     | [fs]Ascia d'Arme                      | 밀리터리 액스      | [ms]Wojskowy Topór             | [fs]Hacha militar                     | ミリタリー・アックス     | [ms]Machado Militar                 | [ms]солдатский топор              | 军斧        |\n|  99 | 9ba  | Bearded Axe                      | 鉤斧        | [fs]Schlagaxt                      | [fs]Hacha barbuda                    | [fs]Hache ébarbée                       | [fs]Ascia Barbuta                     | 비어디드 액스      | [ms]Brodaty Topór              | [fs]Hacha barbada                     | ビアデッド・アックス     | [ms]Machado Farpado                 | [ms]скеггокс                      | 芒刺斧       |\n| 100 | 9bt  | Tabar                            | 長戰斧       | [ms]Tabar                          | [ms]Tabar                            | [ms]Tabard                              | [ms]Tabar                             | 타바           | [ms]Tabar                      | [ms]Tabar                             | タバール           | [ms]Tabar                           | [ms]табар                         | 塔巴战斧      |\n| 101 | 9ga  | Gothic Axe                       | 哥德斧       | [fs]Prunkaxt                       | [fs]Hacha gótica                     | [fs]Hache gothique                      | [fs]Ascia Gotica                      | 고딕 액스        | [ms]Gotycki Topór              | [fs]Hacha gótica                      | ゴシック・アックス      | [ms]Machado Gótico                  | [ms]готический топор              | 哥特斧       |\n| 102 | 9gi  | Ancient Axe                      | 上古斧       | [fs]alte Axt                       | [fs]Hacha antigua                    | [fs]Hache ancienne                      | [fs]Ascia Antica                      | 에인션트 액스      | [ms]Prastary Topór             | [fs]Hacha antigua                     | エンシェント・アックス    | [ms]Machado Ancestral               | [ms]древний топор                 | 古代斧       |\n| 103 | 9wn  | Burnt Wand                       | 焦木魔杖      | [ms]verbrannter Stab               | [fs]Vara quemada                     | [fs]Baguette brûlée                     | [fs]Verga Bruciata                    | 번트 원드        | [fs]Spalona Różdżka            | [fs]Vara quemada                      | バーント・ワンド       | [fs]Varinha Queimada                | [ms]обгорелый жезл                | 烧制魔杖      |\n| 104 | 9yw  | Petrified Wand                   | 石木魔杖      | [ms]versteinerter Stab             | [fs]Vara petrificada                 | [fs]Baguette pétrifiée                  | [fs]Verga Pietrificata                | 페트리파이드 원드    | [fs]Skamieniała Różdżka        | [fs]Vara petrificada                  | ペトリファイド・ワンド    | [fs]Varinha Petrificada             | [ms]окаменелый жезл               | 石化魔杖      |\n| 105 | 9bw  | Tomb Wand                        | 古墓魔杖      | [ms]Grabesstab                     | [fs]Vara fúnebre                     | [fs]Baguette de tombe                   | [fs]Verga Tombale                     | 툼 원드         | [fs]Grobowa Różdżka            | [fs]Vara tumularia                    | トゥーム・ワンド       | [fs]Varinha Tumular                 | [ms]могильный жезл                | 随葬魔杖      |\n| 106 | 9gw  | Grave Wand                       | 墓地魔杖      | [ms]Gruftstab                      | [fs]Vara sepulcral                   | [fs]Baguette de tombeau                 | [fs]Verga Sepolcrale                  | 그레이브 원드      | [fs]Cmentarna Różdżka          | [fs]Vara sepulcral                    | グレイブ・ワンド       | [fs]Varinha Sepulcral               | [ms]загробный жезл                | 陪葬魔杖      |\n| 107 | 9cl  | Cudgel                           | 鬥棍        | [ms]Knüttel                        | [ms]Garrote                          | [ms]Casse-tête                          | [ms]Randello                          | 커절           | [fs]Pałka                      | [ms]Garrote                           | カジェル           | [ms]Tacape                          | [fs]палица                        | 大棒        |\n| 108 | 9sc  | Rune Scepter                     | 符文權杖      | [ns]Runenszepter                   | [ms]Cetro rúnico                     | [ms]Sceptre runique                     | [ms]Scettro Runico                    | 룬 셉터         | [nl]Runiczne Berło             | [ms]Cetro rúnico                      | ルーン・セプター       | [ms]Cetro Rúnico                    | [ms]рунный скипетр                | 符文权杖      |\n| 109 | 9qs  | Holy Water Sprinkler             | 聖水禮杖      | [ms]Weihwasserstab                 | [ms]Hisopo de agua bendita           | [ms]Dispenseur d’eau bénite             | [ms]Aspersorio Sacro                  | 홀리 워터 스프링클러  | [nl]Święcone Kropidło          | [ms]Rociador de agua bendita          | ホーリー・セプター      | [ms]Aspersor de Água Benta          | [ms]источник святой воды          | 圣水喷杖      |\n| 110 | 9ws  | Divine Scepter                   | 聖恩權杖      | [ns]göttliches Szepter             | [ms]Cetro divino                     | [ms]Sceptre divin                       | [ms]Scettro Divino                    | 디바인 셉터       | [nl]Boskie Berło               | [ms]Cetro divino                      | ディバイン・セプター     | [ms]Cetro Divino                    | [ms]божественный скипетр          | 神圣权杖      |\n| 111 | 9sp  | Barbed Club                      | 倒刺棍棒      | [fs]Stachelkeule                   | [fs]Porra con púas                   | [fs]Massue barbelée                     | [fs]Clava Dentata                     | 바브드 클럽       | [fs]Ciernista Maczuga          | [ms]Garrote con púas                  | バーブド・クラブ       | [fs]Clava Farpada                   | [fs]колючая дубина                | 钉刺尖棒      |\n| 112 | 9ma  | Flanged Mace                     | 凸緣釘鎚      | [ms]Kriegsknüppel                  | [fs]Maza rebordeada                  | [fs]Masse à ailettes                    | [fs]Mazza Flangiata                   | 플랜지드 메이스     | [ms]Buzdygan                   | [fs]Maza barretada                    | フランジ・メイス       | [fs]Maça Bordejada                  | [fs]шипастая булава               | 凸缘钉锤      |\n| 113 | 9mt  | Jagged Star                      | 鋸齒釘頭鎚     | [ms]Zackenstern                    | [fs]Estrella dentada                 | [fs]Étoile crénelée                     | [fs]Stella Puntuta                    | 재기드 스타       | [fs]Zębata Gwiazda             | [fs]Estrella dentada                  | ジャグド・スター       | [fs]Estrela Serrilhada              | [fs]утренняя звезда               | 锯齿星锤      |\n| 114 | 9fl  | Knout                            | 刑罪連枷      | [fs]Knute                          | [ms]Knut                             | [ms]Knout                               | [ms]Knut                              | 나우트          | [ms]Knut                       | [ms]Knut                              | ノウト            | [ms]Látego                          | [ms]кнут                          | 链子锤       |\n| 115 | 9wh  | Battle Hammer                    | 戰鬥鐵鎚      | [ms]Kampfhammer                    | [ms]Martillo de batalla              | [ms]Marteau de bataille                 | [ms]Martello da Battaglia             | 배틀 해머        | [ms]Bitewny Młot               | [ms]Martillo de batalla               | バトル・ハンマー       | [ms]Martelo de Batalha              | [ms]боевой молот                  | 战斗锤       |\n| 116 | 9m9  | War Club                         | 征戰重鎚      | [fs]Kriegskeule                    | [fs]Porra de guerra                  | [fs]Massue de guerre                    | [fs]Clava da Guerra                   | 워 클럽         | [fs]Bojowa Maczuga             | [ms]Garrote de guerra                 | ウォー・クラブ        | [fs]Clava Bélica                    | [fs]воинская дубина               | 战棒        |\n| 117 | 9gm  | Martel de Fer                    | 長柄戰鎚      | [ms]Eisenhammer                    | [ms]Martel de fer                    | [ms]Martel de Fer                       | [ms]Martel de Fer                     | 마르텔 드 페르     | [ms]Martel De Fer              | [ms]Martillo de hierro                | マーテル・ドゥ・フェール   | [ms]Martel de Fer                   | [ms]мартель-де-фер                | 尖头锤       |\n| 118 | 9ss  | Gladius                          | 羅馬短劍      | [ms]Gladius                        | [ms]Gladius                          | [ms]Glaive                              | [ms]Gladio                            | 글래디우스        | [ms]Gladius                    | [ms]Gladio                            | グラディウス         | [ms]Gladius                         | [ms]гладиус                       | 角斗短剑      |\n| 119 | 9sm  | Cutlass                          | 水手刀       | [ms]Hacksäbel                      | [ms]Alfanje                          | [ms]Coutelas                            | [fs]Sciabola Corta                    | 커틀러스         | [ms]Kordelas                   | [ms]Alfanje                           | カトラス           | [ms]Alfanje                         | [fs]абордажная сабля              | 短弯刀       |\n| 120 | 9sb  | Shamshir                         | 波斯彎刀      | [ns]Schamschir                     | [ms]Shamshir                         | [ms]Shamshir                            | [fs]Shamshir                          | 샴쉬르          | [ms]Szamszir                   | [ms]Shamshir                          | シャムシール         | [ms]Shamshir                        | [ms]шамшир                        | 沙漠弯刀      |\n| 121 | 9fc  | Tulwar                           | 印度彎刀      | [ns]Tulwar                         | [ms]Tulwar                           | [ms]Tulwar                              | [ms]Tulwar                            | 털워           | [ms]Tulwar                     | [ms]Tulwar                            | タルワール          | [ms]Talwar                          | [ms]тальвар                       | 塔瓦弯刀      |\n| 122 | 9cr  | Dimensional Blade                | 次元刃       | [fs]Dimensionenklinge              | [fs]Espada dimensional               | [fs]Lame dimensionnelle                 | [fs]Spada Dimensionale                | 디멘셔널 블레이드    | [nl]Międzywymiarowe Ostrze     | [fs]Hoja dimensional                  | ディメンショナル・ブレイド  | [fs]Lâmina Dimensional              | [ms]межпространственный клинок    | 次元之刃      |\n| 123 | 9bs  | Battle Sword                     | 戰鬥長劍      | [ns]Kampfschwert                   | [fs]Espada de batalla                | [fs]Épée de bataille                    | [fs]Spada da Battaglia                | 배틀 소드        | [ms]Bitewny Miecz              | [fs]Espada de batalla                 | バトル・ソード        | [fs]Espada de Batalha               | [ms]боевой меч                    | 战斗剑       |\n| 124 | 9ls  | Rune Sword                       | 符文劍       | [ns]Runenschwert                   | [fs]Espada rúnica                    | [fs]Épée runique                        | [fs]Spada Runica                      | 룬 소드         | [ms]Runiczny Miecz             | [fs]Espada rúnica                     | ルーン・ソード        | [fs]Espada Rúnica                   | [ms]рунический меч                | 符文剑       |\n| 125 | 9wd  | Ancient Sword                    | 上古劍       | [ns]altes Schwert                  | [fs]Espada antigua                   | [fs]Épée ancienne                       | [fs]Spada Antica                      | 에인션트 소드      | [ms]Prastary Miecz             | [fs]Espada antigua                    | エンシェント・ソード     | [fs]Espada Ancestral                | [ms]древний меч                   | 古代剑       |\n| 126 | 92h  | Espandon                         | 雙手重劍      | [ns]Espandon                       | [ms]Espadón                          | [ms]Espadon                             | [ms]Espadon                           | 에스팬돈         | [ms]Espandon                   | [ms]Montante                          | エスパドン          | [fs]Espandon                        | [ms]эспадон                       | 西铁大剑      |\n| 127 | 9cm  | Dacian Falx                      | 達西安長刀     | [fs]dakische Sichel                | [fs]Falx dacia                       | [fs]Faux de Dacian                      | [fs]Falce Dacica                      | 다키안 팔크스      | [ms]Damasceński Miecz          | [fs]Falx dacia                        | ダシアン・ファルクス     | [fs]Falx Dácia                      | [ms]дакийский фалькс              | 达契亚镰剑     |\n| 128 | 9gs  | Tusk Sword                       | 長牙劍       | [ns]Stoßschwert                    | [fs]Espada de colmillo               | [fs]Épée d’ivoire                       | [fs]Spada a Zanna                     | 터스크 소드       | [ms]Zębaty Miecz               | [fs]Espada de colmillo                | タスク・ソード        | [fs]Espada de Presas                | [ms]бивенный меч                  | 獠牙剑       |\n| 129 | 9b9  | Gothic Sword                     | 哥德劍       | [ns]Prunkschwert                   | [fs]Espada gótica                    | [fs]Épée gothique                       | [fs]Spada Gotica                      | 고딕 소드        | [ms]Gotycki Miecz              | [fs]Espada gótica                     | ゴシック・ソード       | [fs]Espada Gótica                   | [ms]готический меч                | 哥特剑       |\n| 130 | 9fb  | Zweihander                       | 日耳曼大劍     | [ms]Bidenhänder                    | [fs]Zweihänder                       | [ms]Estramaçon                          | [fs]Zweihander                        | 즈바이핸더        | [ms]Zweihander                 | [fs]Zweihander                        | ツヴァイヘンダー       | [fs]Bihänder                        | [ms]цвайхандер                    | 双手重剑      |\n| 131 | 9gd  | Executioner Sword                | 處刑劍       | [ns]Scharfrichterschwert           | [fs]Espada de ejecución              | [fs]Épée d’exécuteur                    | [fs]Spada del Boia                    | 엑시큐셔너 소드     | [ms]Katowski Miecz             | [fs]Espada de verdugo                 | 処刑人の剣          | [fs]Espada do Carrasco              | [ms]палаческий меч                | 行刑剑       |\n| 132 | 9dg  | Poignard                         | 刺擊短劍      | [ms]Poignard                       | [ms]Puñal                            | [ms]Poignard                            | [ms]Poignard                          | 포이나드         | [ms]Puginał                    | [ms]Puñal                             | ポワニャール         | [ms]Punhal                          | [ms]пуаньяр                       | 锐匕        |\n| 133 | 9di  | Rondel                           | 圓柄匕首      | [ms]Langdolch                      | [ms]Rondel                           | [fs]Dague à rouelles                    | [fs]Daga a Rondelle                   | 런들           | [fs]Rondela                    | [fs]Daga rondel                       | ロンデル           | [ms]Rondel                          | [ms]рондель                       | 袖匕        |\n| 134 | 9kr  | Cinquedeas                       | 闊身短劍      | [ms]Cinquedea                      | [fs]Cinquedea                        | [fp]Cinquedeas                          | [fs]Cinquedea                         | 싱쿠디아         | [fs]Cinquedea                  | [fs]Cinquedea                         | チンクエデア         | [fs]Cinquedeas                      | [fs]чинкуэда                      | 五指短剑      |\n| 135 | 9bl  | Stiletto                         | 窄刃匕首      | [ns]Stilett                        | [ms]Stiletto                         | [ms]Stylet                              | [ms]Stiletto                          | 스틸레토         | [nl]Stiletto                   | [ms]Estilete                          | スティレット         | [ms]Estilete                        | [ms]стилет                        | 小剑        |\n| 136 | 9tk  | Battle Dart                      | 戰鬥飛鏢      | [ms]Kurzpfeil                      | [ms]Dardo de batalla                 | [fs]Fléchette de bataille               | [ms]Dardo da Battaglia                | 배틀 다트        | [fs]Bitewna Strzałka           | [ms]Dardo de batalla                  | バトル・ダーツ        | [fs]Seta de Batalha                 | [ms]боевой дротик                 | 战斗镖       |\n| 137 | 9ta  | Francisca                        | 法蘭西飛斧     | [fs]Frankenaxt                     | [fs]Francisca                        | [fs]Francisque                          | [fs]Francisca                         | 프란시스카        | [fs]Franciska                  | [fs]Francisca                         | フランキスカ         | [ms]Franquisque                     | [fs]франциска                     | 法兰飞斧      |\n| 138 | 9bk  | War Dart                         | 征戰飛鏢      | [ms]Kriegspfeil                    | [ms]Dardo de guerra                  | [fs]Fléchette de guerre                 | [ms]Dardo da Guerra                   | 워 다트         | [fs]Bojowa Strzałka            | [ms]Dardo de guerra                   | ウォー・ダーツ        | [fs]Seta Bélica                     | [ms]воинский дротик               | 战镖        |\n| 139 | 9b8  | Hurlbat                          | 投斧        | [fs]Saufeder                       | [ms]Hurlbat                          | [fs]Hurle-hache                         | [fs]Scure da Lancio                   | 헐배트          | [ms]Dziryt                     | [fs]Hacha doble arrojadiza            | ハルバット          | [ms]Machado Lançável                | [ms]метательная бита              | 飞蝠斧       |\n| 140 | 9ja  | War Javelin                      | 征戰標槍      | [ms]Kriegswurfspieß                | [fs]Jabalina de guerra               | [ms]Javelot de guerre                   | [ms]Giavellotto da Guerra             | 워 재벌린        | [ms]Bojowy Oszczep             | [fs]Jabalina de guerra                | ウォー・ジャベリン      | [ms]Dardo Bélico                    | [ns]воинское копьецо              | 战争标枪      |\n| 141 | 9pi  | Great Pilum                      | 重型標槍      | [ms]großer Spieß                   | [ms]Gran pilum                       | [ms]Grand Pilum                         | [ms]Grande Pilum                      | 그레이트 필럼      | [nl]Wielkie Pilum              | [ms]Gran pilum                        | グレート・ピルム       | [ms]Grande Pilum                    | [ms]большой пилум                 | 重标枪       |\n| 142 | 9s9  | Simbilan                         | 銳矛標槍      | [ms]Simbilan                       | [ms]Simbilan                         | [ms]Simbilan                            | [ms]Simbilan                          | 심빌란          | [ms]Simbilan                   | [fs]Simbilan                          | シンビラン          | [ms]Simbilan                        | [ms]симбилан                      | 重梭镖       |\n| 143 | 9gl  | Spiculum                         | 尖刃槍       | [ms]Wurfstock                      | [ms]Spiculum                         | [ms]Spiculum                            | [ms]Spiculum                          | 스피큘럼         | [nl]Spiculum                   | [ms]Spiculum                          | スピキュラム         | [ms]Spiculum                        | [ms]спикулум                      | 斧刃戟枪      |\n| 144 | 9ts  | Harpoon                          | 魚叉        | [fs]Harpune                        | [ms]Arpón                            | [ms]Harpon                              | [ms]Arpione                           | 하푼           | [ms]Harpun                     | [ms]Arpón                             | ハープーン          | [ms]Arpão                           | [ms]гарпун                        | 鱼叉        |\n| 145 | 9sr  | War Spear                        | 征戰長矛      | [ms]Kampfspeer                     | [fs]Lanza de guerra                  | [fs]Lance de guerre                     | [fs]Lancia da Guerra                  | 워 스피어        | [fs]Bojowa Włócznia            | [fs]Lanza de guerra                   | ウォー・スピア        | [fs]Lança Bélica                    | [ns]воинское копье                | 战矛        |\n| 146 | 9tr  | Fuscina                          | 矛叉        | [ms]Kampfdreizack                  | [fs]Fuscina                          | [fs]Fuscine                             | [fs]Fuscina                           | 푸스키나         | [fs]Fuscina                    | [fs]Fuscina                           | 三叉槍            | [fs]Fuscina                         | [pl]вилы                          | 叉戟枪       |\n| 147 | 9br  | War Fork                         | 征戰軍叉      | [fs]Kriegsforke                    | [fs]Horquilla de guerra              | [fs]Fourche de guerre                   | [ms]Tridente da Guerra                | 워 포크         | [ms]Bojowa Runka               | [fs]Horquilla de guerra               | ウォー・フォーク       | [ms]Garfo Bélico                    | [pl]воинские вилы                 | 战叉        |\n| 148 | 9st  | Yari                             | 三尖槍       | [fs]Yari                           | [ms]Yari                             | [fs]Yari                                | [ms]Yari                              | 야리           | [nl]Yari                       | [fs]Yari                              | 槍              | [fs]Yari                            | [ms]яри                           | 长枪        |\n| 149 | 9p9  | Lance                            | 長槍        | [fs]Lanze                          | [fs]Asta                             | [fs]Haste                               | [fs]Lancia Lunga                      | 랜스           | [fs]Lanca                      | [fs]Asta                              | ランス            | [fs]Lança de Combate                | [ns]массивное копье               | 骑枪        |\n| 150 | 9b7  | Lochaber Axe                     | 鉤斧        | [fs]Lochaberaxt                    | [fs]Hacha de Lochaber                | [fs]Lochabre                            | [fs]Ascia Lochaber                    | 로카버 액스       | [ms]Wyżynny Topór              | [fs]Hacha de Lochaber                 | ロッホバー・アックス     | [ms]Machado Locaber                 | [ms]лохаберкаст                   | 罗佳伯长斧     |\n| 151 | 9vo  | Bill                             | 長柄鍥       | [fs]Pinne                          | [ms]Hocino                           | [fs]Guisarme                            | [ms]Rostro                            | 빌            | [fs]Rohatyna                   | [ms]Pico                              | ビル             | [ms]Bico                            | [fs]кирка                         | 钩镰枪       |\n| 152 | 9s8  | Battle Scythe                    | 戰鬥鐮刀      | [fs]Kampfsense                     | [fs]Guadaña de batalla               | [fs]Faux de bataille                    | [fs]Falce da Battaglia                | 배틀 싸이드       | [fs]Bitewna Kosa               | [fs]Guadaña de batalla                | バトル・サイス        | [fs]Foice de Batalha                | [fs]боевая коса                   | 战斗镰刀      |\n| 153 | 9pa  | Partizan                         | 闊頭槍       | [fs]Partisane                      | [fs]Partesana                        | [fs]Pertuisane                          | [fs]Partigiana                        | 파르티잔         | [fs]Partyzana                  | [fs]Partesana                         | パルチザン          | [fs]Partesana                       | [ms]протазан                      | 游侠戟       |\n| 154 | 9h9  | Bec-de-Corbin                    | 渡鴉喙       | [fs]Helmbarte                      | [ms]Bec de corbin                    | [ms]Bec-de-Corbeau                      | [ms]Becco di Corvo                    | 벡드코방         | [ms]Bec-De-Corbin              | [ms]Bec de Corbin                     | ベク・ド・コルバン      | [fs]Bec-de-corbin                   | [ms]чекан                         | 鸦喙锤戟      |\n| 155 | 9wc  | Grim Scythe                      | 陰森鐮刀      | [fs]Schlachtensense                | [fs]Guadaña lúgubre                  | [fs]Faux macabre                        | [fs]Falce Mortale                     | 그림 싸이드       | [fs]Złowroga Kosa              | [fs]Guadaña lúgubre                   | グリム・サイス        | [fs]Foice Sinistra                  | [fs]жуткая коса                   | 恐怖镰刀      |\n| 156 | 8ss  | Jo Staff                         | 棍杖        | [ms]Schlagstab                     | [ms]Bastón de jo                     | [ms]Bâton de Jo                         | [ms]Bastone di Jo                     | 조 스태프        | [ms]Kostur Jo                  | [ms]Bastón Jo                         | 戦杖             | [ms]Cajado Jo                       | [ms]посох дзе                     | 杖棍        |\n| 157 | 8ls  | Quarterstaff                     | 長棍        | [ms]Kampfstab                      | [ms]Bastón de mando                  | [fs]Canne de combat                     | [ms]Bastone Ferrato                   | 쿼터스태프        | [ms]Okuty Kij                  | [ms]Bastón de combate                 | クォーター・スタッフ     | [ms]Cajado de Combate               | [ms]окованный посох               | 铁头棒       |\n| 158 | 8cs  | Cedar Staff                      | 杉木法杖      | [ms]Zedernstab                     | [ms]Bastón de cedro                  | [ms]Bâton de cèdre                      | [ms]Bastone di Cedro                  | 시더 스태프       | [ms]Cedrowy Kostur             | [ms]Bastón de cedro                   | シーダー・スタッフ      | [ms]Cajado de Cedro                 | [ms]кедровый посох                | 雪松杖       |\n| 159 | 8bs  | Gothic Staff                     | 哥德法杖      | [ms]Prunkstab                      | [ms]Bastón gótico                    | [ms]Bâton gothique                      | [ms]Bastone Gotico                    | 고딕 스태프       | [ms]Gotycki Kostur             | [ms]Bastón gótico                     | ゴシック・スタッフ      | [ms]Cajado Gótico                   | [ms]готический посох              | 哥特杖       |\n| 160 | 8ws  | Rune Staff                       | 符文法杖      | [ms]Runenstab                      | [ms]Bastón rúnico                    | [ms]Bâton runique                       | [ms]Bastone Runico                    | 룬 스태프        | [ms]Runiczny Kostur            | [ms]Bastón rúnico                     | ルーン・スタッフ       | [ms]Cajado Rúnico                   | [ms]рунический посох              | 符文杖       |\n| 161 | 8sb  | Edge Bow                         | 銳弓        | [ms]Schneidebogen                  | [ms]Arco afilado                     | [ms]Arc tranchant                       | [ms]Scaglialame                       | 엣지 보우        | [ms]Przecinający Łuk           | [ms]Arco de filo                      | エッジ・ボウ         | [ms]Arco Cortante                   | [ms]кромчатый лук                 | 刃弓        |\n| 162 | 8hb  | Razor Bow                        | 剃刀弓       | [ms]Klingenbogen                   | [ms]Arco de cuchilla                 | [ms]Arc rasoir                          | [ms]Scagliarasoi                      | 레이저 보우       | [ms]Tnący Łuk                  | [ms]Arco de navajas                   | レイザー・ボウ        | [ms]Arco Navalha                    | [ms]бритвенный лук                | 刀锋弓       |\n| 163 | 8lb  | Cedar Bow                        | 杉木弓       | [ms]Zedernbogen                    | [ms]Arco de cedro                    | [ms]Arc de cèdre                        | [ms]Arco di Cedro                     | 시더 보우        | [ms]Cedrowy Łuk                | [ms]Arco de cedro                     | シーダー・ボウ        | [ms]Arco de Cedro                   | [ms]кедровый лук                  | 雪松弓       |\n| 164 | 8cb  | Double Bow                       | 雙曲弓       | [ms]Doppelbogen                    | [ms]Arco doble                       | [ms]Arc double                          | [ms]Arco Doppio                       | 더블 보우        | [ms]Podwójny Łuk               | [ms]Arco doble                        | ダブル・ボウ         | [ms]Arco Duplo                      | [ms]двойной лук                   | 双臂弓       |\n| 165 | 8s8  | Short Siege Bow                  | 攻城短弓      | [ms]kurzer Belagerungsbogen        | [ms]Arco corto de asedio             | [ms]Arc court de siège                  | [ms]Arco Corto da Assedio             | 숏 시즈 보우      | [ms]Krótki Oblężniczy Łuk      | [ms]Arco corto de asedio              | ショート・シージ・ボウ    | [fs]Besta de Cerco Curta            | [ms]короткий осадный лук          | 小型攻城弓     |\n| 166 | 8l8  | Large Siege Bow                  | 攻城長弓      | [ms]langer Belagerungsbogen        | [ms]Arco grande de asedio            | [ms]Grand arc de siège                  | [ms]Arco Grande da Assedio            | 라지 시즈 보우     | [ms]Wielki Oblężniczy Łuk      | [ms]Arco largo de asedio              | ラージ・シージ・ボウ     | [fs]Besta de Cerco Grande           | [ms]большой осадный лук           | 大型攻城弓     |\n| 167 | 8sw  | Rune Bow                         | 符文弓       | [ms]Runenbogen                     | [ms]Arco rúnico                      | [ms]Arc runique                         | [ms]Arco Runico                       | 룬 보우         | [ms]Runiczny Łuk               | [ms]Arco rúnico                       | ルーン・ボウ         | [ms]Arco Rúnico                     | [ms]рунический лук                | 符文弓       |\n| 168 | 8lw  | Gothic Bow                       | 哥德弓       | [ms]Prunkbogen                     | [ms]Arco gótico                      | [ms]Arc gothique                        | [ms]Arco Gotico                       | 고딕 보우        | [ms]Gotycki Łuk                | [ms]Arco gótico                       | ゴシック・ボウ        | [ms]Arco Gótico                     | [ms]готический лук                | 哥特弓       |\n| 169 | 8lx  | Arbalest                         | 鋼弩        | [fs]Arbaleste                      | [fs]Arbalesta                        | [fs]Arbalestre                          | [fs]Arbalesta                         | 아발리스트        | [ms]Arbalet                    | [fs]Arbalesta                         | アーバレスト         | [fs]Arcobalista                     | [ms]самострел                     | 巨弩        |\n| 170 | 8mx  | Siege Crossbow                   | 攻城弩       | [fs]Belagerungsarmbrust            | [fs]Ballesta de asedio               | [fs]Arbalète de siège                   | [fs]Balestra da Assedio               | 시즈 크로스보우     | [fs]Oblężnicza Kusza           | [fs]Ballesta de asedio                | シージ・クロスボウ      | [fs]Besta de Cerco                  | [ms]осадный арбалет               | 攻城弩       |\n| 171 | 8hx  | Ballista                         | 砲弩        | [fs]Balliste                       | [fs]Balista                          | [fs]Baliste                             | [fs]Balista                           | 발리스타         | [fs]Balista                    | [fs]Balista                           | バリスタ           | [fs]Balista                         | [fs]баллиста                      | 弩炮        |\n| 172 | 8rx  | Chu-Ko-Nu                        | 諸葛弩       | [fs]Chu-Ko-Nu                      | [ms]Chu-ko-nu                        | [fs]Chu-Ko-Nu                           | [ms]Chu-Ko-Nu                         | 추코누          | [nl]Chu-Ko-Nu                  | [fs]Chu-Ko-Nu                         | 連弩             | [fs]Chu-ko-nu                       | [ms]чо-ко-ну                      | 巧工弩       |\n| 173 | qf1  | Khalim's Flail                   | 克林姆的連枷    | Khalims Kultflegel                 | Rompecabezas de Khalim               | Fléau de Khalim                         | Flagello di Khalim                    | 칼림의 도리깨      | Korbacz Khalima                | Mangual de Khalim                     | カリムのフレイル       | Mangual de Khalim                   | Кистень Халима                    | 卡林姆的连枷    |\n| 174 | qf2  | Khalim's Will                    | 克林姆的遺願    | Khalims Wille                      | Voluntad de Khalim                   | Volonté de Khalim                       | Volontà di Khalim                     | 칼림의 의지       | Wola Khalima                   | Voluntad de Khalim                    | カリムの意志         | Vontade de Khalim                   | Воля Халима                       | 卡林姆的意志    |\n| 175 | ktr  | Katar                            | 拳刃        | [ms]Katar                          | [ms]Katar                            | [ms]Katar                               | [fs]Katar                             | 카타르          | [ms]Katar                      | [ms]Katar                             | カタール           | [ms]Katar                           | [ms]катар                         | 拳剑        |\n| 176 | wrb  | Wrist Blade                      | 腕刃        | [fs]Unterarmklinge                 | [fs]Cuchilla de muñeca               | [fs]Lame de poignet                     | [fs]Lama da Polso                     | 리스트 블레이드     | [nl]Naręczne Ostrze            | [fs]Hoja de muñeca                    | リスト・ブレード       | [fs]Lâmina de Pulso                 | [ms]наручный клинок               | 腕刃        |\n| 177 | axf  | Hatchet Hands                    | 斧手        | Axthände                           | [fp]Manos de hachuela                | [mp]Gants tranchants                    | Mani d'Accetta                        | 해칫 핸즈        | [nl]Naręczne Topory            | [fp]Manos de hachuela                 | ハチェット・ハンズ      | [fp]Mãos de Machadinha              | [ms]накулачный топор              | 斧刃拳套      |\n| 178 | ces  | Cestus                           | 刃拳        | [ms]Cestus                         | [ms]Cestus                           | [ms]Cestus                              | [ms]Caestus                           | 세스터스         | [ms]Cestus                     | [ms]Cestus                            | セスタス           | [ms]Cestus                          | [ms]цестус                        | 缠刃拳套      |\n| 179 | clw  | Claws                            | 爪         | [pl]Klauen                         | [fp]Garras                           | [fp]Griffes                             | [mp]Unghioni                          | 클러           | [nl]Pazury                     | [fp]Garras                            | クロー            | [fp]Garras                          | [pl]когти                         | 手爪刀       |\n| 180 | btl  | Blade Talons                     | 刃爪        | [pl]Klingenklauen                  | [fp]Garfas tajantes                  | [fp]Serres                              | [mp]Artigli Acuminati                 | 블레이드 탤런      | [nl]Tnące Pazury               | [fp]Zarpas afiladas                   | ブレイド・タロン       | [fp]Garras Afiadas                  | [pl]острые птичьи когти           | 刃爪        |\n| 181 | skr  | Scissors Katar                   | 剪刃        | [ms]Scherenkatar                   | [ms]Katar tijera                     | [fs]Serpe Katar                         | [fs]Katar a Forbice                   | 시저스 카타르      | [ms]Nożycowy Katar             | [ms]Katar tijera                      | シザー・カタール       | [ms]Katar Tesoura                   | [ms]катар-ножницы                 | 剪咬拳剑      |\n| 182 | 9ar  | Quhab                            | 格鬥刃       | [ns]Quhab                          | [ms]Quhab                            | [ms]Quhab                               | [ms]Quhab                             | 쿠하브          | [ms]Quhab                      | [ms]Quhab                             | クハブ            | [ms]Quhab                           | [ms]кухаб                         | 拳刃        |\n| 183 | 9wb  | Wrist Spike                      | 腕刺        | [ms]Unterarmdorn                   | [fs]Punta de muñeca                  | [fs]Pique de poignet                    | [ms]Aculeo da Polso                   | 리스트 스파이크     | [ms]Naręczny Kolec             | [fs]Púa de muñeca                     | リスト・スパイク       | [ms]Espeto de Pulso                 | [ms]наручный кинжал               | 腕刺        |\n| 184 | 9xf  | Fascia                           | 格鬥爪       | [fs]Faszie                         | [fs]Fascia                           | [ms]Fascia                              | [fs]Dilaniatrice                      | 패시아          | [fs]Fascia                     | [fs]Fascia                            | ファシア           | [fs]Fáscia                          | [fs]фасция                        | 刀刃拳套      |\n| 185 | 9cs  | Hand Scythe                      | 手鐮        | [fs]Handsichel                     | [fs]Guadaña de mano                  | [fs]Petite faux                         | [fs]Falce da Polso                    | 핸드 사이드       | [fs]Naręczna Kosa              | [fs]Guadaña de mano                   | ハンド・サイス        | [fs]Foice Manual                    | [ms]ручной серп                   | 手镰        |\n| 186 | 9lw  | Greater Claws                    | 巨爪        | [pl]Großkrallen                    | [fp]Garras enormes                   | [fp]Grandes griffes                     | [mp]Grandi Unghioni                   | 그레이터 클러      | [nl]Większe Pazury             | [fp]Garras mayores                    | グレーター・クロー      | [fp]Garras Superiores               | [pl]длинные когти                 | 大型手爪刀     |\n| 187 | 9tw  | Greater Talons                   | 巨鷹爪       | [pl]Großklauen                     | [fp]Garfas enormes                   | [fp]Grandes serres                      | [mp]Grandi Artigli                    | 그레이터 탤런      | [nl]Większe Szpony             | [fp]Zarpas mayores                    | グレーター・タロン      | [fp]Patas Superiores                | [pl]длинные птичьи когти          | 大型刃爪      |\n| 188 | 9qr  | Scissors Quhab                   | 格鬥剪刃      | [ns]Scherenquhab                   | [ms]Quhab tijera                     | [fs]Serpe Quhab                         | [fs]Quhab a Forbice                   | 시저스 쿠하브      | [ms]Nożycowy Quhab             | [ms]Quhab tijera                      | シザー・クハブ        | [ms]Quhab Tesoura                   | [ms]кухаб-ножницы                 | 剪咬拳刃      |\n| 189 | 7ar  | Suwayyah                         | 穿擊拳刃      | [ns]Suwayyah                       | [ms]Suwayyah                         | [fs]Suwayyah                            | [fs]Suwayyah                          | 수웨이야         | [ms]Suwayyah                   | [ms]Suwayyah                          | スウェイヤ          | [ms]Suwayyah                        | [fs]сувайя                        | 手推剑       |\n| 190 | 7wb  | Wrist Sword                      | 腕劍        | [ns]Unterarmschwert                | [fs]Espada de muñeca                 | [fs]Épée de poignet                     | [fs]Spada da Polso                    | 리스트 소드       | [ms]Naręczny Miecz             | [fs]Espada de muñeca                  | リスト・ソード        | [fs]Espada de Pulso                 | [ms]наручный меч                  | 腕剑        |\n| 191 | 7xf  | War Fist                         | 征戰拳套      | [fs]Kriegsfaust                    | [ms]Puño de guerra                   | [ms]Poing de guerre                     | [ms]Pugno da Guerra                   | 워 피스트        | [fs]Bojowa Pięść               | [ms]Puño de guerra                    | ウォーフィスト        | [ms]Punho Bélico                    | [ms]воинский кулак                | 战争拳套      |\n| 192 | 7cs  | Battle Cestus                    | 戰鬥刃拳      | [ms]Kampfcestus                    | [ms]Cestus de batalla                | [ms]Cestus de bataille                  | [ms]Caestus da Battaglia              | 배틀 세스터스      | [ms]Bitewny Cestus             | [ms]Cestus de batalla                 | バトル・セスタス       | [ms]Cestus de Batalha               | [ms]боевой цестус                 | 战斗缠刃拳套    |\n| 193 | 7lw  | Feral Claws                      | 蠻獸爪       | [pl]Barbarenkrallen                | [fp]Garras ferales                   | [fp]Griffes sauvages                    | [mp]Unghioni Ferini                   | 페럴 클러        | [nl]Dzikie Szpony              | [fp]Garras salvajes                   | フェラル・クロー       | [fp]Garras Selvagens                | [pl]звериные когти                | 狂野钩爪      |\n| 194 | 7tw  | Runic Talons                     | 符紋爪       | [pl]Runenklauen                    | [fp]Garfas rúnicas                   | [fp]Serres runiques                     | [mp]Artigli Runici                    | 루닉 탤런        | [nl]Runiczne Szpony            | [fp]Zarpas rúnicas                    | ルーニック・タロン      | [fp]Garras Rúnicas                  | [pl]рунные птичьи когти           | 符文刃爪      |\n| 195 | 7qr  | Scissors Suwayyah                | 穿擊剪刃      | [ns]Scherensuwayyah                | [ms]Suwayyah tijera                  | [fs]Serpe Suwayyah                      | [fs]Suwayyah a Forbice                | 시저스 수웨이야     | [ms]Nożycowy Suwayyah          | [ms]Suwayyah tijera                   | シザー・スウェイヤ      | [ms]Suwayyah Tesoura                | [fs]сувайя-ножницы                | 剪咬手推剑     |\n| 196 | 7ha  | Tomahawk                         | 輕斧        | [ns]Tomahawk                       | [ms]Tomahawk                         | [ms]Tomahawk                            | [ms]Tomahawk                          | 토마호크         | [ms]Tomahawk                   | [fs]Tomahawk                          | トマホーク          | [ms]Tomahawk                        | [ms]томагавк                      | 土著战斧      |\n| 197 | 7ax  | Small Crescent                   | 彎月斧       | [fs]Kleine Sichel                  | [fs]Medialuna pequeña                | [ms]Petit croissant                     | [fs]Piccola Falce                     | 스몰 크레센트      | [ms]Mały Żniwnik               | [fs]Medialuna pequeña                 | スモール・クレセント     | [ms]Crescente Pequeno               | [ms]малый серповидный топор       | 新月斧       |\n| 198 | 72a  | Ettin Axe                        | 雙頭斧       | [fs]Ettinaxt                       | [fs]Hacha de Ettin                   | [fs]Hache d’Ettin                       | [fs]Ascia dell'Ettin                  | 에틴 액스        | [ms]Ettinowy Topór             | [fs]Hacha de Ettin                    | エッティン・アックス     | [ms]Machado de Ettin                | [ms]эттинский топор               | 双头巨人斧     |\n| 199 | 7mp  | War Spike                        | 征戰鎬       | [ms]Kriegsdorn                     | [fs]Punta de guerra                  | [fs]Pointe de guerre                    | [ms]Aculeo da Guerra                  | 워 스파이크       | [ms]Bojowy Kolec               | [fs]Púa de guerra                     | ウォー・スパイク       | [ms]Espeto Bélico                   | [ms]воинский шип                  | 战争尖斧      |\n| 200 | 7wa  | Berserker Axe                    | 狂戰斧       | [fs]Berserkeraxt                   | [fs]Hacha de berserker               | [fs]Hache de beserker                   | [fs]Ascia del Berserker               | 버서커 액스       | [ms]Berserkerski Topór         | [fs]Hacha del vesánico                | バーサーカー・アックス    | [ms]Machado do Berserker            | Секира берсерка                   | 狂战士战斧     |\n| 201 | 7la  | Feral Axe                        | 蠻野斧       | [fs]Barbarenaxt                    | [fs]Hacha feral                      | [fs]Hache sauvage                       | [fs]Ascia Ferina                      | 페럴 액스        | [ms]Dziki Topór                | [fs]Hacha salvaje                     | フェラル・アックス      | [ms]Machado Selvagem                | [ms]звериный топор                | 狂野利斧      |\n| 202 | 7ba  | Silver-edged Axe                 | 銀刃斧       | Versilberte Axt                    | [fs]Hacha de filo plateado           | [fs]Hache d’argent                      | [fs]Ascia Argentata                   | 실버 엣지드 액스    | [ms]Srebrnoklingi Topór        | [fs]Hacha argéntea                    | シルバーエッジド・アックス  | [ms]Machado de Prata                | [ms]посеребренный топор           | 镀银斧       |\n| 203 | 7bt  | Decapitator                      | 斬首斧       | [ms]Enthaupter                     | [fs]Decapitadora                     | [fs]Décapiteuse                         | [ms]Decapitatore                      | 디캐피테이터       | [ms]Dekapitator                | [fs]Decapitadora                      | ディキャピテイター      | [ms]Decapitador                     | [ms]главорез                      | 刽子手之斧     |\n| 204 | 7ga  | Champion Axe                     | 豪傑斧       | [fs]Heldenaxt                      | [fs]Hacha del campeón                | [fs]Hache de champion                   | [fs]Ascia del Campione                | 챔피언 액스       | [ms]Czempioński Topór          | [fs]Hacha de campeón                  | チャンピオン・アックス    | [ms]Machado Campeão                 | [ms]элитный топор                 | 冠军斧       |\n| 205 | 7gi  | Glorious Axe                     | 榮光斧       | [fs]Ruhmesaxt                      | [fs]Hacha gloriosa                   | [fs]Hache glorieuse                     | [fs]Ascia Gloriosa                    | 글로리어스 액스     | [ms]Wspaniały Topór            | [fs]Hacha gloriosa                    | グローリアス・アックス    | [ms]Machado Glorioso                | [ms]славный топор                 | 荣耀之斧      |\n| 206 | 7wn  | Polished Wand                    | 拋光魔杖      | [ms]Polierter Stab                 | [fs]Vara pulida                      | [fs]Baguette lisse                      | [fs]Verga Levigata                    | 폴리시드 원드      | [fs]Wypolerowana Różdżka       | [fs]Vara pulida                       | ポリッシュド・ワンド     | [fs]Varinha Polida                  | [ms]отполированный жезл           | 洗练魔杖      |\n| 207 | 7yw  | Ghost Wand                       | 鬼魂魔杖      | [ms]Geisterstab                    | [fs]Vara fantasmal                   | [fs]Baguette fantôme                    | [fs]Verga Fantasma                    | 고스트 원드       | [fs]Upiorna Różdżka            | [fs]Vara fantasmal                    | ゴースト・ワンド       | [fs]Varinha Fantasma                | [ms]призрачный жезл               | 幽灵魔杖      |\n| 208 | 7bw  | Lich Wand                        | 巫妖魔杖      | [ms]Lichstab                       | [fs]Vara de exánime                  | [fs]Baguette de liche                   | [fs]Verga del Lich                    | 리치 원드        | [fs]Kościejowa Różdżka         | [fs]Vara de liche                     | リッチ・ワンド        | [fs]Varinha do Lich                 | [ms]некромантский жезл            | 尸妖魔杖      |\n| 209 | 7gw  | Unearthed Wand                   | 埋骨魔杖      | [ms]Ausgegrabener Stab             | [fs]Vara desenterrada                | [fs]Baguette exhumée                    | [fs]Verga Dissotterrata               | 언어스드 원드      | [fs]Odkopana Różdżka           | [fs]Vara desenterrada                 | アンアースド・ワンド     | [fs]Varinha Descoberta              | [ms]выкопанный жезл               | 出土魔杖      |\n| 210 | 7cl  | Truncheon                        | 打擊棍       | [ms]Schlagstock                    | [fs]Tranca                           | [ms]Assommoir                           | [ms]Manganello                        | 트런천          | [ms]Tłuczek                    | [fs]Macana                            | トランシャン         | [ms]Porrete                         | [ms]буздыган                      | 戒律棒       |\n| 211 | 7sc  | Mighty Scepter                   | 強威權杖      | [ns]Mächtiges Szepter              | [ms]Cetro poderoso                   | [ms]Sceptre de puissance                | [ms]Scettro del Potere                | 마이티 셉터       | [nl]Potężne Berło              | [ms]Cetro poderoso                    | マイティ・セプター      | [ms]Cetro Poderoso                  | [ms]могучий скипетр               | 强威权杖      |\n| 212 | 7qs  | Seraph Rod                       | 熾天使節杖     | [ms]Seraphimstab                   | [fs]Vara de serafín                  | [fs]Baguette séraphine                  | [fs]Verga del Serafino                | 세라프 로드       | [nl]Serafińskie Berło          | [ms]Báculo seráfico                   | セラフ・ロッド        | [ms]Bastão do Serafim               | [ms]серафимов скипетр             | 炽天使杖      |\n| 213 | 7ws  | Caduceus                         | 神使權杖      | [ms]Schlangenstab                  | [ms]Caduceo                          | [ms]Caducée                             | [ms]Caduceo                           | 카두세우스        | [ms]Kaduceusz                  | [ms]Caduceo                           | カドゥケウス         | [ms]Caduceus                        | [ms]кадуцей                       | 使者杖       |\n| 214 | 7sp  | Tyrant Club                      | 暴君棍棒      | [ms]Tyrannentöter                  | [fs]Porra de tirano                  | [fs]Masse du Tyran                      | [fs]Clava del Tiranno                 | 타이런트 클럽      | [fs]Tyraniczna Maczuga         | [fs]Porra de tirano                   | タイラント・クラブ      | [fs]Clava Tirânica                  | [fs]тираническая дубина           | 暴君棒       |\n| 215 | 7ma  | Reinforced Mace                  | 強化釘鎚      | [ms]Verstärkter Streitkolben       | [fs]Maza reforzada                   | [fs]Masse renforcée                     | [fs]Mazza Rinforzata                  | 리인포스드 메이스    | [fs]Wzmocniona Maczuga         | [fs]Maza reforzada                    | リインフォースド・メイス   | [fs]Maça Reforçada                  | [fs]укрепленная булава            | 加固锤       |\n| 216 | 7mt  | Devil Star                       | 妖鬼釘頭鎚     | [ms]Teufelsstern                   | [fs]Estrella diabólica               | [fs]Étoile démoniaque                   | [fs]Stella del Diavolo                | 데빌 스타        | [fs]Diabelska Gwiazda          | [fs]Estrella demoníaca                | デビル・スター        | [fs]Estrela Diabólica               | [fs]дьявольская звезда            | 恶魔流星      |\n| 217 | 7fl  | Scourge                          | 罪罰連枷      | [fs]Geißel                         | [ms]Azote                            | [ms]Fouet                               | [ms]Flagello                          | 스컬지          | [ms]Bicz                       | [ms]Flagelo                           | スコージ           | [ms]Flagelo                         | [fs]плеть                         | 天罚之锤      |\n| 218 | 7wh  | Legendary Mallet                 | 傳說戰鎚      | [ms]Legendärer Hammer              | [ms]Mazo legendario                  | [ms]Maillet légendaire                  | [ms]Maglio Leggendario                | 레전더리 맬릿      | [ms]Legendarny Młot            | [ms]Martillo legendario               | レジェンダリー・マレット   | [fs]Marreta Lendária                | [fs]легендарная колотушка         | 传奇重锤      |\n| 219 | 7m7  | Ogre Maul                        | 巨魔重鎚      | [ms]Ogerhammer                     | [fs]Almádena de ogro                 | [fs]Masse ogre                          | [ms]Maglio dell'Ogre                  | 오우거 마울       | [ms]Ogrzy Kafar                | [ms]Mazo de ogro                      | オーガ・モール        | [ms]Malho Ogro                      | [fs]устрашающая кувалда           | 食人魔锤      |\n| 220 | 7gm  | Thunder Maul                     | 雷霆重鎚      | [ms]Donnerhammer                   | [fs]Almádena del trueno              | [fs]Bombardone                          | [ms]Maglio del Tuono                  | 썬더 마울        | [ms]Grzmiący Kafar             | [ms]Mazo de rayo                      | サンダー・モール       | [ms]Malho Trovejante                | [fs]громовая кувалда              | 雷霆之锤      |\n| 221 | 7ss  | Falcata                          | 法卡塔劍      | [fs]Falkata                        | [fs]Falcata                          | [fs]Falcata                             | [fs]Falcata                           | 팔카타          | [fs]Falcata                    | [fs]Falcata                           | ファルカタ          | [fs]Falcata                         | [fs]фальката                      | 猎鹰剑       |\n| 222 | 7sm  | Ataghan                          | 土耳其彎刀     | [ns]Yatagan                        | [ms]Yatagán                          | [ms]Ataghan                             | [ms]Ataghan                           | 아타간          | [ms]Jatagan                    | [ms]Ataghan                           | ヤタガン           | [ms]Atagã                           | [ms]ятаган                        | 叶根刀       |\n| 223 | 7sb  | Elegant Blade                    | 典雅彎刀      | [fs]Elegante Klinge                | [fs]Espada elegante                  | [fs]Lame élégante                       | [fs]Lama Elegante                     | 엘리건트 블레이드    | [nl]Eleganckie Ostrze          | [fs]Hoja elegante                     | エレガント・ブレイド     | [fs]Lâmina Elegante                 | [ms]изящный клинок                | 精致剑       |\n| 224 | 7fc  | Hydra Edge                       | 多頭蛇刃      | [fs]Hydraschneide                  | [ms]Filo de hidra                    | [ms]Tranchant de l’hydre                | [fs]Lama dell'Idra                    | 히드라 엣지       | [nl]Hydrze Ostrze              | [ms]Filo de hidra                     | ヒュドラ・エッジ       | [fs]Lâmina da Hidra                 | [ms]гидровый клинок               | 九头蛇刃      |\n| 225 | 7cr  | Phase Blade                      | 幻化之刃      | [fs]Phasenklinge                   | [fs]Espada de fase                   | [fs]Épée de phase                       | [fs]Lama Fasica                       | 페이즈 블레이드     | [nl]Fazowe Ostrze              | [fs]Hoja de fase                      | フェーズ・ブレイド      | [fs]Lâmina Fásica                   | [ms]фазовый клинок                | 相位之刃      |\n| 226 | 7bs  | Conquest Sword                   | 征服之劍      | [ns]Erobererschwert                | [fs]Espada de la conquista           | [fs]Épée de conquête                    | [fs]Spada della Conquista             | 컨퀘스트 소드      | [ms]Zdobywczy Miecz            | [fs]Espada conquistadora              | コンクエスト・ソード     | [fs]Espada Conquistadora            | [ms]победный меч                  | 征服剑       |\n| 227 | 7ls  | Cryptic Sword                    | 絕秘劍       | [ns]Rätselhaftes Schwert           | [fs]Espada críptica                  | [fs]Épée mystérieuse                    | [fs]Spada Criptica                    | 크립틱 소드       | [ms]Zagadkowy Miecz            | [fs]Espada enigmática                 | クリプティック・ソード    | [fs]Espada Enigmática               | [ms]таинственный меч              | 秘文剑       |\n| 228 | 7wd  | Mythical Sword                   | 秘儀劍       | [ns]Mythisches Schwert             | [fs]Espada mítica                    | [fs]Épée mythique                       | [fs]Spada Mitologica                  | 미시컬 소드       | [ms]Mityczny Miecz             | [fs]Espada mítica                     | ミシカル・ソード       | [fs]Espada Mítica                   | [ms]мифический меч                | 神话剑       |\n| 229 | 72h  | Legend Sword                     | 傳說劍       | [ns]Legendenschwert                | [fs]Espada de leyenda                | [fs]Épée légendaire                     | [fs]Spada Leggendaria                 | 레전드 소드       | [ms]Legendarny Miecz           | [fs]Espada legendaria                 | レジェンド・ソード      | [fs]Espada Lendária                 | [ms]легендарный меч               | 传说剑       |\n| 230 | 7cm  | Highland Blade                   | 高地劍       | [fs]Hochlandklinge                 | [fs]Espada de las Tierras Altas      | [fs]Épée des Hautes-Terres              | [fs]Spada dell'Altopiano              | 하이랜드 블레이드    | [nl]Góralskie Ostrze           | [fs]Hoja de las Tierras Altas         | ハイランド・ブレイド     | [fs]Lâmina Altaneira                | [ms]высокогорный меч              | 高地剑       |\n| 231 | 7gs  | Balrog Blade                     | 炎魔之刃      | [fs]Balrogklinge                   | [fs]Espada de Balrog                 | [fs]Épée de Balrog                      | [fs]Lama del Balrog                   | 발록 블레이드      | [nl]Balrogowe Ostrze           | [fs]Hoja de balrog                    | バルログ・ブレイド      | [fs]Lâmina de Balrog                | [ms]Балрогов клинок               | 炎魔剑       |\n| 232 | 7b7  | Champion Sword                   | 豪傑大劍      | [ns]Heldenschwert                  | [fs]Espada del campeón               | [fs]Épée de champion                    | [fs]Spada del Campione                | 챔피언 소드       | [ms]Czempioński Miecz          | [fs]Espada campeadora                 | チャンピオン・ソード     | [fs]Espada Campeã                   | [ms]элитный меч                   | 冠军剑       |\n| 233 | 7fb  | Colossus Sword                   | 巨神劍       | Kolossschwert                      | [fs]Espada del coloso                | [fs]Épée de colosse                     | [fs]Spada del Colosso                 | 콜로서스 소드      | [ms]Kolosalny Miecz            | [fs]Espada colosal                    | コロッサス・ソード      | [fs]Espada Colossal                 | [ms]массивный меч                 | 巨神之剑      |\n| 234 | 7gd  | Colossus Blade                   | 巨神刃       | [fs]Kolossklinge                   | [fs]Hoja del coloso                  | [fs]Lame de colosse                     | [fs]Lama Colossale                    | 콜로서스 블레이드    | [nl]Kolosalne Ostrze           | [fs]Hoja colosal                      | コロッサス・ブレイド     | [fs]Lâmina Colossal                 | [ms]массивный клинок              | 巨神之刃      |\n| 235 | 7dg  | Bone Knife                       | 骸骨小刀      | [ns]Knochenmesser                  | [ms]Cuchillo de hueso                | [ms]Coutelas en os                      | [ms]Coltello d'Ossa                   | 본 나이프        | [ms]Kościany Nóż               | [ms]Cuchillo óseo                     | ボーン・ナイフ        | [fs]Faca Óssea                      | [ms]костяной нож                  | 骨刀        |\n| 236 | 7di  | Mithril Point                    | 秘銀尖刀      | [fs]Mithrilspitze                  | [fs]Puya de mithril                  | [ms]Poinçon de Mithril                  | [fs]Punteruolo di Mithril             | 미스릴 포인트      | [ms]Mithrilowy Szpikulec       | [fs]Punta de mithril                  | ミスリル・ポイント      | [fs]Ponta de Mithril                | [ms]мифриловый кинжал             | 秘银刺       |\n| 237 | 7kr  | Fanged Knife                     | 尖齒小刀      | [ns]Fangzahnmesser                 | [ms]Cuchillo canino                  | [ms]Coutelas cranté                     | [ms]Coltello Zannuto                  | 팽드 나이프       | [ms]Zębaty Nóż                 | [ms]Cuchillo dentado                  | ファングド・ナイフ      | [fs]Faca Dentada                    | [ms]нож-клык                      | 牙刃刀       |\n| 238 | 7bl  | Legend Spike                     | 傳說尖刀      | [ms]Legendendorn                   | [fs]Punta de leyenda                 | [fs]Pique légendaire                    | [ms]Aculeo Leggendario                | 레전드 스파이크     | [ms]Legendarny Kolec           | [fs]Púa legendaria                    | レジェンド・スパイク     | [ms]Espeto Lendário                 | [ms]легендарный зубец             | 传说匕刺      |\n| 239 | 7tk  | Flying Knife                     | 高速飛刀      | [ns]Wurfmesser                     | [ms]Cuchillo volador                 | [ms]Coutelas de lancer                  | [ms]Coltello Volante                  | 플라잉 나이프      | [ms]Latający Nóż               | [ms]Cuchillo volador                  | フライング・ナイフ      | [fs]Faca Voadora                    | [ms]летающий нож                  | 飞刀        |\n| 240 | 7ta  | Flying Axe                       | 高速飛斧      | [fs]Flugaxt                        | [fs]Hacha voladora                   | [fs]Hache de jet                        | [fs]Ascia Volante                     | 플라잉 액스       | [ms]Latający Topór             | [fs]Hacha voladora                    | フライング・アックス     | [ms]Machado Voador                  | [ms]летающий топор                | 飞斧        |\n| 241 | 7bk  | Winged Knife                     | 刃翼飛刀      | [ms]Schwingendolch                 | [ms]Cuchillo alado                   | [ms]Coutelas ailé                       | [ms]Coltello Alato                    | 윙드 나이프       | [ms]Skrzydlaty Nóż             | [ms]Cuchillo alado                    | ウィングド・ナイフ      | [fs]Faca Alada                      | [ms]крыловидный нож               | 翼刀        |\n| 242 | 7b8  | Winged Axe                       | 刃翼飛斧      | [fs]Schwingenaxt                   | [fs]Hacha alada                      | [fs]Hache ailée                         | [fs]Ascia Alata                       | 윙드 액스        | [ms]Skrzydlaty Topór           | [fs]Hacha alada                       | ウィングド・アックス     | [ms]Machado Alado                   | [ms]крыловидный топор             | 翼斧        |\n| 243 | 7ja  | Hyperion Javelin                 | 亥伯龍標槍     | [ms]Hyperionwurfspieß              | [fs]Jabalina de Hiperión             | [ms]Javelot d’Hypérion                  | [ms]Giavellotto di Iperione           | 하이페리온 재벌린    | [ms]Hyperionowy Oszczep        | [fs]Jabalina de hiperión              | ハイペリオン・ジャベリン   | [ms]Dardo Hipérion                  | [ms]гиперионский дротик           | 亥伯龙标枪     |\n| 244 | 7pi  | Stygian Pilum                    | 冥河標槍      | [ms]Stygischer Spieß               | [ms]Pilum estigio                    | [ms]Pilum stygien                       | [ms]Giavellotto dello Stige           | 스티지언 필럼      | [nl]Stygijskie Pilum           | [ms]Pilum estigio                     | スティジャン・ピルム     | [ms]Pilum Estígio                   | [ms]стигийский пилум              | 地狱长标枪     |\n| 245 | 7s7  | Balrog Spear                     | 炎魔長矛      | [ms]Balrogspeer                    | [fs]Lanza de Balrog                  | [fs]Lance de Balrog                     | [fs]Lancia del Balrog                 | 발록 스피어       | [fs]Balrogowa Włócznia         | [fs]Lanza de balrog                   | バルログ・スピア       | [fs]Lança de Balrog                 | [ns]Балрогово копье               | 炎魔矛       |\n| 246 | 7gl  | Ghost Glaive                     | 鬼魂刃槍      | [fs]Geistergleve                   | [fs]Guja fantasmal                   | [ms]Glaive fantôme                      | [fs]Guisarma Fantasma                 | 고스트 글레이브     | [fs]Upiorna Glewia             | [fs]Guja fantasmal                    | ゴースト・グレイヴ      | [fs]Glaive Fantasma                 | [fs]призрачная глефа              | 幽灵梭戟      |\n| 247 | 7ts  | Winged Harpoon                   | 飛翼魚叉      | [fs]Geflügelte Harpune             | [ms]Arpón alado                      | [ms]Harpon ailé                         | [ms]Arpione Alato                     | 윙드 하푼        | [ms]Skrzydlaty Harpun          | [ms]Arpón alado                       | ウィングド・ハープーン    | [ms]Arpão Alado                     | [ms]крыловидный гарпун            | 双股叉       |\n| 248 | 7sr  | Hyperion Spear                   | 亥伯龍矛      | [ms]Hyperionspeer                  | [fs]Lanza de Hiperión                | [fs]Lance d’Hypérion                    | [fs]Lancia di Iperione                | 하이페리온 스피어    | [fs]Hyperionowa Włócznia       | [fs]Lanza de hiperión                 | ハイペリオン・スピア     | [fs]Lança Hipérion                  | [ns]гиперионское копье            | 亥伯龙矛      |\n| 249 | 7tr  | Stygian Pike                     | 冥河戰矛      | [fs]Stygische Pike                 | [fs]Pica estigia                     | [fs]Pique stygienne                     | [fs]Picca dello Stige                 | 스티지언 파이크     | [fs]Stygijska Pika             | [fs]Pica estigia                      | スティジャン・パイク     | [ms]Pique Estígio                   | [fs]стигийская пика               | 地狱长枪      |\n| 250 | 7br  | Mancatcher                       | 捕人叉       | [ms]Menschenfänger                 | [ms]Cazahombres                      | [ms]Prédateur                           | [ms]Cacciatore d'Uomini               | 맨캐쳐          | [ms]Widłochwyt                 | [fs]Atrapahombres                     | マンキャッチャー       | [fs]Apanhadora                      | [ms]ухват                         | 捕人枪       |\n| 251 | 7st  | Ghost Spear                      | 鬼魂長矛      | [ms]Geisterspeer                   | [fs]Lanza fantasmal                  | [fs]Lance fantôme                       | [fs]Lancia Fantasma                   | 고스트 스피어      | [fs]Upiorna Włócznia           | [fs]Lanza fantasmal                   | ゴースト・スピア       | [fs]Lança Fantasma                  | [ns]призрачное копье              | 幽灵矛       |\n| 252 | 7p7  | War Pike                         | 征戰長槍      | [fs]Kriegspike                     | [fs]Pica de guerra                   | [fs]Pique de guerre                     | [fs]Picca da Guerra                   | 워 파이크        | [fs]Wojenna Pika               | [fs]Pica de guerra                    | ウォーパイク         | [ms]Pique Bélico                    | [fs]воинская пика                 | 战争长枪      |\n| 253 | 7o7  | Ogre Axe                         | 巨魔斧       | [fs]Ogeraxt                        | [fs]Hacha de ogro                    | [fs]Hache ogre                          | [fs]Ascia dell'Ogre                   | 오우거 액스       | [ms]Ogrzy Topór                | [fs]Hacha de ogro                     | オーガ・アックス       | [ms]Machado Ogro                    | [ms]устрашающий топор             | 食人魔斧      |\n| 254 | 7vo  | Colossus Voulge                  | 巨神長柄斧     | [fs]Kolossvulge                    | [ms]Voulge del coloso                | [ms]Vouge de colosse                    | [fs]Voulge del Colosso                | 콜로서스 불즈      | [fs]Kolosalna Voulge           | [fs]Archa colosal                     | コロッサス・ヴォウジェ    | [fs]Voulge Colossal                 | [ms]массивный вуж                 | 巨型斧戟      |\n| 255 | 7s8  | Thresher                         | 斬鐮        | [ms]Drescher                       | [fs]Trilladora                       | [fs]Batteuse                            | [fs]Trebbiatrice                      | 쓰레셔          | [ms]Rozdzieracz                | [ms]Azotador                          | スレッシャー         | [ms]Debulhador                      | [ms]цеп                           | 砍斧        |\n| 256 | 7pa  | Cryptic Axe                      | 絕秘斧       | [fs]Rätselhafte Axt                | [fs]Hacha críptica                   | [fs]Hache mystérieuse                   | [fs]Ascia Criptica                    | 크립틱 액스       | [ms]Zagadkowy Topór            | [fs]Hacha enigmática                  | クリプティック・アックス   | [mp]Machado Enigmático              | [ms]таинственный топор            | 秘文斧       |\n| 257 | 7h7  | Great Poleaxe                    | 巨型長柄斧     | [fs]Große Stangenaxt               | [fs]Gran hacha larga                 | [fs]Hache de bourreau                   | [fs]Grande Ascia Inastata             | 그레이트 폴액스     | [fs]Wielka Gizarma             | [fs]Gran hacha de petos               | グレート・ポールアックス   | [fs]Grande Acha                     | [ms]большой полэкс                | 重长柄斧      |\n| 258 | 7wc  | Giant Thresher                   | 巨型斬鐮      | [ms]Riesendrescher                 | [fs]Trilladora gigante               | [fs]Batteuse géante                     | [fs]Trebbiatrice Gigante              | 자이언트 쓰레셔     | [ms]Ogromny Rozdzieracz        | [ms]Azotador gigante                  | ジャイアント・スレッシャー  | [ms]Debulhador Gigante              | [ms]огромный цеп                  | 巨型砍斧      |\n| 259 | 6ss  | Walking Stick                    | 手杖        | [ms]Gehstock                       | [ms]Bordón                           | [fs]Grume                               | [ms]Bastone da Passeggio              | 워킹 스틱        | [ms]Kij                        | [ms]Báculo                            | ウォーキング・スティック   | [fs]Bengala                         | [fs]трость                        | 手杖        |\n| 260 | 6ls  | Stalagmite                       | 鐘乳石杖      | [ms]Stalagmit                      | [fs]Estalagmita                      | [fs]Stalagmite                          | [fs]Stalagmite                        | 스탈라그마이트      | [ms]Stalagmit                  | [fs]Estalagmita                       | ストラグマイト        | [fs]Estalagmite                     | [ms]сталагмит                     | 石笋杖       |\n| 261 | 6cs  | Elder Staff                      | 長者法杖      | [ms]Ältestenstab                   | [ms]Bastón de anciano                | [ms]Bâton ancestral                     | [ms]Bastone dell'Anziano              | 엘더 스태프       | [ms]Starszyźniany Kostur       | [ms]Bastón de saúco                   | エルダー・スタッフ      | [ms]Cajado Ancião                   | [ms]бузинный посох                | 接骨木杖      |\n| 262 | 6bs  | Shillelagh                       | 節瘤木杖      | Shillelagh                         | [ms]Shillelagh                       | [ms]Shillelagh                          | [ms]Shillelagh                        | 쉴레일리         | [ms]Kostur                     | [ms]Shillelagh                        | シレーラ           | [ms]Shillelagh                      | [fs]шилейла                       | 橡木棍       |\n| 263 | 6ws  | Archon Staff                     | 統御者法杖     | [ms]Archonstab                     | [ms]Bastón de arconte                | [ms]Bâton de l’Archonte                 | [ms]Bastone dell'Arconte              | 아콘 스태프       | [ms]Archoncki Kostur           | [ms]Bastón de Arconte                 | アルコン・スタッフ      | [ms]Cajado do Arconte               | [ms]архонтов посох                | 统治者之杖     |\n| 264 | 6sb  | Spider Bow                       | 蜘蛛弓       | [ms]Spinnenbogen                   | [ms]Arco de araña                    | [ms]Arc araignée                        | [ms]Arco del Ragno                    | 스파이더 보우      | [ms]Pajęczy Łuk                | [ms]Arco arácnido                     | スパイダー・ボウ       | [ms]Arco Aracnídeo                  | [ms]паучий лук                    | 蜘蛛弓       |\n| 265 | 6hb  | Blade Bow                        | 刀鋒弓       | [ms]Klingenbogen                   | [ms]Arco tajante                     | [ms]Arc lame                            | [ms]Scagliaspade                      | 블레이드 보우      | [ms]Ostry Łuk                  | [ms]Arco de cuchillas                 | ブレイド・ボウ        | [ms]Arco Afiado                     | [ms]лопастной лук                 | 利刃弓       |\n| 266 | 6lb  | Shadow Bow                       | 暗影弓       | [ms]Schattenbogen                  | [ms]Arco sombrío                     | [ms]Arc d’ombre                         | [ms]Arco Ombra                        | 쉐도우 보우       | [ms]Mroczny Łuk                | [ms]Arco de las sombras               | シャドウ・ボウ        | [ms]Arco Sombrio                    | [ms]темный лук                    | 暗影弓       |\n| 267 | 6cb  | Great Bow                        | 巨弓        | [ms]Langbogen                      | [ms]Gran arco                        | [ms]Grand arc                           | [ms]Grande Arco                       | 그레이트 보우      | [ms]Wielki Łuk                 | [ms]Gran arco                         | グレート・ボウ        | [ms]Grande Arco                     | [ms]большой лук                   | 重弓        |\n| 268 | 6s7  | Diamond Bow                      | 鑽石弓       | [ms]Diamantbogen                   | [ms]Arco de diamante                 | [ms]Arc de diamant                      | [ms]Arco di Diamante                  | 다이아몬드 보우     | [ms]Diamentowy Łuk             | [ms]Arco diamantino                   | ダイヤモンド・ボウ      | [ms]Arco Diamante                   | [ms]алмазный лук                  | 钻石弓       |\n| 269 | 6l7  | Crusader Bow                     | 聖教軍長弓     | [ms]Kreuzritterbogen               | [ms]Arco de cruzada                  | [ms]Arc de croisé                       | [ms]Arco del Crociato                 | 크루세이더 보우     | [ms]Krzyżowy Łuk               | [ms]Arco de cruzado                   | クルセイダー・ボウ      | [ms]Arco do Cruzado                 | [ms]рыцарский лук                 | 十字军弓      |\n| 270 | 6sw  | Ward Bow                         | 庇護弓       | [ms]Wächterbogen                   | [ms]Arco de custodia                 | [ms]Arc de protection                   | [ms]Arco della Difesa                 | 워드 보우        | [ms]Strażniczy Łuk             | [ms]Arco de guarda                    | ウォード・ボウ        | [ms]Arco Guardião                   | [ms]охранный лук                  | 防护弓       |\n| 271 | 6lw  | Hydra Bow                        | 多頭蛇弓      | [ms]Hydrabogen                     | [ms]Arco de hidra                    | [ms]Arc de l’hydre                      | [ms]Arco dell'Idra                    | 히드라 보우       | [ms]Hydrzy Łuk                 | [ms]Arco de hidra                     | ヒュドラ・ボウ        | [ms]Arco da Hidra                   | [ms]гидровый лук                  | 九头蛇弓      |\n| 272 | 6lx  | Pellet Bow                       | 彈丸弩       | [ms]Kugelbogen                     | [ms]Arco de perdigones               | [ms]Arc hérissé                         | [ms]Arco di Pellet                    | 팰리트 보우       | [fs]Śrutowa Kusza              | [ms]Arco de perdigones                | パレット・ボウ        | [fs]Besta Bravia                    | [ms]шариковый арбалет             | 弹丸弓       |\n| 273 | 6mx  | Gorgon Crossbow                  | 蛇魔弩       | [fs]Gorgonenarmbrust               | [fs]Ballesta de gorgona              | [fs]Arbalète de gorgone                 | [fs]Balestra della Gorgone            | 고르곤 크로스보우    | [fs]Gorgonia Kusza             | [fs]Ballesta de gorgona               | ゴルゴン・クロスボウ     | [fs]Besta Górgona                   | [ms]горгоний арбалет              | 蛇发女妖弩     |\n| 274 | 6hx  | Colossus Crossbow                | 巨神弩       | [fs]Kolossarmbrust                 | [fs]Ballesta del coloso              | [fs]Arbalète de colosse                 | [fs]Balestra del Colosso              | 콜로서스 크로스보우   | [fs]Kolosalna Kusza            | [fs]Ballesta colosal                  | コロッサス・クロスボウ    | [fs]Besta Colossal                  | [ms]массивный арбалет             | 神臂弩       |\n| 275 | 6rx  | Demon Crossbow                   | 惡魔弩       | [fs]Dämonenarmbrust                | [fs]Ballesta del demonio             | [fs]Arbalète de démon                   | [fs]Balestra Demoniaca                | 데몬 크로스보우     | [fs]Demoniczna Kusza           | [fs]Ballesta demoníaca                | デーモン・クロスボウ     | [fs]Besta Demoníaca                 | [ms]демонический арбалет          | 恶魔弩       |\n| 276 | ob1  | Eagle Orb                        | 鷹之法珠      | [fs]Adlerkugel                     | [ms]Orbe del águila                  | [ms]Orbe de l’aigle                     | [fs]Sfera Aquilina                    | 이글 오브        | [fs]Orla Kula                  | [ms]Orbe aguileño                     | イーグル・オーブ       | [ms]Orbe da Águia                   | [fs]орлиная сфера                 | 鹰眼法珠      |\n| 277 | ob2  | Sacred Globe                     | 神聖天球      | [fs]Heilige Kugel                  | [ms]Globo sacro                      | [ms]Globe sacré                         | [ms]Globo Sacro                       | 세이크리드 글로브    | [fs]Święta Kula                | [ms]Globo sagrado                     | セイクレッド・グローブ    | [ms]Globo Sagrado                   | [ms]священный шар                 | 圣洁之球      |\n| 278 | ob3  | Smoked Sphere                    | 攏煙之球      | [fs]Rauchkugel                     | [fs]Esfera ahumada                   | [fs]Sphère fumée                        | [fs]Sfera Fumosa                      | 스모크드 스피어     | [fs]Dymiąca Kula               | [fs]Esfera ahumada                    | スモークド・スフィア     | [fs]Esfera Esfumaçada               | [fs]дымчатая сфера                | 烟熏法球      |\n| 279 | ob4  | Clasped Orb                      | 握扣法珠      | [fs]Klammerkugel                   | [ms]Orbe aferrado                    | [ms]Orbe enchâssé                       | [fs]Sfera Agganciata                  | 클래스프드 오브     | [fs]Okuta Kula                 | [ms]Orbe aferrado                     | クラスプド・オーブ      | [ms]Orbe Afivelado                  | [fs]стянутая сфера                | 握扣法珠      |\n| 280 | ob5  | Jared's Stone                    | 傑瑞德之石     | Jareds Stein                       | Piedra de Jared                      | Pierre de Jared                         | Pietra di Jared                       | 자레드 스톤       | [ms]Jaredowy Kamień            | [fs]Piedra de Jared                   | ジャレッズ・ストーン     | [fs]Pedra de Jared                  | Камень Джареда                    | 杰瑞德之石     |\n| 281 | am1  | Stag Bow                         | 獵鹿弓       | [ms]Hirschbogen                    | [ms]Arco de ciervo                   | [ms]Arc cervier                         | [ms]Arco del Cervo                    | 스태그 보우       | [ms]Jeleni Łuk                 | [ms]Arco de cuerno                    | スタッグ・ボウ        | [ms]Arco Cervídeo                   | [ms]рогатый лук                   | 猎鹿之弓      |\n| 282 | am2  | Reflex Bow                       | 反射弓       | [ms]Reflexbogen                    | [ms]Arco de reflejos                 | [ms]Arc adrénal                         | [ms]Arco Riflesso                     | 리플렉스 보우      | [ms]Refleksyjny Łuk            | [ms]Arco de reflejo                   | リフレックス・ボウ      | [ms]Arco Reflexivo                  | [ms]рефлексивный лук              | 双曲弓       |\n| 283 | am3  | Maiden Spear                     | 女戰長矛      | [ms]Jungfernspeer                  | [fs]Lanza doncella                   | [fs]Lance de la vierge                  | [fs]Lancia della Vergine              | 메이든 스피어      | [fs]Dziewicza Włócznia         | [fs]Lanza de la doncella              | メイデン・スピア       | [fs]Lança da Dama                   | [ns]девичье копье                 | 处子长矛      |\n| 284 | am4  | Maiden Pike                      | 女戰長槍      | [fs]Jungfernpike                   | [fs]Pica doncella                    | [fs]Pique de la vierge                  | [fs]Picca della Vergine               | 메이든 파이크      | [fs]Dziewicza Pika             | [fs]Pica de la doncella               | メイデン・パイク       | [ms]Pique da Dama                   | [fs]девичья пика                  | 处子长枪      |\n| 285 | am5  | Maiden Javelin                   | 女戰標槍      | [ms]Jungfernwurfspieß              | [fs]Jabalina doncella                | [ms]Javelot de la vierge                | [ms]Giavellotto della Vergine         | 메이든 재벌린      | [ms]Dziewiczy Oszczep          | [fs]Jabalina de la doncella           | メイデン・ジャベリン     | [ms]Dardo da Dama                   | [ms]девичий дротик                | 处子标枪      |\n| 286 | ob6  | Glowing Orb                      | 靈光法珠      | [fs]Leuchtkugel                    | [ms]Orbe encendido                   | [ms]Orbe rayonnant                      | [fs]Sfera Lucente                     | 글로잉 오브       | [fs]Jaśniejąca Kula            | [ms]Orbe fulgurante                   | グローイング・オーブ     | [ms]Orbe Brilhante                  | [fs]светящаяся сфера              | 闪光宝珠      |\n| 287 | ob7  | Crystalline Globe                | 水晶天球      | [fs]Kristallkugel                  | [ms]Globo cristalino                 | [ms]Globe cristallin                    | [ms]Globo Cristallino                 | 크리스탈라인 글로브   | [fs]Kryształowa Kula           | [ms]Globo cristalino                  | クリスタライン・グローブ   | [ms]Globo Cristalino                | [ms]кристальный шар               | 水晶之球      |\n| 288 | ob8  | Cloudy Sphere                    | 雲霧之球      | [fs]Wolkenkugel                    | [fs]Esfera turbia                    | [fs]Sphère nébuleuse                    | [fs]Sfera Annebbiata                  | 클라우디 스피어     | [fs]Pochmurna Kula             | [fs]Esfera nublada                    | クラウディ・スフィア     | [fs]Esfera Nebulosa                 | [fs]туманная сфера                | 云雾法球      |\n| 289 | ob9  | Sparkling Ball                   | 閃耀之球      | [ms]Funkelball                     | [fs]Bola centelleante                | [fs]Boule étincelante                   | [fs]Palla Scintillante                | 스파클링 볼       | [fs]Lśniąca Kula               | [fs]Bola centelleante                 | スパークリング・ボール    | [fs]Esfera Cintilante               | [ms]мерцающий шар                 | 闪光之球      |\n| 290 | oba  | Swirling Crystal                 | 渦流水晶      | [ms]Wirbelnder Kristall            | [ms]Cristal turbulento               | [ms]Tourbillon de cristal               | [ms]Cristallo Roteante                | 스월링 크리스탈     | [ms]Wirujący Kryształ          | [ms]Cristal giratorio                 | スワーリング・クリスタル   | [ms]Cristal Espiralado              | [ms]кружащийся кристалл           | 漩涡水晶      |\n| 291 | am6  | Ashwood Bow                      | 梣木弓       | [ms]Eschenholzbogen                | [ms]Arco de Ashwood                  | [ms]Arc d’ébène                         | [ms]Arco di Frassino                  | 애쉬우드 보우      | [ms]Jesionowy Łuk              | [ms]Arco de fresno                    | アッシュウッド・ボウ     | [ms]Arco de Freixo                  | [ms]ясеневый лук                  | 白蜡木弓      |\n| 292 | am7  | Ceremonial Bow                   | 儀禮弓       | [ms]Zeremonialbogen                | [ms]Arco ceremonial                  | [ms]Arc de cérémonie                    | [ms]Arco Cerimoniale                  | 세러모니얼 보우     | [ms]Ceremonialny Łuk           | [ms]Arco ceremonial                   | セレモニアル・ボウ      | [ms]Arco Cerimonial                 | [ms]ритуальный лук                | 仪式弓       |\n| 293 | am8  | Ceremonial Spear                 | 儀禮長矛      | [ms]Zeremonialspeer                | [fs]Lanza ceremonial                 | [fs]Lance de cérémonie                  | [fs]Lancia Cerimoniale                | 세러모니얼 스피어    | [fs]Ceremonialna Włócznia      | [fs]Lanza ceremonial                  | セレモニアル・スピア     | [fs]Lança Cerimonial                | [ns]ритуальное копье              | 仪式矛       |\n| 294 | am9  | Ceremonial Pike                  | 儀禮長槍      | [fs]Zeremonialpike                 | [fs]Pica ceremonial                  | [fs]Pique de cérémonie                  | [fs]Picca Cerimoniale                 | 세러모니얼 파이크    | [fs]Ceremonialna Pika          | [fs]Pica ceremonial                   | セレモニアル・パイク     | [ms]Pique Cerimonial                | [fs]ритуальная пика               | 仪式长枪      |\n| 295 | ama  | Ceremonial Javelin               | 儀禮標槍      | [ms]Zeremonialwurfspieß            | [fs]Jabalina ceremonial              | [ms]Javelot de cérémonie                | [ms]Giavellotto Cerimoniale           | 세러모니얼 재벌린    | [ms]Ceremonialny Oszczep       | [fs]Jabalina ceremonial               | セレモニアル・ジャベリン   | [ms]Dardo Cerimonial                | [ms]ритуальный дротик             | 仪式标枪      |\n| 296 | obb  | Heavenly Stone                   | 天堂之石      | Himmelsstein                       | [fs]Piedra celestial                 | [fs]Pierre Céleste                      | [fs]Pietra Celestiale                 | 헤븐리 스톤       | [ms]Niebiański Kamień          | [fs]Roca celestial                    | ヘブンリー・ストーン     | [fs]Pedra Celestial                 | [ms]небесный камень               | 天界石       |\n| 297 | obc  | Eldritch Orb                     | 異能法珠      | [fs]Heidenkugel                    | [ms]Orbe sobrenatural                | [ms]Orbe surnaturel                     | [fs]Sfera Ultraterrena                | 엘드리치 오브      | [fs]Mroczna Kula               | [ms]Orbe espeluznante                 | エルドリッチ・オーブ     | [ms]Orbe Ancestral                  | [fs]зловещая сфера                | 怪异法珠      |\n| 298 | obd  | Demon Heart                      | 惡魔心石      | [ns]Dämonenherz                    | [ms]Corazón del demonio              | [ms]Cœur de démon                       | [ms]Cuore Demoniaco                   | 데몬 하트        | [nl]Demonie Serce              | [ms]Corazón demoníaco                 | デーモン・ハート       | [ms]Coração Demoníaco               | [ns]демонское сердце              | 恶魔之心      |\n| 299 | obe  | Vortex Orb                       | 漩渦法珠      | [fs]Wirbelkugel                    | [ms]Orbe vórtice                     | [ms]Orbe du vortex                      | [fs]Sfera del Vortice                 | 볼텍스 오브       | [fs]Wirująca Kula              | [ms]Orbe de vórtice                   | ボルテックス・オーブ     | [ms]Orbe do Vórtice                 | [fs]ураганная сфера               | 旋云宝珠      |\n| 300 | obf  | Dimensional Shard                | 次元法珠      | [fs]Dimensionsscherbe              | [fs]Esquirla dimensional             | [fs]Épine dimensionnelle                | [ms]Frammento Dimensionale            | 디멘셔널 샤드      | [ms]Międzywymiarowy Odłamek    | [ms]Fragmento dimensional             | ディメンショナル・シャード  | [ms]Estilhaço Dimensional           | [ms]межпространственный осколок   | 次元碎片      |\n| 301 | amb  | Matriarchal Bow                  | 女傑之弓      | [ms]Matriarchenbogen               | [ms]Arco matriarcal                  | [ms]Arc matriarcal                      | [ms]Arco Matriarcale                  | 메이트리어컬 보우    | [ms]Matriarchalny Łuk          | [ms]Arco de la matriarca              | メイトリアーカル・ボウ    | [ms]Arco Matriarcal                 | [ms]матриарший лук                | 女族长弓      |\n| 302 | amc  | Grand Matron Bow                 | 主母之弓      | [ms]Großer Matronenbogen           | [ms]Arco de la gran matrona          | [ms]Arc de Gaïa                         | [ms]Arco della Matrona                | 그랜드 메이트런 보우  | [ms]Matroni Łuk                | [ms]Gran arco de la matrona           | グランド・メイトロン・ボウ  | [ms]Grande Arco da Matrona          | [ms]большой матронин лук          | 仕女长之弓     |\n| 303 | amd  | Matriarchal Spear                | 女傑長矛      | [ms]Matriarchenspeer               | [fs]Lanza matriarcal                 | [fs]Lance matriarcale                   | [fs]Lancia Matriarcale                | 메이트리어컬 스피어   | [fs]Matriarchalna Włócznia     | [fs]Lanza de la matriarca             | メイトリアーカル・スピア   | [fs]Lança Matriarcal                | [ns]матриаршее копье              | 女族长矛      |\n| 304 | ame  | Matriarchal Pike                 | 女傑長槍      | [fs]Matriarchenpike                | [fs]Pica matriarcal                  | [fs]Pique matriarcale                   | [fs]Picca Matriarcale                 | 메이트리어컬 파이크   | [fs]Matriarchalna Pika         | [fs]Pica de la matriarca              | メイトリアーカル・パイク   | [ms]Pique Matriarcal                | [fs]матриаршая пика               | 女族长尖枪     |\n| 305 | amf  | Matriarchal Javelin              | 女傑標槍      | [ms]Matriarchenwurfspieß           | [fs]Jabalina matriarcal              | [ms]Javelot matriarcal                  | [ms]Giavellotto Matriarcale           | 메이트리어컬 재벌린   | [ms]Matriarchalny Oszczep      | [fs]Jabalina de la matriarca          | メイトリアーカル・ジャベリン | [ms]Dardo Matriarcal                | [ms]матриарший дротик             | 女族长标枪     |\n| 306 | cap  | Cap                              | 便帽        | [fs]Kappe                          | [ms]Gorro                            | [fs]Coiffe                              | [ms]Cappello                          | 캡            | [ms]Kaptur                     | [ms]Gorro                             | キャップ           | [ms]Barrete                         | [ms]наголовник                    | 软帽        |\n| 307 | skp  | Skull Cap                        | 顱帽        | [ms]Eisenhut                       | [ms]Capacete                         | [fs]Cervellière                         | [fs]Calotta                           | 스컬 캡         | [ms]Szyszak                    | [ms]Casquete                          | スカル・キャップ       | [ms]Barrete da Caveira              | [ms]легкий шлем                   | 骷髅帽       |\n| 308 | hlm  | Helm                             | 頭盔        | [ms]Helm                           | [ms]Yelmo                            | [ms]Heaume                              | [ms]Elmo                              | 헬름           | [ms]Hełm                       | [ms]Yelmo                             | ヘルム            | [ms]Elmo                            | [ms]шлем                          | 头盔        |\n| 309 | fhl  | Full Helm                        | 全罩盔       | [ms]Vollhelm                       | [ms]Yelmo completo                   | [ms]Heaume complet                      | [ms]Elmo Pieno                        | 풀 헬름         | [ms]Zamknięty Hełm             | [ms]Yelmo completo                    | フル・ヘルム         | [ms]Elmo Integral                   | [ms]полный шлем                   | 全护盔       |\n| 310 | ghm  | Great Helm                       | 重盔        | [ms]Großhelm                       | [ms]Gran yelmo                       | [ms]Grand heaume                        | [ms]Grande Elmo                       | 그레이트 헬름      | [ms]Wielki Hełm                | [ms]Gran yelmo                        | グレート・ヘルム       | [ms]Grande Elmo                     | [ms]большой шлем                  | 重盔        |\n| 311 | crn  | Crown                            | 王冠        | [fs]Krone                          | [fs]Corona                           | [fs]Couronne                            | [fs]Corona                            | 크라운          | [fs]Korona                     | [fs]Corona                            | 冠              | [fs]Coroa                           | [fs]корона                        | 王冠        |\n| 312 | msk  | Mask                             | 面具        | [fs]Maske                          | [fs]Máscara                          | [ms]Masque                              | [fs]Maschera                          | 마스크          | [fs]Maska                      | [fs]Máscara                           | 仮面             | [fs]Máscara                         | [fs]маска                         | 覆面甲       |\n| 313 | qui  | Quilted Armor                    | 棉布甲       | [fs]leichte Rüstung                | [fs]Armadura acolchada               | [fs]Armure matelassée                   | [fs]Corazza Imbottita                 | 퀼티드 아머       | [fs]Pikowana Zbroja            | [fs]Armadura acolchonada              | キルテッド・アーマー     | [fs]Armadura Acolchoada             | [ms]стеганый доспех               | 内衬甲       |\n| 314 | lea  | Leather Armor                    | 皮革甲       | [fs]Lederrüstung                   | [fs]Armadura de cuero                | [fs]Armure de cuir                      | [fs]Corazza di Cuoio                  | 레더 아머        | [fs]Skórzana Zbroja            | [fs]Armadura de cuero                 | レザーアーマー        | [fs]Armadura de Couro               | [ms]кожаный доспех                | 皮甲        |\n| 315 | hla  | Hard Leather Armor               | 硬皮甲       | [ns]gehärtetes Leder               | [fs]Armadura de cuero duro           | [fs]Armure de cuir bouilli              | [fs]Corazza di Cuoio Trattato         | 하드 레더 아머     | [fs]Ciężka Skórzana Zbroja     | [fs]Armadura de cuero endurecido      | ハードレザーアーマー     | [fs]Armadura de Couro Rígido        | [ms]плотный кожаный доспех        | 硬皮甲       |\n| 316 | stu  | Studded Leather                  | 鑲釘皮甲      | [ns]beschlagenes Leder             | [ms]Cuero tachonado                  | [fs]Armure en cuir clouté               | [ms]Cuoio Borchiato                   | 스터디드 레더      | [fs]Ćwiekowana Zbroja          | [fs]Armadura de cuero tachonado       | スタデッド・レザーアーマー  | [ms]Couro Cravejado                 | [ms]клепаный кожаный доспех       | 钉皮甲       |\n| 317 | rng  | Ring Mail                        | 環甲        | [ms]Ringpanzer                     | [fs]Cota de anillos                  | [fs]Cotte de mailles                    | [fs]Corazza di Maglia                 | 링 메일         | [fs]Pierścieniowa Zbroja       | [fs]Armadura con anillas              | リング・メイル        | [fs]Malha Anelada                   | [ms]кольчатый доспех              | 环甲        |\n| 318 | scl  | Scale Mail                       | 鱗甲        | [ms]Schuppenpanzer                 | [fs]Cota de escamas                  | [fs]Armure en écaille                   | [fs]Corazza a Scaglie                 | 스케일 메일       | [fs]Zbroja Łuskowa             | [fs]Cota de escamas                   | スケイル・メイル       | [fs]Malha Escamada                  | [ms]чешуйчатый доспех             | 鱼鳞甲       |\n| 319 | chn  | Chain Mail                       | 鎖鍊甲       | [ms]Kettenpanzer                   | [fs]Cota de malla                    | [fs]Tunique de mailles                  | [fs]Cotta di Maglia                   | 체인 메일        | [fs]Kolczuga                   | [fs]Cota de malla                     | チェイン・メイル       | [fs]Cota de Malha                   | [ms]кольчужный доспех             | 锁子甲       |\n| 320 | brs  | Breast Plate                     | 胸鎧        | [ms]Brustpanzer                    | [fs]Coraza blindada                  | [fs]Cuirasse                            | [ms]Pettorale Corazzato               | 브레스트 플레이트    | [ms]Napierśnik                 | [ms]Peto                              | 胸当て            | [fs]Placa Peitoral                  | [fs]кираса                        | 胸片甲       |\n| 321 | spl  | Splint Mail                      | 板甲        | [fs]Bänderrüstung                  | [fs]Cota de láminas                  | [fs]Brigandine                          | [fs]Corazza a Stecche                 | 스플린트 메일      | [fs]Karacenowa Zbroja          | [fs]Cota de pletinas                  | スプリント・メイル      | [fs]Armadura Escamada               | [ms]пластинчатый доспех           | 板条甲       |\n| 322 | plt  | Plate Mail                       | 鎧甲        | [ms]Plattenharnisch                | [fs]Cota de placas                   | [ms]Harnois en plaques                  | [fs]Maglia Rinforzata                 | 플레이트 메일      | [fs]Zbroja Płytowa             | [fs]Cota de placas                    | プレート・メイル       | [fs]Armadura de Placas              | [ms]латный доспех                 | 板链甲       |\n| 323 | fld  | Field Plate                      | 野戰鎧甲      | [ms]Feldharnisch                   | [fs]Coraza de campaña                | [ms]Harnois de guerre                   | [fs]Corazza a Lastre                  | 필드 플레이트      | [fs]Zbroja Polowa              | [fs]Coraza de campaña                 | フィールド・プレート     | [fs]Armadura de Campo               | [ms]полевой латный доспех         | 全身板甲      |\n| 324 | gth  | Gothic Plate                     | 哥德鎧甲      | [ms]Prunkharnisch                  | [fs]Coraza gótica                    | [ms]Harnois gothique                    | [fs]Corazza Gotica                    | 고딕 플레이트      | [fs]Gotycka Zbroja Płytowa     | [fs]Coraza gótica                     | ゴシック・プレート      | [fs]Armadura Gótica                 | [ms]готический доспех             | 哥特甲       |\n| 325 | ful  | Full Plate Mail                  | 全身鎧甲      | [ms]voller Harnisch                | [fs]Cota de placas completa          | [ms]Harnois complet                     | [fs]Corazza di Maglia Completa        | 풀 플레이트 메일    | [fs]Pełna Zbroja Płytowa       | [fs]Cota de placas completa           | フルプレート・メイル     | [fs]Armadura de Placas Integral     | [ms]полный латный доспех          | 全身板链甲     |\n| 326 | aar  | Ancient Armor                    | 上古鎧甲      | [fs]alte Rüstung                   | [fs]Armadura antigua                 | [fs]Armure ancienne                     | [fs]Corazza Antica                    | 에인션트 아머      | [fs]Prastara Zbroja            | [fs]Armadura antigua                  | エンシェント・アーマー    | [fs]Armadura Ancestral              | [ms]древний доспех                | 古代甲       |\n| 327 | ltp  | Light Plate                      | 輕型鎧甲      | [fs]leichte Plattenrüstung         | [fs]Coraza ligera                    | [ms]Harnois léger                       | [fs]Corazza di Piastre Leggera        | 라이트 플레이트     | [fs]Lekka Zbroja Płytowa       | [fs]Coraza ligera                     | ライトプレート        | [fs]Armadura Leve                   | [ms]легкий латный доспех          | 轻板甲       |\n| 328 | buc  | Buckler                          | 小圓盾       | [ms]Beschützer                     | [ms]Broquel                          | [ms]Écu                                 | [ms]Brocchiere                        | 버클러          | [ms]Puklerz                    | [ms]Broquel                           | バックラー          | [ms]Broquel                         | [ms]баклер                        | 小圆盾       |\n| 329 | sml  | Small Shield                     | 小型盾       | [ms]kleiner Schild                 | [ms]Escudo pequeño                   | [ms]Petit bouclier                      | [ms]Scudo Piccolo                     | 스몰 쉴드        | [fs]Mała Tarcza                | [ms]Escudo pequeño                    | 小盾             | [ms]Escudo Pequeno                  | [ms]маленький щит                 | 小盾        |\n| 330 | lrg  | Large Shield                     | 大型盾       | [ms]großer Schild                  | [ms]Escudo grande                    | [ms]Grand bouclier                      | [ms]Scudo Grande                      | 라지 쉴드        | [fs]Duża Tarcza                | [ms]Escudo grande                     | 大盾             | [ms]Escudo Grande                   | [ms]большой щит                   | 大盾        |\n| 331 | kit  | Kite Shield                      | 鳶盾        | [ms]eckiger Schild                 | [ms]Escudo de lágrima                | [ms]Grand écu                           | [ms]Scudo a Losanga                   | 카이트 쉴드       | [fs]Trójkątna Tarcza           | [ms]Escudo de lágrima                 | カイト・シールド       | [ms]Escudo Reforçado                | [ms]каплевидный щит               | 鸢盾        |\n| 332 | tow  | Tower Shield                     | 塔盾        | [ms]hoher Schild                   | [fs]Tarja                            | [ms]Bouclier rectangulaire              | [ms]Scudo a Torre                     | 타워 쉴드        | [fs]Ciężka Tarcza              | [ms]Escudo torre                      | タワー・シールド       | [ms]Escudo Torre                    | [ms]осадный щит                   | 塔盾        |\n| 333 | gts  | Gothic Shield                    | 哥德盾       | [ms]Prunkschild                    | [ms]Escudo gótico                    | [ms]Bouclier gothique                   | [ms]Scudo Gotico                      | 고딕 쉴드        | [fs]Gotycka Tarcza             | [ms]Escudo gótico                     | ゴシック・シールド      | [ms]Escudo Gótico                   | [ms]готический щит                | 哥特盾       |\n| 334 | lgl  | Leather Gloves                   | 皮革手套      | [pl]Lederhandschuhe                | [mp]Guantes de cuero                 | [mp]Gants en cuir                       | [mp]Guanti di Pelle                   | 레더 글러브       | [nl]Skórzane Rękawice          | [mp]Guantes de cuero                  | レザーグローブ        | [fp]Luvas de Couro                  | [pl]кожаные перчатки              | 皮手套       |\n| 335 | vgl  | Heavy Gloves                     | 厚皮手套      | [pl]schwere Handschuhe             | [mp]Guantes pesados                  | [mp]Gants lourds                        | [mp]Guanti Pesanti                    | 헤비 글러브       | [nl]Ciężkie Rękawice           | [mp]Guantes pesados                   | ヘビーグローブ        | [fp]Luvas Pesadas                   | [pl]тяжелые перчатки              | 重手套       |\n| 336 | mgl  | Chain Gloves                     | 鍊甲手套      | [pl]Kettenhandschuhe               | [mp]Guantes de malla                 | [mp]Gants en anneaux                    | [mp]Guanti di Maglia                  | 체인 글러브       | [nl]Kolcze Rękawice            | [mp]Guantes de malla                  | チェイン・グローブ      | [fp]Luvas Encadeadas                | [pl]кольчужные перчатки           | 链甲手套      |\n| 337 | tgl  | Light Gauntlets                  | 輕型護手      | [pl]leichte Panzerhandschuhe       | [mp]Guanteletes ligeros              | [mp]Gantelets légers                    | [mp]Guanti d'Arme Leggeri             | 라이트 건틀릿      | [nl]Lekkie Rękawice            | [mp]Guanteletes ligeros               | ライト・ガントレット     | [fp]Manoplas Leves                  | [pl]легкие рукавицы               | 轻护手       |\n| 338 | hgl  | Gauntlets                        | 鋼鐵護手      | [pl]Panzerhandschuhe               | [mp]Guanteletes                      | [mp]Gantelets                           | [mp]Guanti d'Arme                     | 건틀릿          | [nl]Rękawice                   | [mp]Guanteletes                       | ガントレット         | [fp]Manoplas                        | [pl]рукавицы                      | 护手        |\n| 339 | lbt  | Boots                            | 皮靴        | [pl]Stiefel                        | [fp]Botas                            | [fp]Bottes                              | [mp]Stivali                           | 부츠           | [nl]Buty                       | [fp]Botas                             | ブーツ            | [fp]Botas                           | [pl]сапоги                        | 短靴        |\n| 340 | vbt  | Heavy Boots                      | 重靴        | [pl]schwere Stiefel                | [fp]Botas pesadas                    | [fp]Bottes lourdes                      | [mp]Stivali Pesanti                   | 헤비 부츠        | [nl]Ciężkie Buty               | [fp]Botas pesadas                     | ヘビーブーツ         | [fp]Botas Pesadas                   | [pl]тяжелые сапоги                | 重靴        |\n| 341 | mbt  | Chain Boots                      | 鎖鍊靴       | [pl]Kettenstiefel                  | [fp]Botas de malla                   | [fp]Bottes en anneaux                   | [mp]Stivali di Maglia                 | 체인 부츠        | [nl]Kolcze Buty                | [fp]Botas de malla                    | チェイン・ブーツ       | [fp]Botas Encadeadas                | [pl]кольчужные сапоги             | 锁链靴       |\n| 342 | tbt  | Light Plated Boots               | 輕鎧靴       | [pl]leichte Plattenstiefel         | [fp]Botas de placas ligeras          | [fp]Bottes en plaques légères           | [mp]Stivali di Piastre                | 라이트 플레이트 부츠  | [nl]Lekkie Płytowe Buty        | [fp]Botas laminadas ligeras           | ライトプレート・ブーツ    | [fp]Botas de Placas Leves           | [pl]легкие латные сапоги          | 轻板甲靴      |\n| 343 | hbt  | Greaves                          | 護脛        | [pl]Beinschienen                   | [fp]Grebas                           | [fp]Grèves                              | [mp]Schinieri                         | 그리브          | [nl]Nagolenice                 | [fp]Grebas                            | グリーヴ           | [fp]Grevas                          | [pl]наголенники                   | 护胫靴       |\n| 344 | lbl  | Sash                             | 束帶        | [fs]Schärpe                        | [ms]Fajín                            | [ms]Ceinturon                           | [fs]Fascia                            | 새시           | [fs]Szarfa                     | [ms]Cincho                            | サッシュ           | [fs]Faixa                           | [ms]кушак                         | 腰带        |\n| 345 | vbl  | Light Belt                       | 輕腰帶       | [ms]leichter Gürtel                | [ms]Cinturón ligero                  | [fs]Fine ceinture                       | [fs]Cintura Leggera                   | 라이트 벨트       | [ms]Lekki Pas                  | [ms]Cinturón ligero                   | ライト・ベルト        | [ms]Cinto Leve                      | [ms]легкий пояс                   | 轻腰带       |\n| 346 | mbl  | Belt                             | 腰帶        | [ms]Gürtel                         | [ms]Cinturón                         | [fs]Ceinture                            | [fs]Cintura                           | 벨트           | [ms]Pas                        | [ms]Cinturón                          | ベルト            | [ms]Cinto                           | [ms]пояс                          | 腰带        |\n| 347 | tbl  | Heavy Belt                       | 厚腰帶       | [ms]schwerer Gürtel                | [ms]Cinturón pesado                  | [fs]Ceinture lourde                     | [fs]Cintura Pesante                   | 헤비 벨트        | [ms]Ciężki Pas                 | [ms]Cinturón pesado                   | ヘビーベルト         | [ms]Cinto Pesado                    | [ms]тяжелый пояс                  | 重腰带       |\n| 348 | hbl  | Plated Belt                      | 鎧甲腰帶      | [ms]Plattengürtel                  | [ms]Cinturón de placas               | [fs]Ceinture en plaques                 | [fs]Cintura di Piastre                | 플레이트 벨트      | [ms]Płytowy Pas                | [ms]Cinturón laminado                 | プレート・ベルト       | [ms]Cinto de Placas                 | [ms]латный пояс                   | 板甲腰带      |\n| 349 | bhm  | Bone Helm                        | 骸骨頭盔      | [ms]Knochenhelm                    | [ms]Yelmo de hueso                   | [ms]Heaume en os                        | [ms]Elmo d'Ossa                       | 본 헬름         | [ms]Kościany Hełm              | [ms]Yelmo óseo                        | ボーン・ヘルム        | [ms]Elmo Ósseo                      | [ms]костяной шлем                 | 骨盔        |\n| 350 | bsh  | Bone Shield                      | 骨盾        | [ms]Knochenschild                  | [ms]Escudo de hueso                  | [ms]Bouclier en os                      | [ms]Scudo d'Ossa                      | 본 쉴드         | [fs]Kościana Tarcza            | [ms]Escudo óseo                       | ボーン・シールド       | [ms]Escudo Ósseo                    | [ms]костяной щит                  | 骨盾        |\n| 351 | spk  | Spiked Shield                    | 尖刺盾       | [ms]Dornenschild                   | [ms]Escudo con pinchos               | [ms]Bouclier à pointes                  | [ms]Scudo Puntuto                     | 스파이크 쉴드      | [fs]Kolczasta Tarcza           | [ms]Escudo de púas                    | スパイク・シールド      | [ms]Escudo com Espetos              | [ms]шипастый щит                  | 尖刺盾       |\n| 352 | xap  | War Hat                          | 戰帽        | [ms]Kriegshut                      | [fs]Cofia de guerra                  | [ms]Chapeau de guerre                   | [ms]Cappuccio da Guerra               | 워 햇          | [ms]Bojowy Kaptur              | [ms]Gorro de guerra                   | ウォーハット         | [ms]Chapéu Bélico                   | [ms]воинский наголовник           | 战争帽       |\n| 353 | xkp  | Sallet                           | 便盔        | [ms]Schaller                       | [fs]Celada                           | [fs]Salade                              | [fs]Celata                            | 샐릿           | [fs]Salada                     | [fs]Celada                            | サレット           | [fs]Celada                          | [ms]кабассет                      | 轻盔        |\n| 354 | xlm  | Casque                           | 兜盔        | [ms]Spitzhelm                      | [ms]Morrión                          | [ms]Casque                              | [ms]Casco                             | 캐스크          | [ms]Kask                       | [fs]Barbuta                           | カスク            | [ms]Casquete                        | [fs]каска                         | 护鼻盔       |\n| 355 | xhl  | Basinet                          | 輕盔        | [ms]Kesselhelm                     | [ms]Bacinete                         | [ms]Bassinet                            | [ms]Bacinetto                         | 배서넷          | [ms]Basinet                    | [ms]Bacinete                          | バシネット          | [ms]Bacinete                        | [ms]стальной шлем                 | 喙面盔       |\n| 356 | xhm  | Winged Helm                      | 翼盔        | Flügelhelm                         | [ms]Yelmo alado                      | [ms]Heaume ailé                         | [ms]Elmo Alato                        | 윙드 헬름        | [ms]Uskrzydlony Hełm           | [ms]Yelmo alado                       | ウィングド・ヘルム      | [ms]Elmo Alado                      | [ms]крылатый шлем                 | 翼盔        |\n| 357 | xrn  | Grand Crown                      | 莊嚴王冠      | [fs]große Krone                    | [fs]Gran corona                      | [fs]Couronne d’apparat                  | [fs]Grande Corona                     | 그랜드 크라운      | [fs]Wielka Korona              | [fs]Corona grandiosa                  | グランド・クラウン      | [fs]Grande Coroa                    | [fs]большая корона                | 宝冠盔       |\n| 358 | xsk  | Death Mask                       | 死亡面具      | [fs]Totenmaske                     | [fs]Máscara de la muerte             | [ms]Masque funéraire                    | [fs]Maschera della Morte              | 데스 마스크       | [fs]Pośmiertna Maska           | [fs]Máscara de la muerte              | デスマスク          | [fs]Máscara Mortuária               | [fs]посмертная маска              | 死者面甲      |\n| 359 | xui  | Ghost Armor                      | 鬼魂戰衣      | [fs]Geisterrüstung                 | [fs]Armadura fantasmal               | [fs]Armure fantôme                      | [fs]Corazza Fantasma                  | 고스트 아머       | [fs]Upiorna Zbroja             | [fs]Armadura fantasmal                | ゴースト・アーマー      | [fs]Armadura Fantasma               | [ms]призрачный доспех             | 幽灵甲       |\n| 360 | xea  | Serpentskin Armor                | 海蛇皮甲      | [fs]Schlangenlederrüstung          | [fs]Armadura de piel de serpiente    | [fs]Armure en peau de serpent           | [fs]Corazza di Pelle di Serpente      | 서펀트스킨 아머     | [fs]Wężowa Zbroja              | [fs]Armadura de piel de serpiente     | 蛇革アーマー         | [fs]Armadura de Couro de Serpente   | [ms]змеиный доспех                | 蛇皮甲       |\n| 361 | xla  | Demonhide Armor                  | 魔皮護甲      | [fs]Dämonenlederrüstung            | [fs]Armadura de cuero de demonio     | [fs]Armure en cuir de démon             | [fs]Corazza di Pelle Demoniaca        | 데몬하이드 아머     | [fs]Demoniczna Zbroja          | [fs]Armadura de cuero de demonio      | 魔獣革アーマー        | [fs]Armadura de Couro de Demônio    | [ms]демонический кожаный доспех   | 恶魔皮甲      |\n| 362 | xtu  | Trellised Armor                  | 格網護甲      | [fs]Bänderrüstung                  | [fs]Armadura enrejada                | [fs]Armure treillissée                  | [fs]Corazza Intrecciata               | 트렐리스드 아머     | [fs]Zbroja Pojedynkowa         | [fs]Armadura remachada                | トレリスド・アーマー     | [fs]Armadura Trançada               | [ms]сетчатый доспех               | 镶片铠甲      |\n| 363 | xng  | Linked Mail                      | 鍊扣戰甲      | [ns]Verbundkettenhemd              | [fs]Cota eslabonada                  | [fs]Cotte de mailles liée               | [fs]Maglia ad Anelli                  | 링크드 메일       | [fs]Koszulka Kolcza            | [fs]Cota anillada                     | リンクド・メイル       | [fs]Malha Articulada                | [fs]клепаная кольчуга             | 锁环甲       |\n| 364 | xcl  | Tigulated Mail                   | 鎖鱗戰甲      | [ns]Komplettpanzerhemd             | [fs]Cota articulada                  | [fs]Cotte de mailles tigulée            | [fp]Scaglie Rinforzate                | 티귤레이티드 메일    | [fs]Wzmocniona Kolczuga        | [fs]Cota de láminas                   | ティギュレイテッド・メイル  | [fs]Malha Grumosa                   | [ms]черепичный доспех             | 固片锁甲      |\n| 365 | xhn  | Mesh Armor                       | 鐵網戰甲      | [fs]Kettenrüstung                  | [fs]Armadura mallada                 | [fs]Armure maillée                      | [fs]Corazza di Maglia                 | 메쉬 아머        | [fs]Kolcza Zbroja              | [fs]Armadura mallada                  | メッシュ・アーマー      | [fs]Armadura de Malha               | [ms]сетчатый доспех               | 札甲        |\n| 366 | xrs  | Cuirass                          | 護胸甲       | [ms]Harnisch                       | [ms]Peto                             | [fs]Cuirasse                            | [fs]Corazza Rinforzata                | 퀴래스          | [ms]Kirys                      | [fs]Coraza                            | キュイラス          | [fs]Couraça                         | [fs]кираса                        | 重装胸甲      |\n| 367 | xpl  | Russet Armor                     | 赤褐戰甲      | [fs]Eisenrüstung                   | [fs]Armadura rojiza                  | [fs]Armure rousse                       | [fs]Corazza Lamellare                 | 러셋 아머        | [fs]Brunatna Zbroja            | [fs]Armadura cobriza                  | ラセット・アーマー      | [fs]Armadura Avermelhada            | [ms]терракотовый доспех           | 褐锈甲       |\n| 368 | xlt  | Templar Coat                     | 聖堂騎士戰甲    | [ms]Templermantel                  | [fs]Cota templaria                   | [fs]Cotte de templier                   | [fs]Veste dei Templari                | 템플러 코트       | [fs]Templariańska Zbroja       | [fs]Cota templaria                    | テンペラー・コート      | [fs]Cota Templária                  | [ms]тамплиерский мундир           | 圣殿骑士铠     |\n| 369 | xld  | Sharktooth Armor                 | 鯊齒戰甲      | [fs]Haizahnrüstung                 | [fs]Armadura de dientes de tiburón   | [fs]Armure en dents de requin           | [fs]Corazza di Denti di Squalo        | 샤크투스 아머      | [fs]Rekinia Zbroja             | [fs]Armadura de diente de tiburón     | シャークトゥース・アーマー  | [fs]Armadura de Dente de Tubarão    | [ms]акулий доспех                 | 鲨齿战甲      |\n| 370 | xth  | Embossed Plate                   | 雕紋戰甲      | [fs]gravierte Plattenrüstung       | [fs]Coraza repujada                  | [ms]Harnois estampé                     | [fp]Piastre Goffrate                  | 임바스트 플레이트    | [fs]Tłoczona Zbroja Płytowa    | [fs]Coraza repujada                   | エンボス・プレート      | [fs]Armadura em Relevo              | [ms]гравированный доспех          | 浮雕纹甲      |\n| 371 | xul  | Chaos Armor                      | 混沌戰甲      | [fs]Chaosrüstung                   | [fs]Armadura del caos                | [fs]Armure de chaos                     | [fs]Corazza del Caos                  | 카오스 아머       | [fs]Chaotyczna Zbroja          | [fs]Armadura del caos                 | カオス・アーマー       | [fs]Armadura do Caos                | [ms]хаотический доспех            | 混沌护甲      |\n| 372 | xar  | Ornate Plate                     | 華麗戰甲      | [fs]verzierte Plattenrüstung       | [fs]Coraza ornada                    | [ms]Harnois orné                        | [fp]Piastre Ornate                    | 오네이트 플레이트    | [fs]Zdobiona Zbroja Płytowa    | [fs]Coraza ornamentada                | オーネイト・プレート     | [fs]Armadura Ornamentada            | [ms]изукрашенный доспех           | 花纹战甲      |\n| 373 | xtp  | Mage Plate                       | 法師鎧甲      | [fs]Magierplattenrüstung           | [fs]Coraza de mago                   | [fs]Harnois de mage                     | [fp]Piastre del Mago                  | 메이지 플레이트     | [fs]Zbroja Maga                | [fs]Coraza de mago                    | メイジ・プレート       | [fs]Armadura de Mago                | [ms]магический доспех             | 法师铠       |\n| 374 | xuc  | Defender                         | 防禦盾       | [ms]Verteidiger                    | [ms]Defensor                         | [ms]Défenseur                           | [ms]Difensore                         | 디펜더          | [ms]Obrońca                    | [ms]Defensor                          | ディフェンダー        | [ms]Defensor                        | [ms]защитник                      | 防卫盾       |\n| 375 | xml  | Round Shield                     | 圓型盾       | [ms]Rundschild                     | [ms]Escudo redondo                   | [ms]Bouclier rond                       | [ms]Scudo Rotondo                     | 라운드 쉴드       | [fs]Okrągła Tarcza             | [ms]Escudo redondo                    | ラウンド・シールド      | [ms]Escudo Redondo                  | [ms]круглый щит                   | 圆盾        |\n| 376 | xrg  | Scutum                           | 大圓盾       | [ms]Scutum                         | [ms]Scutum                           | [ms]Scutum                              | [ms]Scutum                            | 스큐텀          | [nl]Scutum                     | [ms]Scutum                            | スクトゥム          | [ms]Scutum                          | [ms]скутум                        | 椭圆盾       |\n| 377 | xit  | Dragon Shield                    | 龍盾        | [ms]Drachenschild                  | [ms]Escudo de dragón                 | [ms]Bouclier de dragon                  | [ms]Scudo del Drago                   | 드래곤 쉴드       | [fs]Smocza Tarcza              | [ms]Escudo de dragón                  | ドラゴン・シールド      | [ms]Escudo Dracônico                | [ms]драконий щит                  | 龙盾        |\n| 378 | xow  | Pavise                           | 大盾        | [ms]Pavese                         | [ms]Pavés                            | [ms]Pavois                              | [ms]Pavese                            | 파비스          | [ms]Pawęż                      | [ms]Pavés                             | パヴィース          | [ms]Pavis                           | [fs]павеза                        | 巨盾        |\n| 379 | xts  | Ancient Shield                   | 上古盾       | [ms]alter Schild                   | [ms]Escudo antiguo                   | [ms]Bouclier ancien                     | [ms]Scudo Antico                      | 에인션트 쉴드      | [fs]Prastara Tarcza            | [ms]Escudo antiguo                    | エンシェント・シールド    | [ms]Escudo Ancestral                | [ms]древний щит                   | 古代盾       |\n| 380 | xlg  | Demonhide Gloves                 | 魔皮手套      | [pl]Dämonenlederhandschuhe         | [mp]Guantes de cuero de demonio      | [mp]Gants en cuir de démon              | [mp]Guanti di Pelle Demoniaca         | 데몬하이드 글러브    | [nl]Demoniczne Rękawice        | [mp]Guantes de cuero de demonio       | 魔獣革グローブ        | [fp]Luvas de Couro de Demônio       | [pl]демонические кожаные перчатки | 恶魔皮手套     |\n| 381 | xvg  | Sharkskin Gloves                 | 鯊皮手套      | [pl]Hailederhandschuhe             | [mp]Guantes de piel de tiburón       | [mp]Gants en peau de requin             | [mp]Guanti di Pelle di Squalo         | 샤크스킨 글러브     | [nl]Rekinie Rękawice           | [mp]Guantes de piel de tiburón        | 鮫革グローブ         | [fp]Luvas de Couro de Tubarão       | [pl]акульи перчатки               | 鲨鱼皮手套     |\n| 382 | xmg  | Heavy Bracers                    | 重型護腕      | [pl]schwere Armschienen            | [mp]Brazales pesados                 | [mp]Manchons lourds                     | [mp]Bracciali Pesanti                 | 헤비 브레이서      | [nl]Ciężkie Karwasze           | [mp]Brazales pesados                  | ヘビーブレイサー       | [fp]Braçadeiras Pesadas             | [pl]тяжелые наручи                | 铁皮手套      |\n| 383 | xtg  | Battle Gauntlets                 | 戰鬥護手      | [pl]Kampfpanzerhandschuhe          | [mp]Guanteletes de batalla           | [mp]Gantelets de bataille               | [mp]Guanti d'Arme da Battaglia        | 배틀 건틀릿       | [nl]Bitewne Rękawice           | [mp]Guanteletes de batalla            | バトル・ガントレット     | [fp]Manoplas de Batalha             | [pl]боевые рукавицы               | 战斗护手      |\n| 384 | xhg  | War Gauntlets                    | 征戰護手      | Kriegspanzerhandschuhe             | [mp]Guanteletes de guerra            | [mp]Gantelets de guerre                 | [mp]Guanti d'Arme da Guerra           | 워 건틀릿        | [nl]Bojowe Rękawice            | [mp]Guanteletes de guerra             | ウォー・ガントレット     | [fp]Manoplas Bélicas                | [pl]воинские рукавицы             | 战争护手      |\n| 385 | xlb  | Demonhide Boots                  | 魔皮長靴      | [pl]Dämonenlederstiefel            | [fp]Botas de cuero de demonio        | [fp]Bottes en cuir de démon             | [mp]Stivali di Pelle Demoniaca        | 데몬하이드 부츠     | [nl]Demoniczne Buty            | [fp]Botas de cuero de demonio         | 魔獣革ブーツ         | [fp]Botas de Couro de Demônio       | [pl]демонические кожаные сапоги   | 恶魔皮靴      |\n| 386 | xvb  | Sharkskin Boots                  | 鯊皮靴       | [pl]Hailederstiefel                | [fp]Botas de piel de tiburón         | [fp]Bottes en peau de requin            | [mp]Stivali di Pelle di Squalo        | 샤크스킨 부츠      | [nl]Rekinie Buty               | [fp]Botas de piel de tiburón          | 鮫革ブーツ          | [fp]Botas de Couro de Tubarão       | [pl]акульи сапоги                 | 鲨鱼皮靴      |\n| 387 | xmb  | Mesh Boots                       | 鐵網靴       | [pl]Ringstiefel                    | [fp]Botas malladas                   | [fp]Bottes maillées                     | [mp]Stivali di Maglia                 | 메쉬 부츠        | [nl]Kolcze Buty                | [fp]Botas malladas                    | メッシュ・ブーツ       | [fp]Botas de Malha                  | [pl]сетчатые сапоги               | 网纹靴       |\n| 388 | xtb  | Battle Boots                     | 戰鬥靴       | [pl]Kampfstiefel                   | [fp]Botas de batalla                 | [fp]Bottes de bataille                  | [mp]Stivali da Battaglia              | 배틀 부츠        | [nl]Bitewne Buty               | [fp]Botas de batalla                  | バトル・ブーツ        | [fp]Botas de Batalha                | [pl]боевые сапоги                 | 战靴        |\n| 389 | xhb  | War Boots                        | 征戰靴       | [pl]Kriegsstiefel                  | [fp]Botas de guerra                  | [fp]Bottes de guerre                    | [mp]Stivali da Guerra                 | 워 부츠         | [nl]Bojowe Buty                | [fp]Botas de guerra                   | ウォーブーツ         | [fp]Botas Bélicas                   | [pl]воинские сапоги               | 战争靴       |\n| 390 | zlb  | Demonhide Sash                   | 魔皮束帶      | [fs]Dämonenlederschärpe            | [ms]Fajín de cuero de demonio        | [fs]Écharpe en cuir de démon            | [fs]Fascia di Pelle Demoniaca         | 데몬하이드 새시     | [ms]Demoniczny Pas             | [ms]Cincho de cuero de demonio        | 魔獣革サッシュ        | [fs]Faixa de Couro de Demônio       | [ms]демонический кожаный кушак    | 恶魔皮带      |\n| 391 | zvb  | Sharkskin Belt                   | 鯊皮腰帶      | [ms]Hailedergürtel                 | [ms]Cinturón de piel de tiburón      | [fs]Ceinture en peau de requin          | [fs]Cintura di Pelle di Squalo        | 샤크스킨 벨트      | [ms]Rekini Pas                 | [ms]Cinturón de piel de tiburón       | 鮫革ベルト          | [ms]Cinto de Couro de Tubarão       | [ms]акулий пояс                   | 鲨鱼皮带      |\n| 392 | zmb  | Mesh Belt                        | 鐵網腰帶      | [ms]Kettengürtel                   | [ms]Cinturón mallado                 | [fs]Ceinture maillée                    | [fs]Cintura di Maglia                 | 메쉬 벨트        | [ms]Kolczy Pas                 | [ms]Cinturón mallado                  | メッシュ・ベルト       | [ms]Cinto de Malha                  | [ms]сетчатый пояс                 | 网纹腰带      |\n| 393 | ztb  | Battle Belt                      | 戰鬥腰帶      | [ms]Kampfgürtel                    | [ms]Cinturón de batalla              | [fs]Ceinture de bataille                | [fs]Cintura da Battaglia              | 배틀 벨트        | [ms]Bitewny Pas                | [ms]Cinturón de batalla               | バトル・ベルト        | [ms]Cinto de Batalha                | [ms]боевой пояс                   | 战斗腰带      |\n| 394 | zhb  | War Belt                         | 征戰腰帶      | [ms]Kriegsgürtel                   | [ms]Cinturón de guerra               | [fs]Ceinture de guerre                  | [fs]Cintura da Guerra                 | 워 벨트         | [ms]Bojowy Pas                 | [ms]Cinturón de guerra                | ウォーベルト         | [ms]Cinto Bélico                    | [ms]воинский пояс                 | 战争腰带      |\n| 395 | xh9  | Grim Helm                        | 陰森頭盔      | [ms]Kampfhelm                      | [ms]Yelmo lúgubre                    | [ms]Heaume macabre                      | [ms]Elmo dell'Orrore                  | 그림 헬름        | [ms]Złowrogi Hełm              | [ms]Yelmo lúgubre                     | グリム・ヘルム        | [ms]Elmo Sinistro                   | [ms]жуткий шлем                   | 恐怖头盔      |\n| 396 | xsh  | Grim Shield                      | 陰森盾牌      | [ms]Kampfschild                    | [ms]Escudo lúgubre                   | [ms]Bouclier macabre                    | [ms]Scudo dell'Orrore                 | 그림 쉴드        | [fs]Złowroga Tarcza            | [ms]Escudo lúgubre                    | グリム・シールド       | [ms]Escudo Sinistro                 | [ms]жуткий щит                    | 恐怖大盾      |\n| 397 | xpk  | Barbed Shield                    | 倒刺盾       | [ms]Stachelschild                  | [ms]Escudo con púas                  | [ms]Bouclier barbelé                    | [ms]Scudo Dentato                     | 바브드 쉴드       | [fs]Ciernista Tarcza           | [ms]Escudo con púas                   | バーブド・シールド      | [ms]Escudo Farpado                  | [ms]колючий щит                   | 尖刃盾       |\n| 398 | dr1  | Wolf Head                        | 狼頭獸帽      | [ms]Wolfskopf                      | [fs]Cabeza de lobo                   | [fs]Tête de loup                        | [fs]Testa di Lupo                     | 울프 헤드        | [fs]Wilcza Głowa               | [fs]Cabeza de lobo                    | ウルフ・ヘッド        | [fs]Cabeça de Lobo                  | [fs]волчья голова                 | 狼头        |\n| 399 | dr2  | Hawk Helm                        | 飛鷹頭盔      | [ms]Falkenhelm                     | [ms]Yelmo del gerifalte              | [ms]Casque de faucon                    | [ms]Elmo del Falco                    | 호크 헬름        | [ms]Jastrzębi Hełm             | [ms]Yelmo de halcón                   | ホーク・ヘルム        | [ms]Elmo Falcônico                  | [ms]ястребиный шлем               | 鹰盔        |\n| 400 | dr3  | Antlers                          | 巨角獸帽      | [ns]Geweih                         | [fs]Cornamenta                       | [mp]Andouillers                         | [fp]Corna                             | 앤틀러스         | [nl]Poroże                     | [fs]Cornamenta                        | アントラー          | [fs]Galhada                         | [pl]бараньи рога                  | 鹿角盔       |\n| 401 | dr4  | Falcon Mask                      | 獵鷹面具      | [fs]Falkenmaske                    | [fs]Máscara del halcón               | [ms]Masque de faucon                    | [fs]Maschera del Falcone              | 팔콘 마스크       | [fs]Sokola Maska               | [fs]Máscara de halcón                 | ファルコン・マスク      | [fs]Máscara Falcônica               | [fs]соколиная маска               | 鹰隼面甲      |\n| 402 | dr5  | Spirit Mask                      | 靈狼面具      | [fs]Geistermaske                   | [fs]Máscara espiritual               | [ms]Masque d’esprit                     | [fs]Maschera dello Spirito            | 스피리트 마스크     | [fs]Duchowa Maska              | [fs]Máscara espiritual                | スピリット・マスク      | [fs]Máscara Espiritual              | [fs]духовная маска                | 狼灵面具      |\n| 403 | ba1  | Jawbone Cap                      | 顎骨帽       | [ms]Kieferknochenhut               | [ms]Casco de mandíbula               | [ms]Casque macabre                      | [ms]Copricapo d'Ossa                  | 조우본 캡        | [ms]Szczękowy Kaptur           | [ms]Capacete con mandíbula            | ジョーボーン・キャップ    | [ms]Barrete Mandibular              | [ms]наголовник с челюстью         | 颚骨帽       |\n| 404 | ba2  | Fanged Helm                      | 尖牙頭盔      | [ms]Stoßzahnhelm                   | [ms]Yelmo canino                     | [ms]Casque ailé                         | [ms]Elmo Zannuto                      | 팽드 헬름        | [ms]Zębaty Hełm                | [ms]Yelmo dentado                     | ファングド・ヘルム      | [ms]Elmo Dentado                    | [ms]клыкастый шлем                | 牙骨盔       |\n| 405 | ba3  | Horned Helm                      | 尖角頭盔      | [ms]Gehörnter Helm                 | [ms]Yelmo enastado                   | [ms]Casque à cornes                     | [ms]Elmo Cornuto                      | 혼드 헬름        | [ms]Rogaty Hełm                | [ms]Yelmo astado                      | ホーンド・ヘルム       | [ms]Elmo Galhado                    | [ms]рогатый шлем                  | 长角盔       |\n| 406 | ba4  | Assault Helmet                   | 突擊頭盔      | [ms]Angriffshelm                   | [ms]Casco de asalto                  | [ms]Casque de combat                    | [ms]Elmetto d'Assalto                 | 어썰트 헬멧       | [ms]Szturmowy Hełm             | [ms]Casco de asalto                   | アサルト・ヘルメット     | [ms]Capacete de Assalto             | [ms]штурмовой шлем                | 强攻盔       |\n| 407 | ba5  | Avenger Guard                    | 復仇者護盔     | [ms]Rächender Wächter              | [fs]Protección vengadora             | [ms]Casque vengeur                      | [fs]Guardia Vendicatrice              | 어벤저 가드       | [fs]Mścicielska Garda          | [fs]Guardia del vengador              | アベンジャー・ガード     | [fs]Proteção Vingadora              | [ms]героический шлем              | 复仇者头盔     |\n| 408 | pa1  | Targe                            | 小盾        | [fs]Targe                          | [fs]Adarga                           | [fs]Targe                               | [fs]Targa                             | 타아지          | [fs]Tarża                      | [fs]Adarga                            | タージ            | [fs]Targa                           | [ms]тарджет                       | 臂盾        |\n| 409 | pa2  | Rondache                         | 輕圓盾       | [fs]Rondache                       | [fs]Rodela                           | [fs]Rondache                            | [fs]Rondaccia                         | 론다쉬          | [fs]Rodela                     | [fs]Rodela                            | ロンダッシュ         | [ms]Rondache                        | [ms]рондаш                        | 轻圆盾       |\n| 410 | pa3  | Heraldic Shield                  | 紋章盾       | [ms]Wappenschild                   | [ms]Escudo heráldico                 | [ms]Bouclier héraldique                 | [ms]Scudo Araldico                    | 헤럴딕 쉴드       | [fs]Heraldyczna Tarcza         | [ms]Escudo heráldico                  | ヘラルディック・シールド   | [ms]Escudo Heráldico                | [ms]геральдический щит            | 纹章盾       |\n| 411 | pa4  | Aerin Shield                     | 艾文之盾      | [ms]Aerins Schild                  | [ms]Escudo aerin                     | [ms]Bouclier d’Aerin                    | [ms]Scudo di Aerin                    | 에어린 쉴드       | [fs]Aerinowa Tarcza            | [ms]Escudo de Aerin                   | エアリン・シールド      | [ms]Escudo Aerin                    | [ms]Эринов щит                    | 艾琳盾       |\n| 412 | pa5  | Crown Shield                     | 冠冕之盾      | [ms]Kronenschild                   | [ms]Escudo de la corona              | [ms]Bouclier de la couronne             | [ms]Scudo Coronato                    | 크라운 쉴드       | [fs]Koronowa Tarcza            | [ms]Escudo coronado                   | クラウン・シールド      | [ms]Escudo da Coroa                 | [ms]королевский щит               | 王冠盾       |\n| 413 | ne1  | Preserved Head                   | 防腐頭顱      | [ms]Konservierter Kopf             | [fs]Cabeza preservada                | [fs]Tête préservée                      | [fs]Testa Mummificata                 | 프리저브드 헤드     | [fs]Spreparowana Głowa         | [fs]Cabeza preservada                 | プリザーブド・ヘッド     | [fs]Cabeça Preservada               | [fs]забальзамированная голова     | 保存完好的头骨   |\n| 414 | ne2  | Zombie Head                      | 殭屍頭顱      | [ms]Zombiekopf                     | [fs]Cabeza de zombi                  | [fs]Tête de zombie                      | [fs]Testa di Zombi                    | 좀비 헤드        | [fs]Trupia Głowa               | [fs]Cabeza de zombi                   | ゾンビ・ヘッド        | [fs]Cabeça Zumbi                    | [fs]зомбякова голова              | 僵尸头骨      |\n| 415 | ne3  | Unraveller Head                  | 解繃者頭顱     | [ms]Zersetzerkopf                  | [fs]Cabeza de desenredador           | [fs]Tête décomposée                     | [fs]Testa di Celato                   | 언레이블러 헤드     | [fs]Szkieletowa Głowa          | [fs]Cabeza de desenredador            | アンラヴェラー・ヘッド    | [fs]Cabeça de Desfiador             | [fs]разматывателева голова        | 剖尸者头骨     |\n| 416 | ne4  | Gargoyle Head                    | 石像鬼頭顱     | [ms]Gargoylekopf                   | [fs]Cabeza de gárgola                | [fs]Tête de gargouille                  | [fs]Testa di Gargoyle                 | 가고일 헤드       | [fs]Gargulcowa Głowa           | [fs]Cabeza de gárgola                 | ガーゴイル・ヘッド      | [fs]Cabeça de Gárgula               | [fs]горгулья голова               | 石像鬼头骨     |\n| 417 | ne5  | Demon Head                       | 惡魔頭顱      | [ms]Dämonenkopf                    | [fs]Cabeza de demonio                | [fs]Tête de démon                       | [fs]Testa di Demone                   | 데몬 헤드        | [fs]Demoniczna Głowa           | [fs]Cabeza de demonio                 | デーモン・ヘッド       | [fs]Cabeça de Demônio               | [fs]демонская голова              | 恶魔头骨      |\n| 418 | ci0  | Circlet                          | 頭環        | [ms]Reif                           | [fs]Aureola                          | [ms]Bandeau                             | [ms]Cerchietto                        | 써클릿          | [fs]Obręcz                     | [fs]Diadema                           | サークレット         | [ms]Diadema                         | [ms]венец                         | 头环        |\n| 419 | ci1  | Coronet                          | 寶冠        | [ns]Krönchen                       | [fs]Coronilla                        | [ms]Tortil                              | [fs]Corona Ferrata                    | 코로니트         | [fs]Koronetka                  | [fs]Coronilla                         | コロネット          | [fs]Coronilha                       | [ms]головной обруч                | 头冠        |\n| 420 | ci2  | Tiara                            | 頭冠        | [fs]Tiara                          | [fs]Tiara                            | [fs]Tiare                               | [fs]Tiara                             | 티아라          | [fs]Tiara                      | [fs]Tiara                             | ティアラ           | [fs]Tiara                           | [fs]тиара                         | 冠冕        |\n| 421 | ci3  | Diadem                           | 權冠        | [ns]Diadem                         | [fs]Diadema                          | [ms]Diadème                             | [ms]Diadema                           | 다이어뎀         | [ms]Diadem                     | [ms]Cintillo                          | ダイアデム          | [fs]Argola                          | [fs]диадема                       | 权冠        |\n| 422 | uap  | Shako                            | 軍帽        | [ms]Tschako                        | [ms]Chacó                            | [ms]Shako                               | [ms]Sciaccò                           | 샤코           | [nl]Czako                      | [ms]Chacó                             | シャコー           | [ms]Shako                           | [ns]шако                          | 军帽        |\n| 423 | ukp  | Hydraskull                       | 多頭蛇顱盔     | [ms]Hydraschädel                   | [ms]Cráneo de hidra                  | [ms]Crâne d’hydre                       | [ms]Teschio d'Idra                    | 히드라스컬        | [fs]Hydrza Czaszka             | [ms]Cráneo de hidra                   | ヒュドラスカル        | [ms]Crânio de Hidra                 | [ms]гидровый череп                | 多头蛇颅      |\n| 424 | ulm  | Armet                            | 覆頰盔       | [ns]Armet                          | [ms]Almete                           | [ms]Armet                               | [ms]Elmo Rinforzato                   | 아메트          | [ms]Armet                      | [ms]Almete                            | アーメット          | [ms]Armet                           | [ms]армет                         | 武装盔       |\n| 425 | uhl  | Giant Conch                      | 巨螺盔       | [fs]Riesenmuschel                  | [fs]Valva gigante                    | [fs]Conque géante                       | [fs]Conchiglia Gigante                | 자이언트 칸크      | [fs]Barbuta                    | [fs]Caracola gigante                  | ジャイアント・コンク     | [fs]Concha Gigante                  | [ms]большой полукруглый шлем      | 巨贝盔       |\n| 426 | uhm  | Spired Helm                      | 巨角頭盔      | [ms]Spitzhelm                      | [ms]Yelmo de agujas                  | [ms]Morion                              | [ms]Elmo Cuspidale                    | 스파이어드 헬름     | [ms]Iglicowy Hełm              | [ms]Yelmo encumbrado                  | スパード・ヘルム       | [ms]Elmo com Chifres                | [ms]гнуторогий шлем               | 塔盔        |\n| 427 | urn  | Corona                           | 日冕之冠      | [fs]Korona                         | [fs]Corona                           | [ms]Fronteau                            | [fs]Corona d'Arme                     | 코로나          | [fs]Zdobiona Korona            | [fs]Gran corona                       | 輪冠             | [fs]Corona                          | [fs]богатая корона                | 宝冠        |\n| 428 | usk  | Demonhead                        | 惡魔頭骨      | [ms]Dämonenschädel                 | [fs]Faz del demonio                  | [fs]Tête de démon                       | [fs]Testa Demoniaca                   | 데몬헤드         | [fs]Demoniczna Maska           | [fs]Cabeza demoníaca                  | デーモンヘッド        | [fs]Cabeça Demoníaca                | [fs]демонская голова              | 恶魔面甲      |\n| 429 | uui  | Dusk Shroud                      | 灰暮罩衣      | [ms]Dämmerschleier                 | [fs]Mortaja del crepúsculo           | [ms]Linceul crépusculaire               | [ms]Sudario del Crepuscolo            | 더스크 슈라우드     | [ms]Wieczorny Całun            | [ms]Embozo crepuscular                | ダスク・シュラウド      | [fs]Mortalha Crepuscular            | [fs]сумеречная пелена             | 灰幕寿衣      |\n| 430 | uea  | Wyrmhide                         | 龍皮甲       | [ns]Wyrmleder                      | [ms]Cuero de vermis                  | [fs]Peau de wyrm                        | [ms]Cuoio di Dragone                  | 웜하이드         | [fs]Gadzia Skóra               | [ms]Pellejo de vermis                 | ウィルムハイド        | [ms]Couro de Serpe                  | [fs]змеиная кожа                  | 龙皮甲       |\n| 431 | ula  | Scarab Husk                      | 聖甲蟲殼皮甲    | [fs]Skarabäusschale                | [mp]Élitros de alfazaque             | [fs]Carapace de scarabée                | [ms]Guscio di Scarabeo                | 스캐럽 허스크      | [fs]Skarabeuszowa Łupina       | [fs]Cáscara de escarabajo             | スカラベ・ハスク       | [fs]Casca de Escaravelho            | [ms]панцирь скарабея              | 圣甲虫壳      |\n| 432 | utu  | Wire Fleece                      | 鋼線毛皮甲     | [ns]Drahtvlies                     | [fs]Lana de alambre                  | [fs]Toison métallique                   | [ms]Vello Metallico                   | 와이어 플리스      | [nl]Druciane Runo              | [ms]Vellón hilado                     | ワイヤー・フリース      | [fs]Trama Interligada               | [fs]плетеная безрукавка           | 羊绒皮甲      |\n| 433 | ung  | Diamond Mail                     | 鑽石鎖甲      | [ns]Diamantpanzerhemd              | [fs]Cota de diamante                 | [fs]Cotte de mailles diamantine         | [fs]Maglia di Diamante                | 다이아몬드 메일     | [fs]Diamentowa Kolczuga        | [fs]Cota diamantina                   | ダイヤモンド・メイル     | [fs]Malha Diamante                  | [fs]алмазная кольчуга             | 钻石甲       |\n| 434 | ucl  | Loricated Mail                   | 綴鱗戰甲      | [ns]Kürasspanzerhemd               | [fs]Cota lorigada                    | [fs]Lorica de mailles                   | [fs]Maglia di Loricato                | 로러케이티드 메일    | [fs]Pancerna Zbroja            | [fs]Cota de loriga                    | ロリケイテッド・メイル    | [fs]Malha Revestida                 | [ms]панцирный доспех              | 覆铁甲       |\n| 435 | uhn  | Boneweave                        | 骸骨網甲      | [ns]Knochengespinst                | [ms]Malla de hueso                   | [fs]Armure en plaques d’os              | [fs]Corazza di Fibra Ossea            | 본위브          | [ms]Kościak                    | [ms]Tramóseo                          | ボーンウィーブ        | [fs]Osteotrama                      | [fs]плетеная кость                | 骨织甲       |\n| 436 | urs  | Great Hauberk                    | 鱗鎧胸甲      | [fs]Große Halsberge                | [fs]Gran loriga                      | [ms]Grand haubert                       | [ms]Grande Usbergo                    | 그레이트 허버크     | [ms]Wielki Haubert             | [ms]Gran hauberto                     | グレート・ホーバーク     | [fs]Grande Cota de Malha            | [ms]тяжелый панцирь               | 大链甲衫      |\n| 437 | upl  | Balrog Skin                      | 炎魔皮板甲     | [ns]Balrogleder                    | [fs]Piel de Balrog                   | [fs]Peau de Balrog                      | [fs]Pelle di Balrog                   | 발록 스킨        | [fs]Balrogowa Skóra            | [fs]Piel de balrog                    | バルログ・スキン       | [fs]Pele de Balrog                  | [fs]Балрогова шкура               | 炎魔皮       |\n| 438 | ult  | Hellforge Plate                  | 地獄鍛甲      | [fs]Höllenschmiedenplattenrüstung  | [fs]Coraza de la Fragua del Infierno | [ms]Harnois des Enfers                  | [fs]Corazza Infernale                 | 헬포지 플레이트     | [fs]Piekielna Zbroja Płytowa   | [fs]Cota de la Forja Infernal         | ヘルフォージ・プレート    | [fs]Armadura da Forja Infernal      | [pl]латы из Адской кузни          | 地狱铸甲      |\n| 439 | uld  | Kraken Shell                     | 海怪之殼      | [fs]Krakenschale                   | [fs]Concha de kraken                 | [fs]Carapace de kraken                  | [ms]Guscio di Kraken                  | 크라켄 쉘        | [fs]Krakenia Skorupa           | [ms]Cascarón del kraken               | クラーケン・シェル      | [ms]Casco do Kraken                 | [fs]раковина кракена              | 深海巨妖之壳    |\n| 440 | uth  | Lacquered Plate                  | 漆護鎧甲      | [fs]Lackierte Plattenrüstung       | [fs]Coraza lacada                    | [ms]Harnois laqué                       | [fs]Corazza Laccata                   | 래커드 플레이트     | [fs]Pancerna Płytówka          | [fs]Cota laqueada                     | ラッカード・プレート     | [fs]Armadura Laqueada               | [ms]лакированный доспех           | 漆甲        |\n| 441 | uul  | Shadow Plate                     | 暗影鎧甲      | [fs]Schattenplattenrüstung         | [fs]Coraza sombría                   | [ms]Harnois d’ombre                     | [fs]Corazza d'Ombra                   | 쉐도우 플레이트     | [fs]Mroczna Zbroja Płytowa     | [fs]Cota de las sombras               | シャドウ・プレート      | [fs]Armadura Sombria                | [ms]сумрачный доспех              | 暗影板甲      |\n| 442 | uar  | Sacred Armor                     | 神聖戰甲      | [fs]Heilige Rüstung                | [fs]Armadura sacra                   | [fs]Armure sacrée                       | [fs]Corazza Sacra                     | 세이크리드 아머     | [ms]Święty Pancerz             | [fs]Armadura sagrada                  | セイクレッド・アーマー    | [fs]Armadura Sagrada                | [ms]священный доспех              | 神圣铠甲      |\n| 443 | utp  | Archon Plate                     | 統御者鎧甲     | [fs]Archonplattenrüstung           | [fs]Coraza de arconte                | [ms]Harnois d’Archonte                  | [fs]Corazza dell'Arconte              | 아콘 플레이트      | [fs]Archoncka Zbroja Płytowa   | [fs]Cota de Arconte                   | アルコン・プレート      | [fs]Armadura do Arconte             | [fs]архонтова броня               | 统治者板甲     |\n| 444 | uuc  | Heater                           | 斗盾        | [ms]Manesseschild                  | [ms]Calentador                       | [ms]Écu incandescent                    | [ms]Scudo Gobbo                       | 히터           | [ms]Kałkan                     | [ms]Brasero                           | ヒーター           | [ms]Aquecedor                       | [ms]клиновидный щит               | 斗盾        |\n| 445 | uml  | Luna                             | 圓月盾       | [fs]Luna                           | [fs]Luna                             | [fs]Lune                                | [fs]Luna                              | 루나           | [fs]Luna                       | [fs]Luna                              | ルナ             | [fs]Luna                            | [fs]луна                          | 月神盾       |\n| 446 | urg  | Hyperion                         | 亥伯龍盾      | [ms]Hyperion                       | [ms]Hiperión                         | [ms]Hypérion                            | [ms]Iperione                          | 하이페리온        | [ms]Hyperion                   | [ms]Hiperión                          | ハイペリオン         | [ms]Hipérion                        | [ms]гиперион                      | 亥伯龙盾      |\n| 447 | uit  | Monarch                          | 君主盾       | [ms]Monarch                        | [ms]Monarca                          | [ms]Bouclier de monarque                | [ms]Monarca                           | 모너크          | [ms]Monarcha                   | [ms]Monarca                           | モナーク           | [ms]Monarca                         | [ms]монарх                        | 统治者大盾     |\n| 448 | uow  | Aegis                            | 禦塔盾       | [fs]Ägis                           | [fs]Égida                            | [fs]Égide                               | [fs]Egida                             | 이지스          | [fs]Egida                      | [fs]Égida                             | アイギス           | [fs]Égide                           | [fs]эгида                         | 圣盾        |\n| 449 | uts  | Ward                             | 庇護盾       | [ms]Schutz                         | [fs]Custodia                         | [fs]Parade                              | [fs]Difesa                            | 워드           | [fs]Straż                      | [fs]Guarda                            | ウォード           | [fs]Proteção                        | [ms]охранитель                    | 守护之盾      |\n| 450 | ulg  | Bramble Mitts                    | 荊棘手套      | [pl]Dornenhandschuhe               | [mp]Mitones de zarza                 | [mp]Gants de ronce                      | [mp]Guanti di Rovo                    | 브램블 미트       | [nl]Kolczaste Rękawiczki       | [mp]Mitones punzantes                 | ブランブル・ミット      | [fp]Luvas Sarçosas                  | [pl]колючие рукавицы              | 防刺手套      |\n| 451 | uvg  | Vampirebone Gloves               | 吸血鬼骸骨手套   | [pl]Vampirknochenhandschuhe        | [mp]Guantes de hueso de vampiro      | [mp]Gants vampiriques                   | [mp]Guanti d'Ossa di Vampiro          | 뱀파이어본 글러브    | [nl]Wampirze Rękawice          | [mp]Guantes de hueso de vampiro       | ヴァンパイアボーン・グローブ | [fp]Luvas Vampíricas                | [pl]вампирьи перчатки             | 吸血鬼骨手套    |\n| 452 | umg  | Vambraces                        | 護臂        | [pl]Vampirschienen                 | [mp]Avambrazos                       | [mp]Protège-bras                        | [mp]Avambracci                        | 뱀브레이스        | [nl]Wampiręcze                 | [mp]Avambrazos                        | ヴァンブレイス        | [mp]Avambraços                      | [pl]латные щитки                  | 护臂手甲      |\n| 453 | utg  | Crusader Gauntlets               | 聖教軍護手     | [pl]Kreuzritterhandschuhe          | [mp]Guanteletes de cruzada           | [mp]Gantelets de croisé                 | [mp]Guanti d'Arme del Crociato        | 크루세이더 건틀릿    | [nl]Krzyżowe Rękawice          | [mp]Guanteletes de cruzado            | クルセイダー・ガントレット  | [fp]Manoplas do Cruzado             | [pl]рыцарские перчатки            | 圣教军护手     |\n| 454 | uhg  | Ogre Gauntlets                   | 巨魔護手      | [pl]Ogerhandschuhe                 | [mp]Guanteletes de ogro              | [mp]Gantelets ogres                     | [mp]Guanti d'Arme dell'Ogre           | 오우거 건틀릿      | [nl]Ogrze Rękawice             | [mp]Guanteletes de ogro               | オーガ・ガントレット     | [fp]Manoplas Ogras                  | [pl]устрашающие рукавицы          | 食人魔护手     |\n| 455 | ulb  | Wyrmhide Boots                   | 龍皮靴       | [pl]Wyrmlederstiefel               | [fp]Botas de cuero de vermis         | [fp]Bottes en peau de wyrm              | [mp]Stivali di Cuoio di Dragone       | 웜하이드 부츠      | [nl]Gadzie Buty                | [fp]Botas de pellejo de vermis        | ウィルムハイド・ブーツ    | [fp]Botas de Couro de Serpe         | [pl]змеиные сапоги                | 飞龙皮靴      |\n| 456 | uvb  | Scarabshell Boots                | 聖甲蟲殼皮靴    | [pl]Skarabäusschalenstiefel        | [fp]Botas de élitro de alfazaque     | [fp]Bottes caparaçonnées                | [mp]Stivali di Gusci di Scarabeo      | 스캐럽쉘 부츠      | [nl]Skarabeuszowe Buty         | [fp]Botas de cascarón de escarabajo   | スカラベシェル・ブーツ    | [fp]Botas de Casco de Escaravelho   | [pl]скарабеевы сапоги             | 圣甲虫壳靴     |\n| 457 | umb  | Boneweave Boots                  | 骸骨網靴      | [pl]Knochengespinststiefel         | [fp]Botas de hueso                   | [fp]Bottes en plaques d’os              | [mp]Stivali di Fibra Ossea            | 본위브 부츠       | [nl]Kościane Buty              | [fp]Botas tramóseas                   | ボーンウィーブ・ブーツ    | [fp]Botas de Osteotrama             | [pl]латно-костяные сапоги         | 骸骨链靴      |\n| 458 | utb  | Mirrored Boots                   | 幻鏡戰靴      | [pl]Verspiegelte Stiefel           | [fp]Botas de espejo                  | [fp]Bottes resplendissantes             | [mp]Stivali Riflessi                  | 미러드 부츠       | [nl]Lustrzane Buty             | [fp]Botas espejadas                   | ミラード・ブーツ       | [fp]Botas Espelhadas                | [pl]зеркальные сапоги             | 镜化靴       |\n| 459 | uhb  | Myrmidon Greaves                 | 勇士護脛      | [fs]Myrmidonbeinschienen           | [fp]Grebas de mirmidón               | [fp]Grèves de myrmidon                  | [mp]Schinieri del Mirmidone           | 뮈르미돈 그리브     | [nl]Myrmidiońskie Nagolenice   | [fp]Grebas de mirmidón                | ミュルミドーン・グリーヴ   | [fp]Grevas Mirmídones               | [pl]мирмидонские наголенники      | 侍从护胫      |\n| 460 | ulc  | Spiderweb Sash                   | 蛛網束帶      | [fs]Spinnennetzschärpe             | [ms]Fajín de tela de araña           | [fs]Ceinture en toile d’araignée        | [fs]Fascia di Ragnatela               | 스파이더웹 새시     | [fs]Pajęcza Szarfa             | [ms]Cincho de telaraña                | スパイダーウェブ・サッシュ  | [fs]Faixa de Teia                   | [ms]паутинный кушак               | 蛛网饰带      |\n| 461 | uvc  | Vampirefang Belt                 | 吸血鬼牙腰帶    | [ms]Vampirzahngürtel               | [ms]Cinturón de colmillo de vampiro  | [fs]Ceinture à crocs de vampire         | [fs]Cintura di Denti di Vampiro       | 뱀파이어팽 벨트     | [ms]Wampirzy Pas               | [ms]Cinturón de comillo de vampiro    | ヴァンパイアファング・ベルト | [ms]Cinto de Presa Vampírica        | [ms]вампирский пояс               | 吸血鬼牙腰带    |\n| 462 | umc  | Mithril Coil                     | 秘銀腰帶      | [fs]Mithrilrolle                   | [fs]Rosca de mithril                 | [fs]Ceinture de mithril                 | [fs]Spira di Mithril                  | 미스릴 코일       | [fs]Mithrilowy Pas             | [ms]Rizo de mithril                   | ミスリル・コイル       | [ms]Cinto de Mithril                | [fs]мифриловая опояска            | 秘银腰带      |\n| 463 | utc  | Troll Belt                       | 食人妖腰帶     | [ms]Trollgürtel                    | [ms]Cinturón de trol                 | [fs]Ceinture trolle                     | [fs]Cintura di Troll                  | 트롤 벨트        | [ms]Trolowy Pas                | [ms]Cinturón de trol                  | トロール・ベルト       | [ms]Cinto Trólico                   | [ms]троллий пояс                  | 巨魔腰带      |\n| 464 | uhc  | Colossus Girdle                  | 巨神腰帶      | [ms]Kolossgurt                     | [fs]Faja del coloso                  | [ms]Ceinturon de colosse                | [fs]Cintola del Colosso               | 콜로서스 거들      | [ms]Kolosalny Pas              | [fs]Faja colosal                      | コロッサス・ガードル     | [ms]Cinturão Colossal               | [ms]массивный ремень              | 巨型护腰      |\n| 465 | uh9  | Bone Visage                      | 骸骨面罩      | [fs]Knochenfratze                  | [ms]Semblante de hueso               | [ms]Casque en os                        | [ms]Volto d'Ossa                      | 본 비지즈        | [nl]Kościane Oblicze           | [ms]Semblante óseo                    | ボーン・ビセッジ       | [ms]Semblante Ósseo                 | [fs]костяная личина               | 白骨面甲      |\n| 466 | ush  | Troll Nest                       | 食人妖骨盾     | [ns]Trollnest                      | [ms]Nido de troles                   | [ms]Repaire troll                       | [ms]Cumulo di Troll                   | 트롤 네스트       | [nl]Trolowe Gniazdo            | [ms]Nido de trol                      | トロール・ネスト       | [ms]Ninho Trólico                   | [ns]троллье гнездо                | 巨魔巢       |\n| 467 | upk  | Blade Barrier                    | 刀刃刺盾      | [fs]Klingenbarriere                | [fs]Barrera tajante                  | [fs]Barrière de lames                   | [fs]Barriera di Lame                  | 블레이드 배리어     | [fs]Tnąca Bariera              | [fs]Barrera de filos                  | ブレイド・バリア       | [fs]Barreira de Lâminas             | [fs]клинковая ограда              | 剑刃屏障      |\n| 468 | dr6  | Alpha Helm                       | 猛狼頭盔      | [ms]Alphahelm                      | [ms]Yelmo alfa                       | [ms]Heaume alpha                        | [ms]Elmo Alfa                         | 알파 헬름        | [ms]Hełm Alfy                  | [ms]Yelmo alfa                        | アルファ・ヘルム       | [ms]Elmo Alfa                       | [ms]волчий шлем                   | 头狼盔       |\n| 469 | dr7  | Griffon Headdress                | 獅鷲獸頭飾     | [ms]Greifenkopfschmuck             | [ms]Tocado de grifo                  | [fs]Coiffe du griffon                   | [ms]Copricapo del Grifone             | 그리폰 헤드레스     | [ms]Gryfi Pióropusz            | [ms]Tocado de grifo                   | グリフォン・ヘッドドレス   | [ms]Quepe de Grifo                  | [ms]грифоний головной убор        | 狮鹫头饰      |\n| 470 | dr8  | Hunter's Guise                   | 獵人面罩      | [fs]Jägerverkleidung               | [ms]Aspecto del cazador              | [ms]Masque de chasseur                  | [fs]Guisa del Cacciatore              | 헌터스 가이즈      | [nl]Łowieckie Przebranie       | [fs]Guisa de cazador                  | ハンターズ・ガイズ      | [ms]Disfarce do Caçador             | [fs]охотничья личина              | 猎人伪装      |\n| 471 | dr9  | Sacred Feathers                  | 聖羽頭飾      | [pl]Heilige Federn                 | [fp]Plumas sacras                    | [fp]Plumes sacrées                      | [fp]Sacre Piume                       | 세이크리드 페더스    | [nl]Święte Pióra               | [fp]Plumas sagradas                   | セイクレッド・フェザー    | [fp]Plumas Sagradas                 | [pl]священные перья               | 圣羽盔       |\n| 472 | dra  | Totemic Mask                     | 圖騰面具      | [fs]Totemmaske                     | [fs]Máscara totémica                 | [ms]Masque totémique                    | [fs]Maschera Totemica                 | 토테믹 마스크      | [fs]Totemiczna Maska           | [fs]Máscara totémica                  | トーテミック・マスク     | [fs]Máscara Totêmica                | [fs]тотемная маска                | 图腾面具      |\n| 473 | ba6  | Jawbone Visor                    | 顎骨面甲      | [ns]Kieferknochenvisier            | [fs]Visera de mandíbula              | [fs]Visière macabre                     | [fs]Visiera d'Ossa                    | 조우본 바이저      | [fs]Szczękowa Przyłbica        | [ms]Visor con mandíbula               | ジョーボーン・バイザー    | [fs]Viseira Mandibular              | [ms]щиток с челюстью              | 颚骨面甲      |\n| 474 | ba7  | Lion Helm                        | 獅牙頭盔      | [ms]Löwenhelm                      | [ms]Yelmo del león                   | [ms]Heaume du lion                      | [ms]Elmo del Leone                    | 라이온 헬름       | [ms]Lwi Hełm                   | [ms]Yelmo de león                     | ライオン・ヘルム       | [ms]Elmo Leonino                    | [ms]львиный шлем                  | 狮盔        |\n| 475 | ba8  | Rage Mask                        | 狂怒面具      | [fs]Wutmaske                       | [fs]Máscara de la cólera             | [ms]Masque rageur                       | [fs]Maschera della Furia              | 레이지 마스크      | [fs]Oszalała Maska             | [fs]Máscara iracunda                  | レイジ・マスク        | [fs]Máscara Furiosa                 | [fs]яростная маска                | 盛怒面甲      |\n| 476 | ba9  | Savage Helmet                    | 凶蠻頭盔      | [ms]Wildenhelm                     | [ms]Casco salvaje                    | [ms]Cabasset sauvage                    | [ms]Elmo Selvaggio                    | 세비지 헬멧       | [ms]Dziki Hełm                 | [ms]Casco salvaje                     | サベッジ・ヘルメット     | [ms]Capacete Selvagem               | [ms]дикий шлем                    | 野蛮头盔      |\n| 477 | baa  | Slayer Guard                     | 殺手護盔      | [ms]Schlächterschutz               | [fs]Protección exterminadora         | [ms]Broquel féroce                      | [fs]Guardia Massacratrice             | 슬레이어 가드      | [fs]Zabójcza Straż             | [fs]Guardia del exterminador          | スレイヤー・ガード      | [fs]Proteção Homicida               | [ms]экзекуторский убор            | 杀戮者头盔     |\n| 478 | pa6  | Akaran Targe                     | 阿卡拉圓盾     | Akarantarge                        | [fs]Adarga de Akaran                 | [fs]Targe d’Akaran                      | [ms]Targa di Akarat                   | 아카란 타아지      | [fs]Akarańska Tarża            | [fs]Adarga de Akara                   | アカラン・タージ       | [fs]Targa de Akaran                 | [ms]акаранский тарджет            | 阿卡兰小盾     |\n| 479 | pa7  | Akaran Rondache                  | 阿卡拉輕圓盾    | [fs]Akaranrondache                 | [fs]Rodela de Akaran                 | [fs]Rondache d’Akaran                   | [ms]Rondaccia di Akarat               | 아카란 론다쉬      | [fs]Akarańska Rodela           | [fs]Rodela de Akara                   | アカラン・ロンダッシュ    | [ms]Rondache de Akaran              | [ms]акаранский рондаш             | 阿卡兰轻圆盾    |\n| 480 | pa8  | Protector Shield                 | 守護之盾      | [ms]Schutzschild                   | [ms]Escudo protector                 | [ms]Bouclier protecteur                 | [ms]Scudo Protettore                  | 프로텍터 쉴드      | [fs]Ochronna Tarcza            | [ms]Escudo protector                  | プロテクター・シールド    | [ms]Escudo Protetor                 | [ms]покровительский щит           | 保卫者之盾     |\n| 481 | pa9  | Gilded Shield                    | 金紋盾       | [ms]Vergoldeter Schild             | [ms]Escudo dorado                    | [ms]Bouclier doré                       | [ms]Scudo Dorato                      | 길디드 쉴드       | [fs]Pozłacana Tarcza           | [ms]Escudo dorado                     | ギルデッド・シールド     | [ms]Escudo Dourado                  | [ms]золоченый щит                 | 镀金盾       |\n| 482 | paa  | Royal Shield                     | 皇家盾       | [ms]Königlicher Schild             | [ms]Escudo real                      | [ms]Bouclier royal                      | [ms]Scudo Reale                       | 로얄 쉴드        | [fs]Królewska Tarcza           | [ms]Escudo real                       | ロイヤル・シールド      | [ms]Escudo Régio                    | [ms]монарший щит                  | 皇家盾       |\n| 483 | ne6  | Mummified Trophy                 | 木乃伊首級     | [fs]Mumifizierte Trophäe           | [ms]Trofeo momificado                | [ms]Trophée momifié                     | [ms]Trofeo Mummificato                | 머미파이드 트로피    | [nl]Zmumifikowane Trofeum      | [ms]Trofeo momificado                 | マミファイド・トロフィー   | [ms]Troféu Mumificado               | [ms]засушенный трофей             | 木乃伊法器     |\n| 484 | ne7  | Fetish Trophy                    | 鬼娃首級      | [fs]Fetischtrophäe                 | [ms]Trofeo de fetiche                | [ms]Trophée fétiche                     | [ms]Trofeo del Feticcio               | 페티쉬 트로피      | [nl]Fetyszowe Trofeum          | [ms]Trofeo de fetiche                 | フェティッシュ・トロフィー  | [ms]Troféu Carranco                 | [ms]трофей-фетиш                  | 鬼娃法器      |\n| 485 | ne8  | Sexton Trophy                    | 司事首級      | [fs]Sextontrophäe                  | [ms]Trofeo de sacristán              | [ms]Trophée de sacristain               | [ms]Trofeo del Necroforo              | 섹스턴 트로피      | [nl]Kapłańskie Trofeum         | [ms]Trofeo de sacristán               | セクストン・トロフィー    | [ms]Troféu Sexton                   | [ms]алтарный трофей               | 教堂司事法器    |\n| 486 | ne9  | Cantor Trophy                    | 領唱者首級     | [fs]Kantortrophäe                  | [ms]Trofeo de cantor                 | [ms]Trophée de chantre                  | [ms]Trofeo del Cantore                | 캔터 트로피       | [nl]Kantorskie Trofeum         | [ms]Trofeo de capiscol                | キャンター・トロフィー    | [ms]Troféu Cantor                   | [ms]хоровой трофей                | 领唱者法器     |\n| 487 | nea  | Hierophant Trophy                | 祭司首級      | Hierophanttrophäe                  | [ms]Trofeo de hierofante             | [ms]Trophée de hiérophante              | [ms]Trofeo dello Ierofante            | 하이어러팬트 트로피   | [nl]Hierofanckie Trofeum       | [ms]Trofeo de hierofante              | ハイエロファント・トロフィー | [ms]Troféu Hierofante               | [ms]жреческий трофей              | 圣师法器      |\n| 488 | drb  | Blood Spirit                     | 血系靈獸帽     | [ms]Blutgeist                      | [ms]Espíritu de la sangre            | [ms]Esprit du sang                      | [ms]Spirito del Sangue                | 블러드 스피리트     | [ms]Krwawy Duch                | [ms]Espíritu de sangre                | ブラッド・スピリット     | [ms]Espírito Sanguíneo              | [ms]кровавый дух                  | 鲜血之灵      |\n| 489 | drc  | Sun Spirit                       | 日陽靈獸帽     | [ms]Sonnengeist                    | [ms]Espíritu del sol                 | [ms]Esprit du soleil                    | [ms]Spirito del Sole                  | 선 스피리트       | [ms]Słoneczny Duch             | [ms]Espíritu de sol                   | サン・スピリット       | [ms]Espírito Solar                  | [ms]солнечный дух                 | 太阳之灵      |\n| 490 | drd  | Earth Spirit                     | 地土靈獸帽     | [ms]Erdgeist                       | [ms]Espíritu de la tierra            | [ms]Esprit de la terre                  | [ms]Spirito della Terra               | 어스 스피리트      | [ms]Ziemny Duch                | [ms]Espíritu de tierra                | アース・スピリット      | [ms]Espírito Terrestre              | [ms]земной дух                    | 大地之灵      |\n| 491 | dre  | Sky Spirit                       | 天翔靈獸帽     | [ms]Himmelsgeist                   | [ms]Espíritu del cielo               | [ms]Esprit des Cieux                    | [ms]Spirito del Cielo                 | 스카이 스피리트     | [ms]Podniebny Duch             | [ms]Espíritu de cielo                 | スカイ・スピリット      | [ms]Espírito Celeste                | [ms]воздушный дух                 | 天空之灵      |\n| 492 | drf  | Dream Spirit                     | 幽夢靈獸帽     | [ms]Traumgeist                     | [ms]Espíritu del sueño               | [ms]Esprit du rêve                      | [ms]Spirito del Sogno                 | 드림 스피리트      | [ms]Senny Duch                 | [ms]Espíritu de sueño                 | ドリーム・スピリット     | [ms]Espírito Onírico                | [ms]иллюзорный дух                | 梦境之灵      |\n| 493 | bab  | Carnage Helm                     | 屠殺頭盔      | [ms]Gemetzelhelm                   | [ms]Yelmo de carnicería              | [ms]Heaume de carnage                   | [ms]Elmo della Carneficina            | 카니지 헬름       | [ms]Rzeźniczy Hełm             | [ms]Yelmo del desmembrador            | カーネッジ・ヘルム      | [ms]Elmo da Carnificina             | [ms]мясницкий шлем                | 屠戮盔       |\n| 494 | bac  | Fury Visor                       | 暴怒面甲      | [ns]Wutvisier                      | [fs]Visera de furia                  | [fs]Visière de fureur                   | [ms]Visiera della Furia               | 퓨리 바이저       | [fs]Gniewna Przyłbica          | [ms]Visor de furia                    | フューリー・バイザー     | [fs]Viseira Furiosa                 | [ms]яростный щиток                | 怒火面甲      |\n| 495 | bad  | Destroyer Helm                   | 毀滅者頭盔     | [ms]Zerstörerhelm                  | [ms]Yelmo destructor                 | [ms]Heaume de destructeur               | [ms]Elmo Distruttore                  | 디스트로이어 헬름    | [ms]Niszczycielski Hełm        | [ms]Yelmo del destructor              | デストロイヤー・ヘルム    | [ms]Elmo Destruidor                 | [ms]разрушительный шлем           | 毁灭者头盔     |\n| 496 | bae  | Conqueror Crown                  | 征服者盔冠     | Erobererkrone                      | [fs]Corona conquistadora             | [fs]Couronne de conquérant              | [fs]Corona del Conquistatore          | 컨커러 크라운      | [fs]Zdobywcza Korona           | [fs]Corona del conquistador           | コンカラー・クラウン     | [fs]Coroa do Conquistador           | [fs]победоносная корона           | 征服者王冠     |\n| 497 | baf  | Guardian Crown                   | 守護者盔冠     | [fs]Wächterkrone                   | [fs]Corona guardiana                 | [fs]Couronne de gardien                 | [fs]Corona del Guardiano              | 가디언 크라운      | [fs]Strażnicza Korona          | [fs]Corona del guardián               | ガーディアン・クラウン    | [fs]Coroa do Guardião               | [fs]защитная корона               | 守护者王冠     |\n| 498 | pab  | Sacred Targe                     | 神聖小盾      | [fs]Heilige Targe                  | [fs]Adarga sacra                     | [fs]Targe sacrée                        | [fs]Targa Sacra                       | 세이크리드 타아지    | [fs]Święta Tarża               | [fs]Adarga sagrada                    | セイクレッド・タージ     | [fs]Targa Sagrada                   | [ms]священный тарджет             | 神圣小盾      |\n| 499 | pac  | Sacred Rondache                  | 神聖輕圓盾     | [fs]Heilige Rondache               | [fs]Rodela sacra                     | [fs]Rondache sacrée                     | [fs]Rondaccia Sacra                   | 세이크리드 론다쉬    | [fs]Święta Rodela              | [fs]Rodela sagrada                    | セイクレッド・ロンダッシュ  | [ms]Rondache Sagrado                | [ms]священный рондаш              | 神圣轻圆盾     |\n| 500 | pad  | Kurast Shield                    | 庫拉斯特盾     | Kurastschild                       | Escudo de Kurast                     | Bouclier de Kurast                      | Scudo di Kurast                       | 쿠라스트 쉴드      | [fs]Kurastowa Tarcza           | [ms]Escudo de Kurast                  | クラスト・シールド      | [ms]Escudo de Kurast                | Щит Кураста                       | 库拉斯特盾     |\n| 501 | pae  | Zakarum Shield                   | 撒卡蘭姆盾     | [ms]Zakarumschild                  | [ms]Escudo de Zakarum                | [ms]Bouclier de Zakarum                 | [ms]Scudo di Zakarum                  | 자카룸 쉴드       | [fs]Zakarumicka Tarcza         | [ms]Escudo de Zakarum                 | ザカラム・シールド      | [ms]Escudo Zakarum                  | [ms]закарумский щит               | 萨卡兰姆盾     |\n| 502 | paf  | Vortex Shield                    | 渦旋盾       | [ms]Wirbelschild                   | [ms]Escudo vórtice                   | [ms]Bouclier du vortex                  | [ms]Scudo del Vortice                 | 볼텍스 쉴드       | [fs]Wirotarcza                 | [ms]Escudo de vórtice                 | ボルテックス・シールド    | [ms]Escudo do Vórtice               | [ms]ураганный щит                 | 漩涡盾       |\n| 503 | neb  | Minion Skull                     | 僕從顱骨      | [ms]Dienerschädel                  | [ms]Cráneo de esbirro                | [ms]Crâne de serviteur                  | [ms]Teschio di Servitore              | 미니언 스컬       | [fs]Czaszka Sługi              | [ms]Cráneo de esbirro                 | ミニオン・スカル       | [fs]Caveira de Lacaio               | [ms]прислужничий череп            | 爪牙颅骨      |\n| 504 | neg  | Hellspawn Skull                  | 地獄爪牙顱骨    | [ms]Höllenbrutschädel              | [ms]Cráneo del averno                | [ms]Crâne de l’engeance infernale       | [ms]Teschio di Creatura Infernale     | 헬스폰 스컬       | [fs]Czaszka Pomiotu Piekieł    | [ms]Cráneo de engendro infernal       | ヘルスポーン・スカル     | [fs]Caveira de Cria Infernal        | [ms]череп отродья Тьмы            | 地狱魔颅骨     |\n| 505 | ned  | Overseer Skull                   | 督軍顱骨      | [ms]Aufseherschädel                | [ms]Cráneo de supervisor             | [ms]Crâne de prophète                   | [ms]Teschio di Sovrintendente         | 오버시어 스컬      | [fs]Nadzorcza Czaszka          | [ms]Cráneo de mayoral                 | オーバーシアー・スカル    | [fs]Caveira de Capataz              | [ms]надзирательский череп         | 督军颅骨      |\n| 506 | nee  | Succubus Skull                   | 魅魔顱骨      | Sukkubusschädel                    | [ms]Cráneo de súcubo                 | [ms]Crâne de succube                    | [ms]Teschio di Succube                | 써큐버스 스컬      | [fs]Sukkubia Czaszka           | [ms]Cráneo de súcubo                  | サキュバス・スカル      | [fs]Caveira de Súcubo               | [ms]суккубский череп              | 魅魔颅骨      |\n| 507 | nef  | Bloodlord Skull                  | 鮮血之王顱骨    | [ms]Blutlordschädel                | [ms]Cráneo de señor de la sangre     | [ms]Crâne de seigneur de sang           | [ms]Teschio di Signore del Sangue     | 블러드로드 스컬     | [fs]Demoniczna Czaszka         | [ms]Cráneo de señor sangriento        | ブラッドロード・スカル    | [fs]Caveira de Senhor Sangrento     | [ms]владыческий череп             | 血王颅骨      |\n| 508 | elx  | Elixir                           | 靈藥        | Elixier                            | Elixir                               | Élixir                                  | Elisir                                | 비약           | Eliksir                        | [ms]Elíxir                            | エリクサー          | [ms]Elixir                          | [ms]эликсир                       | 药剂        |\n| 513 | vps  | Stamina Potion                   | 精力藥水      | Ausdauerelixier                    | Poción de aguante                    | Potion d’endurance                      | Pozione del Vigore                    | 지구력 물약       | Mikstura wytrzymałości         | Poción de vigor                       | スタミナ・ポーション     | Poção de Vigor                      | Зелье выносливости                | 耐力药水      |\n| 514 | yps  | Antidote Potion                  | 解毒藥水      | Gegengiftelixier                   | Poción antídoto                      | Antidote                                | Antidoto                              | 해독 물약        | Antidotum                      | Poción antídoto                       | 解毒のポーション       | Poção de Antídoto                   | Противоядие                       | 解毒药水      |\n| 515 | rvs  | Rejuvenation Potion              | 活力藥水      | Regenerationstrank                 | Poción rejuvenecedora                | Potion de rajeunissement                | Pozione di Rinvigorimento             | 활력 물약        | Mikstura wzmocnienia           | Poción de rejuvenecimiento            | 回復のポーション       | Poção de Rejuvenescimento           | Зелье восстановления              | 复苏药水      |\n| 516 | rvl  | Full Rejuvenation Potion         | 全效活力藥水    | starker Regenerationstrank         | Poción rejuvenecedora total          | Potion de rajeunissement total          | Pozione di Rinvigorimento Superiore   | 대량의 활력 물약    | Mikstura pełnego wzmocnienia   | Poción de rejuvenecimiento total      | 完全回復のポーション     | Poção de Rejuvenescimento Integral  | Зелье полного восстановления      | 完全复苏药水    |\n| 517 | wms  | Thawing Potion                   | 融冰藥水      | Auftauelixier                      | Poción descongelante                 | Potion de dégel                         | Pozione del Disgelo                   | 해동 물약        | Mikstura odtajania             | Poción descongelante                  | 解氷のポーション       | Poção Descongelante                 | Зелье оттаивания                  | 解冻药水      |\n| 518 | tbk  | Tome of Town Portal              | 城鎮傳送之書    | Foliant des Stadtportals           | Tomo del portal de la ciudad         | Tome de portail de retour en ville      | Tomo del Portale Cittadino            | 마을 차원문의 고서   | Księga miejskiego portalu      | Tomo de portal al poblado             | タウン・ポータルの書     | Tomo do Portal da Cidade            | Фолиант возвращения               | 城镇传送之书    |\n| 519 | ibk  | Tome of Identify                 | 鑑定之書      | Foliant der Identifikation         | Tomo de identificación               | Tome d’identification                   | Tomo dell'Identificazione             | 감별의 고서       | Księga identyfikacji           | Tomo de identificación                | 鑑定の書           | Tomo de Identificação               | Фолиант распознания               | 鉴定之书      |\n| 520 | amu  | Amulet                           | 護身符       | [ns]Amulett                        | [ms]Amuleto                          | [fs]Amulette                            | [ms]Amuleto                           | 목걸이          | [ms]Amulet                     | [ms]Amuleto                           | アミュレット         | [ms]Amuleto                         | [ms]амулет                        | 护符        |\n| 521 | vip  | Top of the Horadric Staff        | 赫拉迪姆之杖的杖頂 | Spitze des Horadrimstabes          | Empuñadura del bastón horádrico      | Haut du bâton horadrique                | Testa della Verga Horadrica           | 호라드림 지팡이 꼭지  | Zwieńczenie Kostura Horadrimów | Cabezal del Bastón horádrico          | ホラドリムの杖の頭部     | Topo do Cajado Horádrico            | Навершие хорадримского посоха     | 赫拉迪姆法杖的杖头 |\n| 522 | rin  | Ring                             | 戒指        | [ms]Ring                           | [ms]Anillo                           | [ms]Anneau                              | [ms]Anello                            | 반지           | [ms]Pierścień                  | [ms]Anillo                            | 指輪             | [ms]Anel                            | [ns]кольцо                        | 戒指        |\n| 523 | gld  | Gold                             | 金幣        | Gold                               | de oro                               | or                                      | oro                                   | 금화           | szt. złota                     | Oro                                   | ゴールド           | Ouro                                | золотых                           | 金币        |\n| 524 | bks  | Scroll of Inifuss                | 艾尼弗斯卷軸    | Inifussschriftrolle                | Pergamino de Inifuss                 | Parchemin d’Inifuss                     | Pergamena di Inifuss                  | 이니푸스의 두루마리   | Zwój Inifussa                  | Pergamino de Inifuss                  | イニファスの巻物       | Pergaminho de Inifuss               | Свиток Инифусс                    | 艾尼弗斯卷轴    |\n| 525 | bkd  | Key to the Cairn Stones          | 石陣之鑰      | Schlüssel zu den Monolithen        | Llave de las piedras de Cairn        | Clé pour les Pierres de Cairn           | Chiave per i Monoliti                 | 돌무덤 열쇠       | Wskazówka do Kręgu Kamieni     | Llave de los Menhires de piedra       | ケルン・ストーンの手掛かり  | Chave das Pedras Monumentais        | Ключ от круга камней              | 石阵密文      |\n| 526 | aqv  | Arrows                           | 弓矢        | Pfeile                             | [fp]Flechas                          | [fp]Flèches                             | Frecce                                | 화살           | Strzały                        | Flechas                               | 矢              | Flechas                             | Стрелы                            | 箭矢        |\n| 527 | tch  | Torch                            | 火炬        | Fackel                             | [fs]Antorcha                         | [fs]Torche                              | Torcia                                | 횃불           | Pochodnia                      | Antorcha                              | たいまつ           | Tocha                               | [ms]факел                         | 火把        |\n| 528 | cqv  | Bolts                            | 弩箭        | Bolzen                             | [fp]Saetas                           | [mp]Traits                              | Dardi                                 | 쇠뇌용 화살       | Bełty                          | Saetas                                | ボルト            | Setas                               | [pl]арбалетные болты              | 弩矢        |\n| 529 | tsc  | Scroll of Town Portal            | 城鎮傳送卷軸    | Schriftrolle des Stadtportals      | Pergamino del portal de la ciudad    | Parchemin de portail de retour en ville | Pergamena del Portale Cittadino       | 마을 차원문의 두루마리 | Zwój miejskiego portalu        | Pergamino de portal al poblado        | タウン・ポータルの巻物    | Pergaminho do Portal da Cidade      | Свиток возвращения                | 城镇传送卷轴    |\n| 530 | isc  | Scroll of Identify               | 鑑定卷軸      | Schriftrolle der Identifikation    | Pergamino de identificación          | Parchemin d’identification              | Pergamena dell'Identificazione        | 감별의 두루마리     | Zwój identyfikacji             | Pergamino de identificación           | 鑑定の巻物          | Pergaminho de Identificação         | Свиток распознания                | 鉴定卷轴      |\n| 531 | hrt  | Heart                            | 心臟        | [ns]Herz                           | [ms]Corazón                          | [ms]Cœur                                | [ms]Cuore                             | 심장           | [nl]Serce                      | Corazón                               | の心臓            | Coração                             | [ns]сердце                        | 心脏        |\n| 532 | brz  | Brain                            | 腦         | [ns]Gehirn                         | [ms]Cerebro                          | [ms]Cerveau                             | [ms]Cervello                          | 뇌            | [ms]Mózg                       | Cerebro                               | の脳             | Cérebro                             | [ms]мозг                          | 大脑        |\n| 533 | jaw  | Jawbone                          | 顎骨        | [ms]Kiefer                         | [fs]Mandíbula                        | [fs]Mâchoire                            | [fs]Mascella                          | 턱뼈           | [fs]Szczęka                    | Mandíbula                             | の顎骨            | Mandíbula                           | [fs]челюсть                       | 颚骨        |\n| 534 | eyz  | Eye                              | 眼球        | [ns]Auge                           | [ms]Ojo                              | [ms]Œil                                 | [ms]Occhio                            | 눈            | [nl]Oko                        | Ojo                                   | の目             | Olho                                | [ms]глаз                          | 眼球        |\n| 535 | hrn  | Horn                             | 尖角        | [ns]Horn                           | [ms]Cuerno                           | [fs]Corne                               | [ms]Corno                             | 뿔            | [ms]Róg                        | Cuerno                                | の角             | Chifre                              | [ms]рог                           | 尖角        |\n| 536 | tal  | Tail                             | 尾巴        | [ms]Schwanz                        | [fs]Cola                             | [fs]Queue                               | [fs]Coda                              | 꼬리           | [ms]Ogon                       | Cola                                  | の尻尾            | Cauda                               | [ms]хвост                         | 尾巴        |\n| 537 | flg  | Flag                             | 旗幟        | [fs]Flagge                         | [fs]Bandera                          | [ms]Étendard                            | [fs]Bandiera                          | 깃발           | [fs]Flaga                      | Bandera                               | の旗             | Bandeira                            | [ms]флаг                          | 旗帜        |\n| 538 | fng  | Fang                             | 尖牙        | [ms]Hauer                          | [ms]Colmillo                         | [ms]Croc                                | [fs]Zanna                             | 송곳니          | [ms]Kieł                       | Colmillo                              | の牙             | Presa                               | [ms]клык                          | 尖牙        |\n| 539 | qll  | Quill                            | 刺針        | [ms]Stachel                        | [ms]Cálamo                           | [fs]Plume                               | [fs]Spina Ossea                       | 쇠가시          | [nl]Pióro                      | Péndola                               | の羽根            | Espigão                             | [fs]ость                          | 短匕        |\n| 540 | sol  | Soul                             | 靈魂        | [fs]Seele                          | [fs]Alma                             | [fs]Âme                                 | [fs]Anima                             | 영혼           | [fs]Dusza                      | Alma                                  | の魂             | Alma                                | [fs]душа                          | 灵魂        |\n| 541 | scz  | Scalp                            | 頭皮        | [ms]Skalp                          | [fs]Cabellera                        | [ms]Scalp                               | [ms]Scalpo                            | 머릿가죽         | [ms]Skalp                      | Cabellera                             | の頭皮            | Escalpo                             | [ms]скальп                        | 头皮        |\n| 542 | spe  | Spleen                           | 脾臟        | [fs]Milz                           | [ms]Bazo                             | [ms]Spleen                              | [fs]Milza                             | 지라           | [fs]Śledziona                  | Bazo                                  | の脾臓            | Baço                                | [fs]селезенка                     | 脾脏        |\n| 543 | key  | Key                              | 鑰匙        | Schlüssel                          | [fs]Llave                            | [fs]Clé                                 | Chiave                                | 열쇠           | Klucz                          | Llave                                 | 鍵              | Chave                               | [ms]ключ                          | 钥匙        |\n| 544 | luv  | The Black Tower Key              | 黑塔之鑰      | der Schlüssel des schwarzen Turmes | Llave de la Torre Ennegrecida        | Clé de la Tour noire                    | La Chiave della Torre Nera            | 검은 탑 열쇠      | Klucz do Czarnej Wieży         | La llave de la Torre negra            | 黒い塔の鍵          | Chave da Torre Tenebrosa            | Ключ от Черной башни              | 黑塔钥匙      |\n| 545 | xyz  | Potion of Life                   | 生命藥水      | Elixier des Lebens                 | Poción de vida                       | Potion de vie                           | Pozione della Vita                    | 생명력 물약       | Mikstura Zdrowia               | Poción de vida                        | 生命のポーション       | Poção de Vida                       | Зелье здоровья                    | 生命药水      |\n| 546 | j34  | A Jade Figurine                  | 翠玉塑像      | Jadefigur                          | Una estatuilla de jade               | Statuette de jade                       | Statuetta di Giada                    | 비취 조각상       | Jadeitowa Figurka              | Una Estatuilla de jade                | 翡翠の小像          | Estatueta de Jade                   | Нефритовая статуэтка              | 玉石雕像      |\n| 547 | g34  | The Golden Bird                  | 黃金鳥       | der goldene Vogel                  | Pájaro dorado                        | L’Oiseau de Feu                         | L'Uccello d'Oro                       | 황금 새         | Złoty Ptak                     | El Pájaro Dorado                      | 黄金の鳥           | O Pássaro Dourado                   | Золотая птица                     | 黄金鸟       |\n| 548 | bbb  | Lam Esen's Tome                  | 藍伊森之書     | Lam Esens Foliant                  | Tomo de Lam Esen                     | Livre de Lam Esen                       | Libro di Lam Esen                     | 람 에센의 고서     | Księga Lama Esena              | El Tomo de Lam Esen                   | ラム・エセンの書       | Tomo de Lam Esen                    | Фолиант Лам Эсена                 | 兰姆·艾森之书   |\n| 549 | box  | Horadric Cube                    | 赫拉迪姆方塊    | Horadrimwürfel                     | Cubo horádrico                       | Cube horadrique                         | Cubo Horadrico                        | 호라드림의 함      | Kostka Horadrimów              | Cubo horádrico                        | ホラドリムのキューブ     | Cubo Horádrico                      | Хорадримский куб                  | 赫拉迪姆魔盒    |\n| 550 | tr1  | Horadric Scroll                  | 赫拉迪姆卷軸    | Horadrimschriftrolle               | Pergamino horádrico                  | Parchemin horadrique                    | Pergamena Horadrica                   | 호라드림의 두루마리   | Zwój Horadrimów                | Pergamino horádrico                   | ホラドリムの巻物       | Pergaminho Horádrico                | Хорадримский свиток               | 赫拉迪姆卷轴    |\n| 551 | mss  | Mephisto's Soulstone             | 墨菲斯托的靈魂石  | Mephistos Seelenstein              | Piedra de alma de Mefisto            | Pierre d’âme de Méphisto                | Pietra dell'Anima di Mefisto          | 메피스토의 영혼석    | Kamień Duszy Mefista           | Piedra Esencial de Mefisto            | メフィストのソウルストーン  | Pedra das Almas de Mefisto          | Камень души Мефисто               | 墨菲斯托的灵魂石  |\n| 552 | ass  | Book of Skill                    | 技能之書      | Buch der Fertigkeit                | Libro de habilidad                   | Livre des compétences                   | Libro dell'Abilità                    | 기술 책         | Księga Umiejętności            | Libro de habilidad                    | スキルの書          | Livro de Habilidade                 | Книга умений                      | 技能书       |\n| 553 | qey  | Khalim's Eye                     | 克林姆的眼球    | Khalims Auge                       | Ojo de Khalim                        | Œil de Khalim                           | Occhio di Khalim                      | 칼림의 눈        | Oko Khalima                    | Ojo de Khalim                         | カリムの目          | Olho de Khalim                      | Глаз Халима                       | 卡林姆的眼球    |\n| 554 | qhr  | Khalim's Heart                   | 克林姆的心臟    | Khalims Herz                       | Corazón de Khalim                    | Cœur de Khalim                          | Cuore di Khalim                       | 칼림의 심장       | Serce Khalima                  | Corazón de Khalim                     | カリムの心臓         | Coração de Khalim                   | Сердце Халима                     | 卡林姆的心脏    |\n| 555 | qbr  | Khalim's Brain                   | 克林姆的大腦    | Khalims Gehirn                     | Cerebro de Khalim                    | Cerveau de Khalim                       | Cervello di Khalim                    | 칼림의 뇌        | Mózg Khalima                   | Cerebro de Khalim                     | カリムの脳          | Cérebro de Khalim                   | Мозг Халима                       | 卡林姆的大脑    |\n| 556 | ear  | Ear                              | 耳朵        | Ohr                                | [fs]Oreja                            | [fs]Oreille                             | [ms]Orecchio                          | 귀            | Ucho                           | Oreja                                 | の耳             | Orelha                              | Ухо                               | 耳朵        |\n| 557 | gcv  | Chipped Amethyst                 | 碎裂紫寶石     | lädierter Amethyst                 | Amatista fragmentada                 | Améthyste abîmée                        | Ametista Spezzata                     | 최하급 자수정      | Nadkruszony ametyst            | Amatista mellada                      | 欠けたアメジスト       | Ametista Lascada                    | Надколотый аметист                | 碎裂的紫宝石    |\n| 558 | gfv  | Flawed Amethyst                  | 瑕疵紫寶石     | fehlerhafter Amethyst              | Amatista estropeada                  | Améthyste imparfaite                    | Ametista Incrinata                    | 하급 자수정       | Ametyst ze skazą               | Amatista imperfecta                   | 傷のあるアメジスト      | Ametista Imperfeita                 | Мутный аметист                    | 有瑕疵的紫宝石   |\n| 559 | gsv  | Amethyst                         | 紫寶石       | Amethyst                           | Amatista                             | Améthyste                               | Ametista                              | 자수정          | Ametyst                        | Amatista                              | アメジスト          | Ametista                            | Аметист                           | 紫宝石       |\n| 560 | gzv  | Flawless Amethyst                | 無瑕紫寶石     | makelloser Amethyst                | Amatista sin defectos                | Améthyste sans défaut                   | Ametista Integra                      | 상급 자수정       | Ametyst bez skazy              | Amatista impecable                    | 上質なアメジスト       | Ametista Impecável                  | Безупречный аметист               | 无瑕的紫宝石    |\n| 561 | gpv  | Perfect Amethyst                 | 完美紫寶石     | perfekter Amethyst                 | Amatista perfecta                    | Améthyste parfaite                      | Ametista Perfetta                     | 최상급 자수정      | Doskonały ametyst              | Amatista perfecta                     | 完璧なアメジスト       | Ametista Perfeita                   | Идеальный аметист                 | 完美的紫宝石    |\n| 562 | gcy  | Chipped Topaz                    | 碎裂黃寶石     | lädierter Topas                    | Topacio fragmentado                  | Topaze abîmée                           | Topazio Spezzato                      | 최하급 토파즈      | Nadkruszony topaz              | Topacio mellado                       | 欠けたトパーズ        | Topázio Lascado                     | Надколотый топаз                  | 碎裂的黄宝石    |\n| 563 | gfy  | Flawed Topaz                     | 瑕疵黃寶石     | fehlerhafter Topas                 | Topacio estropeado                   | Topaze imparfaite                       | Topazio Incrinato                     | 하급 토파즈       | Topaz ze skazą                 | Topacio imperfecto                    | 傷のあるトパーズ       | Topázio Imperfeito                  | Мутный топаз                      | 有瑕疵的黄宝石   |\n| 564 | gsy  | Topaz                            | 黃寶石       | Topas                              | Topacio                              | Topaze                                  | Topazio                               | 토파즈          | Topaz                          | Topacio                               | トパーズ           | Topázio                             | Топаз                             | 黄宝石       |\n| 565 | gly  | Flawless Topaz                   | 無瑕黃寶石     | makelloser Topas                   | Topacio sin defectos                 | Topaze sans défaut                      | Topazio Integro                       | 상급 토파즈       | Topaz bez skazy                | Topacio impecable                     | 上質なトパーズ        | Topázio Impecável                   | Безупречный топаз                 | 无瑕的黄宝石    |\n| 566 | gpy  | Perfect Topaz                    | 完美黃寶石     | perfekter Topas                    | Topacio perfecto                     | Topaze parfaite                         | Topazio Perfetto                      | 최상급 토파즈      | Doskonały topaz                | Topacio perfecto                      | 完璧なトパーズ        | Topázio Perfeito                    | Идеальный топаз                   | 完美的黄宝石    |\n| 567 | gcb  | Chipped Sapphire                 | 碎裂藍寶石     | lädierter Saphir                   | Zafiro fragmentado                   | Saphir abîmé                            | Zaffiro Spezzato                      | 최하급 사파이어     | Nadkruszony szafir             | Zafiro mellado                        | 欠けたサファイア       | Safira Lascada                      | Надколотый сапфир                 | 碎裂的蓝宝石    |\n| 568 | gfb  | Flawed Sapphire                  | 瑕疵藍寶石     | fehlerhafter Saphir                | Zafiro estropeado                    | Saphir imparfait                        | Zaffiro Incrinato                     | 하급 사파이어      | Szafir ze skazą                | Zafiro imperfecto                     | 傷のあるサファイア      | Safira Imperfeita                   | Мутный сапфир                     | 有瑕疵的蓝宝石   |\n| 569 | gsb  | Sapphire                         | 藍寶石       | Saphir                             | Zafiro                               | Saphir                                  | Zaffiro                               | 사파이어         | Szafir                         | [ms]Zafiro                            | サファイア          | Safira                              | [ms]Сапфир                        | 蓝宝石       |\n| 570 | glb  | Flawless Sapphire                | 無暇藍寶石     | makelloser Saphir                  | Zafiro sin defectos                  | Saphir sans défaut                      | Zaffiro Integro                       | 상급 사파이어      | Szafir bez skazy               | Zafiro impecable                      | 上質なサファイア       | Safira Impecável                    | Безупречный сапфир                | 无瑕的蓝宝石    |\n| 571 | gpb  | Perfect Sapphire                 | 完美藍寶石     | perfekter Saphir                   | Zafiro perfecto                      | Saphir parfait                          | Zaffiro Perfetto                      | 최상급 사파이어     | Doskonały szafir               | Zafiro perfecto                       | 完璧なサファイア       | Safira Perfeita                     | Идеальный сапфир                  | 完美的蓝宝石    |\n| 572 | gcg  | Chipped Emerald                  | 碎裂綠寶石     | lädierter Smaragd                  | Esmeralda fragmentada                | Émeraude abîmée                         | Smeraldo Spezzato                     | 최하급 에메랄드     | Nadkruszony szmaragd           | Esmeralda mellada                     | 欠けたエメラルド       | Esmeralda Lascada                   | Надколотый изумруд                | 碎裂的绿宝石    |\n| 573 | gfg  | Flawed Emerald                   | 瑕疵綠寶石     | fehlerhafter Smaragd               | Esmeralda estropeada                 | Émeraude imparfaite                     | Smeraldo Incrinato                    | 하급 에메랄드      | Szmaragd ze skazą              | Esmeralda imperfecta                  | 傷のあるエメラルド      | Esmeralda Imperfeita                | Мутный изумруд                    | 有瑕疵的绿宝石   |\n| 574 | gsg  | Emerald                          | 綠寶石       | Smaragd                            | Esmeralda                            | Émeraude                                | Smeraldo                              | 에메랄드         | Szmaragd                       | [fs]Esmeralda                         | エメラルド          | Esmeralda                           | [ms]Изумруд                       | 绿宝石       |\n| 575 | glg  | Flawless Emerald                 | 無瑕綠寶石     | makelloser Smaragd                 | Esmeralda sin defectos               | Émeraude sans défaut                    | Smeraldo Integro                      | 상급 에메랄드      | Szmaragd bez skazy             | Esmeralda impecable                   | 上質なエメラルド       | Esmeralda Impecável                 | Безупречный изумруд               | 无瑕的绿宝石    |\n| 576 | gpg  | Perfect Emerald                  | 完美綠寶石     | perfekter Smaragd                  | Esmeralda perfecta                   | Émeraude parfaite                       | Smeraldo Perfetto                     | 최상급 에메랄드     | Doskonały szmaragd             | Esmeralda perfecta                    | 完璧なエメラルド       | Esmeralda Perfeita                  | Идеальный изумруд                 | 完美的绿宝石    |\n| 577 | gcr  | Chipped Ruby                     | 碎裂紅寶石     | lädierter Rubin                    | Rubí fragmentado                     | Rubis abîmé                             | Rubino Spezzato                       | 최하급 루비       | Nadkruszony rubin              | Rubí mellado                          | 欠けたルビー         | Rubi Lascado                        | Надколотый рубин                  | 碎裂的红宝石    |\n| 578 | gfr  | Flawed Ruby                      | 瑕疵紅寶石     | fehlerhafter Rubin                 | Rubí estropeado                      | Rubis imparfait                         | Rubino Incrinato                      | 하급 루비        | Rubin ze skazą                 | Rubí imperfecto                       | 傷のあるルビー        | Rubi Imperfeito                     | Мутный рубин                      | 有瑕疵的红宝石   |\n| 579 | gsr  | Ruby                             | 紅寶石       | Rubin                              | Rubí                                 | Rubis                                   | Rubino                                | 루비           | Rubin                          | [ms]Rubí                              | ルビー            | Rubi                                | [ms]Рубин                         | 红宝石       |\n| 580 | glr  | Flawless Ruby                    | 無瑕紅寶石     | makelloser Rubin                   | Rubí sin defectos                    | Rubis sans défaut                       | Rubino Integro                        | 상급 루비        | Rubin bez skazy                | Rubí impecable                        | 上質なルビー         | Rubi Impecável                      | Безупречный рубин                 | 无瑕的红宝石    |\n| 581 | gpr  | Perfect Ruby                     | 完美紅寶石     | perfekter Rubin                    | Rubí perfecto                        | Rubis parfait                           | Rubino Perfetto                       | 최상급 루비       | Doskonały rubin                | Rubí perfecto                         | 完璧なルビー         | Rubi Perfeito                       | Идеальный рубин                   | 完美的红宝石    |\n| 582 | gcw  | Chipped Diamond                  | 碎裂鑽石      | lädierter Diamant                  | Diamante fragmentado                 | Diamant abîmé                           | Diamante Spezzato                     | 최하급 다이아몬드    | Nadkruszony diament            | Diamante mellado                      | 欠けたダイヤモンド      | Diamante Lascado                    | Надколотый бриллиант              | 碎裂的钻石     |\n| 583 | gfw  | Flawed Diamond                   | 瑕疵鑽石      | fehlerhafter Diamant               | Diamante estropeado                  | Diamant imparfait                       | Diamante Incrinato                    | 하급 다이아몬드     | Diament ze skazą               | Diamante imperfecto                   | 傷のあるダイヤモンド     | Diamante Imperfeito                 | Мутный бриллиант                  | 有瑕疵的钻石    |\n| 584 | gsw  | Diamond                          | 鑽石        | Diamant                            | Diamante                             | Diamant                                 | Diamante                              | 다이아몬드        | Diament                        | [ms]Diamante                          | ダイアモンド         | Diamante                            | [ms]Алмаз                         | 钻石        |\n| 585 | glw  | Flawless Diamond                 | 無暇鑽石      | makelloser Diamant                 | Diamante sin defectos                | Diamant sans défaut                     | Diamante Integro                      | 상급 다이아몬드     | Diament bez skazy              | Diamante impecable                    | 上質なダイヤモンド      | Diamante Impecável                  | Безупречный бриллиант             | 无瑕的钻石     |\n| 586 | gpw  | Perfect Diamond                  | 完美鑽石      | perfekter Diamant                  | Diamante perfecto                    | Diamant parfait                         | Diamante Perfetto                     | 최상급 다이아몬드    | Doskonały diament              | Diamante perfecto                     | 完璧なダイヤモンド      | Diamante Perfeito                   | Идеальный бриллиант               | 完美的钻石     |\n| 587 | hp1  | Minor Healing Potion             | 弱效生命藥水    | schwacher Heiltrank                | Poción de salud menor                | Potion de vie mineure                   | Pozione Guaritrice Minore             | 미량의 치유 물약    | Mniejsza mikstura leczenia     | Poción de vida menor                  | ライフ・ポーション（極小）  | Poção de Cura Menor                 | Слабое зелье исцеления            | 初级治疗药水    |\n| 588 | hp2  | Light Healing Potion             | 輕效生命藥水    | leichter Heiltrank                 | Poción de salud ligera               | Potion de vie moyenne                   | Pozione Guaritrice Leggera            | 소량의 치유 물약    | Lekka mikstura leczenia        | Poción de vida leve                   | ライフ・ポーション（小）   | Poção de Cura Leve                  | Малое зелье исцеления             | 次级治疗药水    |\n| 589 | hp3  | Healing Potion                   | 生命藥水      | Heiltrank                          | Poción de salud                      | Potion de vie                           | Pozione Guaritrice                    | 치유 물약        | Mikstura leczenia              | Poción de vida                        | ライフ・ポーション（中）   | Poção de Cura                       | Зелье исцеления                   | 治疗药水      |\n| 590 | hp4  | Greater Healing Potion           | 強效生命藥水    | guter Heiltrank                    | Poción de salud superior             | Potion de vie supérieure                | Pozione Guaritrice Maggiore           | 대량의 치유 물약    | Większa mikstura leczenia      | Poción de vida mayor                  | ライフ・ポーション（大）   | Poção de Cura Superior              | Мощное зелье исцеления            | 高级治疗药水    |\n| 591 | hp5  | Super Healing Potion             | 特效生命藥水    | starker Heiltrank                  | Superpoción de salud                 | Super potion de vie                     | Pozione Guaritrice Superiore          | 초대량의 치유 물약   | Super mikstura leczenia        | Poción de vida especial               | ライフ・ポーション（特大）  | Poção de Cura Especial              | Сверхмощное зелье исцеления       | 超级治疗药水    |\n| 592 | mp1  | Minor Mana Potion                | 弱效法力藥水    | schwacher Manatrank                | Poción de maná menor                 | Potion de mana mineure                  | Pozione del Mana Minore               | 미량의 마나 물약    | Mniejsza mikstura many         | Poción de maná menor                  | マナ・ポーション（極小）   | Poção de Mana Menor                 | Слабое зелье маны                 | 初级法力药水    |\n| 593 | mp2  | Light Mana Potion                | 輕效法力藥水    | leichter Manatrank                 | Poción de maná ligera                | Potion de mana moyenne                  | Pozione del Mana Leggera              | 소량의 마나 물약    | Lekka mikstura many            | Poción de maná leve                   | マナ・ポーション（小）    | Poção de Mana Leve                  | Малое зелье маны                  | 次级法力药水    |\n| 594 | mp3  | Mana Potion                      | 法力藥水      | Manatrank                          | Poción de maná                       | Potion de mana                          | Pozione del Mana                      | 마나 물약        | Mikstura many                  | Poción de maná                        | マナ・ポーション（中）    | Poção de Mana                       | Зелье маны                        | 法力药水      |\n| 595 | mp4  | Greater Mana Potion              | 強效法力藥水    | guter Manatrank                    | Poción de maná superior              | Potion de mana supérieure               | Pozione del Mana Maggiore             | 대량의 마나 물약    | Większa mikstura many          | Poción de maná mayor                  | マナ・ポーション（大）    | Poção de Mana Superior              | Мощное зелье маны                 | 高级法力药水    |\n| 596 | mp5  | Super Mana Potion                | 特效法力藥水    | starker Manatrank                  | Superpoción de maná                  | Super potion de mana                    | Pozione del Mana Superiore            | 초대량의 마나 물약   | Super mikstura many            | Poción de maná especial               | マナ・ポーション（特大）   | Poção de Mana Especial              | Сверхмощное зелье маны            | 超级法力药水    |\n| 597 | skc  | Chipped Skull                    | 碎裂骷髏石     | lädierter Schädel                  | Cráneo fragmentado                   | Crâne abîmé                             | Teschio Spezzato                      | 최하급 해골       | Nadkruszona czaszka            | Cráneo mellado                        | 欠けた頭蓋骨         | Caveira Lascada                     | Надколотый череп                  | 碎裂的头骨宝石   |\n| 598 | skf  | Flawed Skull                     | 瑕疵骷髏石     | fehlerhafter Schädel               | Cráneo estropeado                    | Crâne imparfait                         | Teschio Incrinato                     | 하급 해골        | Czaszka ze skazą               | Cráneo imperfecto                     | 傷のある頭蓋骨        | Caveira Imperfeita                  | Поврежденный череп                | 有瑕疵的头骨宝石  |\n| 599 | sku  | Skull                            | 骷髏石       | Schädel                            | Cráneo                               | Crâne                                   | Teschio                               | 해골           | Czaszka                        | Cráneo                                | 頭蓋骨            | Caveira                             | Череп                             | 头骨宝石      |\n| 600 | skl  | Flawless Skull                   | 無暇骷髏石     | makelloser Schädel                 | Cráneo sin defectos                  | Crâne sans défaut                       | Teschio Integro                       | 상급 해골        | Czaszka bez skazy              | Cráneo impecable                      | 上質な頭蓋骨         | Caveira Impecável                   | Безупречный череп                 | 无瑕疵的头骨宝石  |\n| 601 | skz  | Perfect Skull                    | 完美骷髏石     | perfekter Schädel                  | Cráneo perfecto                      | Crâne parfait                           | Teschio Perfetto                      | 최상급 해골       | Doskonała czaszka              | Cráneo perfecto                       | 完璧な頭蓋骨         | Caveira Perfeita                    | Идеальный череп                   | 完美的头骨宝石   |\n| 602 | hrb  | Herb                             | 藥草        | [ns]Kraut                          | [fs]Hierba                           | [fs]Herbe                               | [fs]Erba                              | 약초           | Zioło                          | [fp]Hierbas                           | 薬草             | [fs]Erva                            | [pl]травы                         | 草药        |\n| 603 | cm1  | Small Charm                      | 小型咒符      | [ms]Kleiner Zauber                 | [ms]Dije pequeño                     | [ms]Charme mineur                       | [ms]Talismano Minore                  | 작은 부적        | [ms]Mniejszy Talizman          | [ms]Talismán pequeño                  | 護符（小）          | [ms]Patuá Pequeno                   | [ms]маленький оберег              | 小型神符      |\n| 604 | cm2  | Large Charm                      | 大型咒符      | [ms]Großer Zauber                  | [ms]Dije grande                      | [ms]Grand charme                        | [ms]Talismano Maggiore                | 큰 부적         | [ms]Duży Talizman              | [ms]Talismán grande                   | 護符（中）          | [ms]Patuá Grande                    | [ms]большой оберег                | 大型神符      |\n| 605 | cm3  | Grand Charm                      | 特大咒符      | [ms]Riesenzauber                   | [ms]Dije enorme                      | [ms]Charme majeur                       | [ms]Talismano Superiore               | 거대 부적        | [ms]Wielki Talizman            | [ms]Gran talismán                     | 護符（大）          | [ms]Patuá Grandioso                 | [ms]великий оберег                | 巨型神符      |\n| 610 | r01  | El Rune                          | 符文：艾爾     | [fs]El-Rune                        | Runa El                              | [fs]Rune El                             | [fs]Runa El                           | 엘 룬          | Runa El                        | Runa El                               | エル・ルーン         | Runa El                             | Руна Эл                           | 艾尔符文      |\n| 611 | r02  | Eld Rune                         | 符文：艾德     | [fs]Eld-Rune                       | Runa Eld                             | [fs]Rune Eld                            | [fs]Runa Eld                          | 엘드 룬         | Runa Eld                       | Runa Eld                              | エルド・ルーン        | Runa Eld                            | Руна Элд                          | 艾德符文      |\n| 612 | r03  | Tir Rune                         | 符文：特爾     | [fs]Tir-Rune                       | Runa Tir                             | [fs]Rune Tir                            | [fs]Runa Tir                          | 티르 룬         | Runa Tir                       | Runa Tir                              | ティア・ルーン        | Runa Tir                            | Руна Тир                          | 提尔符文      |\n| 613 | r04  | Nef Rune                         | 符文：那夫     | [fs]Nef-Rune                       | Runa Nef                             | [fs]Rune Nef                            | [fs]Runa Nef                          | 네프 룬         | Runa Nef                       | Runa Nef                              | ネフ・ルーン         | Runa Nef                            | Руна Неф                          | 奈夫符文      |\n| 614 | r05  | Eth Rune                         | 符文：愛斯     | [fs]Eth-Rune                       | Runa Eth                             | [fs]Rune Eth                            | [fs]Runa Eth                          | 에드 룬         | Runa Eth                       | Runa Eth                              | エス・ルーン         | Runa Eth                            | Руна Эт                           | 艾斯符文      |\n| 615 | r06  | Ith Rune                         | 符文：伊司     | [fs]Ith-Rune                       | Runa Ith                             | [fs]Rune Ith                            | [fs]Runa Ith                          | 아이드 룬        | Runa Ith                       | Runa Ith                              | イス・ルーン         | Runa Ith                            | Руна Ит                           | 伊司符文      |\n| 616 | r07  | Tal Rune                         | 符文：塔爾     | [fs]Tal-Rune                       | Runa Tal                             | [fs]Rune Tal                            | [fs]Runa Tal                          | 탈 룬          | Runa Tal                       | Runa Tal                              | タル・ルーン         | Runa Tal                            | Руна Тал                          | 塔尔符文      |\n| 617 | r08  | Ral Rune                         | 符文：拉爾     | [fs]Ral-Rune                       | Runa Ral                             | [fs]Rune Ral                            | [fs]Runa Ral                          | 랄 룬          | Runa Ral                       | Runa Ral                              | ラル・ルーン         | Runa Ral                            | Руна Рал                          | 拉尔符文      |\n| 618 | r09  | Ort Rune                         | 符文：歐特     | [fs]Ort-Rune                       | Runa Ort                             | [fs]Rune Ort                            | [fs]Runa Ort                          | 오르트 룬        | Runa Ort                       | Runa Ort                              | オルト・ルーン        | Runa Ort                            | Руна Орт                          | 欧特符文      |\n| 619 | r10  | Thul Rune                        | 符文：書爾     | [fs]Thul-Rune                      | Runa Thul                            | [fs]Rune Thul                           | [fs]Runa Thul                         | 주울 룬         | Runa Thul                      | Runa Thul                             | スル・ルーン         | Runa Thul                           | Руна Тул                          | 图尔符文      |\n| 620 | r11  | Amn Rune                         | 符文：安姆     | [fs]Amn-Rune                       | Runa Amn                             | [fs]Rune Amn                            | [fs]Runa Amn                          | 앰 룬          | Runa Amn                       | Runa Amn                              | アムン・ルーン        | Runa Amn                            | Руна Амн                          | 安姆符文      |\n| 621 | r12  | Sol Rune                         | 符文：索爾     | [fs]Sol-Rune                       | Runa Sol                             | [fs]Rune Sol                            | [fs]Runa Sol                          | 솔 룬          | Runa Sol                       | Runa Sol                              | ソル・ルーン         | Runa Sol                            | Руна Сол                          | 索尔符文      |\n| 622 | r13  | Shael Rune                       | 符文：夏      | [fs]Shael-Rune                     | Runa Shael                           | [fs]Rune Shael                          | [fs]Runa Shael                        | 샤엘 룬         | Runa Shael                     | Runa Shael                            | シャエル・ルーン       | Runa Shael                          | Руна Шаэл                         | 沙伊符文      |\n| 623 | r14  | Dol Rune                         | 符文：多爾     | [fs]Dol-Rune                       | Runa Dol                             | [fs]Rune Dol                            | [fs]Runa Dol                          | 돌 룬          | Runa Dol                       | Runa Dol                              | ドル・ルーン         | Runa Dol                            | Руна Дол                          | 多尔符文      |\n| 624 | r15  | Hel Rune                         | 符文：海爾     | [fs]Hel-Rune                       | Runa Hel                             | [fs]Rune Hel                            | [fs]Runa Hel                          | 헬 룬          | Runa Hel                       | Runa Hel                              | ヘル・ルーン         | Runa Hel                            | Руна Хел                          | 海尔符文      |\n| 625 | r16  | Io Rune                          | 符文：埃歐     | [fs]Io-Rune                        | Runa Io                              | [fs]Rune Io                             | [fs]Runa Io                           | 이오 룬         | Runa Io                        | Runa Io                               | イオ・ルーン         | Runa Io                             | Руна Ио                           | 艾欧符文      |\n| 626 | r17  | Lum Rune                         | 符文：盧姆     | [fs]Lum-Rune                       | Runa Lum                             | [fs]Rune Lum                            | [fs]Runa Lum                          | 룸 룬          | Runa Lum                       | Runa Lum                              | ラム・ルーン         | Runa Lum                            | Руна Лум                          | 卢姆符文      |\n| 627 | r18  | Ko Rune                          | 符文：科      | [fs]Ko-Rune                        | Runa Ko                              | [fs]Rune Ko                             | [fs]Runa Ko                           | 코 룬          | Runa Ko                        | Runa Ko                               | コー・ルーン         | Runa Ko                             | Руна Ко                           | 科符文       |\n| 628 | r19  | Fal Rune                         | 符文：法爾     | [fs]Fal-Rune                       | Runa Fal                             | [fs]Rune Fal                            | [fs]Runa Fal                          | 팔 룬          | Runa Fal                       | Runa Fal                              | ファル・ルーン        | Runa Fal                            | Руна Фал                          | 法尔符文      |\n| 629 | r20  | Lem Rune                         | 符文：藍姆     | [fs]Lem-Rune                       | Runa Lem                             | [fs]Rune Lem                            | [fs]Runa Lem                          | 렘 룬          | Runa Lem                       | Runa Lem                              | レム・ルーン         | Runa Lem                            | Руна Лем                          | 兰姆符文      |\n| 630 | r21  | Pul Rune                         | 符文：普爾     | [fs]Pul-Rune                       | Runa Pul                             | [fs]Rune Pul                            | [fs]Runa Pul                          | 풀 룬          | Runa Pul                       | Runa Pul                              | プル・ルーン         | Runa Pul                            | Руна Пул                          | 普尔符文      |\n| 631 | r22  | Um Rune                          | 符文：烏姆     | [fs]Um-Rune                        | Runa Um                              | [fs]Rune Um                             | [fs]Runa Um                           | 우움 룬         | Runa Um                        | Runa Um                               | アム・ルーン         | Runa Um                             | Руна Ум                           | 乌姆符文      |\n| 632 | r23  | Mal Rune                         | 符文：馬爾     | [fs]Mal-Rune                       | Runa Mal                             | [fs]Rune Mal                            | [fs]Runa Mal                          | 말 룬          | Runa Mal                       | Runa Mal                              | マル・ルーン         | Runa Mal                            | Руна Мал                          | 玛尔符文      |\n| 633 | r24  | Ist Rune                         | 符文：伊司特    | [fs]Ist-Rune                       | Runa Ist                             | [fs]Rune Ist                            | [fs]Runa Ist                          | 이스트 룬        | Runa Ist                       | Runa Ist                              | イスト・ルーン        | Runa Ist                            | Руна Ист                          | 伊司特符文     |\n| 634 | r25  | Gul Rune                         | 符文：古爾     | [fs]Gul-Rune                       | Runa Gul                             | [fs]Rune Gul                            | [fs]Runa Gul                          | 굴 룬          | Runa Gul                       | Runa Gul                              | ガル・ルーン         | Runa Gul                            | Руна Гул                          | 古尔符文      |\n| 635 | r26  | Vex Rune                         | 符文：伐克斯    | [fs]Vex-Rune                       | Runa Vex                             | [fs]Rune Vex                            | [fs]Runa Vex                          | 벡스 룬         | Runa Vex                       | Runa Vex                              | ヴェックス・ルーン      | Runa Vex                            | Руна Векс                         | 伐克斯符文     |\n| 636 | r27  | Ohm Rune                         | 符文：歐姆     | [fs]Ohm-Rune                       | Runa Ohm                             | [fs]Rune Ohm                            | [fs]Runa Ohm                          | 오움 룬         | Runa Ohm                       | Runa Ohm                              | オーム・ルーン        | Runa Ohm                            | Руна Ом                           | 欧姆符文      |\n| 637 | r28  | Lo Rune                          | 符文：羅      | [fs]Lo-Rune                        | Runa Lo                              | [fs]Rune Lo                             | [fs]Runa Lo                           | 로 룬          | Runa Lo                        | Runa Lo                               | ロー・ルーン         | Runa Lo                             | Руна Ло                           | 罗符文       |\n| 638 | r29  | Sur Rune                         | 符文：瑟      | [fs]Sur-Rune                       | Runa Sur                             | [fs]Rune Sur                            | [fs]Runa Sur                          | 수르 룬         | Runa Sur                       | Runa Sur                              | サー・ルーン         | Runa Sur                            | Руна Сур                          | 瑟符文       |\n| 639 | r30  | Ber Rune                         | 符文：貝      | [fs]Ber-Rune                       | Runa Ber                             | [fs]Rune Ber                            | [fs]Runa Ber                          | 베르 룬         | Runa Ber                       | Runa Ber                              | バー・ルーン         | Runa Ber                            | Руна Бер                          | 贝符文       |\n| 640 | r31  | Jah Rune                         | 符文：喬      | [fs]Jah-Rune                       | Runa Jah                             | [fs]Rune Jah                            | [fs]Runa Jah                          | 자 룬          | Runa Jah                       | Runa Jah                              | ジャー・ルーン        | Runa Jah                            | Руна Джа                          | 扎哈符文      |\n| 641 | r32  | Cham Rune                        | 符文：查姆     | [fs]Cham-Rune                      | Runa Cham                            | [fs]Rune Cham                           | [fs]Runa Cham                         | 참 룬          | Runa Cham                      | Runa Cham                             | チャム・ルーン        | Runa Cham                           | Руна Чам                          | 查姆符文      |\n| 642 | r33  | Zod Rune                         | 符文：薩德     | [fs]Zod-Rune                       | Runa Zod                             | [fs]Rune Zod                            | [fs]Runa Zod                          | 조드 룬         | Runa Zod                       | Runa Zod                              | ゾッド・ルーン        | Runa Zod                            | Руна Зод                          | 佐德符文      |\n| 643 | jew  | Jewel                            | 珠寶        | [ns]Juwel                          | [fs]Joya                             | [ms]Joyau                               | [ms]Gioiello                          | 주얼           | Klejnot                        | [fs]Joya                              | 宝玉             | [fs]Joia                            | [ms]cамоцвет                      | 珠宝        |\n| 644 | ice  | Malah's Potion                   | 瑪拉的藥水     | Malahs Elixier                     | Poción de Malah                      | Potion de Malah                         | Pozione di Malah                      | 말라의 물약       | Mikstura Malah                 | Poción de Malah                       | マラーのポーション      | Poção de Malah                      | Зелье Маллы                       | 马拉的药水     |\n| 645 | 0sc  | Scroll of Knowledge              | 知識卷軸      | Schriftrolle des Wissens           | Pergamino de conocimiento            | Parchemin de connaissance               | Pergamena della Conoscenza            | 지식의 두루마리     | Zwój Wiedzy                    | Pergamino de conocimiento             | 知識の巻物          | Pergaminho do Conhecimento          | Свиток знаний                     | 知识卷轴      |\n| 646 | tr2  | Scroll of Resistance             | 抗性卷軸      | Schriftrolle des Widerstandes      | Pergamino de resistencia             | Parchemin de résistance                 | Pergamena della resistenza            | 저항의 두루마리     | Zwój Odporności                | Pergamino de resistencia              | 耐性の巻物          | Pergaminho de Resistência           | Свиток сопротивления              | 抗性卷轴      |\n| 647 | pk1  | Key of Terror                    | 恐懼之鑰      | Schlüssel des Terrors              | Llave del terror                     | Clé de la Terreur                       | Chiave del Terrore                    | 공포의 열쇠       | Klucz Grozy                    | [fs]Llave de terror                   | 恐怖の鍵           | [fs]Chave do Terror                 | Ключ Ужаса                        | 恐惧之钥      |\n| 648 | pk2  | Key of Hate                      | 憎恨之鑰      | Schlüssel des Hasses               | Llave del odio                       | Clé de la Haine                         | Chiave dell'Odio                      | 증오의 열쇠       | Klucz Nienawiści               | [fs]Llave de odio                     | 憎悪の鍵           | [fs]Chave do Ódio                   | Ключ Ненависти                    | 憎恨之钥      |\n| 649 | pk3  | Key of Destruction               | 毀滅之鑰      | Schlüssel der Zerstörung           | Llave de la destrucción              | Clé de la Destruction                   | Chiave della Distruzione              | 파괴의 열쇠       | Klucz Zniszczenia              | [fs]Llave de destrucción              | 破壊の鍵           | [fs]Chave da Destruição             | Ключ Разрушения                   | 毁灭之钥      |\n| 650 | dhn  | Diablo's Horn                    | 迪亞布羅之角    | Diablos Horn                       | Cuerno de Diablo                     | Corne de Diablo                         | Corno di Diablo                       | 디아블로의 뿔      | Róg Diablo                     | [ms]Cuerno de Diablo                  | ディアブロの角        | [ms]Chifre de Diablo                | Рог Диабло                        | 迪亚波罗的角    |\n| 651 | bey  | Baal's Eye                       | 巴爾之眼      | Baals Auge                         | Ojo de Baal                          | Œil de Baal                             | Occhio di Baal                        | 바알의 눈        | Oko Baala                      | [ms]Ojo de Baal                       | バールの目          | [ms]Olho de Baal                    | Глаз Баала                        | 巴尔的眼睛     |\n| 652 | mbr  | Mephisto's Brain                 | 墨菲斯托之腦    | Mephistos Gehirn                   | Cerebro de Mefisto                   | Cerveau de Méphisto                     | Cervello di Mefisto                   | 메피스토의 뇌      | Mózg Mefista                   | [ms]Cerebro de Mefisto                | メフィストの脳        | [ms]Cérebro de Mefisto              | Мозг Мефисто                      | 墨菲斯托的大脑   |\n| 653 | toa  | Token of Absolution              | 赦免徽章      | Zeichen der Absolution             | Muestra de absolución                | Gage d’absolution                       | Gettone dell'Assoluzione              | 면죄의 징표       | Znak Rozgrzeszenia             | Insignia de la absolución             | 赦しのトークン        | Insígnia da Absolvição              | Талисман очищения                 | 赦免之证      |\n| 654 | tes  | Twisted Essence of Suffering     | 扭曲的苦怨精華   | Verdorbene Essenz des Leidens      | Esencia del sufrimiento retorcida    | Essence tordue de souffrance            | Essenza Perversa della Sofferenza     | 뒤틀린 고통의 정수   | Spaczona Esencja Cierpienia    | [fs]Esencia retorcida de sufrimiento  | 捻じれた苦痛のエッセンス   | [fs]Essência Perversa do Sofrimento | Искаженная сущность Страдания     | 扭曲的痛苦精华   |\n| 655 | ceh  | Charged Essence of Hatred        | 充盈的憎恨精華   | Geladene Essenz des Hasses         | Esencia del odio cargada             | Essence chargée de haine                | Essenza Elettrica dell'Odio           | 차오른 증오의 정수   | Wzmocniona Esencja Nienawiści  | [fs]Esencia cargada de odio           | 蓄積した憎悪のエッセンス   | [fs]Essência Carregada do Ódio      | Заряженная сущность Ненависти     | 充能的憎恨精华   |\n| 656 | bet  | Burning Essence of Terror        | 燃燒的恐懼精華   | Brennende Essenz des Schreckens    | Esencia del terror ardiente          | Essence brûlante de terreur             | Essenza Rovente del Terrore           | 불타는 공포의 정수   | Płonąca Esencja Grozy          | [fs]Esencia ardiente de terror        | 燃え盛る恐怖のエッセンス   | [fs]Essência Flamejante do Terror   | Обжигающая сущность Ужаса         | 燃烧的恐惧精华   |\n| 657 | fed  | Festering Essence of Destruction | 潰爛的毀滅精華   | Eiternde Essenz der Zerstörung     | Esencia de la destrucción infecta    | Essence suintante de destruction        | Essenza Putrescente della Distruzione | 곪은 파괴의 정수    | Ropiejąca Esencja Zniszczenia  | [fs]Esencia pestilente de destrucción | 煮えたぎる破壊のエッセンス  | [fs]Essência Fétida da Destruição   | Гниющая эссенция Разрушения       | 腐烂的毁灭精华   |\n| 658 | std  | Standard of Heroes               | 英雄旗幟      | Standarte der Helden               | Estandarte de los héroes             | Étendard de héros                       | Stendardo degli Eroi                  | 영웅들의 깃발      | Sztandar Bohaterów             | [ms]Estandarte de héroes              | 英雄の旗           | [ms]Estandarte de Heróis            | Знамя героя                       | 英雄的旗帜     |\n"
  },
  {
    "path": "doc/KeyMapping.md",
    "content": "Modifiers:\n\n| string           | key         |\n|------------------|-------------|\n| `SHIFT`          | SHIFT key   |\n| `CONTROL` `CTRL` | CTRL key    |\n| `ALT`            | ALT key     |\n| `WIN`            | Windows key |\n\nKeys:\n\n| string                | key                                      |\n|-----------------------|------------------------------------------|\n| `0`                   | 0 key                                    |\n| `1`                   | 1 key                                    |\n| `2`                   | 2 key                                    |\n| `3`                   | 3 key                                    |\n| `4`                   | 4 key                                    |\n| `5`                   | 5 key                                    |\n| `6`                   | 6 key                                    |\n| `7`                   | 7 key                                    |\n| `8`                   | 8 key                                    |\n| `9`                   | 9 key                                    |\n| `A`                   | A key                                    |\n| `B`                   | B key                                    |\n| `C`                   | C key                                    |\n| `D`                   | D key                                    |\n| `E`                   | E key                                    |\n| `F`                   | F key                                    |\n| `G`                   | G key                                    |\n| `H`                   | H key                                    |\n| `I`                   | I key                                    |\n| `J`                   | J key                                    |\n| `K`                   | K key                                    |\n| `L`                   | L key                                    |\n| `M`                   | M key                                    |\n| `N`                   | N key                                    |\n| `O`                   | O key                                    |\n| `P`                   | P key                                    |\n| `Q`                   | Q key                                    |\n| `R`                   | R key                                    |\n| `S`                   | S key                                    |\n| `T`                   | T key                                    |\n| `U`                   | U key                                    |\n| `V`                   | V key                                    |\n| `W`                   | W key                                    |\n| `X`                   | X key                                    |\n| `Y`                   | Y key                                    |\n| `Z`                   | Z key                                    |\n| `;`                   | ; key                                    |\n| `/`                   | / key                                    |\n| `~`                   | ~ key                                    |\n| `[`                   | [ key                                    |\n| `\\`                   | \\ key                                    |\n| `]`                   | ] key                                    |\n| `'`                   | ' key                                    |\n| `LBUTTON`             | Left mouse button                        |\n| `RBUTTON`             | Right mouse button                       |\n| `CANCEL`              | Control-break processing                 |\n| `MBUTTON`             | Middle mouse button (three-button mouse) |\n| `XBUTTON1`            | X1 mouse button                          |\n| `XBUTTON2`            | X2 mouse button                          |\n| `BACK` `BACKSPACE`    | BACKSPACE key                            |\n| `TAB`                 | TAB key                                  |\n| `CLEAR`               | CLEAR key                                |\n| `RETURN` `ENTER`      | ENTER key                                |\n| `PAUSE`               | PAUSE key                                |\n| `CAPITAL` `CAPSLOCK`  | CAPS LOCK key                            |\n| `KANA`                | IME Kana mode                            |\n| `HANGUL`              | IME Hangul mode                          |\n| `JUNJA`               | IME Junja mode                           |\n| `FINAL`               | IME final mode                           |\n| `HANJA`               | IME Hanja mode                           |\n| `KANJI`               | IME Kanji mode                           |\n| `ESCAPE` `ESC`        | ESC key                                  |\n| `CONVERT`             | IME convert                              |\n| `NONCONVERT`          | IME nonconvert                           |\n| `ACCEPT`              | IME accept                               |\n| `MODECHANGE`          | IME mode change request                  |\n| `SPACE`               | SPACEBAR                                 |\n| `PRIOR`               | PAGE UP key                              |\n| `NEXT`                | PAGE DOWN key                            |\n| `END`                 | END key                                  |\n| `HOME`                | HOME key                                 |\n| `LEFT`                | LEFT ARROW key                           |\n| `UP`                  | UP ARROW key                             |\n| `RIGHT`               | RIGHT ARROW key                          |\n| `DOWN`                | DOWN ARROW key                           |\n| `SELECT`              | SELECT key                               |\n| `PRINT`               | PRINT key                                |\n| `EXECUTE`             | EXECUTE key                              |\n| `SNAPSHOT`            | PRINT SCREEN key                         |\n| `INSERT`              | INS key                                  |\n| `DELETE`              | DEL key                                  |\n| `HELP`                | HELP key                                 |\n| `APPS`                | Applications key (Natural keyboard)      |\n| `SLEEP`               | Computer Sleep key                       |\n| `NUMPAD0` `NUM0`      | Numeric keypad 0 key                     |\n| `NUMPAD1` `NUM1`      | Numeric keypad 1 key                     |\n| `NUMPAD2` `NUM2`      | Numeric keypad 2 key                     |\n| `NUMPAD3` `NUM3`      | Numeric keypad 3 key                     |\n| `NUMPAD4` `NUM4`      | Numeric keypad 4 key                     |\n| `NUMPAD5` `NUM5`      | Numeric keypad 5 key                     |\n| `NUMPAD6` `NUM6`      | Numeric keypad 6 key                     |\n| `NUMPAD7` `NUM7`      | Numeric keypad 7 key                     |\n| `NUMPAD8` `NUM8`      | Numeric keypad 8 key                     |\n| `NUMPAD9` `NUM9`      | Numeric keypad 9 key                     |\n| `MULTIPLY`            | Multiply key                             |\n| `ADD`                 | Add key                                  |\n| `SUBTRACT` `MINUS`    | Subtract key                             |\n| `DECIMAL`             | Decimal key                              |\n| `DIVIDE`              | Divide key                               |\n| `F1`                  | F1 key                                   |\n| `F2`                  | F2 key                                   |\n| `F3`                  | F3 key                                   |\n| `F4`                  | F4 key                                   |\n| `F5`                  | F5 key                                   |\n| `F6`                  | F6 key                                   |\n| `F7`                  | F7 key                                   |\n| `F8`                  | F8 key                                   |\n| `F9`                  | F9 key                                   |\n| `F10`                 | F10 key                                  |\n| `F11`                 | F11 key                                  |\n| `F12`                 | F12 key                                  |\n| `F13`                 | F13 key                                  |\n| `F14`                 | F14 key                                  |\n| `F15`                 | F15 key                                  |\n| `F16`                 | F16 key                                  |\n| `F17`                 | F17 key                                  |\n| `F18`                 | F18 key                                  |\n| `F19`                 | F19 key                                  |\n| `F20`                 | F20 key                                  |\n| `F21`                 | F21 key                                  |\n| `F22`                 | F22 key                                  |\n| `F23`                 | F23 key                                  |\n| `F24`                 | F24 key                                  |\n| `NUMLOCK`             | NUM LOCK key                             |\n| `SCROLL`              | SCROLL LOCK key                          |\n| `BROWSER_BACK`        | Browser Back key                         |\n| `BROWSER_FORWARD`     | Browser Forward key                      |\n| `BROWSER_REFRESH`     | Browser Refresh key                      |\n| `BROWSER_STOP`        | Browser Stop key                         |\n| `BROWSER_SEARCH`      | Browser Search key                       |\n| `BROWSER_FAVORITES`   | Browser Favorites key                    |\n| `BROWSER_HOME`        | Browser Start and Home key               |\n| `VOLUME_MUTE`         | Volume Mute key                          |\n| `VOLUME_DOWN`         | Volume Down key                          |\n| `VOLUME_UP`           | Volume Up key                            |\n| `MEDIA_NEXT_TRACK`    | Next Track key                           |\n| `MEDIA_PREV_TRACK`    | Previous Track key                       |\n| `MEDIA_STOP`          | Stop Media key                           |\n| `MEDIA_PLAY_PAUSE`    | Play/Pause Media key                     |\n| `LAUNCH_MAIL`         | Start Mail key                           |\n| `LAUNCH_MEDIA_SELECT` | Select Media key                         |\n| `LAUNCH_APP1`         | Start Application 1 key                  |\n| `LAUNCH_APP2`         | Start Application 2 key                  |\n| `OEM_PLUS`            | For any country/region, the '+' key      |\n| `OEM_COMMA`           | For any country/region, the ',' key      |\n| `OEM_MINUS`           | For any country/region, the '-' key      |\n| `OEM_PERIOD`          | For any country/region, the '.' key      |\n| `PROCESSKEY`          | IME PROCESS key                          |\n| `ATTN`                | Attn key                                 |\n| `CRSEL`               | CrSel key                                |\n| `EXSEL`               | ExSel key                                |\n| `EREOF`               | Erase EOF key                            |\n| `PLAY`                | Play key                                 |\n| `ZOOM`                | Zoom key                                 |\n| `PA1`                 | PA1 key                                  |\n| `OEM_CLEAR`           | Clear key                                |"
  },
  {
    "path": "doc/LICENSE.lua54",
    "content": "Copyright © 1994–2021 Lua.org, PUC-Rio.\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n"
  },
  {
    "path": "doc/Plugin.md",
    "content": "# Plugin system document\n## Programming Language\n* The plugin system is designed to be written in [lua](https://www.lua.org) language\n\n## User Types\n| name     | fields/methods               | description                                                                                                                                                                                                                                                                                                          |\n|----------|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Config   | show                         | `show` in `[ui]` section of D2RMH.ini                                                                                                                                                                                                                                                                                |\n|          | scale                        | `scale` in `[ui]` section of D2RMH.ini                                                                                                                                                                                                                                                                               |\n||||\n| Player   | act                          | Current ACT (0=>ACT I, ... 4=>ACT V)                                                                                                                                                                                                                                                                                 |\n|          | seed                         | Map generation seed                                                                                                                                                                                                                                                                                                  |\n|          | difficulty                   | Difficulty, 0=>Normal 1=>Nightmare 2=>Hell                                                                                                                                                                                                                                                                           |\n|          | map                          | Current map level id                                                                                                                                                                                                                                                                                                 |\n|          | pos_x                        | Position X                                                                                                                                                                                                                                                                                                           |\n|          | pos_y                        | Position Y                                                                                                                                                                                                                                                                                                           |\n|          | name                         | Player Name                                                                                                                                                                                                                                                                                                          |\n|          | stats                        | Player Stats in array with subindex:<br/>1 =>Strength<br/>2 =>Energy<br/>3 =>Dexterity<br/>4 =>Vitality<br/>5 =>Statpts<br/>6 =>Newskills<br/>7 =>Hitpoints<br/>8 =>Maxhp<br/>9 =>Mana<br/>10 =>Maxmana<br/>11 =>Stamina<br/>12 =>Maxstamina<br/>13 =>Level<br/>14 =>Experience<br/>15 =>Gold<br/>16 =>Goldbank<br/> |\n||||\n| Skill    | level                        | Skill level                                                                                                                                                                                                                                                                                                          |\n|          | quantity                     | Skill Quantity (Throw weapon/Scrolls/etc.)                                                                                                                                                                                                                                                                           |\n||||\n| TextList | x                            | Position X, should be in `[0.0,1.0]`, the size rate relative to D2R window width                                                                                                                                                                                                                                     |\n|          | y                            | Position Y, should be in `[0.0,1.0]`, the size rate relative to D2R window height                                                                                                                                                                                                                                    |\n|          | align                        | Text align: 0=>left 1=>center 2->right                                                                                                                                                                                                                                                                               |\n|          | valign                       | Text verticle align: 0=>top 1=>bottom                                                                                                                                                                                                                                                                                |\n|          | add(str, duration, fontSize) | add a string to TextList, duplicated strings will be merged.<br/>`duraion`: in milliseconds<br/>`fontSize`: 0 for default message font size, -1 for move string to end of text list                                                                                                                                  |\n|          | clear()                      | clear whole TextList                                                                                                                                                                                                                                                                                                 |                                                                                                                                                                                                                                                                                                 |\n\n\n## Functions\n| name                                                     | returns  | description                                                                                                                                                                          |\n|----------------------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| register_plugin(interval, func)                          |          | Register a plugin, runs `func` in `interval`(in milliseconds)                                                                                                                        |\n| register_plugin(hotkey, on, interval, func, toggle_func) |          | Register a plugin, runs `func` in `interval`(in milliseconds)<br/>Use `hotkey` to toggle<br/>`on` is the default enabled status<br/>`toggle_func` is called when toggle using hotkey |\n| register_hotkey(hotkey, func)                            |          | Register a hotkey. When the key is pressed, run `func`                                                                                                                               |\n| kill_process()                                           |          | Kill D2R process                                                                                                                                                                     |\n| message_box(str,type)                                    | int      | Popup a message box, with `str` and `type`(check `uType` and return value on [MSDN](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxw))              |\n| flush_overlay()                                          |          | Flush the drawing overlay                                                                                                                                                            |\n| reload_config()                                          |          | Reload config file                                                                                                                                                                   |\n| get_config()                                             | Config   | Get current config                                                                                                                                                                   |\n| get_player()                                             | Player   | Get current player                                                                                                                                                                   |\n| get_skill(skill_id)                                      | Skill    | Find skill data                                                                                                                                                                      |\n| create_text_list(name)                                   | TextList | Create a text list, or get existing one if there is already a text list with name=`name`                                                                                             |\n| remove_text_list(name)                                   |          | Remove a text list                                                                                                                                                                   |\n| key_press(key)                                           |          | press a key                                                                                                                                                                          |\n| mouse_move(x, y)                                         |          | Move mouse cursor to (x, y) in D2R window                                                                                                                                            |\n| mouse_click(which)                                       |          | Mouse button click, `which`: (0=LeftButton 1=RightButton 2=MiddleButton                                                                                                              |\n| delay(ms)                                                |          | Delay for `ms` milliseconds                                                                                                                                                          |"
  },
  {
    "path": "doc/Skill.md",
    "content": "﻿| Skill Name                 | ID  | CharClass |\n|:---------------------------|:----|:----------|\n| Attack                     | 0   |           |\n| Kick                       | 1   |           |\n| Throw                      | 2   |           |\n| Unsummon                   | 3   |           |\n| Left Hand Throw            | 4   |           |\n| Left Hand Swing            | 5   |           |\n| Magic Arrow                | 6   | ama       |\n| Fire Arrow                 | 7   | ama       |\n| Inner Sight                | 8   | ama       |\n| Critical Strike            | 9   | ama       |\n| Jab                        | 10  | ama       |\n| Cold Arrow                 | 11  | ama       |\n| Multiple Shot              | 12  | ama       |\n| Dodge                      | 13  | ama       |\n| Power Strike               | 14  | ama       |\n| Poison Javelin             | 15  | ama       |\n| Exploding Arrow            | 16  | ama       |\n| Slow Missiles              | 17  | ama       |\n| Avoid                      | 18  | ama       |\n| Impale                     | 19  | ama       |\n| Lightning Bolt             | 20  | ama       |\n| Ice Arrow                  | 21  | ama       |\n| Guided Arrow               | 22  | ama       |\n| Penetrate                  | 23  | ama       |\n| Charged Strike             | 24  | ama       |\n| Plague Javelin             | 25  | ama       |\n| Strafe                     | 26  | ama       |\n| Immolation Arrow           | 27  | ama       |\n| Dopplezon                  | 28  | ama       |\n| Evade                      | 29  | ama       |\n| Fend                       | 30  | ama       |\n| Freezing Arrow             | 31  | ama       |\n| Valkyrie                   | 32  | ama       |\n| Pierce                     | 33  | ama       |\n| Lightning Strike           | 34  | ama       |\n| Lightning Fury             | 35  | ama       |\n| Fire Bolt                  | 36  | sor       |\n| Warmth                     | 37  | sor       |\n| Charged Bolt               | 38  | sor       |\n| Ice Bolt                   | 39  | sor       |\n| Frozen Armor               | 40  | sor       |\n| Inferno                    | 41  | sor       |\n| Static Field               | 42  | sor       |\n| Telekinesis                | 43  | sor       |\n| Frost Nova                 | 44  | sor       |\n| Ice Blast                  | 45  | sor       |\n| Blaze                      | 46  | sor       |\n| Fire Ball                  | 47  | sor       |\n| Nova                       | 48  | sor       |\n| Lightning                  | 49  | sor       |\n| Shiver Armor               | 50  | sor       |\n| Fire Wall                  | 51  | sor       |\n| Enchant                    | 52  | sor       |\n| Chain Lightning            | 53  | sor       |\n| Teleport                   | 54  | sor       |\n| Glacial Spike              | 55  | sor       |\n| Meteor                     | 56  | sor       |\n| Thunder Storm              | 57  | sor       |\n| Energy Shield              | 58  | sor       |\n| Blizzard                   | 59  | sor       |\n| Chilling Armor             | 60  | sor       |\n| Fire Mastery               | 61  | sor       |\n| Hydra                      | 62  | sor       |\n| Lightning Mastery          | 63  | sor       |\n| Frozen Orb                 | 64  | sor       |\n| Cold Mastery               | 65  | sor       |\n| Amplify Damage             | 66  | nec       |\n| Teeth                      | 67  | nec       |\n| Bone Armor                 | 68  | nec       |\n| Skeleton Mastery           | 69  | nec       |\n| Raise Skeleton             | 70  | nec       |\n| Dim Vision                 | 71  | nec       |\n| Weaken                     | 72  | nec       |\n| Poison Dagger              | 73  | nec       |\n| Corpse Explosion           | 74  | nec       |\n| Clay Golem                 | 75  | nec       |\n| Iron Maiden                | 76  | nec       |\n| Terror                     | 77  | nec       |\n| Bone Wall                  | 78  | nec       |\n| Golem Mastery              | 79  | nec       |\n| Raise Skeletal Mage        | 80  | nec       |\n| Confuse                    | 81  | nec       |\n| Life Tap                   | 82  | nec       |\n| Poison Explosion           | 83  | nec       |\n| Bone Spear                 | 84  | nec       |\n| BloodGolem                 | 85  | nec       |\n| Attract                    | 86  | nec       |\n| Decrepify                  | 87  | nec       |\n| Bone Prison                | 88  | nec       |\n| Summon Resist              | 89  | nec       |\n| IronGolem                  | 90  | nec       |\n| Lower Resist               | 91  | nec       |\n| Poison Nova                | 92  | nec       |\n| Bone Spirit                | 93  | nec       |\n| FireGolem                  | 94  | nec       |\n| Revive                     | 95  | nec       |\n| Sacrifice                  | 96  | pal       |\n| Smite                      | 97  | pal       |\n| Might                      | 98  | pal       |\n| Prayer                     | 99  | pal       |\n| Resist Fire                | 100 | pal       |\n| Holy Bolt                  | 101 | pal       |\n| Holy Fire                  | 102 | pal       |\n| Thorns                     | 103 | pal       |\n| Defiance                   | 104 | pal       |\n| Resist Cold                | 105 | pal       |\n| Zeal                       | 106 | pal       |\n| Charge                     | 107 | pal       |\n| Blessed Aim                | 108 | pal       |\n| Cleansing                  | 109 | pal       |\n| Resist Lightning           | 110 | pal       |\n| Vengeance                  | 111 | pal       |\n| Blessed Hammer             | 112 | pal       |\n| Concentration              | 113 | pal       |\n| Holy Freeze                | 114 | pal       |\n| Vigor                      | 115 | pal       |\n| Conversion                 | 116 | pal       |\n| Holy Shield                | 117 | pal       |\n| Holy Shock                 | 118 | pal       |\n| Sanctuary                  | 119 | pal       |\n| Meditation                 | 120 | pal       |\n| Fist of the Heavens        | 121 | pal       |\n| Fanaticism                 | 122 | pal       |\n| Conviction                 | 123 | pal       |\n| Redemption                 | 124 | pal       |\n| Salvation                  | 125 | pal       |\n| Bash                       | 126 | bar       |\n| Sword Mastery              | 127 | bar       |\n| Axe Mastery                | 128 | bar       |\n| Mace Mastery               | 129 | bar       |\n| Howl                       | 130 | bar       |\n| Find Potion                | 131 | bar       |\n| Leap                       | 132 | bar       |\n| Double Swing               | 133 | bar       |\n| Pole Arm Mastery           | 134 | bar       |\n| Throwing Mastery           | 135 | bar       |\n| Spear Mastery              | 136 | bar       |\n| Taunt                      | 137 | bar       |\n| Shout                      | 138 | bar       |\n| Stun                       | 139 | bar       |\n| Double Throw               | 140 | bar       |\n| Increased Stamina          | 141 | bar       |\n| Find Item                  | 142 | bar       |\n| Leap Attack                | 143 | bar       |\n| Concentrate                | 144 | bar       |\n| Iron Skin                  | 145 | bar       |\n| Battle Cry                 | 146 | bar       |\n| Frenzy                     | 147 | bar       |\n| Increased Speed            | 148 | bar       |\n| Battle Orders              | 149 | bar       |\n| Grim Ward                  | 150 | bar       |\n| Whirlwind                  | 151 | bar       |\n| Berserk                    | 152 | bar       |\n| Natural Resistance         | 153 | bar       |\n| War Cry                    | 154 | bar       |\n| Battle Command             | 155 | bar       |\n| Fire Hit                   | 156 |           |\n| UnHolyBolt                 | 157 |           |\n| SkeletonRaise              | 158 |           |\n| MaggotEgg                  | 159 |           |\n| ShamanFire                 | 160 |           |\n| MagottUp                   | 161 |           |\n| MagottDown                 | 162 |           |\n| MagottLay                  | 163 |           |\n| AndrialSpray               | 164 |           |\n| Jump                       | 165 |           |\n| Swarm Move                 | 166 |           |\n| Nest                       | 167 |           |\n| Quick Strike               | 168 |           |\n| VampireFireball            | 169 |           |\n| VampireFirewall            | 170 |           |\n| VampireMeteor              | 171 |           |\n| GargoyleTrap               | 172 |           |\n| SpiderLay                  | 173 |           |\n| VampireHeal                | 174 |           |\n| VampireRaise               | 175 |           |\n| Submerge                   | 176 |           |\n| FetishAura                 | 177 |           |\n| FetishInferno              | 178 |           |\n| ZakarumHeal                | 179 |           |\n| Emerge                     | 180 |           |\n| Resurrect                  | 181 |           |\n| Bestow                     | 182 |           |\n| MissileSkill1              | 183 |           |\n| MonTeleport                | 184 |           |\n| PrimeLightning             | 185 |           |\n| PrimeBolt                  | 186 |           |\n| PrimeBlaze                 | 187 |           |\n| PrimeFirewall              | 188 |           |\n| PrimeSpike                 | 189 |           |\n| PrimeIceNova               | 190 |           |\n| PrimePoisonball            | 191 |           |\n| PrimePoisonNova            | 192 |           |\n| DiabLight                  | 193 |           |\n| DiabCold                   | 194 |           |\n| DiabFire                   | 195 |           |\n| FingerMageSpider           | 196 |           |\n| DiabWall                   | 197 |           |\n| DiabRun                    | 198 |           |\n| DiabPrison                 | 199 |           |\n| PoisonBallTrap             | 200 |           |\n| AndyPoisonBolt             | 201 |           |\n| HireableMissile            | 202 |           |\n| DesertTurret               | 203 |           |\n| ArcaneTower                | 204 |           |\n| MonBlizzard                | 205 |           |\n| Mosquito                   | 206 |           |\n| CursedBallTrapRight        | 207 |           |\n| CursedBallTrapLeft         | 208 |           |\n| MonFrozenArmor             | 209 |           |\n| MonBoneArmor               | 210 |           |\n| MonBoneSpirit              | 211 |           |\n| MonCurseCast               | 212 |           |\n| HellMeteor                 | 213 |           |\n| RegurgitatorEat            | 214 |           |\n| MonFrenzy                  | 215 |           |\n| QueenDeath                 | 216 |           |\n| Scroll of Identify         | 217 |           |\n| Book of Identify           | 218 |           |\n| Scroll of Townportal       | 219 |           |\n| Book of Townportal         | 220 |           |\n| Raven                      | 221 | dru       |\n| Plague Poppy               | 222 | dru       |\n| Wearwolf                   | 223 | dru       |\n| Shape Shifting             | 224 | dru       |\n| Firestorm                  | 225 | dru       |\n| Oak Sage                   | 226 | dru       |\n| Summon Spirit Wolf         | 227 | dru       |\n| Wearbear                   | 228 | dru       |\n| Molten Boulder             | 229 | dru       |\n| Arctic Blast               | 230 | dru       |\n| Cycle of Life              | 231 | dru       |\n| Feral Rage                 | 232 | dru       |\n| Maul                       | 233 | dru       |\n| Eruption                   | 234 | dru       |\n| Cyclone Armor              | 235 | dru       |\n| Heart of Wolverine         | 236 | dru       |\n| Summon Fenris              | 237 | dru       |\n| Rabies                     | 238 | dru       |\n| Fire Claws                 | 239 | dru       |\n| Twister                    | 240 | dru       |\n| Vines                      | 241 | dru       |\n| Hunger                     | 242 | dru       |\n| Shock Wave                 | 243 | dru       |\n| Volcano                    | 244 | dru       |\n| Tornado                    | 245 | dru       |\n| Spirit of Barbs            | 246 | dru       |\n| Summon Grizzly             | 247 | dru       |\n| Fury                       | 248 | dru       |\n| Armageddon                 | 249 | dru       |\n| Hurricane                  | 250 | dru       |\n| Fire Trauma                | 251 | ass       |\n| Claw Mastery               | 252 | ass       |\n| Psychic Hammer             | 253 | ass       |\n| Tiger Strike               | 254 | ass       |\n| Dragon Talon               | 255 | ass       |\n| Shock Field                | 256 | ass       |\n| Blade Sentinel             | 257 | ass       |\n| Quickness                  | 258 | ass       |\n| Fists of Fire              | 259 | ass       |\n| Dragon Claw                | 260 | ass       |\n| Charged Bolt Sentry        | 261 | ass       |\n| Wake of Fire Sentry        | 262 | ass       |\n| Weapon Block               | 263 | ass       |\n| Cloak of Shadows           | 264 | ass       |\n| Cobra Strike               | 265 | ass       |\n| Blade Fury                 | 266 | ass       |\n| Fade                       | 267 | ass       |\n| Shadow Warrior             | 268 | ass       |\n| Claws of Thunder           | 269 | ass       |\n| Dragon Tail                | 270 | ass       |\n| Lightning Sentry           | 271 | ass       |\n| Inferno Sentry             | 272 | ass       |\n| Mind Blast                 | 273 | ass       |\n| Blades of Ice              | 274 | ass       |\n| Dragon Flight              | 275 | ass       |\n| Death Sentry               | 276 | ass       |\n| Blade Shield               | 277 | ass       |\n| Venom                      | 278 | ass       |\n| Shadow Master              | 279 | ass       |\n| Royal Strike               | 280 | ass       |\n| Wake Of Destruction Sentry | 281 |           |\n| Imp Inferno                | 282 |           |\n| Imp Fireball               | 283 |           |\n| Baal Taunt                 | 284 |           |\n| Baal Corpse Explode        | 285 |           |\n| Baal Monster Spawn         | 286 |           |\n| Catapult Charged Ball      | 287 |           |\n| Catapult Spike Ball        | 288 |           |\n| Suck Blood                 | 289 |           |\n| Cry Help                   | 290 |           |\n| Healing Vortex             | 291 |           |\n| Teleport 2                 | 292 |           |\n| Self-resurrect             | 293 |           |\n| Vine Attack                | 294 |           |\n| Overseer Whip              | 295 |           |\n| Barbs Aura                 | 296 |           |\n| Wolverine Aura             | 297 |           |\n| Oak Sage Aura              | 298 |           |\n| Imp Fire Missile           | 299 |           |\n| Impregnate                 | 300 |           |\n| Siege Beast Stomp          | 301 |           |\n| MinionSpawner              | 302 |           |\n| CatapultBlizzard           | 303 |           |\n| CatapultPlague             | 304 |           |\n| CatapultMeteor             | 305 |           |\n| BoltSentry                 | 306 |           |\n| CorpseCycler               | 307 |           |\n| DeathMaul                  | 308 |           |\n| Defense Curse              | 309 |           |\n| Blood Mana                 | 310 |           |\n| mon inferno sentry         | 311 |           |\n| mon death sentry           | 312 |           |\n| sentry lightning           | 313 |           |\n| fenris rage                | 314 |           |\n| Baal Tentacle              | 315 |           |\n| Baal Nova                  | 316 |           |\n| Baal Inferno               | 317 |           |\n| Baal Cold Missiles         | 318 |           |\n| MegademonInferno           | 319 |           |\n| EvilHutSpawner             | 320 |           |\n| CountessFirewall           | 321 |           |\n| ImpBolt                    | 322 |           |\n| Horror Arctic Blast        | 323 |           |\n| death sentry ltng          | 324 |           |\n| VineCycler                 | 325 |           |\n| BearSmite                  | 326 |           |\n| Resurrect2                 | 327 |           |\n| BloodLordFrenzy            | 328 |           |\n| Baal Teleport              | 329 |           |\n| Imp Teleport               | 330 |           |\n| Baal Clone Teleport        | 331 |           |\n| ZakarumLightning           | 332 |           |\n| VampireMissile             | 333 |           |\n| MephistoMissile            | 334 |           |\n| DoomKnightMissile          | 335 |           |\n| RogueMissile               | 336 |           |\n| HydraMissile               | 337 |           |\n| NecromageMissile           | 338 |           |\n| MonBow                     | 339 |           |\n| MonFireArrow               | 340 |           |\n| MonColdArrow               | 341 |           |\n| MonExplodingArrow          | 342 |           |\n| MonFreezingArrow           | 343 |           |\n| MonPowerStrike             | 344 |           |\n| SuccubusBolt               | 345 |           |\n| MephFrostNova              | 346 |           |\n| MonIceSpear                | 347 |           |\n| ShamanIce                  | 348 |           |\n| Diablogeddon               | 349 |           |\n| Delerium Change            | 350 |           |\n| NihlathakCorpseExplosion   | 351 |           |\n| SerpentCharge              | 352 |           |\n| Trap Nova                  | 353 |           |\n| UnHolyBoltEx               | 354 |           |\n| ShamanFireEx               | 355 |           |\n| Imp Fire Missile Ex        | 356 |           |\n"
  },
  {
    "path": "doc/TODO.md",
    "content": "### Scheduled\n* draw various objects in graphics\n\n### Need more research, may not be implemented\n* find ilvl for items\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "include(GetVersion)\n\noption(USE_FREETYPE \"Use FreeType to render TTF fonts\" OFF)\nfile(GLOB D2RMH_SRC_FILES\n    d2r/*.cpp d2r/*.h\n    data/*.cpp data/*.h\n    plugin/*.cpp plugin/*.h\n    render/*.cpp render/*.h\n    ui/*.cpp ui/*.h\n    util/*.cpp util/*.h\n    *.cpp *.h\n    res/res.rc)\nif(NOT MSVC)\n  set(D2RMH_SRC_FILES ${D2RMH_SRC_FILES} res/manifest.rc)\nendif()\nadd_executable(D2RMH WIN32 ${D2RMH_SRC_FILES})\nget_project_version(D2RMH)\nadd_custom_target(D2RMH_RES DEPENDS res/D2RMH.ico)\nadd_dependencies(D2RMH D2RMH_RES)\nif(TARGET d2mapapi_piped)\n  add_dependencies(D2RMH d2mapapi_piped)\nendif()\nif(USE_FREETYPE)\n  find_package(Freetype REQUIRED)\n  target_compile_definitions(D2RMH PRIVATE USE_FREETYPE)\n  target_link_libraries(D2RMH Freetype::Freetype)\nendif()\ntarget_include_directories(D2RMH PRIVATE .)\ntarget_link_libraries(D2RMH casc glad stb inih sol3 d2mapapi_pipehost dwmapi shlwapi comctl32 winmm)\nset_target_properties(D2RMH PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n"
  },
  {
    "path": "src/cfg.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"cfg.h\"\n\n#include \"util/util.h\"\n\n#include \"ini.h\"\n\n#include <windows.h>\n#include <algorithm>\n#include <cstring>\n\n#if defined(_MSC_VER)\n#define strcasecmp _stricmp\n#endif\n\nstatic Cfg sCfg;\nconst Cfg *cfg = &sCfg;\n\n#define LOADVAL(n, m) else if (!strcmp(name, #n)) { sCfg.m = value; }\n#define LOADVALW(n, m) else if (!strcmp(name, #n)) { sCfg.m = util::utf8toucs4(value); }\n#define LOADVALN(n, m) else if (!strcmp(name, #n)) { sCfg.m = decltype(sCfg.m)(strtol(value, nullptr, 0)); }\n#define LOADVALF(n, m) else if (!strcmp(name, #n)) { sCfg.m = strtof(value, nullptr); }\n#define LOADVALC(n, m) else if (!strcmp(name, #n)) { sCfg.m = calcColor(value); }\n\ninline uint32_t calcColor(const char *value) {\n    uint32_t c = strtoul(value, nullptr, 0);\n    const char *tok = strchr(value, ',');\n    if (tok) {\n        c |= strtoul(++tok, nullptr, 0) << 8;\n        tok = strchr(tok, ',');\n        if (tok) {\n            c |= strtoul(++tok, nullptr, 0) << 16;\n            tok = strchr(tok, ',');\n            if (tok) {\n                c |= strtoul(++tok, nullptr, 0) * sCfg.alpha / 255 << 24;\n            } else {\n                c |= 0xFF000000u;\n            }\n        }\n    }\n    return c;\n}\n\nvoid loadCfg(const std::string &filename) {\n    sCfg = Cfg {};\n    int section = -1;\n    ini_parse(filename.c_str(), [](void* user, const char* section,\n                                   const char* name, const char* value)->int {\n        if (!name) {\n            if (!strcmp(section, \"main\")) { *(int*)user = 0; }\n            else if (!strcmp(section, \"ui\")) { *(int*)user = 1; }\n            else if (!strcmp(section, \"enchants\")) { *(int*)user = 2; }\n            else if (!strcmp(section, \"sound\")) { *(int*)user = 3; }\n            else { *(int*)user = -1; }\n            return 1;\n        }\n        switch (*(int*)user) {\n        case 0:\n            if (false) {}\n            LOADVALW(d2_path, d2Path)\n            LOADVAL(font_file_path, fontFilePath)\n            LOADVALN(font_size, fontSize)\n            LOADVALN(msg_font_size, msgFontSize)\n            LOADVAL(language, language)\n            break;\n        case 1:\n            if (false) {}\n            LOADVALN(fps, fps)\n            LOADVALN(show, show)\n            LOADVALN(draw_on_game_bar, drawOnGameBar)\n            LOADVALN(panel_mask, panelMask)\n            LOADVALN(full_line, fullLine)\n            LOADVALN(line_style, lineStyle)\n            LOADVALN(position, position)\n            LOADVAL(map_area, mapArea)\n            LOADVALF(scale, scale)\n            LOADVALN(map_centered, mapCentered)\n\n            LOADVALN(alpha, alpha)\n            LOADVALN(neighbour_map_bounds, neighbourMapBounds)\n            LOADVALC(walkable_color, walkableColor)\n            LOADVALC(edge_color, edgeColor)\n            LOADVALC(text_color, textColor)\n            LOADVALC(player_inner_color, playerInnerColor)\n            LOADVALC(player_outer_color, playerOuterColor)\n            LOADVALC(non_party_player_inner_color, nonPartyPlayerInnerColor)\n            LOADVALC(non_party_player_outer_color, nonPartyPlayerOuterColor)\n            LOADVALC(line_color, lineColor)\n            LOADVALC(waypoint_color, waypointColor)\n            LOADVALC(portal_color, portalColor)\n            LOADVALC(chest_color, chestColor)\n            LOADVALC(quest_color, questColor)\n            LOADVALC(shrine_color, shrineColor)\n            LOADVALC(well_color, wellColor)\n            LOADVALC(unique_monster_color, uniqueMonsterColor)\n            LOADVALC(monster_color, monsterColor)\n            LOADVALC(npc_color, npcColor)\n            LOADVALC(door_color, doorColor)\n            LOADVALC(msg_bg_color, msgBgColor)\n            LOADVAL(msg_position, msgPosition)\n            LOADVALW(text_panel_pattern, panelPattern)\n            LOADVAL(text_panel_position, panelPosition)\n\n            LOADVALN(show_player_names, showPlayerNames)\n            LOADVALN(show_npc_names, showNpcNames)\n            LOADVALN(show_objects, showObjects)\n            LOADVALN(show_items, showItems)\n            LOADVALN(show_npc_name, showNpcNames)\n            LOADVALN(show_monsters, showMonsters)\n            LOADVALN(show_monster_names, showMonsterNames)\n            LOADVALN(show_monster_enchants, showMonsterEnchants)\n            LOADVALN(show_monster_immunities, showMonsterImmunities)\n            /* backward compatibility */\n            LOADVALN(show_normal_monsters, showNormalMonsters)\n            LOADVALN(show_monster_name, showMonsterNames)\n            LOADVALN(show_monster_enchant, showMonsterEnchants)\n            LOADVALN(show_monster_immune, showMonsterImmunities)\n            LOADVALF(object_size_minimal, objectSizeMinimal)\n            break;\n        case 2:\n            if (false) {}\n            LOADVALW(extra_strong, encTxtExtraStrong)\n            LOADVALW(extra_fast, encTxtExtraFast)\n            LOADVALW(cursed, encTxtCursed)\n            LOADVALW(magic_resistant, encTxtMagicResistant)\n            LOADVALW(fire_enchanted, encTxtFireEnchanted)\n            LOADVALW(ligntning_enchanted, encTxtLigntningEnchanted)\n            LOADVALW(cold_enchanted, encTxtColdEnchanted)\n            LOADVALW(mana_burn, encTxtManaBurn)\n            LOADVALW(teleportation, encTxtTeleportation)\n            LOADVALW(spectral_hit, encTxtSpectralHit)\n            LOADVALW(stone_skin, encTxtStoneSkin)\n            LOADVALW(multiple_shots, encTxtMultipleShots)\n            LOADVALW(fanatic, encTxtFanatic)\n            LOADVALW(berserker, encTxtBerserker)\n\n            LOADVALW(might_aura, MightAura)\n            LOADVALW(holyFire_aura, HolyFireAura)\n            LOADVALW(blessedAim_aura, BlessedAimAura)\n            LOADVALW(holyFreeze_aura, HolyFreezeAura)\n            LOADVALW(holyShock_aura, HolyShockAura)\n            LOADVALW(conviction_aura, ConvictionAura)\n            LOADVALW(fanaticism_aura, FanaticismAura)\n\n            LOADVALW(physical_immunity, encTxtPhysicalImmunity)\n            LOADVALW(magic_immunity, encTxtMagicImmunity)\n            LOADVALW(fire_immunity, encTxtFireImmunity)\n            LOADVALW(lightning_immunity, encTxtLightningImmunity)\n            LOADVALW(cold_immunity, encTxtColdImmunity)\n            LOADVALW(poison_immunity, encTxtPoisonImmunity)\n            break;\n        case 3: {\n            if (strncmp(name, \"sound[\", 6) != 0) { break; }\n            auto index = size_t(strtol(name + 6, nullptr, 0));\n            if (!index) { break; }\n            if (index >= sCfg.sounds.size()) { sCfg.sounds.resize(index + 1); }\n            auto vlen = strlen(value);\n            if (!strcasecmp(value + vlen - 4, \".wav\")) {\n                sCfg.sounds[index] = {util::utf8toucs4(value), false};\n            } else {\n                sCfg.sounds[index] = {util::utf8toucs4(value), true};\n            }\n            break;\n        }\n        default:\n            break;\n        }\n        return 1;\n    }, &section);\n    sCfg.scale = std::clamp(sCfg.scale, 1.f, 4.f);\n    if (sCfg.showNormalMonsters) { sCfg.showMonsters = 2; }\n    if (sCfg.lineStyle == 0 && sCfg.fullLine > 0) {\n        sCfg.lineStyle = sCfg.fullLine;\n    }\n    if (!sCfg.mapArea.empty()) {\n        auto vec = util::splitString(sCfg.mapArea, ',');\n        if (vec.size() > 1) {\n            sCfg.mapAreaW = std::clamp(strtof(vec[0].c_str(), nullptr), 0.f, 1.f);\n            sCfg.mapAreaH = std::clamp(strtof(vec[1].c_str(), nullptr), 0.f, 1.f);\n        } else {\n            sCfg.mapAreaW = sCfg.mapAreaH = std::clamp(strtof(sCfg.mapArea.c_str(), nullptr), 0.f, 1.f);\n        }\n    }\n    if (!sCfg.msgPosition.empty()) {\n        auto vec = util::splitString(sCfg.msgPosition, ',');\n        auto sz = vec.size();\n        if (sz > 0) {\n            sCfg.msgPositionX = std::clamp(strtof(vec[0].c_str(), nullptr), 0.f, 1.f) - .5f;\n        }\n        if (sz > 1) {\n            sCfg.msgPositionY = std::clamp(strtof(vec[1].c_str(), nullptr), 0.f, 1.f) - .5f;\n        }\n        if (sz > 2) {\n            sCfg.msgAlign = std::clamp(int(strtol(vec[2].c_str(), nullptr, 0)), 0, 2);\n        }\n    }\n    if (!sCfg.panelPattern.empty()) {\n        sCfg.panelPatterns.clear();\n        typename std::wstring::size_type last = 0;\n        while (true) {\n            auto pos = sCfg.panelPattern.find(L\"{newline}\", last);\n            auto pos2 = sCfg.panelPattern.find(L\"{n}\", last);\n            int sepLen;\n            if (pos > pos2) {\n                pos = pos2;\n                sepLen = 3;\n            } else {\n                sepLen = 9;\n            }\n            if (pos == std::wstring::npos) {\n                break;\n            }\n            sCfg.panelPatterns.emplace_back(sCfg.panelPattern.substr(last, pos - last));\n            last = pos + sepLen;\n        }\n        if (last < sCfg.panelPattern.size()) {\n            sCfg.panelPatterns.emplace_back(sCfg.panelPattern.substr(last));\n        }\n    }\n    if (!sCfg.panelPosition.empty()) {\n        auto vec = util::splitString(sCfg.panelPosition, ',');\n        auto sz = vec.size();\n        if (sz > 0) {\n            sCfg.panelPositionX = std::clamp(strtof(vec[0].c_str(), nullptr), 0.f, 1.f) - .5f;\n        }\n        if (sz > 1) {\n            sCfg.panelPositionY = std::clamp(strtof(vec[1].c_str(), nullptr), 0.f, 1.f) - .5f;\n        }\n        if (sz > 2) {\n            sCfg.panelAlign = std::clamp(int(strtol(vec[2].c_str(), nullptr, 0)), 0, 2);\n        }\n    }\n    for (auto *color:\n        {&sCfg.walkableColor, &sCfg.edgeColor, &sCfg.textColor, &sCfg.playerInnerColor, &sCfg.playerOuterColor,\n         &sCfg.lineColor, &sCfg.waypointColor, &sCfg.portalColor, &sCfg.chestColor, &sCfg.questColor, &sCfg.shrineColor,\n         &sCfg.wellColor, &sCfg.uniqueMonsterColor, &sCfg.monsterColor, &sCfg.npcColor, &sCfg.doorColor,\n         &sCfg.msgBgColor,}) {\n        *color = (((*color >> 24) * sCfg.alpha / 255) << 24) | (*color & 0xFFFFFFu);\n    }\n    if (sCfg.language.empty()) {\n        HKEY key;\n        if (RegOpenKeyExW(HKEY_CURRENT_USER, L\"SOFTWARE\\\\Blizzard Entertainment\\\\Battle.net\\\\Launch Options\\\\OSI\", 0, KEY_READ, &key) == ERROR_SUCCESS) {\n            char lang[16];\n            DWORD langSize = 16;\n            bool result = RegQueryValueExA(key, \"LOCALE\", nullptr, nullptr, LPBYTE(lang), &langSize) == ERROR_SUCCESS;\n            RegCloseKey(key);\n            if (result) {\n                sCfg.language = lang;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/cfg.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <vector>\n#include <string>\n\nstruct Cfg {\n    std::wstring d2Path = L\".\";\n    std::string fontFilePath;\n    int fontSize = 14;\n    int msgFontSize = 24;\n    std::string language;\n\n    int fps = 25;\n    int show = 0;\n    int drawOnGameBar = 1;\n    uint32_t panelMask = 0x1FF;\n    int fullLine = 0;\n    int lineStyle = 0;\n    int position = 2;\n    std::string mapArea;\n    float mapAreaW = .0f;\n    float mapAreaH = .0f;\n    float scale = 2.f;\n    int mapCentered = 1;\n    uint8_t alpha = 255;\n    int neighbourMapBounds = -1;\n#define RGBA(r, g, b, a) (uint32_t(r) | (uint32_t(g) << 8) | (uint32_t(b) << 16) | (uint32_t(a) << 24))\n    uint32_t walkableColor = RGBA(20, 20, 20, 50);\n    uint32_t edgeColor = RGBA(128, 128, 128, 240);\n    uint32_t textColor = RGBA(255, 255, 255, 180);\n    uint32_t playerInnerColor = RGBA(255, 128, 128, 80);\n    uint32_t playerOuterColor = RGBA(51, 255, 255, 180);\n    uint32_t nonPartyPlayerInnerColor = RGBA(255, 128, 128, 80);\n    uint32_t nonPartyPlayerOuterColor = RGBA(255, 20, 20, 180);\n    uint32_t lineColor = RGBA(204, 204, 204, 144);\n    uint32_t waypointColor = RGBA(153, 153, 255, 200);\n    uint32_t portalColor = RGBA(255, 255, 102, 160);\n    uint32_t chestColor = RGBA(255, 104, 104, 160);\n    uint32_t questColor = RGBA(104, 104, 255, 160);\n    uint32_t shrineColor = RGBA(255, 51, 178, 160);\n    uint32_t wellColor = RGBA(51, 51, 255, 160);\n    uint32_t uniqueMonsterColor = RGBA(192, 166, 130, 204);\n    uint32_t monsterColor = RGBA(255, 0, 0, 128);\n    uint32_t npcColor = RGBA(160, 160, 160, 160);\n    uint32_t doorColor = RGBA(80, 255, 80, 180);\n    uint32_t msgBgColor = RGBA(1, 1, 1, 128);\n#undef RGBA\n    std::string msgPosition = \"0.95,0.25,2\";\n    float msgPositionX = .0f;\n    float msgPositionY = .0f;\n    int msgAlign = 0;\n    std::wstring panelPattern;\n    std::string panelPosition = \"0.93,0.015,2\";\n    std::vector<std::wstring> panelPatterns;\n    float panelPositionX = .0f;\n    float panelPositionY = .0f;\n    int panelAlign = 0;\n\n    int showPlayerNames = 1;\n    int showNpcNames = 1;\n    int showObjects = 1;\n    int showItems = 1;\n    int showMonsters = 1;\n    int showNormalMonsters = 0;\n    int showMonsterNames = 0;\n    int showMonsterEnchants = 1;\n    int showMonsterImmunities = 1;\n    float objectSizeMinimal = 6;\n\n    std::wstring encTxtExtraStrong = L\"S\";\n    std::wstring encTxtExtraFast = L\"F\";\n    std::wstring encTxtCursed = L\"{2}C\";\n    std::wstring encTxtMagicResistant = L\"M\";\n    std::wstring encTxtFireEnchanted = L\"{1}FE\";\n    std::wstring encTxtLigntningEnchanted = L\"{9}LE\";\n    std::wstring encTxtColdEnchanted = L\"{3}CE\";\n    std::wstring encTxtManaBurn = L\"{3}MB\";\n    std::wstring encTxtTeleportation = L\"T\";\n    std::wstring encTxtSpectralHit = L\"H\";\n    std::wstring encTxtStoneSkin = L\"{4}SS\";\n    std::wstring encTxtMultipleShots = L\"{12}MS\";\n    std::wstring encTxtFanatic = L\"{11}F\";\n    std::wstring encTxtBerserker = L\"{4}B\";\n\n    std::wstring MightAura = L\"{4}A\";\n    std::wstring HolyFireAura = L\"{1}A\";\n    std::wstring BlessedAimAura = L\"A\";\n    std::wstring HolyFreezeAura = L\"{3}A\";\n    std::wstring HolyShockAura = L\"{9}A\";\n    std::wstring ConvictionAura = L\"{11}A\";\n    std::wstring FanaticismAura = L\"{5}A\";\n\n    std::wstring encTxtPhysicalImmunity = L\"{4}i\";\n    std::wstring encTxtMagicImmunity = L\"{8}i\";\n    std::wstring encTxtFireImmunity = L\"{1}i\";\n    std::wstring encTxtLightningImmunity = L\"{9}i\";\n    std::wstring encTxtColdImmunity = L\"{3}i\";\n    std::wstring encTxtPoisonImmunity = L\"{2}i\";\n\n    std::vector<std::pair<std::wstring, bool>> sounds;\n};\n\nextern void loadCfg(const std::string &filename = \"D2RMH.ini\");\n\nextern const Cfg *cfg;\n"
  },
  {
    "path": "src/d2r/d2rdefs.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <cstdint>\n\nnamespace d2r {\n\nenum class StatId {\n    /*   0 */ Strength,\n    /*   1 */ Energy,\n    /*   2 */ Dexterity,\n    /*   3 */ Vitality,\n    /*   4 */ Statpts,\n    /*   5 */ Newskills,\n    /*   6 */ Hitpoints,\n    /*   7 */ Maxhp,\n    /*   8 */ Mana,\n    /*   9 */ Maxmana,\n    /*  10 */ Stamina,\n    /*  11 */ Maxstamina,\n    /*  12 */ Level,\n    /*  13 */ Experience,\n    /*  14 */ Gold,\n    /*  15 */ Goldbank,\n    /*  16 */ ItemArmorPercent,\n    /*  17 */ ItemMaxdamagePercent,\n    /*  18 */ ItemMindamagePercent,\n    /*  19 */ Tohit,\n    /*  20 */ Toblock,\n    /*  21 */ Mindamage,\n    /*  22 */ Maxdamage,\n    /*  23 */ SecondaryMindamage,\n    /*  24 */ SecondaryMaxdamage,\n    /*  25 */ Damagepercent,\n    /*  26 */ Manarecovery,\n    /*  27 */ Manarecoverybonus,\n    /*  28 */ Staminarecoverybonus,\n    /*  29 */ Lastexp,\n    /*  30 */ Nextexp,\n    /*  31 */ Armorclass,\n    /*  32 */ ArmorclassVsMissile,\n    /*  33 */ ArmorclassVsHth,\n    /*  34 */ NormalDamageReduction,\n    /*  35 */ MagicDamageReduction,\n    /*  36 */ Damageresist,\n    /*  37 */ Magicresist,\n    /*  38 */ Maxmagicresist,\n    /*  39 */ Fireresist,\n    /*  40 */ Maxfireresist,\n    /*  41 */ Lightresist,\n    /*  42 */ Maxlightresist,\n    /*  43 */ Coldresist,\n    /*  44 */ Maxcoldresist,\n    /*  45 */ Poisonresist,\n    /*  46 */ Maxpoisonresist,\n    /*  47 */ Damageaura,\n    /*  48 */ Firemindam,\n    /*  49 */ Firemaxdam,\n    /*  50 */ Lightmindam,\n    /*  51 */ Lightmaxdam,\n    /*  52 */ Magicmindam,\n    /*  53 */ Magicmaxdam,\n    /*  54 */ Coldmindam,\n    /*  55 */ Coldmaxdam,\n    /*  56 */ Coldlength,\n    /*  57 */ Poisonmindam,\n    /*  58 */ Poisonmaxdam,\n    /*  59 */ Poisonlength,\n    /*  60 */ Lifedrainmindam,\n    /*  61 */ Lifedrainmaxdam,\n    /*  62 */ Manadrainmindam,\n    /*  63 */ Manadrainmaxdam,\n    /*  64 */ Stamdrainmindam,\n    /*  65 */ Stamdrainmaxdam,\n    /*  66 */ Stunlength,\n    /*  67 */ Velocitypercent,\n    /*  68 */ Attackrate,\n    /*  69 */ OtherAnimrate,\n    /*  70 */ Quantity,\n    /*  71 */ Value,\n    /*  72 */ Durability,\n    /*  73 */ Maxdurability,\n    /*  74 */ Hpregen,\n    /*  75 */ ItemMaxdurabilityPercent,\n    /*  76 */ ItemMaxhpPercent,\n    /*  77 */ ItemMaxmanaPercent,\n    /*  78 */ ItemAttackertakesdamage,\n    /*  79 */ ItemGoldbonus,\n    /*  80 */ ItemMagicbonus,\n    /*  81 */ ItemKnockback,\n    /*  82 */ ItemTimeduration,\n    /*  83 */ ItemAddclassskills,\n    /*  84 */ Unsentparam1,\n    /*  85 */ ItemAddexperience,\n    /*  86 */ ItemHealafterkill,\n    /*  87 */ ItemReducedprices,\n    /*  88 */ ItemDoubleherbduration,\n    /*  89 */ ItemLightradius,\n    /*  90 */ ItemLightcolor,\n    /*  91 */ ItemReqPercent,\n    /*  92 */ ItemLevelreq,\n    /*  93 */ ItemFasterattackrate,\n    /*  94 */ ItemLevelreqpct,\n    /*  95 */ Lastblockframe,\n    /*  96 */ ItemFastermovevelocity,\n    /*  97 */ ItemNonclassskill,\n    /*  98 */ State,\n    /*  99 */ ItemFastergethitrate,\n    /* 100 */ MonsterPlayercount,\n    /* 101 */ SkillPoisonOverrideLength,\n    /* 102 */ ItemFasterblockrate,\n    /* 103 */ SkillBypassUndead,\n    /* 104 */ SkillBypassDemons,\n    /* 105 */ ItemFastercastrate,\n    /* 106 */ SkillBypassBeasts,\n    /* 107 */ ItemSingleskill,\n    /* 108 */ ItemRestinpeace,\n    /* 109 */ CurseResistance,\n    /* 110 */ ItemPoisonlengthresist,\n    /* 111 */ ItemNormaldamage,\n    /* 112 */ ItemHowl,\n    /* 113 */ ItemStupidity,\n    /* 114 */ ItemDamagetomana,\n    /* 115 */ ItemIgnoretargetac,\n    /* 116 */ ItemFractionaltargetac,\n    /* 117 */ ItemPreventheal,\n    /* 118 */ ItemHalffreezeduration,\n    /* 119 */ ItemTohitPercent,\n    /* 120 */ ItemDamagetargetac,\n    /* 121 */ ItemDemondamagePercent,\n    /* 122 */ ItemUndeaddamagePercent,\n    /* 123 */ ItemDemonTohit,\n    /* 124 */ ItemUndeadTohit,\n    /* 125 */ ItemThrowable,\n    /* 126 */ ItemElemskill,\n    /* 127 */ ItemAllskills,\n    /* 128 */ ItemAttackertakeslightdamage,\n    /* 129 */ IronmaidenLevel,\n    /* 130 */ LifetapLevel,\n    /* 131 */ ThornsPercent,\n    /* 132 */ Bonearmor,\n    /* 133 */ Bonearmormax,\n    /* 134 */ ItemFreeze,\n    /* 135 */ ItemOpenwounds,\n    /* 136 */ ItemCrushingblow,\n    /* 137 */ ItemKickdamage,\n    /* 138 */ ItemManaafterkill,\n    /* 139 */ ItemHealafterdemonkill,\n    /* 140 */ ItemExtrablood,\n    /* 141 */ ItemDeadlystrike,\n    /* 142 */ ItemAbsorbfirePercent,\n    /* 143 */ ItemAbsorbfire,\n    /* 144 */ ItemAbsorblightPercent,\n    /* 145 */ ItemAbsorblight,\n    /* 146 */ ItemAbsorbmagicPercent,\n    /* 147 */ ItemAbsorbmagic,\n    /* 148 */ ItemAbsorbcoldPercent,\n    /* 149 */ ItemAbsorbcold,\n    /* 150 */ ItemSlow,\n    /* 151 */ ItemAura,\n    /* 152 */ ItemIndesctructible,\n    /* 153 */ ItemCannotbefrozen,\n    /* 154 */ ItemStaminadrainpct,\n    /* 155 */ ItemReanimate,\n    /* 156 */ ItemPierce,\n    /* 157 */ ItemMagicarrow,\n    /* 158 */ ItemExplosivearrow,\n    /* 159 */ ItemThrowMindamage,\n    /* 160 */ ItemThrowMaxdamage,\n    /* 161 */ SkillHandofathena,\n    /* 162 */ SkillStaminapercent,\n    /* 163 */ SkillPassiveStaminapercent,\n    /* 164 */ SkillConcentration,\n    /* 165 */ SkillEnchant,\n    /* 166 */ SkillPierce,\n    /* 167 */ SkillConviction,\n    /* 168 */ SkillChillingarmor,\n    /* 169 */ SkillFrenzy,\n    /* 170 */ SkillDecrepify,\n    /* 171 */ SkillArmorPercent,\n    /* 172 */ Alignment,\n    /* 173 */ Target0,\n    /* 174 */ Target1,\n    /* 175 */ Goldlost,\n    /* 176 */ ConversionLevel,\n    /* 177 */ ConversionMaxhp,\n    /* 178 */ UnitDooverlay,\n    /* 179 */ AttackVsMontype,\n    /* 180 */ DamageVsMontype,\n    /* 181 */ Fade,\n    /* 182 */ ArmorOverridePercent,\n    /* 183 */ Unused183,\n    /* 184 */ Unused184,\n    /* 185 */ Unused185,\n    /* 186 */ Unused186,\n    /* 187 */ Unused187,\n    /* 188 */ ItemAddskillTab,\n    /* 189 */ Unused189,\n    /* 190 */ Unused190,\n    /* 191 */ Unused191,\n    /* 192 */ Unused192,\n    /* 193 */ Unused193,\n    /* 194 */ ItemNumsockets,\n    /* 195 */ ItemSkillonattack,\n    /* 196 */ ItemSkillonkill,\n    /* 197 */ ItemSkillondeath,\n    /* 198 */ ItemSkillonhit,\n    /* 199 */ ItemSkillonlevelup,\n    /* 200 */ Unused200,\n    /* 201 */ ItemSkillongethit,\n    /* 202 */ Unused202,\n    /* 203 */ Unused203,\n    /* 204 */ ItemChargedSkill,\n    /* 205 */ Unused205,\n    /* 206 */ Unused206,\n    /* 207 */ Unused207,\n    /* 208 */ Unused208,\n    /* 209 */ Unused209,\n    /* 210 */ Unused210,\n    /* 211 */ Unused211,\n    /* 213 */ PassiveMasteryGethitRate,\n    /* 213 */ PassiveMasteryAttackSpeed,\n    /* 214 */ ItemArmorPerlevel,\n    /* 215 */ ItemArmorpercentPerlevel,\n    /* 216 */ ItemHpPerlevel,\n    /* 217 */ ItemManaPerlevel,\n    /* 218 */ ItemMaxdamagePerlevel,\n    /* 219 */ ItemMaxdamagePercentPerlevel,\n    /* 220 */ ItemStrengthPerlevel,\n    /* 221 */ ItemDexterityPerlevel,\n    /* 222 */ ItemEnergyPerlevel,\n    /* 223 */ ItemVitalityPerlevel,\n    /* 224 */ ItemTohitPerlevel,\n    /* 225 */ ItemTohitpercentPerlevel,\n    /* 226 */ ItemColdDamagemaxPerlevel,\n    /* 227 */ ItemFireDamagemaxPerlevel,\n    /* 228 */ ItemLtngDamagemaxPerlevel,\n    /* 229 */ ItemPoisDamagemaxPerlevel,\n    /* 230 */ ItemResistColdPerlevel,\n    /* 231 */ ItemResistFirePerlevel,\n    /* 232 */ ItemResistLtngPerlevel,\n    /* 233 */ ItemResistPoisPerlevel,\n    /* 234 */ ItemAbsorbColdPerlevel,\n    /* 235 */ ItemAbsorbFirePerlevel,\n    /* 236 */ ItemAbsorbLtngPerlevel,\n    /* 237 */ ItemAbsorbPoisPerlevel,\n    /* 238 */ ItemThornsPerlevel,\n    /* 239 */ ItemFindGoldPerlevel,\n    /* 240 */ ItemFindMagicPerlevel,\n    /* 241 */ ItemRegenstaminaPerlevel,\n    /* 242 */ ItemStaminaPerlevel,\n    /* 243 */ ItemDamageDemonPerlevel,\n    /* 244 */ ItemDamageUndeadPerlevel,\n    /* 245 */ ItemTohitDemonPerlevel,\n    /* 246 */ ItemTohitUndeadPerlevel,\n    /* 247 */ ItemCrushingblowPerlevel,\n    /* 248 */ ItemOpenwoundsPerlevel,\n    /* 249 */ ItemKickDamagePerlevel,\n    /* 250 */ ItemDeadlystrikePerlevel,\n    /* 251 */ ItemFindGemsPerlevel,\n    /* 252 */ ItemReplenishDurability,\n    /* 253 */ ItemReplenishQuantity,\n    /* 254 */ ItemExtraStack,\n    /* 255 */ ItemFindItem,\n    /* 256 */ ItemSlashDamage,\n    /* 257 */ ItemSlashDamagePercent,\n    /* 258 */ ItemCrushDamage,\n    /* 259 */ ItemCrushDamagePercent,\n    /* 260 */ ItemThrustDamage,\n    /* 261 */ ItemThrustDamagePercent,\n    /* 262 */ ItemAbsorbSlash,\n    /* 263 */ ItemAbsorbCrush,\n    /* 264 */ ItemAbsorbThrust,\n    /* 265 */ ItemAbsorbSlashPercent,\n    /* 266 */ ItemAbsorbCrushPercent,\n    /* 267 */ ItemAbsorbThrustPercent,\n    /* 268 */ ItemArmorBytime,\n    /* 269 */ ItemArmorpercentBytime,\n    /* 270 */ ItemHpBytime,\n    /* 271 */ ItemManaBytime,\n    /* 272 */ ItemMaxdamageBytime,\n    /* 273 */ ItemMaxdamagePercentBytime,\n    /* 274 */ ItemStrengthBytime,\n    /* 275 */ ItemDexterityBytime,\n    /* 276 */ ItemEnergyBytime,\n    /* 277 */ ItemVitalityBytime,\n    /* 278 */ ItemTohitBytime,\n    /* 279 */ ItemTohitpercentBytime,\n    /* 280 */ ItemColdDamagemaxBytime,\n    /* 281 */ ItemFireDamagemaxBytime,\n    /* 282 */ ItemLtngDamagemaxBytime,\n    /* 283 */ ItemPoisDamagemaxBytime,\n    /* 284 */ ItemResistColdBytime,\n    /* 285 */ ItemResistFireBytime,\n    /* 286 */ ItemResistLtngBytime,\n    /* 287 */ ItemResistPoisBytime,\n    /* 288 */ ItemAbsorbColdBytime,\n    /* 289 */ ItemAbsorbFireBytime,\n    /* 290 */ ItemAbsorbLtngBytime,\n    /* 291 */ ItemAbsorbPoisBytime,\n    /* 292 */ ItemFindGoldBytime,\n    /* 293 */ ItemFindMagicBytime,\n    /* 294 */ ItemRegenstaminaBytime,\n    /* 295 */ ItemStaminaBytime,\n    /* 296 */ ItemDamageDemonBytime,\n    /* 297 */ ItemDamageUndeadBytime,\n    /* 298 */ ItemTohitDemonBytime,\n    /* 299 */ ItemTohitUndeadBytime,\n    /* 300 */ ItemCrushingblowBytime,\n    /* 301 */ ItemOpenwoundsBytime,\n    /* 302 */ ItemKickDamageBytime,\n    /* 303 */ ItemDeadlystrikeBytime,\n    /* 304 */ ItemFindGemsBytime,\n    /* 305 */ ItemPierceCold,\n    /* 306 */ ItemPierceFire,\n    /* 307 */ ItemPierceLtng,\n    /* 308 */ ItemPiercePois,\n    /* 309 */ ItemDamageVsMonster,\n    /* 310 */ ItemDamagePercentVsMonster,\n    /* 311 */ ItemTohitVsMonster,\n    /* 312 */ ItemTohitPercentVsMonster,\n    /* 313 */ ItemAcVsMonster,\n    /* 314 */ ItemAcPercentVsMonster,\n    /* 315 */ Firelength,\n    /* 316 */ Burningmin,\n    /* 317 */ Burningmax,\n    /* 318 */ ProgressiveDamage,\n    /* 319 */ ProgressiveSteal,\n    /* 320 */ ProgressiveOther,\n    /* 321 */ ProgressiveFire,\n    /* 322 */ ProgressiveCold,\n    /* 323 */ ProgressiveLightning,\n    /* 324 */ ItemExtraCharges,\n    /* 325 */ ProgressiveTohit,\n    /* 326 */ PoisonCount,\n    /* 327 */ DamageFramerate,\n    /* 328 */ PierceIdx,\n    /* 329 */ PassiveFireMastery,\n    /* 330 */ PassiveLtngMastery,\n    /* 331 */ PassiveColdMastery,\n    /* 332 */ PassivePoisMastery,\n    /* 333 */ PassiveFirePierce,\n    /* 334 */ PassiveLtngPierce,\n    /* 335 */ PassiveColdPierce,\n    /* 336 */ PassivePoisPierce,\n    /* 337 */ PassiveCriticalStrike,\n    /* 338 */ PassiveDodge,\n    /* 339 */ PassiveAvoid,\n    /* 340 */ PassiveEvade,\n    /* 341 */ PassiveWarmth,\n    /* 342 */ PassiveMasteryMeleeTh,\n    /* 343 */ PassiveMasteryMeleeDmg,\n    /* 344 */ PassiveMasteryMeleeCrit,\n    /* 345 */ PassiveMasteryThrowTh,\n    /* 346 */ PassiveMasteryThrowDmg,\n    /* 347 */ PassiveMasteryThrowCrit,\n    /* 348 */ PassiveWeaponblock,\n    /* 349 */ PassiveSummonResist,\n    /* 350 */ ModifierlistSkill,\n    /* 351 */ ModifierlistLevel,\n    /* 352 */ LastSentHpPct,\n    /* 353 */ SourceUnitType,\n    /* 354 */ SourceUnitId,\n    /* 355 */ Shortparam1,\n    /* 356 */ Questitemdifficulty,\n    /* 357 */ PassiveMagMastery,\n    /* 358 */ PassiveMagPierce,\n    /* 359 */ SkillCooldown,\n    /* 360 */ SkillMissileDamageScale,\n    TotalCount,\n};\n\n#pragma pack(push, 1)\n\nstruct DrlgRoom2 {\n    uint64_t unk0[2];\n    /* 0x10  DrlgRoom2 **pRoomsNear */\n    uint64_t roomsNearListPtr;\n    uint64_t unk1[5];\n    /* 0x40  DWORD *levelDef */\n    uint64_t levelPresetPtr;\n    /* 0x48  DrlgRoom2 *pNext */\n    uint64_t nextPtr;\n    /* 0x50 */\n    uint16_t roomsNear;\n    uint16_t unk2;\n    uint32_t roomTiles;\n    /* 0x58  DrlgRoom1 *room1 */\n    uint64_t room1Ptr;\n    /* 0x60  DWORD dwPosX; DWORD dwPosY; DWORD dwSizeX; DWORD dwSizeY; */\n    uint32_t posX, posY, sizeX, sizeY;\n    /* 0x70 */\n    uint32_t unk3;\n    uint32_t presetType;\n    /* 0x78  RoomTile *pRoomTiles */\n    uint64_t roomTilesPtr;\n    uint64_t unk4[2];\n    /* 0x90  DrlgLevel *pLevel */\n    uint64_t levelPtr;\n    /* 0x98  PresetUnit *pPresetUnits */\n    uint64_t presetUnitsPtr;\n};\n\nstruct DrlgRoom1 {\n    /* 0x00  DrlgRoom1 **pRoomsNear; */\n    uint64_t roomsNearListPtr;\n    uint64_t unk0[2];\n    /* 0x18  DrlgRoom2 *pRoom2; */\n    uint64_t room2Ptr;\n    uint64_t unk1[4];\n    /* 0x40 */\n    uint32_t roomsNear;\n    uint32_t unk2;\n    /* 0x48  DrlgAct *pAct */\n    uint64_t actAddr;\n    uint64_t unk3[11];\n    /* 0xA8  UnitAny *pUnitFirst */\n    uint64_t unitFirstAddr;\n    /* 0xB0  DrlgRoom1 *pNext */\n    uint64_t nextPtr;\n};\n\nstruct DynamicPath {\n    uint16_t offsetX;\n    uint16_t posX;\n    uint16_t offsetY;\n    uint16_t posY;\n    uint32_t mapPosX;\n    uint32_t mapPosY;\n    uint32_t targetX;\n    uint32_t targetY;\n    uint32_t unk0[2];\n    /* 0x20  DrlgRoom1 *pRoom1 */\n    uint64_t room1Ptr;\n};\n\nstruct StaticPath {\n    /* DrlgRoom1 *pRoom1; */\n    uint64_t room1Ptr;\n    uint32_t mapPosX;\n    uint32_t dwMapPosY;\n    uint32_t posX;\n    uint32_t posY;\n};\n\nstruct DrlgAct {\n    uint64_t unk0[3];\n    uint32_t unk1;\n    uint32_t seed;\n    /* 0x20 DrlgRoom1 *room1 */\n    uint64_t room1Ptr;\n    uint32_t actId;\n    uint32_t unk2;\n    uint64_t unk3[9];\n    /* 0x78 DrlgMisc *misc */\n    uint64_t miscPtr;\n};\n\nstruct MonsterData {\n    /* MonsterTxt *pMonsterTxt */\n    uint64_t monsterTxtPtr;\n    uint8_t components[16];\n    uint16_t nameSeed;\n    /*  struct MonsterFlag {\n            BYTE fOther:1;  //set for some champs, uniques\n            BYTE fUnique:1; //super unique\n            BYTE fChamp:1;\n            BYTE fBoss:1;   //unique monster ,usually boss\n            BYTE fMinion:1;\n            BYTE fPoss:1;   //possessed\n            BYTE fGhost:1;  //ghostly\n            BYTE fMulti:1;  //multishotfiring\n        };\n    */\n    uint8_t flag;\n    uint8_t lastMode;\n    uint32_t duriel;\n    uint8_t enchants[9];\n    uint8_t unk0;\n    uint16_t uniqueNo;\n    uint32_t unk1;\n    uint16_t unk2;\n    uint16_t mercNameId;\n    uint32_t unk3;\n};\n\nstruct ItemData {\n    uint32_t quality;\n    uint32_t seedLow;\n    uint32_t seedHigh;\n    uint32_t ownerId;\n    uint32_t fingerprint;\n    uint32_t commandFlags;\n    uint32_t itemFlags;\n    uint64_t unk0[2];\n    uint64_t actionStamp;\n    uint32_t fileIndex; /* index from data files UniqueItems.txt, SetItems.txt, QualityItems.txt, LowQualityItems.txt */\n    uint32_t itemLevel;\n    uint16_t format;\n    uint16_t rarePrefix;\n    uint16_t rareSuffix;\n    uint16_t autoPrefix;\n    uint16_t magicPrefix[3];\n    uint16_t magicSuffix[3];\n    uint8_t bodyLocation; /* Id from BodyLocs.txt */\n    uint8_t itemLocation; /* 0x80-ground  0xFF-equiped or on-hand  0-inv  3-cube  4-stash */\n    uint16_t unk1;\n    uint32_t unk2;\n    uint16_t earLevel;\n    uint8_t invGfxIdx;\n    char playerName[16];\n    uint8_t unk3[5];\n    uint64_t ownerInvPtr;\n    uint64_t prevItemPtr;\n    uint64_t nextItemPtr;\n    uint8_t unk4;\n    uint8_t location; /* 0-ground 1-cube/stash/inv 2-belt 3-body 4-2nd hand */\n    uint8_t unk5[6];\n};\n\nstruct StatEx {\n    uint16_t param;\n    uint16_t statId;\n    int32_t value;\n};\n\nstruct Stats {\n    /* StatEx *pStat */\n    uint64_t statPtr;\n    uint64_t statCount;\n    uint64_t statCapacity;\n};\n\nstruct StatList {\n    /* Unit *pUnit */\n    uint64_t unitPtr;\n    uint32_t ownerType;\n    uint32_t ownerId;\n    uint32_t unk0[3];\n    uint32_t flag;\n    uint32_t stateNo;\n    uint32_t expireFrame;\n    uint32_t skillNo;\n    uint32_t skillLevel;\n    /* State sBaseStat */\n    Stats baseStat;\n    uint64_t unk1;\n    uint64_t prevList;\n    uint64_t nextList;\n    uint64_t prev;\n    uint64_t nextListEx;\n    uint64_t next;\n    uint64_t unk2;\n    /* State sFullStat */\n    Stats fullStat;\n    /* State sModStat */\n    Stats modStat;\n};\n\nstruct Skill {\n    uint64_t skillTxtPtr;\n    uint64_t nextSkillPtr;\n    uint32_t mode;\n    uint32_t flag0;\n    uint32_t unk0[2];\n    uint32_t tagets;\n    uint32_t targetType;\n    uint32_t targetId;\n    uint32_t unk1;\n    uint64_t unk2;\n    uint32_t skillLevel;\n    uint32_t levelBonus;\n    uint32_t quantity;\n    uint32_t flags;\n};\n\nstruct SkillInfo {\n    uint64_t firstSkillPtr;\n    uint64_t leftSkillPtr;\n    uint64_t rightSkillPtr;\n    uint64_t currSkillPtr;\n};\n\nstruct UnitInventory {\n    uint32_t magic;\n    uint32_t unk0;\n    uint64_t ownerPtr;\n    uint64_t firstItemPtr;\n    uint64_t lastItemPtr;\n    uint64_t invInfoPtr;\n    uint64_t invInfoSize;\n    uint64_t invInfoCapacity;\n    uint32_t weaponId;\n    uint32_t unk1;\n    uint64_t cursorItemPtr;\n    uint32_t ownerId;\n    uint32_t filledSockets;\n};\n\nstruct UnitAny {\n    uint32_t unitType;\n    uint32_t txtFileNo;\n    uint32_t unitId;\n    uint32_t mode;\n    /* 0x10\n    union {\n        PlayerData *pPlayerData;\n        MonsterData *pMonsterData;\n        ObjectData *pObjectData;\n        ItemData *pItemData;\n        MissileData *pMissileData;\n    };\n     */\n    uint64_t unionPtr;\n    uint64_t unk0;\n    /* 0x20  DrlgAct *pAct */\n    uint64_t actPtr;\n    uint64_t seed;\n    /* 0x30 */\n    uint64_t initSeed;\n    /* 0x38  for Player/Monster: DynamicPath *pPath\n     *       for Object:         StaticPath  *pPath */\n    uint64_t pathPtr;\n    /* 0x40 */\n    uint32_t unk2[8];\n    /* 0x60 */\n    uint32_t gfxFrame;\n    uint32_t frameRemain;\n    /* 0x68 */\n    uint32_t frameRate;\n    uint32_t unk3;\n    /* 0x70\n    uint8_t *pGfxUnk;\n    uint32_t *pGfxInfo;\n     */\n    uint64_t gfxUnkPtr;\n    uint64_t gfxInfoPtr;\n    /* 0x80 */\n    uint64_t unk4;\n    /* 0x88 StatList *pStats */\n    uint64_t statListPtr;\n    /* 0x90 UnitInventory *pInventory */\n    uint64_t inventoryPtr;\n    uint64_t unk5[13];\n    uint64_t skillPtr;\n    uint64_t unk6[9];\n    uint64_t nextPtr;\n    uint64_t roomNextPtr;\n};\n\nstruct PvPInfo {\n    uint32_t unitId;\n    uint32_t flags; /* 0x01-unlocked, 0x02-mute, 0x04-muted, 0x08-hostile */\n    uint64_t nextPtr;\n};\n\nstruct VectorData {\n    uint64_t ptr;\n    uint32_t size;\n    uint32_t unk0;\n    uint32_t capacity;\n    uint32_t unk1;\n};\n\nstruct GameInfo {\n    uint64_t unk0[5];\n    VectorData gameName;\n    char gameNameBuffer[0x40];\n    VectorData gamePass;\n    char gamePassBuffer[0x40];\n    VectorData region;\n    char regionBuffer[0x18];\n    uint64_t unk1[32];\n    VectorData season;\n    char seasonBuffer[0x18];\n};\n\nstruct RosterUnit {\n    char name[16];\n    uint64_t unk0[7];\n    uint32_t unitId;\n    uint32_t lifePercent;\n    uint32_t kills;\n    uint32_t classId;\n    uint16_t level;\n    uint16_t partyId;\n    uint32_t actId;\n    uint32_t posX;\n    uint32_t posY;\n    uint32_t flags; /* 0x01-normal, 0x02-invited */\n    uint32_t unk3;\n    uint64_t pvpInfoPtr; // 70\n    uint64_t unk4[6]; // 78\n    uint16_t unk5; // A8\n    char name2[16]; // AA\n    uint16_t unk6[3]; // BA\n    uint64_t unk7[7]; // C0\n    uint8_t unk8[7]; // F8\n    char utf8name[49]; // FF\n    uint64_t unk9; // 0x130\n    uint32_t order; // 0x138\n    uint32_t unk10[3]; // 0x13C\n    uint64_t nextPtr; // 0x148\n};\n\n#pragma pack(pop)\n\n}\n"
  },
  {
    "path": "src/d2r/mapstructs.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <array>\n#include <string>\n#include <cstdint>\n\nnamespace d2r {\n\nstruct MapPlayer {\n    uint32_t act;\n    uint32_t seed;\n    uint32_t levelId;\n    int posX, posY;\n    char name[16];\n    uint32_t classId;\n    uint16_t level;\n    uint16_t party;\n    uint8_t difficulty;\n    bool levelChanged;\n    std::array<int32_t, 16> stats;\n    uint64_t skillPtr;\n};\nstruct MapMonster {\n    int x, y;\n    const std::array<std::wstring, 13> *name;\n    wchar_t enchants[32];\n    uint8_t flag;\n    bool isNpc;\n    bool isUnique;\n};\nstruct MapObject {\n    int x, y;\n    const std::array<std::wstring, 13> *name;\n    uint8_t type;\n    uint8_t flag;\n    float w, h;\n};\nstruct MapItem {\n    int x, y;\n    const std::array<std::wstring, 13> *name;\n    uint8_t flag;\n    uint8_t color;\n};\n\n}\n"
  },
  {
    "path": "src/d2r/processdata.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"processdata.h\"\n\n#include \"d2rdefs.h\"\n#include \"cfg.h\"\n\n#include \"util/ntprocess.h\"\n#include \"data/gamedata.h\"\n\n#include <windows.h>\n\nnamespace d2r {\n\nextern wchar_t enchantStrings[256][4];\nextern wchar_t auraStrings[187][4];\nextern wchar_t immunityStrings[6][4];\nextern uint8_t statsMapping[size_t(StatId::TotalCount)];\n\nenum {\n    InventoryPanelOffset = 0x01,\n    CharacterPanelOffset = 0x02,\n    SkillFloatSelOffset = 0x03,\n    SkillTreePanelOffset = 0x04,\n    ChatMenuOffset = 0x08,\n    SystemMenuOffset = 0x09,\n    InGameMapOffset = 0x0A,\n    QuestPanelOffset = 0x0E,\n    WaypointPanelOffset = 0x13,\n    PartyPanelOffset = 0x15,\n    MercenaryOffset = 0x1E,\n};\n\n#define READ(a, v) util::readMemory64(handle, (a), sizeof(v), &(v))\n#define READN(a, v, n) util::readMemory64(handle, (a), (n), (v))\n\nProcessData::ProcessData() :\n    mapObjects(1024) {\n    mapMonsters.reserve(1024);\n    mapItems.reserve(1024);\n}\n\nProcessData::~ProcessData() {\n    if (handle) {\n        UnhookWinEvent(HWINEVENTHOOK(hook));\n        hook = nullptr;\n        CloseHandle(handle);\n    }\n}\n\nvoid ProcessData::resetData() {\n    if (handle) {\n        UnhookWinEvent(HWINEVENTHOOK(hook));\n        hook = nullptr;\n        CloseHandle(handle);\n        handle = nullptr;\n    }\n\n    hwnd = nullptr;\n\n    baseAddr = 0;\n    baseSize = 0;\n\n    hashTableBaseAddr = 0;\n    uiBaseAddr = 0;\n    isExpansionAddr = 0;\n    rosterDataAddr = 0;\n    gameInfoAddr = 0;\n\n    mapEnabled = 0;\n    panelEnabled = 0;\n    focusedPlayer = 0;\n    currPlayer = nullptr;\n\n    gameName.clear();\n    gamePass.clear();\n    region.clear();\n    season.clear();\n\n    realTombLevelId = 0;\n    superUniqueTombLevelId = 0;\n\n    mapPlayers.clear();\n    mapMonsters.clear();\n    mapObjects.clear();\n    mapItems.clear();\n    knownItems.clear();\n}\n\nvoid ProcessData::updateData() {\n    uint8_t lastDifficulty;\n    uint32_t lastSeed, lastAct, lastLevelId;\n    if (currPlayer) {\n        lastDifficulty = currPlayer->difficulty;\n        lastSeed = currPlayer->seed;\n        lastAct = currPlayer->act;\n        lastLevelId = currPlayer->levelId;\n    } else {\n        lastDifficulty = uint8_t(-1);\n        lastSeed = 0;\n        lastAct = uint32_t(-1);\n        lastLevelId = uint32_t(-1);\n    }\n\n    mapPlayers.clear();\n    if (cfg->showMonsters) {\n        mapMonsters.clear();\n    }\n    if (cfg->showItems) {\n        mapItems.clear();\n    }\n\n    /* Address from MapAssist: read obfuscated map seed */\n    uint64_t mapSeedPtr;\n    if (!READ(mapSeedAddr, mapSeedPtr)) {\n        return;\n    }\n    uint32_t seedCheck;\n    if (!READ(mapSeedPtr + 0x110, seedCheck)) {\n        return;\n    }\n    if (!READ(mapSeedPtr + (seedCheck ? 0x840 : 0x10C0), currSeed)) {\n        return;\n    }\n\n    readRosters();\n    readUnitHashTable(hashTableBaseAddr, [this, lastDifficulty, lastSeed, lastAct, lastLevelId](const UnitAny &unit) {\n        if (!unit.unitId || !unit.actPtr || !unit.inventoryPtr) { return; }\n        uint64_t token;\n        if (unit.unitId != focusedPlayer) {\n            /* --START-- remove this if using readRoomUnits() */\n            /* mode is 17 when this is a corpse */\n            if (unit.mode != 17) { return; }\n            DrlgAct act;\n            if (!READ(unit.actPtr, act)) { return; }\n            auto &player = mapPlayers[unit.unitId];\n            player.skillPtr = unit.skillPtr;\n            player.name[0] = 0;\n            READ(unit.unionPtr, player.name);\n            player.levelChanged = false;\n            player.act = act.actId;\n            player.seed = currSeed;\n            READ(act.miscPtr + 0x830, player.difficulty);\n            player.stats.fill(0);\n            readPlayerStats(unit, [&player](uint16_t statId, int32_t value) {\n                if (statId > 15) {\n                    return;\n                }\n                player.stats[statId] = value;\n            });\n            DynamicPath path;\n            if (!READ(unit.pathPtr, path)) { return; }\n            player.posX = path.posX;\n            player.posY = path.posY;\n            DrlgRoom1 room1;\n            if (!READ(path.room1Ptr, room1)) { return; }\n            DrlgRoom2 room2;\n            if (!READ(room1.room2Ptr, room2)) { return; }\n            if (!READ(room2.levelPtr + 0x1F8, player.levelId)) { return; }\n            /* --END-- remove this if using readRoomUnits() */\n            return;\n        }\n        DrlgAct act;\n        auto &player = mapPlayers[unit.unitId];\n        player.skillPtr = unit.skillPtr;\n        player.name[0] = 0;\n        READ(unit.unionPtr, player.name);\n        player.stats.fill(0);\n        readPlayerStats(unit, [&player](uint16_t statId, int32_t value) {\n            if (statId > 15) {\n                return;\n            }\n            player.stats[statId] = value;\n        });\n        if (!READ(unit.actPtr, act)) { return; }\n        READ(act.miscPtr + 0x830, player.difficulty);\n        player.levelChanged = false;\n        player.seed = currSeed;\n        if (lastDifficulty != player.difficulty || lastSeed != currSeed) {\n            readGameInfo();\n            player.levelChanged = true;\n            knownItems.clear();\n        }\n        player.act = act.actId;\n        if (lastAct != act.actId) {\n            player.levelChanged = true;\n        }\n        if (player.levelChanged) {\n            /* get real TalTomb level id */\n            READ(act.miscPtr + 0x120, realTombLevelId);\n            READ(act.miscPtr + 0x874, superUniqueTombLevelId);\n        }\n        DynamicPath path;\n        if (!READ(unit.pathPtr, path)) { return; }\n        player.posX = path.posX;\n        player.posY = path.posY;\n        DrlgRoom1 room1;\n        if (!READ(path.room1Ptr, room1)) { return; }\n        DrlgRoom2 room2;\n        if (!READ(room1.room2Ptr, room2)) { return; }\n        uint32_t levelId;\n        if (!READ(room2.levelPtr + 0x1F8, levelId)) { return; }\n\n        player.levelId = levelId;\n        if (levelId != lastLevelId) {\n            player.levelChanged = true;\n        }\n        if (player.levelChanged) {\n            if (cfg->showObjects) {\n                mapObjects.clear();\n            }\n        }\n/*  this is another way of reading all units from memory, we may need this if we need to see units on neighbour levels\n        std::unordered_set<uint64_t> rset(256);\n        rset.insert(path.room1Ptr);\n        readRoomUnits(room1, rset);\n*/\n    });\n    if (!focusedPlayer) {\n        return;\n    }\n    uint8_t mem[0x28];\n    READ(uiBaseAddr, mem);\n    mapEnabled = mem[InGameMapOffset];\n    uint32_t enableBits = 0;\n    if (mem[InventoryPanelOffset]) { enableBits |= 0x01; }\n    if (mem[CharacterPanelOffset]) { enableBits |= 0x02; }\n    if (mem[SkillTreePanelOffset]) { enableBits |= 0x04; }\n    if (mem[SystemMenuOffset]) { enableBits |= 0x08; }\n    if (mem[QuestPanelOffset]) { enableBits |= 0x10; }\n    if (mem[PartyPanelOffset]) { enableBits |= 0x20; }\n    if (mem[MercenaryOffset]) { enableBits |= 0x40; }\n    if (mem[WaypointPanelOffset]) { enableBits |= 0x80; }\n    if (mem[SkillFloatSelOffset]) { enableBits |= 0x100; }\n    panelEnabled = enableBits;\n\n    if (cfg->showMonsters) {\n        readUnitHashTable(hashTableBaseAddr + 8 * 0x80, [this](const auto &unit) {\n            readUnit(unit);\n        });\n    }\n    if (cfg->showObjects) {\n        readUnitHashTable(hashTableBaseAddr + 8 * 0x100, [this](const auto &unit) {\n            readUnit(unit);\n        });\n    }\n    if (cfg->showItems) {\n        readUnitHashTable(hashTableBaseAddr + 8 * 0x200, [this](const auto &unit) {\n            readUnit(unit);\n        });\n    }\n}\n\ninline bool matchMem(size_t sz, const uint8_t *mem, const uint8_t *search, const uint8_t *mask) {\n    for (size_t i = 0; i < sz; ++i) {\n        uint8_t m = mask[i];\n        if ((mem[i] & m) != (search[i] & m)) { return false; }\n    }\n    return true;\n}\n\ninline size_t searchMem(const uint8_t *mem, size_t sz, const uint8_t *search, const uint8_t *mask, size_t searchSz) {\n    if (sz < searchSz) { return size_t(-1); }\n    size_t e = sz - searchSz + 1;\n    for (size_t i = 0; i < e; ++i) {\n        if (matchMem(searchSz, mem + i, search, mask)) {\n            return i;\n        }\n    }\n    return size_t(-1);\n}\n\nvoid ProcessData::updateOffset() {\n    auto *mem = new(std::nothrow) uint8_t[size_t(baseSize)];\n    if (mem && READN(baseAddr, mem, uint32_t(baseSize))) {\n        const uint8_t search0[] = {0x48, 0x03, 0xC7, 0x49, 0x8B, 0x8C, 0xC6 };\n        const uint8_t mask0[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\n        auto off = searchMem(mem, size_t(baseSize), search0, mask0, sizeof(search0));\n        if (off != size_t(-1)) {\n            int32_t rel;\n            if (READ(baseAddr + off + 7, rel)) {\n                hashTableBaseAddr = baseAddr + rel;\n            }\n        }\n\n        const uint8_t search1[] = {0x48, 0x89, 0x45, 0xB7, 0x4C, 0x8D, 0x35, 0, 0, 0, 0 };\n        const uint8_t mask1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};\n        off = searchMem(mem, size_t(baseSize), search1, mask1, sizeof(search1));\n        if (off != size_t(-1)) {\n            int32_t rel;\n            if (READ(baseAddr + off + 7, rel)) {\n                uiBaseAddr = baseAddr + off + 11 + rel;\n            }\n        }\n\n        const uint8_t search2[] = {0x48, 0x8B, 0x05, 0, 0, 0, 0, 0x48, 0x8B, 0xD9, 0xF3, 0x0F, 0x10, 0x50};\n        const uint8_t mask2[] = {0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\n        off = searchMem(mem, size_t(baseSize), search2, mask2, sizeof(search2));\n        if (off != size_t(-1)) {\n            int32_t rel;\n            if (READ(baseAddr + off + 3, rel)) {\n                isExpansionAddr = baseAddr + off + 7 + rel;\n            }\n        }\n\n        const uint8_t search3[] = {0x02, 0x45, 0x33, 0xD2, 0x4D, 0x8B};\n        const uint8_t mask3[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\n        off = searchMem(mem, size_t(baseSize), search3, mask3, sizeof(search3));\n        if (off != size_t(-1)) {\n            int32_t rel;\n            if (READ(baseAddr + off - 3, rel)) {\n                rosterDataAddr = baseAddr + off + 1 + rel;\n            }\n        }\n\n        const uint8_t search4[] = {0x44, 0x88, 0x25, 0, 0, 0, 0, 0x66, 0x44, 0x89, 0x25};\n        const uint8_t mask4[] = {0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF};\n        off = searchMem(mem, size_t(baseSize), search4, mask4, sizeof(search4));\n        if (off != size_t(-1)) {\n            int32_t rel;\n            if (READ(baseAddr + off + 3, rel)) {\n                gameInfoAddr = baseAddr + off - 0x121 + rel;\n            }\n        }\n\n        const uint8_t search5[] = {0x41, 0x8B, 0xF9, 0x48, 0x8D, 0x0D, 0, 0, 0, 0};\n        const uint8_t mask5[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};\n        off = searchMem(mem, size_t(baseSize), search5, mask5, sizeof(search5));\n        if (off != size_t(-1)) {\n            int32_t rel;\n            if (READ(baseAddr + off + 6, rel)) {\n                mapSeedAddr = baseAddr + off + 0xEA + rel;\n            }\n        }\n    }\n    delete[] mem;\n}\n\nSkill *ProcessData::getSkill(uint16_t id) {\n    if (!currPlayer) { return nullptr; }\n    SkillInfo si;\n    if (READ(currPlayer->skillPtr, si)) {\n        static Skill sk;\n        uint64_t ptr = si.firstSkillPtr;\n        while (ptr && READ(ptr, sk)) {\n            uint16_t skillId;\n            READ(sk.skillTxtPtr, skillId);\n            if (skillId == id) { return &sk; }\n            ptr = sk.nextSkillPtr;\n        }\n    }\n    return nullptr;\n}\n\nvoid ProcessData::readRosters() {\n    uint64_t addr;\n    READ(rosterDataAddr, addr);\n    bool first = true;\n    while (addr) {\n        RosterUnit mem;\n        if (!READ(addr, mem)) { break; }\n        auto &p = mapPlayers[mem.unitId];\n        p.classId = mem.classId;\n        p.level = mem.level;\n        p.party = mem.partyId;\n        memcpy(p.name, mem.name, 16);\n        if (first) {\n            focusedPlayer = mem.unitId;\n            currPlayer = &p;\n            first = false;\n        } else {\n            p.posX = mem.posX;\n            p.posY = mem.posY;\n            p.act = mem.actId;\n        }\n        addr = mem.nextPtr;\n    }\n}\n\nvoid ProcessData::readUnitHashTable(uint64_t addr, const std::function<void(const UnitAny &)> &callback) {\n    uint64_t addrList[0x80];\n    if (!READ(addr, addrList)) { return; }\n    for (auto paddr: addrList) {\n        while (paddr) {\n            UnitAny unit;\n            if (READ(paddr, unit)) {\n                callback(unit);\n            }\n            paddr = unit.nextPtr;\n        }\n    }\n}\n\nvoid ProcessData::readStatList(uint64_t addr, uint32_t unitId, const std::function<void(const StatList &)> &callback) {\n    StatList stats;\n    if (!READ(addr, stats)) { return; }\n    do {\n        /* check if this is owner stat or aura */\n        if (!unitId || stats.ownerId == unitId) {\n            callback(stats);\n        }\n        if (!(stats.flag & 0x80000000u)) { break; }\n        if (!stats.nextListEx || !READ(stats.nextListEx, stats)) { break; }\n    } while (true);\n}\n\nvoid ProcessData::readPlayerStats(const UnitAny &unit, const std::function<void(uint16_t, int32_t)> &callback) {\n    readStatList(unit.statListPtr, 0, [this, &callback](const StatList &stats) {\n        if (!(stats.flag & 0x80000000u)) { return; }\n        static StatEx statEx[256];\n        auto cnt = std::min(255u, uint32_t(stats.fullStat.statCount));\n        if (!READN(stats.fullStat.statPtr, statEx, sizeof(StatEx) * cnt)) { return; }\n        StatEx *st = statEx;\n        st[cnt].statId = 0xFFFF;\n        uint16_t statId;\n        for (; (statId = st->statId) != 0xFFFF; ++st) {\n            if (statId >= 16) { break; }\n            callback(statId, statId >= 6 && statId <= 11 ? (st->value >> 8) : st->value);\n        }\n    });\n}\n\nvoid ProcessData::readUnit(const UnitAny &unit) {\n    switch (unit.unitType) {\n    case 0:readUnitPlayer(unit);\n        break;\n    case 1:if (cfg->showMonsters) { readUnitMonster(unit); }\n        break;\n    case 2:if (cfg->showObjects) { readUnitObject(unit); }\n        break;\n    case 4:if (cfg->showItems) { readUnitItem(unit); }\n        break;\n    }\n}\n\nvoid ProcessData::readUnitPlayer(const UnitAny &unit) {\n    if (unit.unitId == focusedPlayer) { return; }\n    DrlgAct act;\n    if (!READ(unit.actPtr, act)) { return; }\n    auto &player = mapPlayers[unit.unitId];\n    player.name[0] = 0;\n    READ(unit.unionPtr, player.name);\n    player.levelChanged = false;\n    player.act = act.actId;\n    player.seed = currSeed;\n    READ(act.miscPtr + 0x830, player.difficulty);\n    player.stats.fill(0);\n    readPlayerStats(unit, [&player](uint16_t statId, int32_t value) {\n        if (statId > 15) {\n            return;\n        }\n        player.stats[statId] = value;\n    });\n    DynamicPath path;\n    if (!READ(unit.pathPtr, path)) { return; }\n    player.posX = path.posX;\n    player.posY = path.posY;\n    DrlgRoom1 room1;\n    if (!READ(path.room1Ptr, room1)) { return; }\n    DrlgRoom2 room2;\n    if (!READ(room1.room2Ptr, room2)) { return; }\n    if (!READ(room2.levelPtr + 0x1F8, player.levelId)) { return; }\n}\n\nvoid ProcessData::readUnitMonster(const UnitAny &unit) {\n    if (unit.mode == 0 || unit.mode == 12 || unit.txtFileNo >= data::gamedata->monsters.size()) { return; }\n    MonsterData monData;\n    if (!READ(unit.unionPtr, monData)) { return; }\n    auto isUnique = (monData.flag & 0x0E) != 0;\n    auto &txtData = data::gamedata->monsters[unit.txtFileNo];\n    auto isNpc = std::get<1>(txtData);\n    auto sm = cfg->showMonsters;\n    if (!isNpc && !(sm == 2 || (isUnique && sm == 1))) { return; }\n    DynamicPath path;\n    if (!READ(unit.pathPtr, path)) { return; }\n    auto &mon = mapMonsters.emplace_back();\n    mon.x = path.posX;\n    mon.y = path.posY;\n    mon.isNpc = isNpc;\n    mon.isUnique = isUnique;\n    mon.flag = monData.flag;\n    if (isNpc) {\n        if (cfg->showNpcNames) {\n            if (monData.mercNameId == uint16_t(-1) || monData.mercNameId >= data::gamedata->mercNames.size()) {\n                /* show only npcs' name, hide summons' name */\n                if (isNpc == 1) { mon.name = std::get<2>(txtData); }\n            } else {\n                mon.name = &data::gamedata->mercNames[monData.mercNameId];\n            }\n        }\n        return;\n    } else if (auto sn = cfg->showMonsterNames; (sn == 2 || (isUnique && sn == 1))) {\n        /* Super unique */\n        if ((monData.flag & 2) && monData.uniqueNo < data::gamedata->superUniques.size()) {\n            mon.name = data::gamedata->superUniques[monData.uniqueNo].second;\n        } else {\n            mon.name = std::get<2>(txtData);\n        }\n    }\n    int off = 0;\n    bool hasAura = false;\n    if (auto sme = cfg->showMonsterEnchants; sme == 2 || (isUnique && sme == 1)) {\n        uint8_t id;\n        for (int n = 0; n < 9 && (id = monData.enchants[n]) != 0; ++n) {\n            if (id == 30) {\n                hasAura = true;\n                continue;\n            }\n            const auto *str = enchantStrings[id];\n            while (*str) {\n                mon.enchants[off++] = *str++;\n            }\n        }\n    }\n    auto smi = cfg->showMonsterImmunities;\n    bool showMI = smi == 2 || (isUnique && smi == 1);\n    if (!showMI && !hasAura) {\n        mon.enchants[off] = 0;\n        return;\n    }\n    readStatList(unit.statListPtr, unit.unitId, [this, &off, &mon, hasAura, showMI](const StatList &stats) {\n        if (stats.stateNo) {\n            if (!hasAura) { return; }\n            const wchar_t *str = auraStrings[stats.stateNo];\n            while (*str) {\n                mon.enchants[off++] = *str++;\n            }\n            return;\n        }\n        if (!showMI) { return; }\n        static StatEx statEx[64];\n        auto cnt = std::min(64u, uint32_t(stats.baseStat.statCount));\n        if (!READN(stats.baseStat.statPtr, statEx, sizeof(StatEx) * cnt)) { return; }\n        StatEx *st = statEx;\n        for (; cnt; --cnt, ++st) {\n            auto statId = st->statId;\n            if (statId >= uint16_t(StatId::TotalCount)) { continue; }\n            auto mapping = statsMapping[statId];\n            if (!mapping || st->value < 100) { continue; }\n            const wchar_t *str = immunityStrings[mapping];\n            while (*str) {\n                mon.enchants[off++] = *str++;\n            }\n        }\n    });\n    mon.enchants[off] = 0;\n}\n\nvoid ProcessData::readUnitObject(const UnitAny &unit) {\n    if (/* Portals */ unit.txtFileNo != 59 && unit.txtFileNo != 60 && /* destroyed/opened */ unit.mode == 2) {\n        StaticPath path;\n        if (READ(unit.pathPtr, path)) {\n            mapObjects.erase(path.posX | (uint32_t(path.posY) << 16));\n        }\n        return;\n    }\n    auto ite = data::gamedata->objects[0].find(unit.txtFileNo);\n    if (ite == data::gamedata->objects[0].end()) { return; }\n    auto type = std::get<0>(ite->second);\n    switch (type) {\n    case data::TypePortal:\n    case data::TypeWell:\n    case data::TypeShrine: {\n        uint8_t flag;\n        READ(unit.unionPtr + 8, flag);\n        StaticPath path;\n        if (!READ(unit.pathPtr, path)) { break; }\n        auto &obj = mapObjects[path.posX | (uint32_t(path.posY) << 16)];\n        if (obj.x) { break; }\n        obj.type = std::get<0>(ite->second);\n        obj.name = type == data::TypeShrine && flag < data::gamedata->shrines.size() ?\n                   data::gamedata->shrines[flag].second : std::get<2>(ite->second);\n        obj.x = path.posX;\n        obj.y = path.posY;\n        obj.flag = flag;\n        obj.w = std::get<3>(ite->second) * .5f;\n        obj.h = std::get<4>(ite->second) * .5f;\n        break;\n    }\n    default:break;\n    }\n}\n\nvoid ProcessData::readUnitItem(const UnitAny &unit) {\n    ItemData item;\n    if (!unit.actPtr /* ground items has pAct set */\n        || !READ(unit.unionPtr, item)\n        || item.ownerInvPtr || item.location != 0\n        || (item.itemFlags & 0x01) /* InStore */) { return; }\n    /* the item is on the ground */\n    uint32_t sockets = 0;\n    if (item.itemFlags & 0x800u) {\n        readStatList(unit.statListPtr, unit.unitId, [this, &sockets](const StatList &stats) {\n            if (stats.stateNo) { return; }\n            static StatEx statEx[64];\n            auto cnt = std::min(64u, uint32_t(stats.baseStat.statCount));\n            if (!READN(stats.baseStat.statPtr, statEx, sizeof(StatEx) * cnt)) { return; }\n            StatEx *st = statEx;\n            for (; cnt; --cnt, ++st) {\n                if (st->statId != uint16_t(StatId::ItemNumsockets)) { continue; }\n                sockets = st->value;\n                break;\n            }\n        });\n    }\n    auto n = data::filterItem(&unit, &item, sockets);\n    if (!n) { return; }\n    StaticPath path;\n    if (!READ(unit.pathPtr, path)) { return; }\n    auto &mitem = mapItems.emplace_back();\n    mitem.x = path.posX;\n    mitem.y = path.posY;\n    mitem.name = unit.txtFileNo < data::gamedata->items.size() ? data::gamedata->items[unit.txtFileNo].second : nullptr;\n    mitem.flag = n & 0x0F;\n    auto color = (n >> 4) & 0x0F;\n    if (color == 0) {\n        if (auto quality = uint32_t(item.quality - 1); quality < 8) {\n            const uint8_t qualityColors[8] = {15, 15, 5, 3, 2, 9, 4, 8};\n            color = qualityColors[quality];\n        }\n    }\n    mitem.color = color;\n    auto snd = size_t(n >> 8);\n    if (snd > 0 && knownItems.find(unit.unitId) == knownItems.end()) {\n        knownItems.insert(unit.unitId);\n        if (snd < cfg->sounds.size() && !cfg->sounds[snd].first.empty()) {\n            if (cfg->sounds[snd].second) {\n                PlaySoundW(cfg->sounds[snd].first.c_str(), nullptr, SND_ALIAS | SND_ASYNC | SND_NODEFAULT);\n            } else {\n                PlaySoundW(cfg->sounds[snd].first.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);\n            }\n        }\n    }\n}\n\nvoid ProcessData::readGameInfo() {\n    GameInfo gameInfo;\n    if (READ(gameInfoAddr, gameInfo)) {\n        gameName.assign(gameInfo.gameNameBuffer, gameInfo.gameNameBuffer + gameInfo.gameName.size);\n        gamePass.assign(gameInfo.gamePassBuffer, gameInfo.gamePassBuffer + gameInfo.gamePass.size);\n        region.assign(gameInfo.regionBuffer, gameInfo.regionBuffer + gameInfo.region.size);\n        season.assign(gameInfo.seasonBuffer, gameInfo.seasonBuffer + gameInfo.season.size);\n    } else {\n        gameName.clear();\n        gamePass.clear();\n        region.clear();\n        season.clear();\n    }\n}\n\n/*\nvoid ProcessData::readRoomUnits(const DrlgRoom1 &room1, std::unordered_set<uint64_t> &roomList) {\n    auto *currProcess = currProcess_;\n    DrlgRoom2 room2;\n    READ(room1.room2Ptr, room2);\n    uint64_t roomsNear[64];\n    uint64_t addr = room1.unitFirstAddr;\n    while (addr) {\n        UnitAny unit;\n        if (!READ(addr, unit)) { break; }\n        readUnit(unit);\n        addr = unit.roomNextPtr;\n    }\n    auto count = std::min(64u, room1.roomsNear);\n    if (READN(room1.roomsNearListPtr, roomsNear, count * sizeof(uint64_t))) {\n        for (auto i = 0u; i < count; ++i) {\n            auto addr = roomsNear[i];\n            if (roomList.find(addr) != roomList.end()) { continue; }\n            DrlgRoom1 room;\n            if (!READ(addr, room)) { continue; }\n            roomList.insert(addr);\n            readRoomUnits(room, roomList);\n        }\n    }\n}\n*/\n\n}\n"
  },
  {
    "path": "src/d2r/processdata.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"mapstructs.h\"\n#include <vector>\n#include <unordered_map>\n#include <unordered_set>\n#include <functional>\n\nnamespace d2r {\n\nstruct UnitAny;\nstruct DrlgRoom1;\nstruct StatList;\nstruct Skill;\n\nclass ProcessData final {\npublic:\n    ProcessData();\n    ~ProcessData();\n    void resetData();\n    void updateData();\n    void updateOffset();\n    Skill *getSkill(uint16_t id);\n\nprivate:\n    void readRosters();\n    void readUnitHashTable(uint64_t addr, const std::function<void(const UnitAny &)> &callback);\n    void readStatList(uint64_t addr, uint32_t unitId, const std::function<void(const StatList &)> &callback);\n    void readPlayerStats(const UnitAny &unit, const std::function<void(uint16_t, int32_t)> &callback);\n    void readUnit(const UnitAny &unit);\n    void readUnitPlayer(const UnitAny &unit);\n    void readUnitMonster(const UnitAny &unit);\n    void readUnitObject(const UnitAny &unit);\n    void readUnitItem(const UnitAny &unit);\n    void readGameInfo();\n\npublic:\n    void *handle = nullptr;\n    void *hwnd = nullptr;\n    void *hook = nullptr;\n\n    uint64_t baseAddr = 0;\n    uint64_t baseSize = 0;\n\n    uint64_t hashTableBaseAddr = 0;\n    uint64_t uiBaseAddr = 0;\n    uint64_t isExpansionAddr = 0;\n    uint64_t rosterDataAddr = 0;\n    uint64_t gameInfoAddr = 0;\n    uint64_t mapSeedAddr = 0;\n    uint32_t currSeed = 0;\n\n    uint8_t mapEnabled = 0;\n    uint32_t panelEnabled = 0;\n\n    uint32_t focusedPlayer = 0;\n    const MapPlayer *currPlayer = nullptr;\n\n    std::wstring gameName, gamePass, region, season;\n\n    uint32_t realTombLevelId = 0;\n    uint32_t superUniqueTombLevelId = 0;\n\n    std::unordered_map<uint32_t, MapPlayer> mapPlayers;\n    std::vector<MapMonster> mapMonsters;\n    std::unordered_map<uint32_t, MapObject> mapObjects;\n    std::vector<MapItem> mapItems;\n    std::unordered_set<uint32_t> knownItems;\n};\n\n}\n"
  },
  {
    "path": "src/d2r/processmanager.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"processmanager.h\"\n\n#include \"cfg.h\"\n#include \"d2rdefs.h\"\n#include \"util/ntprocess.h\"\n#include \"util/util.h\"\n\n#include <windows.h>\n#include <psapi.h>\n#include <shlwapi.h>\n#include <cstdio>\n\nnamespace d2r {\n\n#include \"stringdefs.inl\"\nuint8_t statsMapping[size_t(StatId::TotalCount)] = {};\n\nstatic inline void loadEncText(wchar_t *output, const std::wstring &input) {\n    if (input.empty()) {\n        output[0] = 0;\n        return;\n    }\n    const wchar_t *inp = input.c_str();\n    std::wstring out;\n    if (inp[0] != '{') {\n        out.push_back(char(15));\n    }\n    while (*inp) {\n        if (*inp == '{') {\n            wchar_t *endptr;\n            out.push_back(char(std::min(15u, uint32_t(std::wcstol(inp + 1, &endptr, 0)))));\n            inp = endptr;\n            while (*inp && *inp != '}') ++inp;\n            if (*inp) {\n                ++inp;\n            }\n        } else {\n            out.push_back(*inp++);\n        }\n    }\n    if (out.length() > 3) { out.resize(3); }\n    for (auto c: out) {\n        *output++ = c;\n    }\n    *output = 0;\n}\n\nenum {\n    InventoryPanelOffset = 0x01,\n    CharacterPanelOffset = 0x02,\n    SkillFloatSelOffset = 0x03,\n    SkillTreePanelOffset = 0x04,\n    ChatMenuOffset = 0x08,\n    SystemMenuOffset = 0x09,\n    InGameMapOffset = 0x0A,\n    QuestPanelOffset = 0x0E,\n    WaypointPanelOffset = 0x13,\n    PartyPanelOffset = 0x15,\n    MercenaryOffset = 0x1E,\n};\n\n#define READ(a, v) readMemory64(currProcess->handle, (a), sizeof(v), &(v))\n#define READN(a, v, n) readMemory64(currProcess->handle, (a), (n), (v))\n\nProcessManager::ProcessManager(uint32_t searchInterval) :\n    searchInterval_(std::chrono::milliseconds(searchInterval)) {\n    std::pair<StatId, size_t> statsMappingInit[] = {\n        {StatId::Damageresist, 0},\n        {StatId::Magicresist, 1},\n        {StatId::Fireresist, 2},\n        {StatId::Lightresist, 3},\n        {StatId::Coldresist, 4},\n        {StatId::Poisonresist, 5},\n    };\n    for (auto[k, v]: statsMappingInit) {\n        statsMapping[size_t(k)] = v;\n    }\n\n    loadFromCfg();\n}\n\nvoid ProcessManager::killProcess() {\n    TerminateProcess(HANDLE(currProcess_->handle), 0);\n}\n\ninline bool matchMem(size_t sz, const uint8_t *mem, const uint8_t *search, const uint8_t *mask) {\n    for (size_t i = 0; i < sz; ++i) {\n        uint8_t m = mask[i];\n        if ((mem[i] & m) != (search[i] & m)) { return false; }\n    }\n    return true;\n}\n\ninline size_t searchMem(const uint8_t *mem, size_t sz, const uint8_t *search, const uint8_t *mask, size_t searchSz) {\n    if (sz < searchSz) { return size_t(-1); }\n    size_t e = sz - searchSz + 1;\n    for (size_t i = 0; i < e; ++i) {\n        if (matchMem(searchSz, mem + i, search, mask)) {\n            return i;\n        }\n    }\n    return size_t(-1);\n}\n\nstatic std::function<void(int, int, int, int)> sizeCallback;\n\nvoid onSizeChange(HWND hwnd) {\n    if (!sizeCallback) { return; }\n    RECT rc;\n    if (GetClientRect(hwnd, &rc)) {\n        /* check WS_CAPTION for windowed mode */\n        if (GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION) {\n            POINT pt = {rc.left, rc.top};\n            if (ClientToScreen(hwnd, &pt)) {\n                rc.left = pt.x;\n                rc.top = pt.y;\n            }\n            pt = {rc.right, rc.bottom};\n            if (ClientToScreen(hwnd, &pt)) {\n                rc.right = pt.x;\n                rc.bottom = pt.y;\n            }\n        }\n    } else {\n        HMONITOR hm = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);\n        MONITORINFO mi;\n        mi.cbSize = sizeof(MONITORINFO);\n        GetMonitorInfo(hm, &mi);\n        rc = mi.rcWork;\n    }\n    sizeCallback(rc.left, rc.top, rc.right, rc.bottom);\n}\n\nvoid ProcessManager::updateData() {\n    auto foregroundWnd = GetForegroundWindow();\n    if (!currProcess_ || foregroundWnd != currProcess_->hwnd) {\n        for (auto ite = processes_.begin(); ite != processes_.end();) {\n            DWORD ret = WaitForSingleObject(ite->second.handle, 0);\n            if (ret == WAIT_TIMEOUT) {\n                ++ite;\n            } else {\n                if (processCloseCallback_) {\n                    processCloseCallback_(ite->first);\n                }\n                ite = processes_.erase(ite);\n            }\n        }\n        currProcess_ = nullptr;\n        auto now = util::getCurrTime();\n        if (now >= nextSearchTime_) {\n            searchForProcess(foregroundWnd);\n            nextSearchTime_ = now + searchInterval_;\n            if (currProcess_ && currProcess_->hwnd) {\n                onSizeChange(HWND(currProcess_->hwnd));\n            }\n        }\n    }\n    if (!currProcess_) {\n        return;\n    }\n    currProcess_->updateData();\n}\n\nvoid ProcessManager::setWindowPosCallback(const std::function<void(int, int, int, int)> &cb) {\n    sizeCallback = cb;\n    if (currProcess_) {\n        onSizeChange((HWND)currProcess_->hwnd);\n    }\n}\n\nSkill *ProcessManager::getSkill(uint16_t id) {\n    if (!currProcess_) { return nullptr; }\n    return currProcess_->getSkill(id);\n}\n\nVOID CALLBACK hookCb(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild,\n                     DWORD idEventThread, DWORD dwmsEventTime) {\n    onSizeChange(hwnd);\n}\n\nvoid ProcessManager::searchForProcess(void *hwnd) {\n    if (!hwnd) {\n        currProcess_ = nullptr;\n        return;\n    }\n    auto ite = processes_.find(hwnd);\n    if (ite != processes_.end()) {\n        currProcess_ = &ite->second;\n        return;\n    }\n    DWORD processId = 0;\n    if (!GetWindowThreadProcessId((HWND)hwnd, &processId)) { return; }\n    HANDLE handle =\n        OpenProcess(PROCESS_VM_READ | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, processId);\n    if (!handle) { return; }\n    wchar_t fullpath[MAX_PATH];\n    if (!GetProcessImageFileNameW(handle, fullpath, MAX_PATH)) {\n        CloseHandle(handle);\n        return;\n    }\n    if (StrCmpIW(PathFindFileNameW(fullpath), L\"D2R.exe\") != 0) {\n        CloseHandle(handle);\n        return;\n    }\n    Sleep(1000);\n    uint64_t baseAddr, baseSize = 0;\n    util::getModules(handle, [&baseAddr, &baseSize](uint64_t addr, uint64_t size, const wchar_t *name) {\n        if (StrCmpIW(name, L\"D2R.exe\") != 0) {\n            return true;\n        }\n        baseAddr = addr;\n        baseSize = size;\n        return false;\n    });\n    if (!baseSize) {\n        CloseHandle(handle);\n        return;\n    }\n    auto &procInfo = processes_[(void *)hwnd];\n    procInfo.handle = handle;\n    procInfo.hwnd = hwnd;\n    procInfo.baseAddr = baseAddr;\n    procInfo.baseSize = baseSize;\n\n    currProcess_ = &procInfo;\n    procInfo.hook = SetWinEventHook(EVENT_SYSTEM_MOVESIZEEND,\n                                    EVENT_SYSTEM_MOVESIZEEND,\n                                    nullptr,\n                                    hookCb,\n                                    processId,\n                                    0,\n                                    WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);\n    onSizeChange(HWND(procInfo.hwnd));\n    currProcess_->updateOffset();\n}\n\nvoid ProcessManager::loadFromCfg() {\n    loadEncText(enchantStrings[5], cfg->encTxtExtraStrong);\n    loadEncText(enchantStrings[6], cfg->encTxtExtraFast);\n    loadEncText(enchantStrings[7], cfg->encTxtCursed);\n    loadEncText(enchantStrings[8], cfg->encTxtMagicResistant);\n    loadEncText(enchantStrings[9], cfg->encTxtFireEnchanted);\n    loadEncText(enchantStrings[17], cfg->encTxtLigntningEnchanted);\n    loadEncText(enchantStrings[18], cfg->encTxtColdEnchanted);\n    loadEncText(enchantStrings[25], cfg->encTxtManaBurn);\n    loadEncText(enchantStrings[26], cfg->encTxtTeleportation);\n    loadEncText(enchantStrings[27], cfg->encTxtSpectralHit);\n    loadEncText(enchantStrings[28], cfg->encTxtStoneSkin);\n    loadEncText(enchantStrings[29], cfg->encTxtMultipleShots);\n    loadEncText(enchantStrings[37], cfg->encTxtFanatic);\n    loadEncText(enchantStrings[39], cfg->encTxtBerserker);\n\n    loadEncText(auraStrings[33], cfg->MightAura);\n    loadEncText(auraStrings[35], cfg->HolyFireAura);\n    loadEncText(auraStrings[40], cfg->BlessedAimAura);\n    loadEncText(auraStrings[43], cfg->HolyFreezeAura);\n    loadEncText(auraStrings[46], cfg->HolyShockAura);\n    loadEncText(auraStrings[28], cfg->ConvictionAura);\n    loadEncText(auraStrings[49], cfg->FanaticismAura);\n\n    loadEncText(immunityStrings[0], cfg->encTxtPhysicalImmunity);\n    loadEncText(immunityStrings[1], cfg->encTxtMagicImmunity);\n    loadEncText(immunityStrings[2], cfg->encTxtFireImmunity);\n    loadEncText(immunityStrings[3], cfg->encTxtLightningImmunity);\n    loadEncText(immunityStrings[4], cfg->encTxtColdImmunity);\n    loadEncText(immunityStrings[5], cfg->encTxtPoisonImmunity);\n}\n\n}\n"
  },
  {
    "path": "src/d2r/processmanager.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"processdata.h\"\n\n#include <unordered_map>\n#include <unordered_set>\n#include <string>\n#include <vector>\n#include <array>\n#include <functional>\n#include <chrono>\n#include <cstdint>\n\nnamespace d2r {\n\nstruct UnitAny;\nstruct DrlgRoom1;\nstruct StatList;\nstruct Skill;\n\nclass ProcessManager final {\npublic:\n    explicit ProcessManager(uint32_t searchInterval = 100);\n\n    void killProcess();\n\n    void updateData();\n    void setWindowPosCallback(const std::function<void(int, int, int, int)> &cb);\n    void setProcessCloseCallback(const std::function<void(void*)> &cb) {\n        processCloseCallback_ = cb;\n    }\n\n    void *hwnd() { return currProcess_ ? currProcess_->hwnd : nullptr; }\n    [[nodiscard]] inline bool available() const { return currProcess_ != nullptr; }\n    [[nodiscard]] inline bool mapEnabled() const { return currProcess_->mapEnabled != 0; }\n    [[nodiscard]] inline uint32_t panelEnabled() const { return currProcess_->panelEnabled; }\n    [[nodiscard]] inline uint32_t realTombLevelId() const { return currProcess_->realTombLevelId; }\n    [[nodiscard]] inline uint32_t superUniqueTombLevelId() const { return currProcess_->superUniqueTombLevelId; }\n\n    [[nodiscard]] inline const MapPlayer *currPlayer() const { return currProcess_->currPlayer; }\n    [[nodiscard]] inline const std::unordered_map<uint32_t, MapPlayer> &players() const { return currProcess_->mapPlayers; }\n    [[nodiscard]] inline const std::vector<MapMonster> &monsters() const { return currProcess_->mapMonsters; }\n    [[nodiscard]] inline const std::unordered_map<uint32_t, MapObject> &objects() const { return currProcess_->mapObjects; }\n    [[nodiscard]] inline const std::vector<MapItem> &items() const { return currProcess_->mapItems; }\n\n    [[nodiscard]] inline const std::wstring &gameName() const { return currProcess_->gameName; }\n    [[nodiscard]] inline const std::wstring &gamePass() const { return currProcess_->gamePass; }\n    [[nodiscard]] inline const std::wstring &region() const { return currProcess_->region; }\n    [[nodiscard]] inline const std::wstring &season() const { return currProcess_->season; }\n\n    void reloadConfig() { loadFromCfg(); currProcess_ = nullptr; }\n\n    /* functions for plugins */\n    Skill *getSkill(uint16_t id);\n\nprivate:\n    void searchForProcess(void *hwnd);\n    void loadFromCfg();\n\nprivate:\n    std::chrono::steady_clock::time_point nextSearchTime_;\n    std::chrono::steady_clock::duration searchInterval_;\n\n    std::unordered_map<void*, ProcessData> processes_;\n    ProcessData *currProcess_ = nullptr;\n\n    std::function<void(void*)> processCloseCallback_;\n};\n\n}\n"
  },
  {
    "path": "src/d2r/storage.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"storage.h\"\n\n#include <CascLib.h>\n#include <windows.h>\n\nnamespace d2r {\n\nStorage storage;\n\nstruct StorageCtx {\n    HANDLE storage = nullptr;\n};\n\nd2r::Storage::Storage() noexcept: ctx_(new(std::nothrow) StorageCtx) {\n}\n\nd2r::Storage::~Storage() {\n    if (ctx_->storage) {\n        CascCloseStorage(ctx_->storage);\n    }\n    delete ctx_;\n}\n\nbool d2r::Storage::init() {\n    HKEY key;\n    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L\"SOFTWARE\"\n#if defined(_M_AMD64)\n                                          \"\\\\WOW6432Node\"\n#endif\n                                          \"\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\Diablo II Resurrected\", 0, KEY_READ, &key) != ERROR_SUCCESS) { return false; }\n    wchar_t regpath[MAX_PATH];\n    DWORD pathSize = sizeof(regpath);\n    bool result = RegQueryValueExW(key, L\"InstallSource\", nullptr, nullptr, LPBYTE(regpath), &pathSize) == ERROR_SUCCESS;\n    RegCloseKey(key);\n    if (!result) { return false; }\n    /* CascOpenStorage may fail in rare case, just retry for 3 times */\n    int counter = 3;\n    while (!CascOpenStorage(regpath, CASC_LOCALE_ALL, &ctx_->storage) && --counter) {\n        if (GetCascError() == ERROR_NOT_SUPPORTED || GetCascError() == ERROR_INVALID_PARAMETER) {\n            return false;\n        }\n        Sleep(500);\n    }\n    return result;\n}\n\nbool Storage::readFile(const char *filename, std::vector<uint8_t> &data) {\n    if (!ctx_->storage) { return false; }\n    HANDLE file;\n    if (!CascOpenFile(ctx_->storage, filename, CASC_LOCALE_ALL, CASC_OPEN_BY_NAME, &file)) {\n        return false;\n    }\n    auto size = CascGetFileSize(file, nullptr);\n    data.resize(size);\n    auto result = CascReadFile(file, data.data(), size, nullptr);\n    CascCloseFile(file);\n    return result;\n}\n\n}\n"
  },
  {
    "path": "src/d2r/storage.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <vector>\n#include <cstdint>\n\nnamespace d2r {\n\nstruct StorageCtx;\n\nclass Storage final {\npublic:\n    Storage() noexcept;\n    ~Storage();\n    bool init();\n    bool readFile(const char *filename, std::vector<uint8_t> &data);\n\nprivate:\n    StorageCtx *ctx_;\n};\n\nextern Storage storage;\n\n}\n"
  },
  {
    "path": "src/d2r/stringdefs.inl",
    "content": "wchar_t enchantStrings[256][4] = {\n    /*  0 */ L\"\",\n    /*  1 */ L\"\",\n    /*  2 */ L\"\",\n    /*  3 */ L\"\",\n    /*  4 */ L\"\",\n    /*  5 */ L\"S\",\n    /*  6 */ L\"\\x0F\" \"F\",\n    /*  7 */ L\"\\x02\" \"C\",\n    /*  8 */ L\"M\",\n    /*  9 */ L\"\\x01\" \"FE\",\n    /* 10 */ L\"\",\n    /* 11 */ L\"\",\n    /* 12 */ L\"\",\n    /* 13 */ L\"\",\n    /* 14 */ L\"\",\n    /* 15 */ L\"\",\n    /* 16 */ L\"\",\n    /* 17 */ L\"\\x09\" \"LE\",\n    /* 18 */ L\"\\x03\" \"CE\",\n    /* 19 */ L\"\",\n    /* 20 */ L\"\",\n    /* 21 */ L\"\",\n    /* 22 */ L\"\",\n    /* 23 */ L\"\",\n    /* 24 */ L\"\",\n    /* 25 */ L\"\\x03\" \"MB\",\n    /* 26 */ L\"T\",\n    /* 27 */ L\"H\",\n    /* 28 */ L\"\\x04\" \"SS\",\n    /* 29 */ L\"\\x0C\" \"MS\",\n    /* 30 */ L\"A\",\n    /* 31 */ L\"\",\n    /* 32 */ L\"\",\n    /* 33 */ L\"\",\n    /* 34 */ L\"\",\n    /* 35 */ L\"\",\n    /* 36 */ L\"\",\n    /* 37 */ L\"\\x0B\" \"F\",\n    /* 38 */ L\"\",\n    /* 39 */ L\"\\x04\" \"B\",\n    /* 40 */ L\"\",\n    /* 41 */ L\"\",\n    /* 42 */ L\"\",\n    /* 43 */ L\"\",\n};\n\nwchar_t auraStrings[187][4] = {\n    /*   0 */ L\"\",\n    /*   1 */ L\"\",\n    /*   2 */ L\"\",\n    /*   3 */ L\"\",\n    /*   4 */ L\"\",\n    /*   5 */ L\"\",\n    /*   6 */ L\"\",\n    /*   7 */ L\"\",\n    /*   8 */ L\"\",\n    /*   9 */ L\"\",\n    /*  10 */ L\"\",\n    /*  11 */ L\"\",\n    /*  12 */ L\"\",\n    /*  13 */ L\"\",\n    /*  14 */ L\"\",\n    /*  15 */ L\"\",\n    /*  16 */ L\"\",\n    /*  17 */ L\"\",\n    /*  18 */ L\"\",\n    /*  19 */ L\"\",\n    /*  20 */ L\"\",\n    /*  21 */ L\"\",\n    /*  22 */ L\"\",\n    /*  23 */ L\"\",\n    /*  24 */ L\"\",\n    /*  25 */ L\"\",\n    /*  26 */ L\"\",\n    /*  27 */ L\"\",\n    /*  28 */ L\"\\x0B\" \"A\",\n    /*  29 */ L\"\",\n    /*  30 */ L\"\",\n    /*  31 */ L\"\",\n    /*  32 */ L\"\",\n    /*  33 */ L\"\\x04\" \"A\",\n    /*  34 */ L\"\",\n    /*  35 */ L\"\\x01\" \"A\",\n    /*  36 */ L\"\",\n    /*  37 */ L\"\",\n    /*  38 */ L\"\",\n    /*  39 */ L\"\",\n    /*  40 */ L\"A\",\n    /*  41 */ L\"\",\n    /*  42 */ L\"\",\n    /*  43 */ L\"\\x03\" \"A\",\n    /*  44 */ L\"\",\n    /*  45 */ L\"\",\n    /*  46 */ L\"\\x09\" \"A\",\n    /*  47 */ L\"\",\n    /*  48 */ L\"\",\n    /*  49 */ L\"\\x05\" \"A\",\n    /*  50 */ L\"\",\n    /*  51 */ L\"\",\n    /*  52 */ L\"\",\n    /*  53 */ L\"\",\n    /*  54 */ L\"\",\n    /*  55 */ L\"\",\n    /*  56 */ L\"\",\n    /*  57 */ L\"\",\n    /*  58 */ L\"\",\n    /*  59 */ L\"\",\n    /*  60 */ L\"\",\n    /*  61 */ L\"\",\n    /*  62 */ L\"\",\n    /*  63 */ L\"\",\n    /*  64 */ L\"\",\n    /*  65 */ L\"\",\n    /*  66 */ L\"\",\n    /*  67 */ L\"\",\n    /*  68 */ L\"\",\n    /*  69 */ L\"\",\n    /*  70 */ L\"\",\n    /*  71 */ L\"\",\n    /*  72 */ L\"\",\n    /*  73 */ L\"\",\n    /*  74 */ L\"\",\n    /*  75 */ L\"\",\n    /*  76 */ L\"\",\n    /*  77 */ L\"\",\n    /*  78 */ L\"\",\n    /*  79 */ L\"\",\n    /*  80 */ L\"\",\n    /*  81 */ L\"\",\n    /*  82 */ L\"\",\n    /*  83 */ L\"\",\n    /*  84 */ L\"\",\n    /*  85 */ L\"\",\n    /*  86 */ L\"\",\n    /*  87 */ L\"\",\n    /*  88 */ L\"\",\n    /*  89 */ L\"\",\n    /*  90 */ L\"\",\n    /*  91 */ L\"\",\n    /*  92 */ L\"\",\n    /*  93 */ L\"\",\n    /*  94 */ L\"\",\n    /*  95 */ L\"\",\n    /*  96 */ L\"\",\n    /*  97 */ L\"\",\n    /*  98 */ L\"\",\n    /*  99 */ L\"\",\n    /* 100 */ L\"\",\n    /* 101 */ L\"\",\n    /* 102 */ L\"\",\n    /* 103 */ L\"\",\n    /* 104 */ L\"\",\n    /* 105 */ L\"\",\n    /* 106 */ L\"\",\n    /* 107 */ L\"\",\n    /* 108 */ L\"\",\n    /* 109 */ L\"\",\n    /* 110 */ L\"\",\n    /* 111 */ L\"\",\n    /* 112 */ L\"\",\n    /* 113 */ L\"\",\n    /* 114 */ L\"\",\n    /* 115 */ L\"\",\n    /* 116 */ L\"\",\n    /* 117 */ L\"\",\n    /* 118 */ L\"\",\n    /* 119 */ L\"\",\n    /* 120 */ L\"\",\n    /* 121 */ L\"\",\n    /* 122 */ L\"\",\n    /* 123 */ L\"\",\n    /* 124 */ L\"\",\n    /* 125 */ L\"\",\n    /* 126 */ L\"\",\n    /* 127 */ L\"\",\n    /* 128 */ L\"\",\n    /* 129 */ L\"\",\n    /* 130 */ L\"\",\n    /* 131 */ L\"\",\n    /* 132 */ L\"\",\n    /* 133 */ L\"\",\n    /* 134 */ L\"\",\n    /* 135 */ L\"\",\n    /* 136 */ L\"\",\n    /* 137 */ L\"\",\n    /* 138 */ L\"\",\n    /* 139 */ L\"\",\n    /* 140 */ L\"\",\n    /* 141 */ L\"\",\n    /* 142 */ L\"\",\n    /* 143 */ L\"\",\n    /* 144 */ L\"\",\n    /* 145 */ L\"\",\n    /* 146 */ L\"\",\n    /* 147 */ L\"\",\n    /* 148 */ L\"\",\n    /* 149 */ L\"\",\n    /* 150 */ L\"\",\n    /* 151 */ L\"\",\n    /* 152 */ L\"\",\n    /* 153 */ L\"\",\n    /* 154 */ L\"\",\n    /* 155 */ L\"\",\n    /* 156 */ L\"\",\n    /* 157 */ L\"\",\n    /* 158 */ L\"\",\n    /* 159 */ L\"\",\n    /* 160 */ L\"\",\n    /* 161 */ L\"\",\n    /* 162 */ L\"\",\n    /* 163 */ L\"\",\n    /* 164 */ L\"\",\n    /* 165 */ L\"\",\n    /* 166 */ L\"\",\n    /* 167 */ L\"\",\n    /* 168 */ L\"\",\n    /* 169 */ L\"\",\n    /* 170 */ L\"\",\n    /* 171 */ L\"\",\n    /* 172 */ L\"\",\n    /* 173 */ L\"\",\n    /* 174 */ L\"\",\n    /* 175 */ L\"\",\n    /* 176 */ L\"\",\n    /* 177 */ L\"\",\n    /* 178 */ L\"\",\n    /* 179 */ L\"\",\n    /* 180 */ L\"\",\n    /* 181 */ L\"\",\n    /* 182 */ L\"\",\n    /* 183 */ L\"\",\n    /* 184 */ L\"\",\n    /* 185 */ L\"\",\n    /* 186 */ L\"\",\n};\n\nwchar_t immunityStrings[6][4] = {\n    L\"\\x04\" \"i\",\n    L\"\\x08\" \"i\",\n    L\"\\x01\" \"i\",\n    L\"\\x09\" \"i\",\n    L\"\\x03\" \"i\",\n    L\"\\x02\" \"i\",\n};\n"
  },
  {
    "path": "src/data/d2txt.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"d2txt.h\"\n\n#include \"viewstream.h\"\n#include <fstream>\n#include <sstream>\n\nnamespace data {\n\nbool D2TXT::load(const std::string &filename) {\n    std::ifstream ifs(filename);\n    if (!ifs.is_open()) { return false; }\n    loadInternal(ifs);\n    ifs.close();\n    return true;\n}\n\nbool D2TXT::load(const void *data, size_t size) {\n    std::string_view sv(static_cast<const char *>(data), size);\n    view_istream<char> stm(sv);\n    loadInternal(stm);\n    return true;\n}\n\nvoid D2TXT::loadInternal(std::istream &stm) {\n    bool processedTitle = false;\n    for (std::string line; std::getline(stm, line);) {\n        std::istringstream stm2(line);\n        size_t col = 0;\n        if (processedTitle) {\n            auto base = values_.size();\n            values_.resize(base + columns_);\n            for (std::string val; col < columns_ && std::getline(stm2, val, '\\t'); col++) {\n                values_[base + col] = std::make_pair(val, std::strtol(val.c_str(), nullptr, 0));\n            }\n        } else {\n            for (std::string val; std::getline(stm2, val, '\\t'); col++) {\n                colIdxByName_[val] = int(col);\n            }\n            columns_ = col;\n            processedTitle = true;\n        }\n    }\n}\n\n}\n"
  },
  {
    "path": "src/data/d2txt.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <unordered_map>\n#include <vector>\n#include <iostream>\n#include <string>\n#include <cstddef>\n\nnamespace data {\n\nclass D2TXT final {\npublic:\n    D2TXT() = default;\n    D2TXT(const D2TXT &other) = delete;\n\n    bool load(const std::string &filename);\n    bool load(const void *data, size_t size);\n    [[nodiscard]] inline size_t rows() const { return values_.size() / columns_; }\n    [[nodiscard]] inline size_t columns() const { return columns_; }\n    [[nodiscard]] inline int colIndexByName(const std::string &name) const {\n        const auto ite = colIdxByName_.find(name);\n        if (ite == colIdxByName_.end()) {\n            return -1;\n        }\n        return ite->second;\n    }\n    [[nodiscard]] inline const std::pair<std::string, int> &value(size_t row, size_t col) const {\n        static std::pair<std::string, int> empty = {\"\", 0};\n        if (columns_ == 0) {\n            return empty;\n        }\n        auto idx = row * columns_ + col;\n        if (idx >= values_.size()) { return empty; }\n        return values_[idx];\n    }\n\nprivate:\n    void loadInternal(std::istream &stm);\n\nprivate:\n    size_t columns_ = 0;\n    std::unordered_map<std::string, int> colIdxByName_;\n    std::vector<std::pair<std::string, int>> values_;\n};\n\n}\n"
  },
  {
    "path": "src/data/gamedata.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"gamedata.h\"\n\n#include \"viewstream.h\"\n#include \"d2txt.h\"\n#include \"d2r/storage.h\"\n#include \"d2r/d2rdefs.h\"\n#include \"util/util.h\"\n\n#include \"ini.h\"\n#include \"json/json.hpp\"\n\n#include <algorithm>\n#include <cstring>\n#include <cstdlib>\n\nnamespace data {\n\nstatic Data sgamedata;\nconst Data *gamedata = &sgamedata;\n\n/* itemFilters[id][quality-1][ethereal][sockets] = style | (color << 4) | (sound << 8) */\nstatic uint16_t itemFilters[1000][8][2][7] = {};\n\nstatic inline uint32_t strToUInt(const std::string &str, bool searchItemCode) {\n    if (!searchItemCode) {\n        return uint32_t(strtoul(str.c_str(), nullptr, 0));\n    }\n    auto ite = sgamedata.itemIdByCode.find(str);\n    if (ite != sgamedata.itemIdByCode.end()) {\n        return ite->second;\n    }\n    uint32_t id = 0;\n    for (auto c: str) {\n        if (c < '0' || c > '9') { return 0; }\n        id = id * 10 + (c - '0');\n    }\n    return id;\n}\n\nstatic inline std::vector<std::pair<uint32_t, uint32_t>> calcRanges(const std::string &str,\n                                                                    bool searchItemCode,\n                                                                    uint32_t maxValue) {\n    std::vector<std::pair<uint32_t, uint32_t>> result;\n    auto vec = util::splitString(str, ',');\n    for (const auto &v: vec) {\n        auto vec2 = util::splitString(v, '-');\n        if (vec2.empty()) {\n            continue;\n        }\n        auto startPos = strToUInt(vec2[0], searchItemCode);\n        uint32_t endPos;\n        if (vec2.size() > 1) {\n            endPos = strToUInt(vec2[1], searchItemCode);\n            if (endPos < startPos) endPos = startPos;\n        } else {\n            endPos = startPos;\n        }\n        if (startPos >= maxValue) {\n            startPos = 0;\n            endPos = maxValue - 1;\n        } else {\n            if (endPos >= maxValue) endPos = maxValue - 1;\n        }\n        result.emplace_back(startPos, endPos);\n    }\n    return result;\n}\n\nstatic void loadItemFilter(const char *key, const char *value) {\n    auto res = uint16_t(strtoul(value, nullptr, 0));\n    if (res) {\n        auto *sub = strchr(value, ',');\n        if (sub) {\n            char *endptr = nullptr;\n            res |= uint16_t(std::min(15ul, strtoul(sub + 1, &endptr, 0)) << 4);\n            if (endptr && *endptr == ',') {\n                res |= uint16_t(std::min(255ul, strtoul(endptr + 1, nullptr, 0)) << 8);\n            }\n        }\n    }\n\n    std::vector<std::pair<uint32_t, uint32_t>> ranges[4] = {};\n    const uint32_t maxValues[4] = {1000, 8, 2, 7};\n    size_t index = 0;\n    while (true) {\n        auto pos = strcspn(key, \"+*#\");\n        ranges[index] = calcRanges(std::string(key, pos), index == 0, maxValues[index]);\n        if (!key[pos]) { break; }\n        switch (key[pos]) {\n        case '+': index = 1;\n            break;\n        case '#': index = 2;\n            break;\n        case '*': index = 3;\n            break;\n        default: break;\n        }\n        key += pos + 1;\n    }\n    for (int i = 0; i < 4; ++i) {\n        if (ranges[i].empty()) {\n            ranges[i].emplace_back(0, maxValues[i] - 1);\n        }\n    }\n    for (auto r0: ranges[0]) {\n        for (auto i = r0.first; i <= r0.second; ++i) {\n            for (auto r1: ranges[1]) {\n                for (auto j = r1.first; j <= r1.second; ++j) {\n                    for (auto r2: ranges[2]) {\n                        for (auto k = r2.first; k <= r2.second; ++k) {\n                            for (auto r3: ranges[3]) {\n                                for (auto l = r3.first; l <= r3.second; ++l) {\n                                    itemFilters[i][j][k][l] = res;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\ninline void assignJsonLngArray(Data::LngString &arr, nlohmann::basic_json<> &j) {\n#define ASSIGN(n) arr[LNG_##n] = util::utf8toucs4(j[#n].get<std::string>())\n    ASSIGN(enUS);\n    ASSIGN(zhTW);\n    ASSIGN(deDE);\n    ASSIGN(esES);\n    ASSIGN(frFR);\n    ASSIGN(itIT);\n    ASSIGN(koKR);\n    ASSIGN(plPL);\n    ASSIGN(esMX);\n    ASSIGN(jaJP);\n    ASSIGN(ptBR);\n    ASSIGN(ruRU);\n    ASSIGN(zhCN);\n#undef ASSIGN\n}\n\ninline void loadJsonLng(std::unordered_map<std::string, Data::LngString> &jlng, d2r::Storage &storage, const char *filename) {\n    std::vector<uint8_t> mem;\n    if (storage.readFile(filename, mem)) {\n        std::string_view sv(reinterpret_cast<const char*>(mem.data()), mem.size());\n        view_istream<char> stm(sv);\n        nlohmann::json j;\n        stm >> j;\n        for (auto j2: j) {\n            auto key = j2[\"Key\"].get<std::string>();\n            auto &arr = jlng[key];\n            assignJsonLngArray(arr, j2);\n        }\n    }\n}\n\ninline void loadJsonLngById(std::unordered_map<uint32_t, Data::LngString> &jlng, d2r::Storage &storage, const char *filename) {\n    std::vector<uint8_t> mem;\n    if (storage.readFile(filename, mem)) {\n        std::string_view sv(reinterpret_cast<const char*>(mem.data()), mem.size());\n        view_istream<char> stm(sv);\n        nlohmann::json j;\n        stm >> j;\n        for (auto j2: j) {\n            auto key = j2[\"id\"].get<uint32_t>();\n            auto &arr = jlng[key];\n            assignJsonLngArray(arr, j2);\n        }\n    }\n}\n\ninline void loadTxt(D2TXT &txt, d2r::Storage &storage, const char *filename) {\n    std::vector<uint8_t> mem;\n    if (storage.readFile(filename, mem)) {\n        txt.load(mem.data(), mem.size());\n    }\n}\n\ntemplate<typename T>\ninline Data::LngString *moveStrings(std::unordered_map<T, Data::LngString> &to, std::unordered_map<T, Data::LngString> &from, const T &key) {\n    auto dstIte = to.find(key);\n    if (dstIte != to.end()) {\n        return &dstIte->second;\n    }\n    auto ite = from.find(key);\n    if (ite == from.end()) {\n        return nullptr;\n    }\n    auto &result = to[key];\n    result = std::move(ite->second);\n    from.erase(ite);\n    return &result;\n}\n\ninline EObjType objTypeFromString(const std::string &key) {\n    if (key == \"Waypoint\") { return TypeWayPoint; }\n    if (key == \"Quest\") { return TypeQuest; }\n    if (key == \"Portal\") { return TypePortal; }\n    if (key == \"Chest\") { return TypeChest; }\n    if (key == \"Shrine\") { return TypeShrine; }\n    if (key == \"Well\") { return TypeWell; }\n    if (key == \"Door\") { return TypeDoor; }\n    return TypeNone;\n}\n\ninline void loadD2RData() {\n    struct UserParseData {\n        /* -1-not used  0-guides  1-useful_names  2-useful_objects  3-name_replace */\n        int section = -1;\n        std::map<int, std::pair<std::string, std::string>> usefulObjectOp, usefulObjects, usefulNpcs;\n        std::map<std::string, std::set<std::string>> guides;\n    } parseData;\n    ini_parse(\"D2RMH_gamedata.ini\", [](void* user, const char* section, const char* name, const char* value)->int {\n        auto *pd = (UserParseData*)user;\n        if (!name) {\n            if (!strcmp(section, \"guides\")) {\n                pd->section = 0;\n            } else if (!strcmp(section, \"useful_object_op\")) {\n                pd->section = 1;\n            } else if (!strcmp(section, \"useful_objects\")) {\n                pd->section = 2;\n            } else if (!strcmp(section, \"useful_npcs\")) {\n                pd->section = 3;\n            } else {\n                pd->section = -1;\n            }\n            return 1;\n        }\n        switch (pd->section) {\n        case 0: {\n            if (strtoul(value, nullptr, 0) == 0) {\n                break;\n            }\n            if (strncmp(name, \"guide[\", 6) != 0) {\n                break;\n            }\n            const char *start = name + 6;\n            const char *token = strchr(name, ']');\n            if (token == nullptr) { break; }\n            const char *start2 = strchr(token + 1, '[');\n            if (start2 == nullptr) { break; }\n            ++start2;\n            const char *token2 = strchr(start2, ']');\n            if (token2 == nullptr) { break; }\n            pd->guides[std::string(start, token)].insert(std::string(start2, token2));\n            break;\n        }\n        case 1: {\n            const char *token = strchr(value, ',');\n            pd->usefulObjectOp[strtol(name, nullptr, 0)] = token == nullptr ? std::make_pair(value, \"\")\n                                                                            : std::make_pair(std::string(value, token), token + 1);\n            break;\n        }\n        case 2: {\n            const char *token = strchr(value, ',');\n            pd->usefulObjects[strtol(name, nullptr, 0)] = token == nullptr ? std::make_pair(value, \"\")\n                                                                           : std::make_pair(std::string(value, token), token + 1);\n            break;\n        }\n        case 3: {\n            const char *token = strchr(value, ',');\n            pd->usefulNpcs[strtol(name, nullptr, 0)] = token == nullptr ? std::make_pair(value, \"\")\n                                                                        : std::make_pair(std::string(value, token), token + 1);\n            break;\n        }\n        default:\n            break;\n        }\n        return 1;\n    }, &parseData);\n\n    std::unordered_map<std::string, Data::LngString> names;\n    std::unordered_map<uint32_t, Data::LngString> mercNames;\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/item-names.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/item-runes.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/item-nameaffixes.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/item-modifiers.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/levels.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/monsters.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/npcs.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/objects.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/shrines.json\");\n    loadJsonLng(names, d2r::storage, \"data:data/local/lng/strings/ui.json\");\n    loadJsonLngById(mercNames, d2r::storage, \"data:data/local/lng/strings/mercenaries.json\");\n    names.erase(\"dummy\");\n    names.erase(\"Dummy\");\n    names.erase(\"unused\");\n\n    D2TXT levelTxt, objTxt, monTxt, shrineTxt, superuTxt;\n    D2TXT itemTxt[3];\n    loadTxt(levelTxt, d2r::storage, \"data:data/global/excel/levels.txt\");\n    loadTxt(objTxt, d2r::storage, \"data:data/global/excel/objects.txt\");\n    loadTxt(monTxt, d2r::storage, \"data:data/global/excel/monstats.txt\");\n    loadTxt(shrineTxt, d2r::storage, \"data:data/global/excel/shrines.txt\");\n    loadTxt(superuTxt, d2r::storage, \"data:data/global/excel/superuniques.txt\");\n    loadTxt(itemTxt[0], d2r::storage, \"data:data/global/excel/weapons.txt\");\n    loadTxt(itemTxt[1], d2r::storage, \"data:data/global/excel/armor.txt\");\n    loadTxt(itemTxt[2], d2r::storage, \"data:data/global/excel/misc.txt\");\n\n    std::map<std::wstring, int> levelIdByName;\n\n    for (const auto *s: {\"strCreateGameNormalText\", \"strCreateGameNightmareText\", \"strCreateGameHellText\"}) {\n        std::string key = s;\n        moveStrings(sgamedata.strings, names, key);\n    }\n    auto idx0 = levelTxt.colIndexByName(\"Id\");\n    auto idx1 = levelTxt.colIndexByName(\"LevelName\");\n    auto rows = levelTxt.rows();\n    for (size_t i = 0; i < rows; ++i) {\n        auto id = levelTxt.value(i, idx0).second;\n        const auto &key = levelTxt.value(i, idx1).first;\n        const auto *arr = moveStrings(sgamedata.strings, names, key);\n        if (arr) {\n            levelIdByName[(*arr)[0]] = id;\n            if (id >= sgamedata.levels.size()) { sgamedata.levels.resize(id + 1); }\n            sgamedata.levels[id] = {key, arr};\n        }\n    }\n\n    idx0 = objTxt.colIndexByName(\"*ID\");\n    idx1 = objTxt.colIndexByName(\"Name\");\n    auto idx2 = objTxt.colIndexByName(\"OperateFn\");\n    auto idx3 = objTxt.colIndexByName(\"SizeX\");\n    auto idx4 = objTxt.colIndexByName(\"SizeY\");\n    auto idx5 = objTxt.colIndexByName(\"IsDoor\");\n    rows = objTxt.rows();\n    for (size_t i = 0; i < rows; ++i) {\n        auto id = objTxt.value(i, idx0).second;\n        if (objTxt.value(i, idx5).second) {\n            sgamedata.objects[0][id] = {TypeDoor, \"\", nullptr,\n                                        float(std::max(1, objTxt.value(i, idx3).second)),\n                                        float(std::max(1, objTxt.value(i, idx4).second))};\n            continue;\n        }\n        auto op = objTxt.value(i, idx2).second;\n        auto kite = parseData.usefulObjectOp.find(op);\n        EObjType tp;\n        std::string key;\n        if (kite == parseData.usefulObjectOp.end()) {\n            auto ite = parseData.usefulObjects.find(id);\n            if (ite == parseData.usefulObjects.end()) { continue; }\n            key = ite->second.second;\n            tp = objTypeFromString(ite->second.first);\n        } else {\n            key = kite->second.second;\n            tp = objTypeFromString(kite->second.first);\n        }\n        if (key.empty()) { key = objTxt.value(i, idx1).first; }\n        const auto *arr = moveStrings(sgamedata.strings, names, key);\n        if (arr) {\n            auto minValue = tp == TypeWayPoint ? 3 : 2;\n            auto w = float(std::max(minValue, objTxt.value(i, idx3).second));\n            auto h = float(std::max(minValue, objTxt.value(i, idx4).second));\n            sgamedata.objects[0][id] = {tp, key, arr, w, h};\n        }\n    }\n\n    idx0 = monTxt.colIndexByName(\"*hcIdx\");\n    idx1 = monTxt.colIndexByName(\"NameStr\");\n    idx2 = monTxt.colIndexByName(\"npc\");\n    idx3 = monTxt.colIndexByName(\"Align\");\n    idx4 = monTxt.colIndexByName(\"inTown\");\n    idx5 = monTxt.colIndexByName(\"enabled\");\n    rows = monTxt.rows();\n    for (size_t i = 0; i < rows; ++i) {\n        auto id = monTxt.value(i, idx0).second;\n        auto ite = parseData.usefulNpcs.find(id);\n        const Data::LngString *arr = nullptr;\n        if (ite != parseData.usefulNpcs.end()) {\n            std::string key = ite->second.second;\n            if (key.empty()) { key = monTxt.value(i, idx1).first; }\n            arr = moveStrings(sgamedata.strings, names, key);\n            if (arr) {\n                sgamedata.objects[1][id] = {objTypeFromString(ite->second.first), key, arr, 2.f, 2.f};\n            }\n        }\n        if (monTxt.value(i, idx5).second) {\n            auto key = monTxt.value(i, idx1).first;\n            if (!arr) { arr = moveStrings(sgamedata.strings, names, key); }\n            uint8_t monType = monTxt.value(i, idx2).second ? 1 :\n                              monTxt.value(i, idx3).second ? 2 :\n                              monTxt.value(i, idx4).second ? 1 : 0;\n            if (id >= sgamedata.monsters.size()) { sgamedata.monsters.resize(id + 1); }\n            sgamedata.monsters[id] = {arr ? key : \"\", monType, arr};\n        }\n    }\n\n    idx0 = shrineTxt.colIndexByName(\"Code\");\n    idx1 = shrineTxt.colIndexByName(\"StringName\");\n    rows = shrineTxt.rows();\n    for (size_t i = 0; i < rows; ++i) {\n        auto id = shrineTxt.value(i, idx0).second;\n        auto key = shrineTxt.value(i, idx1).first;\n        const auto *arr = moveStrings(sgamedata.strings, names, key);\n        if (arr) {\n            if (id >= sgamedata.shrines.size()) { sgamedata.shrines.resize(id + 1); }\n            sgamedata.shrines[id] = {key, arr};\n        }\n    }\n\n    idx0 = superuTxt.colIndexByName(\"hcIdx\");\n    idx1 = superuTxt.colIndexByName(\"Name\");\n    rows = superuTxt.rows();\n    for (size_t i = 0; i < rows; ++i) {\n        auto id = superuTxt.value(i, idx0).second;\n        auto key = superuTxt.value(i, idx1).first;\n        const auto *arr = moveStrings(sgamedata.strings, names, key);\n        if (arr) {\n            if (id >= sgamedata.superUniques.size()) { sgamedata.superUniques.resize(id + 1); }\n            sgamedata.superUniques[id] = {key, arr};\n        }\n    }\n\n    uint32_t itemIndex = 0;\n    for (const auto &item : itemTxt) {\n        idx0 = item.colIndexByName(\"name\");\n        idx1 = item.colIndexByName(\"code\");\n        idx2 = item.colIndexByName(\"namestr\");\n        rows = item.rows();\n        for (size_t i = 0; i < rows; ++i) {\n            const auto &name = item.value(i, idx0).first;\n            if (name == \"Expansion\") { continue; }\n            const auto &code = item.value(i, idx1).first;\n            const auto &key = item.value(i, idx2).first;\n            const auto *arr = moveStrings(sgamedata.strings, names, key);\n            if (arr) {\n                if (itemIndex >= sgamedata.items.size()) { sgamedata.items.resize(itemIndex + 1); }\n                sgamedata.items[itemIndex] = {key, arr};\n                sgamedata.itemIdByCode[key] = itemIndex;\n            }\n            itemIndex++;\n        }\n    }\n\n    for (auto &p: mercNames) {\n        auto ite = mercNames.find(p.first);\n        if (ite == mercNames.end()) {\n            continue;\n        }\n        if (p.first >= sgamedata.mercNames.size()) { sgamedata.mercNames.resize(p.first + 1); }\n        sgamedata.mercNames[p.first] = std::move(ite->second);\n    }\n    mercNames.clear();\n\n    for (auto &p: parseData.guides) {\n        int id;\n        if (p.first[0] >= '0' && p.first[0] <= '9') {\n            id = strtol(p.first.c_str(), nullptr, 0);\n        } else {\n            auto ite = levelIdByName.find(util::utf8toucs4(p.first));\n            if (ite == levelIdByName.end()) {\n                continue;\n            }\n            id = ite->second;\n        }\n        for (auto &s: p.second) {\n            if (s.empty()) { continue; }\n            if (s[0] == '-') {\n                sgamedata.guides[id].insert(0x20000 | strtoul(s.data() + 1, nullptr, 0));\n            } else if (s[0] == '+') {\n                sgamedata.guides[id].insert(0x10000 | strtoul(s.data() + 1, nullptr, 0));\n            } else if (s[0] >= '0' && s[0] <= '9'){\n                sgamedata.guides[id].insert(strtoul(s.data(), nullptr, 0));\n            }\n            auto ite2 = levelIdByName.find(util::utf8toucs4(s));\n            if (ite2 == levelIdByName.end()) {\n                continue;\n            }\n            sgamedata.guides[id].insert(ite2->second);\n        }\n    }\n}\n\nvoid loadData() {\n    loadD2RData();\n    int section = -1;\n    ini_parse(\"D2RMH_item.ini\", [](void *user, const char *section,\n                                   const char *name, const char *value) -> int {\n        auto *isec = (int *)user;\n        if (!name) {\n            if (!strcmp(section, \"items\")) { *isec = 0; }\n            else { *isec = -1; }\n            return 1;\n        }\n        switch (*isec) {\n        case 0: {\n            loadItemFilter(name, value);\n            break;\n        }\n        default:break;\n        }\n        return 1;\n    }, &section);\n}\n\nuint16_t filterItem(const d2r::UnitAny *unit, const d2r::ItemData *item, uint32_t sockets) {\n    if (sockets > 6) { return 0; }\n    auto id = unit->txtFileNo;\n    if (id >= 1000) { return 0; }\n    auto quality = item->quality - 1;\n    if (quality >= 8) { return 0; }\n    auto ethereal = (item->itemFlags & 0x00400000) ? 1 : 0;\n    return itemFilters[id][quality][ethereal][sockets];\n}\n\n}\n"
  },
  {
    "path": "src/data/gamedata.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <array>\n#include <set>\n#include <vector>\n#include <unordered_map>\n#include <string>\n\nnamespace d2r {\nstruct UnitAny;\nstruct ItemData;\n}\n\nnamespace data {\n\nenum EObjType {\n    TypeNone,\n    TypeWayPoint,\n    TypePortal,\n    TypeChest,\n    TypeQuest,\n    TypeShrine,\n    TypeWell,\n    TypeMonster,\n    TypeUniqueMonster,\n    TypeNpc,\n    TypeDoor,\n    TypeMax,\n};\n\nenum ELNG {\n    LNG_enUS,\n    LNG_zhTW,\n    LNG_deDE,\n    LNG_esES,\n    LNG_frFR,\n    LNG_itIT,\n    LNG_koKR,\n    LNG_plPL,\n    LNG_esMX,\n    LNG_jaJP,\n    LNG_ptBR,\n    LNG_ruRU,\n    LNG_zhCN,\n    LNG_MAX,\n};\n\nstruct Data {\n    using LngString = std::array<std::wstring, LNG_MAX>;\n    std::unordered_map<std::string, LngString> strings;\n    std::vector<std::pair<std::string, const LngString*>> levels, shrines, superUniques, items;\n    std::vector<std::tuple<std::string, uint8_t, const LngString*>> monsters;\n    std::unordered_map<std::string, uint32_t> itemIdByCode;\n    std::unordered_map<int, std::tuple<EObjType, std::string, const LngString*, float, float>> objects[2];\n    std::unordered_map<int, std::set<int>> guides;\n    std::vector<LngString> mercNames;\n};\n\nextern void loadData();\nextern uint16_t filterItem(const d2r::UnitAny *unit, const d2r::ItemData *item, uint32_t sockets);\n\nextern const Data *gamedata;\n\n}\n"
  },
  {
    "path": "src/data/viewstream.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <iostream>\n#include <string_view>\n#include <cstring>\n\ntemplate<typename CharType, class TraitsType >\nclass view_streambuf final: public std::basic_streambuf<CharType, TraitsType > {\nprivate:\n    typedef std::basic_streambuf<CharType, TraitsType > super_type;\n    typedef view_streambuf<CharType, TraitsType> self_type;\npublic:\n\n    /**\n    *  These are standard types.  They permit a standardized way of\n    *  referring to names of (or names dependent on) the template\n    *  parameters, which are specific to the implementation.\n    */\n    typedef typename super_type::char_type char_type;\n    typedef typename super_type::traits_type traits_type;\n    typedef typename traits_type::int_type int_type;\n    typedef typename traits_type::pos_type pos_type;\n    typedef typename traits_type::off_type off_type;\n\n    typedef typename std::basic_string_view<char_type, traits_type> source_view;\n\n    explicit view_streambuf(const source_view& src) noexcept:\n        super_type(),\n        src_( src )\n    {\n        auto *buff = const_cast<char_type*>( src_.data() );\n        this->setg( buff , buff, buff + src_.length() );\n    }\n\n    std::streamsize xsgetn(char_type* _s, std::streamsize _n) override\n    {\n        if(0 == _n)\n            return 0;\n        if( (this->gptr() + _n) >= this->egptr() ) {\n            _n =  this->egptr() - this->gptr();\n            if(0 == _n && !traits_type::not_eof(this->underflow() ) )\n                return -1;\n        }\n        std::memmove(static_cast<void*>(_s), this->gptr(), size_t(_n));\n        this->gbump( static_cast<int>(_n) );\n        return _n;\n    }\n\n    int_type pbackfail(int_type _c) override\n    {\n        char_type *pos = this->gptr() - 1;\n        *pos = traits_type::to_char_type(_c );\n        this->pbump(-1);\n        return 1;\n    }\n\n    int_type underflow() override\n    {\n        return traits_type::eof();\n    }\n\n    std::streamsize showmanyc() override\n    {\n        return static_cast<std::streamsize>( this->egptr() - this->gptr() );\n    }\n\n    ~view_streambuf() override = default;\nprivate:\n    const source_view& src_;\n};\n\ntemplate<typename _char_type>\nclass view_istream final:public std::basic_istream<_char_type, std::char_traits<_char_type> > {\npublic:\n    view_istream(const view_istream&) = delete;\n    view_istream& operator=(const view_istream&) = delete;\nprivate:\n    typedef std::basic_istream<_char_type, std::char_traits<_char_type> > super_type;\n    typedef view_streambuf<_char_type, std::char_traits<_char_type> > streambuf_type;\npublic:\n    typedef _char_type  char_type;\n    typedef typename super_type::int_type int_type;\n    typedef typename super_type::pos_type pos_type;\n    typedef typename super_type::off_type off_type;\n    typedef typename super_type::traits_type traits_type;\n    typedef typename streambuf_type::source_view source_view;\n\n    explicit view_istream(const source_view& src):\n        super_type( nullptr ),\n        sb_(nullptr)\n    {\n        sb_ = new streambuf_type(src);\n        this->init( sb_ );\n    }\n\n\n    view_istream(view_istream&& other) noexcept:\n        super_type( std::forward<view_istream>(other) ),\n        sb_( std::move( other.sb_ ) )\n    {}\n\n    view_istream& operator=(view_istream&& rhs) noexcept\n    {\n        view_istream( std::forward<view_istream>(rhs) ).swap( *this );\n        return *this;\n    }\n\n    ~view_istream() override {\n        delete sb_;\n    }\n\nprivate:\n    streambuf_type *sb_;\n};\n"
  },
  {
    "path": "src/main.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"cfg.h\"\n\n#include \"d2r/storage.h\"\n#include \"render/renderer.h\"\n#include \"ui/maprenderer.h\"\n#include \"ui/window.h\"\n#include \"util/util.h\"\n#include \"util/os_structs.h\"\n\n#include \"d2map.h\"\n\nint WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {\n    osInit();\n    HANDLE evt = CreateEventW(nullptr, FALSE, FALSE, L\"Global\\\\D2RMH_EVENT\");\n    if (!evt) {\n        return -1;\n    }\n    if (GetLastError() == ERROR_ALREADY_EXISTS) {\n        CloseHandle(evt);\n        MessageBoxW(nullptr, L\"A D2RMH instance is already running!\", L\"D2RMH\", MB_OK | MB_ICONERROR);\n        return 0;\n    }\n    loadCfg();\n    if (!d2r::storage.init()) {\n        MessageBoxW(nullptr, L\"Failed to init D2RMH storage!\", L\"D2RMH\", MB_OK | MB_ICONERROR);\n        return -1;\n    }\n    d2mapapi::PipedChildProcess pcp;\n    if (!pcp.start(L\"d2mapapi_piped.exe\", (wchar_t *)cfg->d2Path.c_str())) {\n        MessageBoxA(nullptr, pcp.errMsg().c_str(), nullptr, MB_OK | MB_ICONERROR);\n        return -1;\n    }\n    data::loadData();\n\n    ui::Window wnd(100, 100, 500, 400);\n    render::Renderer renderer(&wnd);\n    if (cfg->fps > 0) {\n        renderer.limitFPS(cfg->fps);\n    } else {\n        render::Renderer::setSwapInterval(-cfg->fps);\n    }\n\n    ui::MapRenderer map(renderer, pcp);\n    wnd.enableTrayMenu(true,\n                       (const wchar_t *)1,\n                       L\"D2RMH \" VERSION_STRING_FULL,\n                       L\"D2RMH is running.\\nYou can close it from tray-icon popup menu.\",\n                       L\"D2RMH \" VERSION_STRING);\n    wnd.addAboutMenu();\n    wnd.addTrayMenuItem(L\"Reload Config\", -1, 0, [&wnd, &renderer, &map]() {\n        loadCfg();\n        wnd.reloadConfig();\n        if (cfg->fps > 0) {\n            renderer.limitFPS(cfg->fps);\n        } else {\n            render::Renderer::setSwapInterval(-cfg->fps);\n        }\n        map.reloadConfig();\n    });\n    wnd.addTrayMenuItem(L\"Quit\", -1, 0, [&wnd]() { wnd.quit(); });\n    while (wnd.run()) {\n        util::updateTime();\n        renderer.prepare();\n        map.update();\n        renderer.begin();\n        map.render();\n        renderer.end();\n    }\n    return 0;\n}\n"
  },
  {
    "path": "src/plugin/plugin.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"plugin.h\"\n\n#include \"d2r/d2rdefs.h\"\n#include \"d2r/processmanager.h\"\n#include \"ui/maprenderer.h\"\n#include \"ui/window.h\"\n#include \"cfg.h\"\n#include \"util/util.h\"\n\n#define SOL_ALL_SAFETIES_ON 1\n#include <sol/sol.hpp>\n\n#include <windows.h>\n#include <shlwapi.h>\n#include <chrono>\n#include <vector>\n#include <queue>\n#include <tuple>\n#include <cstdint>\n\nnamespace plugin {\n\nvoid PluginTextList::add(const char *text, uint32_t timeout, int fontSize) {\n    auto wstr = util::utf8toucs4(text);\n    for (auto ite = textList.begin(); ite != textList.end(); ++ite) {\n        auto tout = util::getCurrTime() + std::chrono::milliseconds(timeout);\n        if (ite->text == wstr && (fontSize < 0 || ite->fontSize == fontSize)) {\n            if (fontSize < 0 && ite + 1 != textList.end()) {\n                auto fsize = ite->fontSize;\n                textList.erase(ite);\n                textList.emplace_back(PluginText{wstr, tout, fsize});\n            } else {\n                ite->timeout = tout;\n            }\n            return;\n        }\n    }\n    textList.emplace_back(PluginText{wstr, util::getCurrTime() + std::chrono::milliseconds(timeout),\n                                     fontSize < 0 ? 0 : fontSize});\n}\n\nstruct PluginCtx {\n    sol::state lua;\n    std::vector<std::tuple<std::chrono::milliseconds, sol::function, sol::function, bool>> plugins;\n    using FuncPair = std::pair<std::chrono::steady_clock::time_point, size_t>;\n    std::priority_queue<FuncPair, std::vector<FuncPair>, std::greater<>> timedRunning;\n};\n\nPlugin::Plugin(d2r::ProcessManager *process, ui::MapRenderer *renderer) :\n    ctx_(new PluginCtx), d2rProcess_(process), mapRenderer_(renderer), window_(renderer->getRenderer().owner()) {\n}\n\nPlugin::~Plugin() {\n    window_->clearHotkeys();\n    delete ctx_;\n}\n\nvoid Plugin::load() {\n    window_->clearHotkeys();\n    delete ctx_;\n    ctx_ = new PluginCtx;\n    ctx_->lua = sol::state();\n    auto &lua = ctx_->lua;\n    lua.open_libraries();\n\n    addCFunctions();\n    WIN32_FIND_DATAW ffd = {};\n    HANDLE find = FindFirstFileW(L\"plugins\\\\*.lua\", &ffd);\n    if (find == INVALID_HANDLE_VALUE) {\n        return;\n    }\n    do {\n        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\n            continue;\n        }\n        wchar_t filename[MAX_PATH] = L\"plugins\";\n        PathAppendW(filename, ffd.cFileName);\n        auto file = CreateFileW(filename,\n                                GENERIC_READ,\n                                FILE_SHARE_READ,\n                                nullptr,\n                                OPEN_EXISTING,\n                                FILE_ATTRIBUTE_NORMAL,\n                                nullptr);\n        if (file == INVALID_HANDLE_VALUE) {\n            continue;\n        }\n        std::string data;\n        data.resize(ffd.nFileSizeLow);\n        DWORD bytesRead;\n        ReadFile(file, data.data(), ffd.nFileSizeLow, &bytesRead, nullptr);\n        CloseHandle(file);\n        sol::protected_function_result pfr = lua.safe_script(data, &sol::script_pass_on_error);\n        if (!pfr.valid()) {\n            sol::error err = pfr;\n            window_->messageBox(util::utf8toucs4(err.what()).c_str(), filename, MB_ICONERROR);\n        }\n    } while (FindNextFileW(find, &ffd));\n    FindClose(find);\n}\n\nvoid Plugin::run() {\n    if (ctx_->timedRunning.empty()) { return; }\n    auto now = util::getCurrTime();\n    do {\n        auto &pair = ctx_->timedRunning.top();\n        if (now < pair.first) {\n            break;\n        }\n        auto index = pair.second;\n        auto &plugin = ctx_->plugins[index];\n        auto dur = std::get<0>(plugin);\n        auto next = pair.first + dur;\n        if (next <= now) {\n            next = now + dur;\n        }\n        ctx_->timedRunning.pop();\n        ctx_->timedRunning.push(std::make_pair(next, index));\n        if (std::get<3>(plugin)) {\n            const auto &func = std::get<1>(plugin);\n            if (func) { func(); }\n        }\n    } while (true);\n}\n\nvoid Plugin::onEnterGame() {\n    for (auto &p: ctx_->plugins) {\n        const auto &func = std::get<2>(p);\n        if (func) { func(std::get<3>(p)); }\n    }\n}\n\nvoid Plugin::addCFunctions() {\n    auto &lua = ctx_->lua;\n    lua.new_usertype<Cfg>(\n        \"Config\",\n        \"show\", &Cfg::show,\n        \"scale\", &Cfg::scale\n    );\n    lua.new_usertype<d2r::Skill>(\n        \"Skill\",\n        \"level\", &d2r::Skill::skillLevel,\n        \"quantity\", &d2r::Skill::quantity\n    );\n    lua.new_usertype<PluginTextList>(\n        \"TextList\",\n        \"x\", &PluginTextList::x,\n        \"y\", &PluginTextList::y,\n        \"align\", &PluginTextList::align,\n        \"valign\", &PluginTextList::valign,\n        \"add\", &PluginTextList::add,\n        \"clear\", &PluginTextList::clear\n    );\n    lua.new_usertype<d2r::MapPlayer>(\n        \"Player\",\n        \"act\", &d2r::MapPlayer::act,\n        \"seed\", &d2r::MapPlayer::seed,\n        \"difficulty\", &d2r::MapPlayer::difficulty,\n        \"map\", &d2r::MapPlayer::levelId,\n        \"pos_x\", &d2r::MapPlayer::posX,\n        \"pos_y\", &d2r::MapPlayer::posY,\n        \"name\", &d2r::MapPlayer::name,\n        \"stats\", &d2r::MapPlayer::stats\n    );\n\n    auto registerFunc = [this](uint32_t interval, const sol::function &func, const sol::function &toggleFunc, bool on) {\n        auto index = ctx_->plugins.size();\n        auto dur = std::chrono::milliseconds(interval);\n        ctx_->plugins.emplace_back(dur, func, toggleFunc, on);\n        ctx_->timedRunning.push(std::make_pair(util::getCurrTime() + dur, index));\n        return index;\n    };\n    auto registerHotkeyForFunc = [this](const std::string &hotkey, int index) {\n        window_->registerHotkey(hotkey, [this, index] {\n            auto &on = std::get<3>(ctx_->plugins[index]);\n            on = !on;\n            const auto &func = std::get<2>(ctx_->plugins[index]);\n            if (func) {\n                func(on);\n            }\n        });\n    };\n    lua[\"register_plugin\"] = sol::overload([registerFunc](uint32_t interval, const sol::function &func) {\n                                               registerFunc(interval, func, sol::function(), true);\n                                           },\n                                           [registerFunc, registerHotkeyForFunc](const std::string &hotkey,\n                                                                                 bool on,\n                                                                                 uint32_t interval,\n                                                                                 const sol::function &func) {\n                                               auto index = registerFunc(interval, func, sol::function(), on);\n                                               registerHotkeyForFunc(hotkey, index);\n                                           },\n                                           [registerFunc, registerHotkeyForFunc](const std::string &hotkey,\n                                                                                 bool on,\n                                                                                 uint32_t interval,\n                                                                                 const sol::function &func,\n                                                                                 const sol::function &toggleFunc) {\n                                               auto index = registerFunc(interval, func, toggleFunc, on);\n                                               registerHotkeyForFunc(hotkey, index);\n                                           });\n    lua[\"register_hotkey\"] = [this](const std::string &hotkey, const sol::function &func) {\n        window_->registerHotkey(hotkey, func);\n    };\n    lua[\"get_config\"] = [] {\n        return (Cfg *)cfg;\n    };\n    lua[\"flush_overlay\"] = [this] {\n        mapRenderer_->forceFlush();\n    };\n    lua[\"reload_config\"] = [this] {\n        loadCfg();\n        auto &ren = mapRenderer_->getRenderer();\n        ren.owner()->reloadConfig();\n        if (cfg->fps > 0) {\n            ren.limitFPS(cfg->fps);\n        } else {\n            render::Renderer::setSwapInterval(-cfg->fps);\n        }\n        mapRenderer_->reloadConfig();\n    };\n\n    lua[\"get_player\"] = [this] {\n        return d2rProcess_->currPlayer();\n    };\n    lua[\"get_skill\"] = [this](uint16_t id) {\n        return d2rProcess_->getSkill(id);\n    };\n    lua[\"kill_process\"] = [this] {\n        d2rProcess_->killProcess();\n    };\n    lua[\"create_text_list\"] = [this](const std::string &str) {\n        auto &res = mapRenderer_->getPluginText(str);\n        res.textList.clear();\n        return &res;\n    };\n    lua[\"remove_text_list\"] = [this](const std::string &str) {\n        mapRenderer_->removePluginText(str);\n    };\n    lua[\"message_box\"] = [this](const std::string &str, uint32_t type) {\n        window_->messageBox(util::utf8toucs4(str).c_str(), L\"D2RMH\", type);\n    };\n    lua[\"key_press\"] = [this](const std::string &str) {\n        auto hwnd = (HWND)d2rProcess_->hwnd();\n        if (!hwnd) { return; }\n        uint32_t mods;\n        auto vkey = util::mapStringToVKey(str, mods);\n        SendMessageA(hwnd, WM_KEYDOWN, vkey, 1);\n        Sleep(5);\n        SendMessageA(hwnd, WM_KEYUP, vkey, 0xC0000001u);\n    };\n    lua[\"mouse_move\"] = [this](int x, int y) {\n        auto hwnd = (HWND)d2rProcess_->hwnd();\n        if (!hwnd) { return; }\n        POINT pt = {x, y};\n        ClientToScreen(hwnd, &pt);\n        SetCursorPos(pt.x, pt.y);\n    };\n    lua[\"mouse_click\"] = [this](int which) {\n        auto hwnd = (HWND)d2rProcess_->hwnd();\n        if (!hwnd) { return; }\n        UINT msg, msg2;\n        switch (which) {\n        case 1:\n            msg = WM_RBUTTONDOWN; msg2 = WM_RBUTTONUP;\n            break;\n        case 2:\n            msg = WM_MBUTTONDOWN; msg2 = WM_MBUTTONUP;\n            break;\n        default:\n            msg = WM_LBUTTONDOWN; msg2 = WM_LBUTTONUP;\n            break;\n        }\n        SendMessageA(hwnd, msg, 0, 0);\n        Sleep(5);\n        SendMessageA(hwnd, msg2, 0, 0);\n    };\n    lua[\"delay\"] = [this](uint32_t millisecs) {\n        Sleep(millisecs);\n    };\n}\n\n}\n"
  },
  {
    "path": "src/plugin/plugin.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <chrono>\n#include <vector>\n#include <string>\n\nnamespace d2r {\nclass ProcessManager;\n}\nnamespace ui {\nclass MapRenderer;\nclass Window;\n}\n\nnamespace plugin {\n\nstruct PluginCtx;\n\nstruct PluginText {\n    std::wstring text;\n    std::chrono::steady_clock::time_point timeout;\n    int fontSize;\n};\nstruct PluginTextList {\n    float x = .2f, y = .78f;\n    int align = 0;\n    int valign = 1;\n    std::vector<PluginText> textList;\n    void add(const char *text, uint32_t timeout, int fontSize);\n    void clear() { textList.clear(); }\n};\n\nclass Plugin final {\npublic:\n    Plugin(d2r::ProcessManager *process, ui::MapRenderer *renderer);\n    ~Plugin();\n    void load();\n    void run();\n    void onEnterGame();\n\nprivate:\n    void addCFunctions();\n\nprivate:\n    PluginCtx *ctx_;\n    d2r::ProcessManager *d2rProcess_;\n    ui::MapRenderer *mapRenderer_;\n    ui::Window *window_;\n};\n\n}\n"
  },
  {
    "path": "src/render/HandmadeMath.h",
    "content": "/*\n  HandmadeMath.h v1.13.0\n\n  This is a single header file with a bunch of useful functions for game and\n  graphics math operations.\n\n  =============================================================================\n\n  To disable SSE intrinsics, you MUST\n\n  #define HANDMADE_MATH_NO_SSE\n\n  in EXACTLY one C or C++ file that includes this header, BEFORE the\n  include, like this:\n\n     #define HANDMADE_MATH_NO_SSE\n     #include \"HandmadeMath.h\"\n\n  =============================================================================\n\n  If you would prefer not to use the HMM_ prefix on function names, you can\n\n  #define HMM_PREFIX\n\n  To use a custom prefix instead, you can\n\n  #define HMM_PREFIX(name) YOUR_PREFIX_##name\n\n  =============================================================================\n\n  To use HandmadeMath without the CRT, you MUST\n\n     #define HMM_SINF MySinF\n     #define HMM_COSF MyCosF\n     #define HMM_TANF MyTanF\n     #define HMM_SQRTF MySqrtF\n     #define HMM_EXPF MyExpF\n     #define HMM_LOGF MyLogF\n     #define HMM_ACOSF MyACosF\n     #define HMM_ATANF MyATanF\n     #define HMM_ATAN2F MYATan2F\n\n  Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F,\n  ExpF, and LogF in EXACTLY one C or C++ file that includes this header,\n  BEFORE the include, like this:\n\n     #define HMM_SINF MySinF\n     #define HMM_COSF MyCosF\n     #define HMM_TANF MyTanF\n     #define HMM_SQRTF MySqrtF\n     #define HMM_EXPF MyExpF\n     #define HMM_LOGF MyLogF\n     #define HMM_ACOSF MyACosF\n     #define HMM_ATANF MyATanF\n     #define HMM_ATAN2F MyATan2F\n     #include \"HandmadeMath.h\"\n\n  If you do not define all of these, HandmadeMath.h will use the\n  versions of these functions that are provided by the CRT.\n\n  =============================================================================\n\n  LICENSE\n\n  This software is in the public domain. Where that dedication is not\n  recognized, you are granted a perpetual, irrevocable license to copy,\n  distribute, and modify this file as you see fit.\n\n  CREDITS\n\n  Written by Zakary Strange (strangezak@protonmail.com && @strangezak)\n\n  Functionality:\n   Matt Mascarenhas (@miblo_)\n   Aleph\n   FieryDrake (@fierydrake)\n   Gingerbill (@TheGingerBill)\n   Ben Visness (@bvisness)\n   Trinton Bullard (@Peliex_Dev)\n   @AntonDan\n\n  Fixes:\n   Jeroen van Rijn (@J_vanRijn)\n   Kiljacken (@Kiljacken)\n   Insofaras (@insofaras)\n   Daniel Gibson (@DanielGibson)\n*/\n\n// Dummy macros for when test framework is not present.\n#ifndef COVERAGE\n#define COVERAGE(a, b)\n#endif\n\n#ifndef ASSERT_COVERED\n#define ASSERT_COVERED(a)\n#endif\n\n/* let's figure out if SSE is really available (unless disabled anyway)\n   (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support)\n   => only use \"#ifdef HANDMADE_MATH__USE_SSE\" to check for SSE support below this block! */\n#ifndef HANDMADE_MATH_NO_SSE\n\n# ifdef _MSC_VER\n   /* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */\n#  if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 )\n#   define HANDMADE_MATH__USE_SSE 1\n#  endif\n# else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */\n#  ifdef __SSE__ /* they #define __SSE__ if it's supported */\n#   define HANDMADE_MATH__USE_SSE 1\n#  endif /*  __SSE__ */\n# endif /* not _MSC_VER */\n\n#endif /* #ifndef HANDMADE_MATH_NO_SSE */\n\n#ifdef HANDMADE_MATH__USE_SSE\n#include <xmmintrin.h>\n#endif\n\n#ifndef HANDMADE_MATH_H\n#define HANDMADE_MATH_H\n\n#ifdef _MSC_VER\n#pragma warning(disable:4201)\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#if (defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) || defined(__clang__)\n#pragma GCC diagnostic ignored \"-Wmissing-braces\"\n#endif\n#ifdef __clang__\n#pragma GCC diagnostic ignored \"-Wgnu-anonymous-struct\"\n#pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"\n#endif\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#define HMM_DEPRECATED(msg) __attribute__((deprecated(msg)))\n#elif defined(_MSC_VER)\n#define HMM_DEPRECATED(msg) __declspec(deprecated(msg))\n#else\n#define HMM_DEPRECATED(msg)\n#endif\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#define HMM_INLINE static inline\n\n#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \\\n    !defined(HMM_SQRTF) || !defined(HMM_EXPF) || !defined(HMM_LOGF) || \\\n    !defined(HMM_ACOSF) || !defined(HMM_ATANF)|| !defined(HMM_ATAN2F)\n#include <math.h>\n#endif\n\n#ifndef HMM_SINF\n#define HMM_SINF sinf\n#endif\n\n#ifndef HMM_COSF\n#define HMM_COSF cosf\n#endif\n\n#ifndef HMM_TANF\n#define HMM_TANF tanf\n#endif\n\n#ifndef HMM_SQRTF\n#define HMM_SQRTF sqrtf\n#endif\n\n#ifndef HMM_EXPF\n#define HMM_EXPF expf\n#endif\n\n#ifndef HMM_LOGF\n#define HMM_LOGF logf\n#endif\n\n#ifndef HMM_ACOSF\n#define HMM_ACOSF acosf\n#endif\n\n#ifndef HMM_ATANF\n#define HMM_ATANF atanf\n#endif\n\n#ifndef HMM_ATAN2F\n#define HMM_ATAN2F atan2f\n#endif\n\n#define HMM_PI32 3.14159265359f\n#define HMM_PI 3.14159265358979323846\n\n#define HMM_MIN(a, b) ((a) > (b) ? (b) : (a))\n#define HMM_MAX(a, b) ((a) < (b) ? (b) : (a))\n#define HMM_ABS(a) ((a) > 0 ? (a) : -(a))\n#define HMM_MOD(a, m) (((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)))\n#define HMM_SQUARE(x) ((x) * (x))\n\n#ifndef HMM_PREFIX\n#define HMM_PREFIX(name) HMM_##name\n#endif\n\ntypedef union hmm_vec2\n{\n    struct\n    {\n        float X, Y;\n    };\n\n    struct\n    {\n        float U, V;\n    };\n\n    struct\n    {\n        float Left, Right;\n    };\n\n    struct\n    {\n        float Width, Height;\n    };\n\n    float Elements[2];\n\n#ifdef __cplusplus\n    inline float &operator[](const int &Index)\n    {\n        return Elements[Index];\n    }\n#endif\n} hmm_vec2;\n\ntypedef union hmm_vec3\n{\n    struct\n    {\n        float X, Y, Z;\n    };\n\n    struct\n    {\n        float U, V, W;\n    };\n\n    struct\n    {\n        float R, G, B;\n    };\n\n    struct\n    {\n        hmm_vec2 XY;\n        float Ignored0_;\n    };\n\n    struct\n    {\n        float Ignored1_;\n        hmm_vec2 YZ;\n    };\n\n    struct\n    {\n        hmm_vec2 UV;\n        float Ignored2_;\n    };\n\n    struct\n    {\n        float Ignored3_;\n        hmm_vec2 VW;\n    };\n\n    float Elements[3];\n\n#ifdef __cplusplus\n    inline float &operator[](const int &Index)\n    {\n        return Elements[Index];\n    }\n#endif\n} hmm_vec3;\n\ntypedef union hmm_vec4\n{\n    struct\n    {\n        union\n        {\n            hmm_vec3 XYZ;\n            struct\n            {\n                float X, Y, Z;\n            };\n        };\n\n        float W;\n    };\n    struct\n    {\n        union\n        {\n            hmm_vec3 RGB;\n            struct\n            {\n                float R, G, B;\n            };\n        };\n\n        float A;\n    };\n\n    struct\n    {\n        hmm_vec2 XY;\n        float Ignored0_;\n        float Ignored1_;\n    };\n\n    struct\n    {\n        float Ignored2_;\n        hmm_vec2 YZ;\n        float Ignored3_;\n    };\n\n    struct\n    {\n        float Ignored4_;\n        float Ignored5_;\n        hmm_vec2 ZW;\n    };\n\n    float Elements[4];\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 InternalElementsSSE;\n#endif\n\n#ifdef __cplusplus\n    inline float &operator[](const int &Index)\n    {\n        return Elements[Index];\n    }\n#endif\n} hmm_vec4;\n\ntypedef union hmm_mat4\n{\n    float Elements[4][4];\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 Columns[4];\n\n    HMM_DEPRECATED(\"Our matrices are column-major, so this was named incorrectly. Use Columns instead.\")\n    __m128 Rows[4];\n#endif\n\n#ifdef __cplusplus\n    inline hmm_vec4 operator[](const int &Index)\n    {\n        hmm_vec4 Result;\n        float* Column = Elements[Index];\n        \n\n        Result.Elements[0] = Column[0];\n        Result.Elements[1] = Column[1];\n        Result.Elements[2] = Column[2];\n        Result.Elements[3] = Column[3];\n\n        return Result;\n    }\n#endif\n} hmm_mat4;\n\ntypedef union hmm_quaternion\n{\n    struct\n    {\n        union\n        {\n            hmm_vec3 XYZ;\n            struct\n            {\n                float X, Y, Z;\n            };\n        };\n\n        float W;\n    };\n\n    float Elements[4];\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 InternalElementsSSE;\n#endif\n} hmm_quaternion;\n\ntypedef signed int hmm_bool;\n\ntypedef hmm_vec2 hmm_v2;\ntypedef hmm_vec3 hmm_v3;\ntypedef hmm_vec4 hmm_v4;\ntypedef hmm_mat4 hmm_m4;\n\n\n/*\n * Floating-point math functions\n */\n\nCOVERAGE(HMM_SinF, 1)\nHMM_INLINE float HMM_PREFIX(SinF)(float Radians)\n{\n    ASSERT_COVERED(HMM_SinF);\n\n    float Result = HMM_SINF(Radians);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_CosF, 1)\nHMM_INLINE float HMM_PREFIX(CosF)(float Radians)\n{\n    ASSERT_COVERED(HMM_CosF);\n\n    float Result = HMM_COSF(Radians);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_TanF, 1)\nHMM_INLINE float HMM_PREFIX(TanF)(float Radians)\n{\n    ASSERT_COVERED(HMM_TanF);\n\n    float Result = HMM_TANF(Radians);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_ACosF, 1)\nHMM_INLINE float HMM_PREFIX(ACosF)(float Radians)\n{\n    ASSERT_COVERED(HMM_ACosF);\n\n    float Result = HMM_ACOSF(Radians);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_ATanF, 1)\nHMM_INLINE float HMM_PREFIX(ATanF)(float Radians)\n{\n    ASSERT_COVERED(HMM_ATanF);\n\n    float Result = HMM_ATANF(Radians);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_ATan2F, 1)\nHMM_INLINE float HMM_PREFIX(ATan2F)(float Left, float Right)\n{\n    ASSERT_COVERED(HMM_ATan2F);\n\n    float Result = HMM_ATAN2F(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_ExpF, 1)\nHMM_INLINE float HMM_PREFIX(ExpF)(float Float)\n{\n    ASSERT_COVERED(HMM_ExpF);\n\n    float Result = HMM_EXPF(Float);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LogF, 1)\nHMM_INLINE float HMM_PREFIX(LogF)(float Float)\n{\n    ASSERT_COVERED(HMM_LogF);\n\n    float Result = HMM_LOGF(Float);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SquareRootF, 1)\nHMM_INLINE float HMM_PREFIX(SquareRootF)(float Float)\n{\n    ASSERT_COVERED(HMM_SquareRootF);\n\n    float Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 In = _mm_set_ss(Float);\n    __m128 Out = _mm_sqrt_ss(In);\n    Result = _mm_cvtss_f32(Out);\n#else\n    Result = HMM_SQRTF(Float);\n#endif\n\n    return(Result);\n}\n\nCOVERAGE(HMM_RSquareRootF, 1)\nHMM_INLINE float HMM_PREFIX(RSquareRootF)(float Float)\n{\n    ASSERT_COVERED(HMM_RSquareRootF);\n\n    float Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 In = _mm_set_ss(Float);\n    __m128 Out = _mm_rsqrt_ss(In);\n    Result = _mm_cvtss_f32(Out);\n#else\n    Result = 1.0f/HMM_PREFIX(SquareRootF)(Float);\n#endif\n\n    return(Result);\n}\n\nCOVERAGE(HMM_Power, 2)\nHMM_INLINE float HMM_PREFIX(Power)(float Base, int Exponent)\n{\n    ASSERT_COVERED(HMM_Power);\n\n    float Result = 1.0f;\n    float Mul = Exponent < 0 ? 1.f / Base : Base;\n    int X = Exponent < 0 ? -Exponent : Exponent;\n    while (X)\n    {\n        if (X & 1)\n        {\n            ASSERT_COVERED(HMM_Power);\n\n            Result *= Mul;\n        }\n\n        Mul *= Mul;\n        X >>= 1;\n    }\n\n    return (Result);\n}\n\nCOVERAGE(HMM_PowerF, 1)\nHMM_INLINE float HMM_PREFIX(PowerF)(float Base, float Exponent)\n{\n    ASSERT_COVERED(HMM_PowerF);\n\n    float Result = HMM_EXPF(Exponent * HMM_LOGF(Base));\n\n    return (Result);\n}\n\n\n/*\n * Utility functions\n */\n\nCOVERAGE(HMM_ToRadians, 1)\nHMM_INLINE float HMM_PREFIX(ToRadians)(float Degrees)\n{\n    ASSERT_COVERED(HMM_ToRadians);\n\n    float Result = Degrees * (HMM_PI32 / 180.0f);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Lerp, 1)\nHMM_INLINE float HMM_PREFIX(Lerp)(float A, float Time, float B)\n{\n    ASSERT_COVERED(HMM_Lerp);\n\n    float Result = (1.0f - Time) * A + Time * B;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Clamp, 1)\nHMM_INLINE float HMM_PREFIX(Clamp)(float Min, float Value, float Max)\n{\n    ASSERT_COVERED(HMM_Clamp);\n\n    float Result = Value;\n\n    if(Result < Min)\n    {\n        Result = Min;\n    }\n\n    if(Result > Max)\n    {\n        Result = Max;\n    }\n\n    return (Result);\n}\n\n\n/*\n * Vector initialization\n */\n\nCOVERAGE(HMM_Vec2, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Vec2)(float X, float Y)\n{\n    ASSERT_COVERED(HMM_Vec2);\n\n    hmm_vec2 Result;\n\n    Result.X = X;\n    Result.Y = Y;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Vec2i, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Vec2i)(int X, int Y)\n{\n    ASSERT_COVERED(HMM_Vec2i);\n\n    hmm_vec2 Result;\n\n    Result.X = (float)X;\n    Result.Y = (float)Y;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Vec3, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Vec3)(float X, float Y, float Z)\n{\n    ASSERT_COVERED(HMM_Vec3);\n\n    hmm_vec3 Result;\n\n    Result.X = X;\n    Result.Y = Y;\n    Result.Z = Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Vec3i, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Vec3i)(int X, int Y, int Z)\n{\n    ASSERT_COVERED(HMM_Vec3i);\n\n    hmm_vec3 Result;\n\n    Result.X = (float)X;\n    Result.Y = (float)Y;\n    Result.Z = (float)Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Vec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Vec4)(float X, float Y, float Z, float W)\n{\n    ASSERT_COVERED(HMM_Vec4);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_setr_ps(X, Y, Z, W);\n#else\n    Result.X = X;\n    Result.Y = Y;\n    Result.Z = Z;\n    Result.W = W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Vec4i, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Vec4i)(int X, int Y, int Z, int W)\n{\n    ASSERT_COVERED(HMM_Vec4i);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_setr_ps((float)X, (float)Y, (float)Z, (float)W);\n#else\n    Result.X = (float)X;\n    Result.Y = (float)Y;\n    Result.Z = (float)Z;\n    Result.W = (float)W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Vec4v, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Vec4v)(hmm_vec3 Vector, float W)\n{\n    ASSERT_COVERED(HMM_Vec4v);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W);\n#else\n    Result.XYZ = Vector;\n    Result.W = W;\n#endif\n\n    return (Result);\n}\n\n\n/*\n * Binary vector operations\n */\n\nCOVERAGE(HMM_AddVec2, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(AddVec2)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_AddVec2);\n\n    hmm_vec2 Result;\n\n    Result.X = Left.X + Right.X;\n    Result.Y = Left.Y + Right.Y;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec3, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(AddVec3)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_AddVec3);\n\n    hmm_vec3 Result;\n\n    Result.X = Left.X + Right.X;\n    Result.Y = Left.Y + Right.Y;\n    Result.Z = Left.Z + Right.Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(AddVec4)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_AddVec4);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_add_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n#else\n    Result.X = Left.X + Right.X;\n    Result.Y = Left.Y + Right.Y;\n    Result.Z = Left.Z + Right.Z;\n    Result.W = Left.W + Right.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec2, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(SubtractVec2)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec2);\n\n    hmm_vec2 Result;\n\n    Result.X = Left.X - Right.X;\n    Result.Y = Left.Y - Right.Y;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec3, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(SubtractVec3)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec3);\n\n    hmm_vec3 Result;\n\n    Result.X = Left.X - Right.X;\n    Result.Y = Left.Y - Right.Y;\n    Result.Z = Left.Z - Right.Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(SubtractVec4)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec4);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_sub_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n#else\n    Result.X = Left.X - Right.X;\n    Result.Y = Left.Y - Right.Y;\n    Result.Z = Left.Z - Right.Z;\n    Result.W = Left.W - Right.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(MultiplyVec2)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2);\n\n    hmm_vec2 Result;\n\n    Result.X = Left.X * Right.X;\n    Result.Y = Left.Y * Right.Y;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2f, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(MultiplyVec2f)(hmm_vec2 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2f);\n\n    hmm_vec2 Result;\n\n    Result.X = Left.X * Right;\n    Result.Y = Left.Y * Right;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(MultiplyVec3)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3);\n\n    hmm_vec3 Result;\n\n    Result.X = Left.X * Right.X;\n    Result.Y = Left.Y * Right.Y;\n    Result.Z = Left.Z * Right.Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3f, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(MultiplyVec3f)(hmm_vec3 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3f);\n\n    hmm_vec3 Result;\n\n    Result.X = Left.X * Right;\n    Result.Y = Left.Y * Right;\n    Result.Z = Left.Z * Right;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyVec4)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n#else\n    Result.X = Left.X * Right.X;\n    Result.Y = Left.Y * Right.Y;\n    Result.Z = Left.Z * Right.Z;\n    Result.W = Left.W * Right.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4f, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyVec4f)(hmm_vec4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4f);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 Scalar = _mm_set1_ps(Right);\n    Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Scalar);\n#else\n    Result.X = Left.X * Right;\n    Result.Y = Left.Y * Right;\n    Result.Z = Left.Z * Right;\n    Result.W = Left.W * Right;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec2, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(DivideVec2)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2);\n\n    hmm_vec2 Result;\n\n    Result.X = Left.X / Right.X;\n    Result.Y = Left.Y / Right.Y;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec2f, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(DivideVec2f)(hmm_vec2 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2f);\n\n    hmm_vec2 Result;\n\n    Result.X = Left.X / Right;\n    Result.Y = Left.Y / Right;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec3, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(DivideVec3)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3);\n\n    hmm_vec3 Result;\n\n    Result.X = Left.X / Right.X;\n    Result.Y = Left.Y / Right.Y;\n    Result.Z = Left.Z / Right.Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec3f, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(DivideVec3f)(hmm_vec3 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3f);\n\n    hmm_vec3 Result;\n\n    Result.X = Left.X / Right;\n    Result.Y = Left.Y / Right;\n    Result.Z = Left.Z / Right;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(DivideVec4)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n#else\n    Result.X = Left.X / Right.X;\n    Result.Y = Left.Y / Right.Y;\n    Result.Z = Left.Z / Right.Z;\n    Result.W = Left.W / Right.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec4f, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(DivideVec4f)(hmm_vec4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4f);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 Scalar = _mm_set1_ps(Right);\n    Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Scalar);\n#else\n    Result.X = Left.X / Right;\n    Result.Y = Left.Y / Right;\n    Result.Z = Left.Z / Right;\n    Result.W = Left.W / Right;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_EqualsVec2, 1)\nHMM_INLINE hmm_bool HMM_PREFIX(EqualsVec2)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec2);\n\n    hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_EqualsVec3, 1)\nHMM_INLINE hmm_bool HMM_PREFIX(EqualsVec3)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec3);\n\n    hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_EqualsVec4, 1)\nHMM_INLINE hmm_bool HMM_PREFIX(EqualsVec4)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec4);\n\n    hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotVec2, 1)\nHMM_INLINE float HMM_PREFIX(DotVec2)(hmm_vec2 VecOne, hmm_vec2 VecTwo)\n{\n    ASSERT_COVERED(HMM_DotVec2);\n\n    float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotVec3, 1)\nHMM_INLINE float HMM_PREFIX(DotVec3)(hmm_vec3 VecOne, hmm_vec3 VecTwo)\n{\n    ASSERT_COVERED(HMM_DotVec3);\n\n    float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotVec4, 1)\nHMM_INLINE float HMM_PREFIX(DotVec4)(hmm_vec4 VecOne, hmm_vec4 VecTwo)\n{\n    ASSERT_COVERED(HMM_DotVec4);\n\n    float Result;\n\n    // NOTE(zak): IN the future if we wanna check what version SSE is support\n    // we can use _mm_dp_ps (4.3) but for now we will use the old way.\n    // Or a r = _mm_mul_ps(v1, v2), r = _mm_hadd_ps(r, r), r = _mm_hadd_ps(r, r) for SSE3\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 SSEResultOne = _mm_mul_ps(VecOne.InternalElementsSSE, VecTwo.InternalElementsSSE);\n    __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1));\n    SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);\n    SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));\n    SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);\n    _mm_store_ss(&Result, SSEResultOne);\n#else\n    Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z) + (VecOne.W * VecTwo.W);\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Cross, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Cross)(hmm_vec3 VecOne, hmm_vec3 VecTwo)\n{\n    ASSERT_COVERED(HMM_Cross);\n\n    hmm_vec3 Result;\n\n    Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y);\n    Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z);\n    Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X);\n\n    return (Result);\n}\n\n\n/*\n * Unary vector operations\n */\n\nCOVERAGE(HMM_LengthSquaredVec2, 1)\nHMM_INLINE float HMM_PREFIX(LengthSquaredVec2)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_LengthSquaredVec2);\n\n    float Result = HMM_PREFIX(DotVec2)(A, A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthSquaredVec3, 1)\nHMM_INLINE float HMM_PREFIX(LengthSquaredVec3)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_LengthSquaredVec3);\n\n    float Result = HMM_PREFIX(DotVec3)(A, A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthSquaredVec4, 1)\nHMM_INLINE float HMM_PREFIX(LengthSquaredVec4)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_LengthSquaredVec4);\n\n    float Result = HMM_PREFIX(DotVec4)(A, A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthVec2, 1)\nHMM_INLINE float HMM_PREFIX(LengthVec2)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_LengthVec2);\n\n    float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec2)(A));\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthVec3, 1)\nHMM_INLINE float HMM_PREFIX(LengthVec3)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_LengthVec3);\n\n    float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec3)(A));\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthVec4, 1)\nHMM_INLINE float HMM_PREFIX(LengthVec4)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_LengthVec4);\n\n    float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec4)(A));\n\n    return(Result);\n}\n\nCOVERAGE(HMM_NormalizeVec2, 2)\nHMM_INLINE hmm_vec2 HMM_PREFIX(NormalizeVec2)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_NormalizeVec2);\n\n    hmm_vec2 Result = {0};\n\n    float VectorLength = HMM_PREFIX(LengthVec2)(A);\n\n    /* NOTE(kiljacken): We need a zero check to not divide-by-zero */\n    if (VectorLength != 0.0f)\n    {\n        ASSERT_COVERED(HMM_NormalizeVec2);\n\n        Result.X = A.X * (1.0f / VectorLength);\n        Result.Y = A.Y * (1.0f / VectorLength);\n    }\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NormalizeVec3, 2)\nHMM_INLINE hmm_vec3 HMM_PREFIX(NormalizeVec3)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_NormalizeVec3);\n\n    hmm_vec3 Result = {0};\n\n    float VectorLength = HMM_PREFIX(LengthVec3)(A);\n\n    /* NOTE(kiljacken): We need a zero check to not divide-by-zero */\n    if (VectorLength != 0.0f)\n    {\n        ASSERT_COVERED(HMM_NormalizeVec3);\n\n        Result.X = A.X * (1.0f / VectorLength);\n        Result.Y = A.Y * (1.0f / VectorLength);\n        Result.Z = A.Z * (1.0f / VectorLength);\n    }\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NormalizeVec4, 2)\nHMM_INLINE hmm_vec4 HMM_PREFIX(NormalizeVec4)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_NormalizeVec4);\n\n    hmm_vec4 Result = {0};\n\n    float VectorLength = HMM_PREFIX(LengthVec4)(A);\n\n    /* NOTE(kiljacken): We need a zero check to not divide-by-zero */\n    if (VectorLength != 0.0f)\n    {\n        ASSERT_COVERED(HMM_NormalizeVec4);\n\n        float Multiplier = 1.0f / VectorLength;\n\n#ifdef HANDMADE_MATH__USE_SSE\n        __m128 SSEMultiplier = _mm_set1_ps(Multiplier);\n        Result.InternalElementsSSE = _mm_mul_ps(A.InternalElementsSSE, SSEMultiplier);\n#else\n        Result.X = A.X * Multiplier;\n        Result.Y = A.Y * Multiplier;\n        Result.Z = A.Z * Multiplier;\n        Result.W = A.W * Multiplier;\n#endif\n    }\n\n    return (Result);\n}\n\nCOVERAGE(HMM_FastNormalizeVec2, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(FastNormalizeVec2)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_FastNormalizeVec2);\n\n    return HMM_PREFIX(MultiplyVec2f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec2)(A, A)));\n}\n\nCOVERAGE(HMM_FastNormalizeVec3, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(FastNormalizeVec3)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_FastNormalizeVec3);\n\n    return HMM_PREFIX(MultiplyVec3f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec3)(A, A)));\n}\n\nCOVERAGE(HMM_FastNormalizeVec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(FastNormalizeVec4)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_FastNormalizeVec4);\n\n    return HMM_PREFIX(MultiplyVec4f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec4)(A, A)));\n}\n\n\n/*\n * SSE stuff\n */\n\n#ifdef HANDMADE_MATH__USE_SSE\nCOVERAGE(HMM_LinearCombineSSE, 1)\nHMM_INLINE __m128 HMM_PREFIX(LinearCombineSSE)(__m128 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_LinearCombineSSE);\n\n    __m128 Result;\n    Result = _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x00), Right.Columns[0]);\n    Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x55), Right.Columns[1]));\n    Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xaa), Right.Columns[2]));\n    Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xff), Right.Columns[3]));\n\n    return (Result);\n}\n#endif\n\n\n/*\n * Matrix functions\n */\n\nCOVERAGE(HMM_Mat4, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Mat4)(void)\n{\n    ASSERT_COVERED(HMM_Mat4);\n\n    hmm_mat4 Result = {0};\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Mat4d, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Mat4d)(float Diagonal)\n{\n    ASSERT_COVERED(HMM_Mat4d);\n\n    hmm_mat4 Result = HMM_PREFIX(Mat4)();\n\n    Result.Elements[0][0] = Diagonal;\n    Result.Elements[1][1] = Diagonal;\n    Result.Elements[2][2] = Diagonal;\n    Result.Elements[3][3] = Diagonal;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Transpose, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Transpose)(hmm_mat4 Matrix)\n{\n    ASSERT_COVERED(HMM_Transpose);\n\n    hmm_mat4 Result = Matrix;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    _MM_TRANSPOSE4_PS(Result.Columns[0], Result.Columns[1], Result.Columns[2], Result.Columns[3]);\n#else\n    int Columns;\n    for(Columns = 0; Columns < 4; ++Columns)\n    {\n        int Rows;\n        for(Rows = 0; Rows < 4; ++Rows)\n        {\n            Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];\n        }\n    }\n#endif\n\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddMat4, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(AddMat4)(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_AddMat4);\n\n    hmm_mat4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.Columns[0] = _mm_add_ps(Left.Columns[0], Right.Columns[0]);\n    Result.Columns[1] = _mm_add_ps(Left.Columns[1], Right.Columns[1]);\n    Result.Columns[2] = _mm_add_ps(Left.Columns[2], Right.Columns[2]);\n    Result.Columns[3] = _mm_add_ps(Left.Columns[3], Right.Columns[3]);\n#else\n     int Columns;\n    for(Columns = 0; Columns < 4; ++Columns)\n    {\n        int Rows;\n        for(Rows = 0; Rows < 4; ++Rows)\n        {\n            Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows];\n        }\n    }\n#endif\n\n   \n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractMat4, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(SubtractMat4)(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractMat4);\n\n    hmm_mat4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.Columns[0] = _mm_sub_ps(Left.Columns[0], Right.Columns[0]);\n    Result.Columns[1] = _mm_sub_ps(Left.Columns[1], Right.Columns[1]);\n    Result.Columns[2] = _mm_sub_ps(Left.Columns[2], Right.Columns[2]);\n    Result.Columns[3] = _mm_sub_ps(Left.Columns[3], Right.Columns[3]);\n#else\n    int Columns;\n    for(Columns = 0; Columns < 4; ++Columns)\n    {\n        int Rows;\n        for(Rows = 0; Rows < 4; ++Rows)\n        {\n            Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows];\n        }\n    }\n#endif\n \n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(MultiplyMat4)(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4);\n\n    hmm_mat4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.Columns[0] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[0], Left);\n    Result.Columns[1] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[1], Left);\n    Result.Columns[2] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[2], Left);\n    Result.Columns[3] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[3], Left);\n#else\n    int Columns;\n    for(Columns = 0; Columns < 4; ++Columns)\n    {\n        int Rows;\n        for(Rows = 0; Rows < 4; ++Rows)\n        {\n            float Sum = 0;\n            int CurrentMatrice;\n            for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice)\n            {\n                Sum += Left.Elements[CurrentMatrice][Rows] * Right.Elements[Columns][CurrentMatrice];\n            }\n\n            Result.Elements[Columns][Rows] = Sum;\n        }\n    }\n#endif\n\n    return (Result);\n}\n\n\nCOVERAGE(HMM_MultiplyMat4f, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(MultiplyMat4f)(hmm_mat4 Matrix, float Scalar)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4f);\n\n    hmm_mat4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 SSEScalar = _mm_set1_ps(Scalar);\n    Result.Columns[0] = _mm_mul_ps(Matrix.Columns[0], SSEScalar);\n    Result.Columns[1] = _mm_mul_ps(Matrix.Columns[1], SSEScalar);\n    Result.Columns[2] = _mm_mul_ps(Matrix.Columns[2], SSEScalar);\n    Result.Columns[3] = _mm_mul_ps(Matrix.Columns[3], SSEScalar);\n#else\n    int Columns;\n    for(Columns = 0; Columns < 4; ++Columns)\n    {\n        int Rows;\n        for(Rows = 0; Rows < 4; ++Rows)\n        {\n            Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar;\n        }\n    }\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4ByVec4, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyMat4ByVec4)(hmm_mat4 Matrix, hmm_vec4 Vector)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4ByVec4);\n\n    hmm_vec4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = HMM_PREFIX(LinearCombineSSE)(Vector.InternalElementsSSE, Matrix);\n#else\n    int Columns, Rows;\n    for(Rows = 0; Rows < 4; ++Rows)\n    {\n        float Sum = 0;\n        for(Columns = 0; Columns < 4; ++Columns)\n        {\n            Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns];\n        }\n\n        Result.Elements[Rows] = Sum;\n    }\n#endif\n\n    return (Result);\n}\n\n\nCOVERAGE(HMM_DivideMat4f, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(DivideMat4f)(hmm_mat4 Matrix, float Scalar)\n{\n    ASSERT_COVERED(HMM_DivideMat4f);\n\n    hmm_mat4 Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 SSEScalar = _mm_set1_ps(Scalar);\n    Result.Columns[0] = _mm_div_ps(Matrix.Columns[0], SSEScalar);\n    Result.Columns[1] = _mm_div_ps(Matrix.Columns[1], SSEScalar);\n    Result.Columns[2] = _mm_div_ps(Matrix.Columns[2], SSEScalar);\n    Result.Columns[3] = _mm_div_ps(Matrix.Columns[3], SSEScalar);\n#else\n    int Columns;\n    for(Columns = 0; Columns < 4; ++Columns)\n    {\n        int Rows;\n        for(Rows = 0; Rows < 4; ++Rows)\n        {\n            Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar;\n        }\n    }\n#endif\n\n    return (Result);\n}\n\n/*\n * Common graphics transformations\n */\n\nCOVERAGE(HMM_Orthographic, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Orthographic)(float Left, float Right, float Bottom, float Top, float Near, float Far)\n{\n    ASSERT_COVERED(HMM_Orthographic);\n\n    hmm_mat4 Result = HMM_PREFIX(Mat4)();\n\n    Result.Elements[0][0] = 2.0f / (Right - Left);\n    Result.Elements[1][1] = 2.0f / (Top - Bottom);\n    Result.Elements[2][2] = 2.0f / (Near - Far);\n    Result.Elements[3][3] = 1.0f;\n\n    Result.Elements[3][0] = (Left + Right) / (Left - Right);\n    Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);\n    Result.Elements[3][2] = (Far + Near) / (Near - Far);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Perspective, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Perspective)(float FOV, float AspectRatio, float Near, float Far)\n{\n    ASSERT_COVERED(HMM_Perspective);\n\n    hmm_mat4 Result = HMM_PREFIX(Mat4)();\n\n    // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml\n\n    float Cotangent = 1.0f / HMM_PREFIX(TanF)(FOV * (HMM_PI32 / 360.0f));\n\n    Result.Elements[0][0] = Cotangent / AspectRatio;\n    Result.Elements[1][1] = Cotangent;\n    Result.Elements[2][3] = -1.0f;\n    Result.Elements[2][2] = (Near + Far) / (Near - Far);\n    Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);\n    Result.Elements[3][3] = 0.0f;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Translate, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Translate)(hmm_vec3 Translation)\n{\n    ASSERT_COVERED(HMM_Translate);\n\n    hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f);\n\n    Result.Elements[3][0] = Translation.X;\n    Result.Elements[3][1] = Translation.Y;\n    Result.Elements[3][2] = Translation.Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Rotate, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Rotate)(float Angle, hmm_vec3 Axis)\n{\n    ASSERT_COVERED(HMM_Rotate);\n\n    hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f);\n\n    Axis = HMM_PREFIX(NormalizeVec3)(Axis);\n\n    float SinTheta = HMM_PREFIX(SinF)(HMM_PREFIX(ToRadians)(Angle));\n    float CosTheta = HMM_PREFIX(CosF)(HMM_PREFIX(ToRadians)(Angle));\n    float CosValue = 1.0f - CosTheta;\n\n    Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta;\n    Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta);\n    Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta);\n\n    Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta);\n    Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta;\n    Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta);\n\n    Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta);\n    Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta);\n    Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta;\n\n    return (Result);\n}\n\n\n\nCOVERAGE(HMM_Scale, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Scale)(hmm_vec3 Scale)\n{\n    ASSERT_COVERED(HMM_Scale);\n\n    hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f);\n\n    Result.Elements[0][0] = Scale.X;\n    Result.Elements[1][1] = Scale.Y;\n    Result.Elements[2][2] = Scale.Z;\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LookAt, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(LookAt)(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up)\n{\n    ASSERT_COVERED(HMM_LookAt);\n\n    hmm_mat4 Result;\n\n    hmm_vec3 F = HMM_PREFIX(NormalizeVec3)(HMM_PREFIX(SubtractVec3)(Center, Eye));\n    hmm_vec3 S = HMM_PREFIX(NormalizeVec3)(HMM_PREFIX(Cross)(F, Up));\n    hmm_vec3 U = HMM_PREFIX(Cross)(S, F);\n\n    Result.Elements[0][0] = S.X;\n    Result.Elements[0][1] = U.X;\n    Result.Elements[0][2] = -F.X;\n    Result.Elements[0][3] = 0.0f;\n\n    Result.Elements[1][0] = S.Y;\n    Result.Elements[1][1] = U.Y;\n    Result.Elements[1][2] = -F.Y;\n    Result.Elements[1][3] = 0.0f;\n\n    Result.Elements[2][0] = S.Z;\n    Result.Elements[2][1] = U.Z;\n    Result.Elements[2][2] = -F.Z;\n    Result.Elements[2][3] = 0.0f;\n\n    Result.Elements[3][0] = -HMM_PREFIX(DotVec3)(S, Eye);\n    Result.Elements[3][1] = -HMM_PREFIX(DotVec3)(U, Eye);\n    Result.Elements[3][2] = HMM_PREFIX(DotVec3)(F, Eye);\n    Result.Elements[3][3] = 1.0f;\n\n    return (Result);\n}\n\n/*\n * Quaternion operations\n */\n\nCOVERAGE(HMM_Quaternion, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Quaternion)(float X, float Y, float Z, float W)\n{\n    ASSERT_COVERED(HMM_Quaternion);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_setr_ps(X, Y, Z, W);\n#else\n    Result.X = X;\n    Result.Y = Y;\n    Result.Z = Z;\n    Result.W = W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_QuaternionV4, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(QuaternionV4)(hmm_vec4 Vector)\n{\n    ASSERT_COVERED(HMM_QuaternionV4);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = Vector.InternalElementsSSE;\n#else\n    Result.X = Vector.X;\n    Result.Y = Vector.Y;\n    Result.Z = Vector.Z;\n    Result.W = Vector.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddQuaternion, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(AddQuaternion)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_AddQuaternion);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_add_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n#else\n\n    Result.X = Left.X + Right.X;\n    Result.Y = Left.Y + Right.Y;\n    Result.Z = Left.Z + Right.Z;\n    Result.W = Left.W + Right.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractQuaternion, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(SubtractQuaternion)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_SubtractQuaternion);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_sub_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n#else\n\n    Result.X = Left.X - Right.X;\n    Result.Y = Left.Y - Right.Y;\n    Result.Z = Left.Z - Right.Z;\n    Result.W = Left.W - Right.W;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternion, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(MultiplyQuaternion)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternion);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(0, 0, 0, 0)), _mm_setr_ps(0.f, -0.f, 0.f, -0.f));\n    __m128 SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(0, 1, 2, 3));\n    __m128 SSEResultThree = _mm_mul_ps(SSEResultTwo, SSEResultOne);\n\n    SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(1, 1, 1, 1)) , _mm_setr_ps(0.f, 0.f, -0.f, -0.f));\n    SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(1, 0, 3, 2));\n    SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));\n\n    SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(2, 2, 2, 2)), _mm_setr_ps(-0.f, 0.f, 0.f, -0.f));\n    SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(2, 3, 0, 1));\n    SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));\n\n    SSEResultOne = _mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(3, 3, 3, 3));\n    SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(3, 2, 1, 0));\n    Result.InternalElementsSSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));\n#else\n    Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X);\n    Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y);\n    Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z);\n    Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W);\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionF, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(MultiplyQuaternionF)(hmm_quaternion Left, float Multiplicative)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionF);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 Scalar = _mm_set1_ps(Multiplicative);\n    Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Scalar);\n#else\n    Result.X = Left.X * Multiplicative;\n    Result.Y = Left.Y * Multiplicative;\n    Result.Z = Left.Z * Multiplicative;\n    Result.W = Left.W * Multiplicative;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideQuaternionF, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(DivideQuaternionF)(hmm_quaternion Left, float Dividend)\n{\n    ASSERT_COVERED(HMM_DivideQuaternionF);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 Scalar = _mm_set1_ps(Dividend);\n    Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Scalar);\n#else\n    Result.X = Left.X / Dividend;\n    Result.Y = Left.Y / Dividend;\n    Result.Z = Left.Z / Dividend;\n    Result.W = Left.W / Dividend;\n#endif\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotQuaternion, 1)\nHMM_INLINE float HMM_PREFIX(DotQuaternion)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_DotQuaternion);\n\n    float Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 SSEResultOne = _mm_mul_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);\n    __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1));\n    SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);\n    SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));\n    SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);\n    _mm_store_ss(&Result, SSEResultOne);\n#else\n    Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W);\n#endif\n\n    return (Result);\n}\n\n\nCOVERAGE(HMM_InverseQuaternion, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(InverseQuaternion)(hmm_quaternion Left)\n{\n    ASSERT_COVERED(HMM_InverseQuaternion);\n    \n    hmm_quaternion Result;\n\n    Result.X = -Left.X;\n    Result.Y = -Left.Y;\n    Result.Z = -Left.Z;\n    Result.W = Left.W;\n\n    Result = HMM_PREFIX(DivideQuaternionF)(Result, (HMM_PREFIX(DotQuaternion)(Left, Left)));\n\n    return (Result);\n}\n\n\nCOVERAGE(HMM_NormalizeQuaternion, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(NormalizeQuaternion)(hmm_quaternion Left)\n{\n    ASSERT_COVERED(HMM_NormalizeQuaternion);\n\n    hmm_quaternion Result;\n\n    float Length = HMM_PREFIX(SquareRootF)(HMM_PREFIX(DotQuaternion)(Left, Left));\n    Result = HMM_PREFIX(DivideQuaternionF)(Left, Length);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NLerp, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(NLerp)(hmm_quaternion Left, float Time, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_NLerp);\n\n    hmm_quaternion Result;\n\n#ifdef HANDMADE_MATH__USE_SSE\n    __m128 ScalarLeft = _mm_set1_ps(1.0f - Time);\n    __m128 ScalarRight = _mm_set1_ps(Time);\n    __m128 SSEResultOne = _mm_mul_ps(Left.InternalElementsSSE, ScalarLeft);\n    __m128 SSEResultTwo = _mm_mul_ps(Right.InternalElementsSSE, ScalarRight);\n    Result.InternalElementsSSE = _mm_add_ps(SSEResultOne, SSEResultTwo);\n#else\n    Result.X = HMM_PREFIX(Lerp)(Left.X, Time, Right.X);\n    Result.Y = HMM_PREFIX(Lerp)(Left.Y, Time, Right.Y);\n    Result.Z = HMM_PREFIX(Lerp)(Left.Z, Time, Right.Z);\n    Result.W = HMM_PREFIX(Lerp)(Left.W, Time, Right.W);\n#endif\n    Result = HMM_PREFIX(NormalizeQuaternion)(Result);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_Slerp, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Slerp)(hmm_quaternion Left, float Time, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_Slerp);\n\n    hmm_quaternion Result;\n    hmm_quaternion QuaternionLeft;\n    hmm_quaternion QuaternionRight;\n\n    float Cos_Theta = HMM_PREFIX(DotQuaternion)(Left, Right);\n    float Angle = HMM_PREFIX(ACosF)(Cos_Theta);\n\n    float S1 = HMM_PREFIX(SinF)((1.0f - Time) * Angle);\n    float S2 = HMM_PREFIX(SinF)(Time * Angle);\n    float Is = 1.0f / HMM_PREFIX(SinF)(Angle);\n\n    QuaternionLeft = HMM_PREFIX(MultiplyQuaternionF)(Left, S1);\n    QuaternionRight = HMM_PREFIX(MultiplyQuaternionF)(Right, S2);\n\n    Result = HMM_PREFIX(AddQuaternion)(QuaternionLeft, QuaternionRight);\n    Result = HMM_PREFIX(MultiplyQuaternionF)(Result, Is);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_QuaternionToMat4, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(QuaternionToMat4)(hmm_quaternion Left)\n{\n    ASSERT_COVERED(HMM_QuaternionToMat4);\n\n    hmm_mat4 Result;\n\n    hmm_quaternion NormalizedQuaternion = HMM_PREFIX(NormalizeQuaternion)(Left);\n\n    float XX, YY, ZZ,\n          XY, XZ, YZ,\n          WX, WY, WZ;\n\n    XX = NormalizedQuaternion.X * NormalizedQuaternion.X;\n    YY = NormalizedQuaternion.Y * NormalizedQuaternion.Y;\n    ZZ = NormalizedQuaternion.Z * NormalizedQuaternion.Z;\n    XY = NormalizedQuaternion.X * NormalizedQuaternion.Y;\n    XZ = NormalizedQuaternion.X * NormalizedQuaternion.Z;\n    YZ = NormalizedQuaternion.Y * NormalizedQuaternion.Z;\n    WX = NormalizedQuaternion.W * NormalizedQuaternion.X;\n    WY = NormalizedQuaternion.W * NormalizedQuaternion.Y;\n    WZ = NormalizedQuaternion.W * NormalizedQuaternion.Z;\n\n    Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ);\n    Result.Elements[0][1] = 2.0f * (XY + WZ);\n    Result.Elements[0][2] = 2.0f * (XZ - WY);\n    Result.Elements[0][3] = 0.0f;\n\n    Result.Elements[1][0] = 2.0f * (XY - WZ);\n    Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ);\n    Result.Elements[1][2] = 2.0f * (YZ + WX);\n    Result.Elements[1][3] = 0.0f;\n\n    Result.Elements[2][0] = 2.0f * (XZ + WY);\n    Result.Elements[2][1] = 2.0f * (YZ - WX);\n    Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY);\n    Result.Elements[2][3] = 0.0f;\n\n    Result.Elements[3][0] = 0.0f;\n    Result.Elements[3][1] = 0.0f;\n    Result.Elements[3][2] = 0.0f;\n    Result.Elements[3][3] = 1.0f;\n\n    return (Result);\n}\n\n// This method taken from Mike Day at Insomniac Games.\n// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf\n//\n// Note that as mentioned at the top of the paper, the paper assumes the matrix\n// would be *post*-multiplied to a vector to rotate it, meaning the matrix is\n// the transpose of what we're dealing with. But, because our matrices are\n// stored in column-major order, the indices *appear* to match the paper.\n//\n// For example, m12 in the paper is row 1, column 2. We need to transpose it to\n// row 2, column 1. But, because the column comes first when referencing\n// elements, it looks like M.Elements[1][2].\n//\n// Don't be confused! Or if you must be confused, at least trust this\n// comment. :)\nCOVERAGE(HMM_Mat4ToQuaternion, 4)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Mat4ToQuaternion)(hmm_mat4 M)\n{\n    float T;\n    hmm_quaternion Q;\n\n    if (M.Elements[2][2] < 0.0f) {\n        if (M.Elements[0][0] > M.Elements[1][1]) {\n            ASSERT_COVERED(HMM_Mat4ToQuaternion);\n\n            T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2];\n            Q = HMM_PREFIX(Quaternion)(\n                T,\n                M.Elements[0][1] + M.Elements[1][0],\n                M.Elements[2][0] + M.Elements[0][2],\n                M.Elements[1][2] - M.Elements[2][1]\n            );\n        } else {\n            ASSERT_COVERED(HMM_Mat4ToQuaternion);\n\n            T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2];\n            Q = HMM_PREFIX(Quaternion)(\n                M.Elements[0][1] + M.Elements[1][0],\n                T,\n                M.Elements[1][2] + M.Elements[2][1],\n                M.Elements[2][0] - M.Elements[0][2]\n            );\n        }\n    } else {\n        if (M.Elements[0][0] < -M.Elements[1][1]) {\n            ASSERT_COVERED(HMM_Mat4ToQuaternion);\n\n            T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2];\n            Q = HMM_PREFIX(Quaternion)(\n                M.Elements[2][0] + M.Elements[0][2],\n                M.Elements[1][2] + M.Elements[2][1],\n                T,\n                M.Elements[0][1] - M.Elements[1][0]\n            );\n        } else {\n            ASSERT_COVERED(HMM_Mat4ToQuaternion);\n\n            T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2];\n            Q = HMM_PREFIX(Quaternion)(\n                M.Elements[1][2] - M.Elements[2][1],\n                M.Elements[2][0] - M.Elements[0][2],\n                M.Elements[0][1] - M.Elements[1][0],\n                T\n            );\n        }\n    }\n\n    Q = HMM_PREFIX(MultiplyQuaternionF)(Q, 0.5f / HMM_PREFIX(SquareRootF)(T));\n\n    return Q;\n}\n\nCOVERAGE(HMM_QuaternionFromAxisAngle, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(QuaternionFromAxisAngle)(hmm_vec3 Axis, float AngleOfRotation)\n{\n    ASSERT_COVERED(HMM_QuaternionFromAxisAngle);\n\n    hmm_quaternion Result;\n\n    hmm_vec3 AxisNormalized = HMM_PREFIX(NormalizeVec3)(Axis);\n    float SineOfRotation = HMM_PREFIX(SinF)(AngleOfRotation / 2.0f);\n\n    Result.XYZ = HMM_PREFIX(MultiplyVec3f)(AxisNormalized, SineOfRotation);\n    Result.W = HMM_PREFIX(CosF)(AngleOfRotation / 2.0f);\n\n    return (Result);\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#ifdef __cplusplus\n\nCOVERAGE(HMM_LengthVec2CPP, 1)\nHMM_INLINE float HMM_PREFIX(Length)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_LengthVec2CPP);\n\n    float Result = HMM_PREFIX(LengthVec2)(A);\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthVec3CPP, 1)\nHMM_INLINE float HMM_PREFIX(Length)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_LengthVec3CPP);\n\n    float Result = HMM_PREFIX(LengthVec3)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthVec4CPP, 1)\nHMM_INLINE float HMM_PREFIX(Length)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_LengthVec4CPP);\n\n    float Result = HMM_PREFIX(LengthVec4)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthSquaredVec2CPP, 1)\nHMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_LengthSquaredVec2CPP);\n\n    float Result = HMM_PREFIX(LengthSquaredVec2)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthSquaredVec3CPP, 1)\nHMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_LengthSquaredVec3CPP);\n\n    float Result = HMM_PREFIX(LengthSquaredVec3)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_LengthSquaredVec4CPP, 1)\nHMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_LengthSquaredVec4CPP);\n\n    float Result = HMM_PREFIX(LengthSquaredVec4)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NormalizeVec2CPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Normalize)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_NormalizeVec2CPP);\n\n    hmm_vec2 Result = HMM_PREFIX(NormalizeVec2)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NormalizeVec3CPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Normalize)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_NormalizeVec3CPP);\n\n    hmm_vec3 Result = HMM_PREFIX(NormalizeVec3)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NormalizeVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Normalize)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_NormalizeVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(NormalizeVec4)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_FastNormalizeVec2CPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(FastNormalize)(hmm_vec2 A)\n{\n    ASSERT_COVERED(HMM_FastNormalizeVec2CPP);\n\n    hmm_vec2 Result = HMM_PREFIX(FastNormalizeVec2)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_FastNormalizeVec3CPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(FastNormalize)(hmm_vec3 A)\n{\n    ASSERT_COVERED(HMM_FastNormalizeVec3CPP);\n\n    hmm_vec3 Result = HMM_PREFIX(FastNormalizeVec3)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_FastNormalizeVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(FastNormalize)(hmm_vec4 A)\n{\n    ASSERT_COVERED(HMM_FastNormalizeVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(FastNormalizeVec4)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_NormalizeQuaternionCPP, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Normalize)(hmm_quaternion A)\n{\n    ASSERT_COVERED(HMM_NormalizeQuaternionCPP);\n\n    hmm_quaternion Result = HMM_PREFIX(NormalizeQuaternion)(A);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotVec2CPP, 1)\nHMM_INLINE float HMM_PREFIX(Dot)(hmm_vec2 VecOne, hmm_vec2 VecTwo)\n{\n    ASSERT_COVERED(HMM_DotVec2CPP);\n\n    float Result = HMM_PREFIX(DotVec2)(VecOne, VecTwo);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotVec3CPP, 1)\nHMM_INLINE float HMM_PREFIX(Dot)(hmm_vec3 VecOne, hmm_vec3 VecTwo)\n{\n    ASSERT_COVERED(HMM_DotVec3CPP);\n\n    float Result = HMM_PREFIX(DotVec3)(VecOne, VecTwo);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotVec4CPP, 1)\nHMM_INLINE float HMM_PREFIX(Dot)(hmm_vec4 VecOne, hmm_vec4 VecTwo)\n{\n    ASSERT_COVERED(HMM_DotVec4CPP);\n\n    float Result = HMM_PREFIX(DotVec4)(VecOne, VecTwo);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DotQuaternionCPP, 1)\nHMM_INLINE float HMM_PREFIX(Dot)(hmm_quaternion QuatOne, hmm_quaternion QuatTwo)\n{\n    ASSERT_COVERED(HMM_DotQuaternionCPP);\n\n    float Result = HMM_PREFIX(DotQuaternion)(QuatOne, QuatTwo);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec2CPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Add)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_AddVec2CPP);\n\n    hmm_vec2 Result = HMM_PREFIX(AddVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec3CPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Add)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_AddVec3CPP);\n\n    hmm_vec3 Result = HMM_PREFIX(AddVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Add)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_AddVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(AddVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddMat4CPP, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Add)(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_AddMat4CPP);\n\n    hmm_mat4 Result = HMM_PREFIX(AddMat4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddQuaternionCPP, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Add)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_AddQuaternionCPP);\n\n    hmm_quaternion Result = HMM_PREFIX(AddQuaternion)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec2CPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Subtract)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec2CPP);\n\n    hmm_vec2 Result = HMM_PREFIX(SubtractVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec3CPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Subtract)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec3CPP);\n\n    hmm_vec3 Result = HMM_PREFIX(SubtractVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Subtract)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(SubtractVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractMat4CPP, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Subtract)(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractMat4CPP);\n\n    hmm_mat4 Result = HMM_PREFIX(SubtractMat4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractQuaternionCPP, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Subtract)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_SubtractQuaternionCPP);\n\n    hmm_quaternion Result = HMM_PREFIX(SubtractQuaternion)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2CPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Multiply)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2CPP);\n\n    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2fCPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Multiply)(hmm_vec2 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2fCPP);\n\n    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3CPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Multiply)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3CPP);\n\n    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3fCPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Multiply)(hmm_vec3 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3fCPP);\n\n    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4fCPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_vec4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4fCPP);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4CPP, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Multiply)(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4CPP);\n\n    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4fCPP, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Multiply)(hmm_mat4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4fCPP);\n\n    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4ByVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_mat4 Matrix, hmm_vec4 Vector)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4ByVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyMat4ByVec4)(Matrix, Vector);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionCPP, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Multiply)(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionCPP);\n\n    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternion)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionFCPP, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Multiply)(hmm_quaternion Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionFCPP);\n\n    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec2CPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Divide)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2CPP);\n\n    hmm_vec2 Result = HMM_PREFIX(DivideVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec2fCPP, 1)\nHMM_INLINE hmm_vec2 HMM_PREFIX(Divide)(hmm_vec2 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2fCPP);\n\n    hmm_vec2 Result = HMM_PREFIX(DivideVec2f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec3CPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Divide)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3CPP);\n\n    hmm_vec3 Result = HMM_PREFIX(DivideVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec3fCPP, 1)\nHMM_INLINE hmm_vec3 HMM_PREFIX(Divide)(hmm_vec3 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3fCPP);\n\n    hmm_vec3 Result = HMM_PREFIX(DivideVec3f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec4CPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Divide)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4CPP);\n\n    hmm_vec4 Result = HMM_PREFIX(DivideVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec4fCPP, 1)\nHMM_INLINE hmm_vec4 HMM_PREFIX(Divide)(hmm_vec4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4fCPP);\n\n    hmm_vec4 Result = HMM_PREFIX(DivideVec4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideMat4fCPP, 1)\nHMM_INLINE hmm_mat4 HMM_PREFIX(Divide)(hmm_mat4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideMat4fCPP);\n\n    hmm_mat4 Result = HMM_PREFIX(DivideMat4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideQuaternionFCPP, 1)\nHMM_INLINE hmm_quaternion HMM_PREFIX(Divide)(hmm_quaternion Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideQuaternionFCPP);\n\n    hmm_quaternion Result = HMM_PREFIX(DivideQuaternionF)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_EqualsVec2CPP, 1)\nHMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec2CPP);\n\n    hmm_bool Result = HMM_PREFIX(EqualsVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_EqualsVec3CPP, 1)\nHMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec3CPP);\n\n    hmm_bool Result = HMM_PREFIX(EqualsVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_EqualsVec4CPP, 1)\nHMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec4CPP);\n\n    hmm_bool Result = HMM_PREFIX(EqualsVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec2Op, 1)\nHMM_INLINE hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_AddVec2Op);\n\n    hmm_vec2 Result = HMM_PREFIX(AddVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec3Op, 1)\nHMM_INLINE hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_AddVec3Op);\n\n    hmm_vec3 Result = HMM_PREFIX(AddVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec4Op, 1)\nHMM_INLINE hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_AddVec4Op);\n\n    hmm_vec4 Result = HMM_PREFIX(AddVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddMat4Op, 1)\nHMM_INLINE hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_AddMat4Op);\n\n    hmm_mat4 Result = HMM_PREFIX(AddMat4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddQuaternionOp, 1)\nHMM_INLINE hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_AddQuaternionOp);\n\n    hmm_quaternion Result = HMM_PREFIX(AddQuaternion)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec2Op, 1)\nHMM_INLINE hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec2Op);\n\n    hmm_vec2 Result = HMM_PREFIX(SubtractVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec3Op, 1)\nHMM_INLINE hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec3Op);\n\n    hmm_vec3 Result = HMM_PREFIX(SubtractVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractVec4Op, 1)\nHMM_INLINE hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec4Op);\n\n    hmm_vec4 Result = HMM_PREFIX(SubtractVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractMat4Op, 1)\nHMM_INLINE hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractMat4Op);\n\n    hmm_mat4 Result = HMM_PREFIX(SubtractMat4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_SubtractQuaternionOp, 1)\nHMM_INLINE hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_SubtractQuaternionOp);\n\n    hmm_quaternion Result = HMM_PREFIX(SubtractQuaternion)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2Op, 1)\nHMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2Op);\n\n    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3Op, 1)\nHMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3Op);\n\n    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4Op, 1)\nHMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4Op);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4Op, 1)\nHMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4Op);\n\n    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionOp, 1)\nHMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionOp);\n\n    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternion)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2fOp, 1)\nHMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2fOp);\n\n    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3fOp, 1)\nHMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3fOp);\n\n    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4fOp, 1)\nHMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4fOp);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4fOp, 1)\nHMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4fOp);\n\n    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionFOp, 1)\nHMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionFOp);\n\n    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec2fOpLeft, 1)\nHMM_INLINE hmm_vec2 operator*(float Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2fOpLeft);\n\n    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Right, Left);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec3fOpLeft, 1)\nHMM_INLINE hmm_vec3 operator*(float Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3fOpLeft);\n\n    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Right, Left);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyVec4fOpLeft, 1)\nHMM_INLINE hmm_vec4 operator*(float Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4fOpLeft);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Right, Left);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4fOpLeft, 1)\nHMM_INLINE hmm_mat4 operator*(float Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4fOpLeft);\n\n    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Right, Left);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionFOpLeft, 1)\nHMM_INLINE hmm_quaternion operator*(float Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionFOpLeft);\n\n    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Right, Left);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_MultiplyMat4ByVec4Op, 1)\nHMM_INLINE hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4ByVec4Op);\n\n    hmm_vec4 Result = HMM_PREFIX(MultiplyMat4ByVec4)(Matrix, Vector);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec2Op, 1)\nHMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2Op);\n\n    hmm_vec2 Result = HMM_PREFIX(DivideVec2)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec3Op, 1)\nHMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3Op);\n\n    hmm_vec3 Result = HMM_PREFIX(DivideVec3)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec4Op, 1)\nHMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4Op);\n\n    hmm_vec4 Result = HMM_PREFIX(DivideVec4)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec2fOp, 1)\nHMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2fOp);\n\n    hmm_vec2 Result = HMM_PREFIX(DivideVec2f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec3fOp, 1)\nHMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3fOp);\n\n    hmm_vec3 Result = HMM_PREFIX(DivideVec3f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideVec4fOp, 1)\nHMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4fOp);\n\n    hmm_vec4 Result = HMM_PREFIX(DivideVec4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideMat4fOp, 1)\nHMM_INLINE hmm_mat4 operator/(hmm_mat4 Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideMat4fOp);\n\n    hmm_mat4 Result = HMM_PREFIX(DivideMat4f)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_DivideQuaternionFOp, 1)\nHMM_INLINE hmm_quaternion operator/(hmm_quaternion Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideQuaternionFOp);\n\n    hmm_quaternion Result = HMM_PREFIX(DivideQuaternionF)(Left, Right);\n\n    return (Result);\n}\n\nCOVERAGE(HMM_AddVec2Assign, 1)\nHMM_INLINE hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_AddVec2Assign);\n\n    return (Left = Left + Right);\n}\n\nCOVERAGE(HMM_AddVec3Assign, 1)\nHMM_INLINE hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_AddVec3Assign);\n\n    return (Left = Left + Right);\n}\n\nCOVERAGE(HMM_AddVec4Assign, 1)\nHMM_INLINE hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_AddVec4Assign);\n\n    return (Left = Left + Right);\n}\n\nCOVERAGE(HMM_AddMat4Assign, 1)\nHMM_INLINE hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_AddMat4Assign);\n\n    return (Left = Left + Right);\n}\n\nCOVERAGE(HMM_AddQuaternionAssign, 1)\nHMM_INLINE hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_AddQuaternionAssign);\n\n    return (Left = Left + Right);\n}\n\nCOVERAGE(HMM_SubtractVec2Assign, 1)\nHMM_INLINE hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec2Assign);\n\n    return (Left = Left - Right);\n}\n\nCOVERAGE(HMM_SubtractVec3Assign, 1)\nHMM_INLINE hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec3Assign);\n\n    return (Left = Left - Right);\n}\n\nCOVERAGE(HMM_SubtractVec4Assign, 1)\nHMM_INLINE hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractVec4Assign);\n\n    return (Left = Left - Right);\n}\n\nCOVERAGE(HMM_SubtractMat4Assign, 1)\nHMM_INLINE hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right)\n{\n    ASSERT_COVERED(HMM_SubtractMat4Assign);\n\n    return (Left = Left - Right);\n}\n\nCOVERAGE(HMM_SubtractQuaternionAssign, 1)\nHMM_INLINE hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right)\n{\n    ASSERT_COVERED(HMM_SubtractQuaternionAssign);\n\n    return (Left = Left - Right);\n}\n\nCOVERAGE(HMM_MultiplyVec2Assign, 1)\nHMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2Assign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyVec3Assign, 1)\nHMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3Assign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyVec4Assign, 1)\nHMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4Assign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyVec2fAssign, 1)\nHMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec2fAssign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyVec3fAssign, 1)\nHMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec3fAssign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyVec4fAssign, 1)\nHMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyVec4fAssign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyMat4fAssign, 1)\nHMM_INLINE hmm_mat4 &operator*=(hmm_mat4 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyMat4fAssign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_MultiplyQuaternionFAssign, 1)\nHMM_INLINE hmm_quaternion &operator*=(hmm_quaternion &Left, float Right)\n{\n    ASSERT_COVERED(HMM_MultiplyQuaternionFAssign);\n\n    return (Left = Left * Right);\n}\n\nCOVERAGE(HMM_DivideVec2Assign, 1)\nHMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2Assign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideVec3Assign, 1)\nHMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3Assign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideVec4Assign, 1)\nHMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4Assign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideVec2fAssign, 1)\nHMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec2fAssign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideVec3fAssign, 1)\nHMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec3fAssign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideVec4fAssign, 1)\nHMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideVec4fAssign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideMat4fAssign, 1)\nHMM_INLINE hmm_mat4 &operator/=(hmm_mat4 &Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideMat4fAssign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_DivideQuaternionFAssign, 1)\nHMM_INLINE hmm_quaternion &operator/=(hmm_quaternion &Left, float Right)\n{\n    ASSERT_COVERED(HMM_DivideQuaternionFAssign);\n\n    return (Left = Left / Right);\n}\n\nCOVERAGE(HMM_EqualsVec2Op, 1)\nHMM_INLINE hmm_bool operator==(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec2Op);\n\n    return HMM_PREFIX(EqualsVec2)(Left, Right);\n}\n\nCOVERAGE(HMM_EqualsVec3Op, 1)\nHMM_INLINE hmm_bool operator==(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec3Op);\n\n    return HMM_PREFIX(EqualsVec3)(Left, Right);\n}\n\nCOVERAGE(HMM_EqualsVec4Op, 1)\nHMM_INLINE hmm_bool operator==(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec4Op);\n\n    return HMM_PREFIX(EqualsVec4)(Left, Right);\n}\n\nCOVERAGE(HMM_EqualsVec2OpNot, 1)\nHMM_INLINE hmm_bool operator!=(hmm_vec2 Left, hmm_vec2 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec2OpNot);\n\n    return !HMM_PREFIX(EqualsVec2)(Left, Right);\n}\n\nCOVERAGE(HMM_EqualsVec3OpNot, 1)\nHMM_INLINE hmm_bool operator!=(hmm_vec3 Left, hmm_vec3 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec3OpNot);\n\n    return !HMM_PREFIX(EqualsVec3)(Left, Right);\n}\n\nCOVERAGE(HMM_EqualsVec4OpNot, 1)\nHMM_INLINE hmm_bool operator!=(hmm_vec4 Left, hmm_vec4 Right)\n{\n    ASSERT_COVERED(HMM_EqualsVec4OpNot);\n\n    return !HMM_PREFIX(EqualsVec4)(Left, Right);\n}\n\nCOVERAGE(HMM_UnaryMinusVec2, 1)\nHMM_INLINE hmm_vec2 operator-(hmm_vec2 In)\n{\n    ASSERT_COVERED(HMM_UnaryMinusVec2);\n\n    hmm_vec2 Result;\n    Result.X = -In.X;\n    Result.Y = -In.Y;\n    return(Result);\n}\n\nCOVERAGE(HMM_UnaryMinusVec3, 1)\nHMM_INLINE hmm_vec3 operator-(hmm_vec3 In)\n{\n    ASSERT_COVERED(HMM_UnaryMinusVec3);\n\n    hmm_vec3 Result;\n    Result.X = -In.X;\n    Result.Y = -In.Y;\n    Result.Z = -In.Z;\n    return(Result);\n}\n\nCOVERAGE(HMM_UnaryMinusVec4, 1)\nHMM_INLINE hmm_vec4 operator-(hmm_vec4 In)\n{\n    ASSERT_COVERED(HMM_UnaryMinusVec4);\n\n    hmm_vec4 Result;\n#if HANDMADE_MATH__USE_SSE\n    Result.InternalElementsSSE = _mm_xor_ps(In.InternalElementsSSE, _mm_set1_ps(-0.0f));\n#else\n    Result.X = -In.X;\n    Result.Y = -In.Y;\n    Result.Z = -In.Z;\n    Result.W = -In.W;\n#endif\n    return(Result);\n}\n\n#endif /* __cplusplus */\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n#endif /* HANDMADE_MATH_H */\n\n\n\n"
  },
  {
    "path": "src/render/d2font.cpp",
    "content": "#include \"d2font.h\"\n\n#include \"cfg.h\"\n#include \"d2r/storage.h\"\n\n#include <iostream>\n#include <cstring>\n\nnamespace render {\n\nbool D2Font::add(const std::string &filename, int param) {\n    originFontSize_ = param;\n    if (filename.empty()) {\n        std::vector<uint8_t> dc6, tbl, pal;\n        char path[256], dc6file[256], tblfile[256];\n        const char *lngDir = \"latin2\";\n        if (cfg->language == \"enUS\") {\n            lngDir = \"latin\";\n        } else if (cfg->language == \"jaJP\" || cfg->language == \"zhTW\" || cfg->language == \"zhCN\") {\n            lngDir = \"chi\";\n        } else if (cfg->language == \"koKR\") {\n            lngDir = \"kor\";\n        }\n        snprintf(path, 256, \"data:data/local/font/%s/font%2d\", lngDir, param);\n        snprintf(dc6file, 256, \"%s.dc6\", path);\n        snprintf(tblfile, 256, \"%s.tbl\", path);\n        d2r::storage.readFile(dc6file, dc6);\n        d2r::storage.readFile(tblfile, tbl);\n        d2r::storage.readFile(\"data:data/global/palette/fechar/pal.dat\", pal);\n        return loadMem(dc6.data(), dc6.size(), tbl.data(), tbl.size(), pal.data(), pal.size());\n    }\n    return load(filename + \".dc6\", filename + \".tbl\", filename + \".pal\");\n}\n\nbool D2Font::makeCache(Font::FontData *fd, uint32_t ch, int fontSize) {\n    if (ch > 65535) {\n        return false;\n    }\n    auto &tbl = tblCharacters_[ch];\n    DC6FrameHeader hdr;\n    std::vector<uint32_t> data;\n    read(tbl.dc6Index, hdr, data);\n    fd->w = hdr.width;\n    fd->h = hdr.height;\n    fd->ix0 = 0;\n    fd->iy0 = tblHeader_.capHeight;\n    fd->advW = tbl.width;\n    fd->origW = uint8_t(uint32_t(originFontSize_));\n\n    if (!updateTexture(fd->rpidx, fd->rpx, fd->rpy, fd->w, fd->h, (const uint8_t*)data.data())) {\n        memset(fd, 0, sizeof(FontData));\n        return false;\n    }\n    return true;\n}\n\nbool D2Font::load(const std::string &dc6file, const std::string &tblfile, const std::string &palfile) {\n    std::vector<uint8_t> dc6, tbl;\n    uint8_t pal[768];\n\n    if (std::ifstream ifs(dc6file, std::ios::in | std::ios::binary); ifs.is_open()) {\n        ifs.seekg(0, std::ios::end);\n        auto size = ifs.tellg();\n        ifs.seekg(0, std::ios::beg);\n        dc6.resize(size);\n        ifs.read((char *)dc6.data(), size);\n        ifs.close();\n    } else {\n        return false;\n    }\n    if (std::ifstream ifs(tblfile, std::ios::in | std::ios::binary); ifs.is_open()) {\n        ifs.seekg(0, std::ios::end);\n        auto size = ifs.tellg();\n        ifs.seekg(0, std::ios::beg);\n        tbl.resize(size);\n        ifs.read((char *)tbl.data(), size);\n        ifs.close();\n    } else {\n        return false;\n    }\n    if (std::ifstream ifs(palfile, std::ios::in | std::ios::binary); ifs.is_open()) {\n        ifs.seekg(0, std::ios::end);\n        auto size = ifs.tellg();\n        if (size < 768) {\n            ifs.close();\n            return false;\n        }\n        ifs.seekg(0, std::ios::beg);\n        ifs.read((char *)pal, 768);\n        ifs.close();\n    } else {\n        return false;\n    }\n\n    return loadMem(dc6.data(), dc6.size(), tbl.data(), tbl.size(), pal, 768);\n}\n\nbool D2Font::loadMem(const void *dc6, size_t dc6Size, const void *tbl, size_t tblSize, const void *pal, size_t palSize) {\n    if (palSize < 768) {\n        return false;\n    }\n    if (tblSize < sizeof(TblHeader)) {\n        return false;\n    }\n    if (dc6Size < sizeof(DC6Header)) {\n        return false;\n    }\n\n    const auto *palData = (const uint8_t *)pal;\n    for (int i = 0; i < 256; i++) {\n        auto idx = i * 3;\n        palette_[i] = 0xFF000000u | (uint32_t(palData[idx]) << 16) | (uint32_t(palData[idx + 1]) << 8) | uint32_t(palData[idx + 2]);\n    }\n\n    memcpy(&tblHeader_, tbl, sizeof(TblHeader));\n    const auto *tblData = (const uint8_t*)tbl + sizeof(TblHeader);\n    tblSize -= sizeof(TblHeader);\n    auto tblCharSize = sizeof(TblCharacter) * tblHeader_.numChars;\n    if (tblCharSize > tblSize) {\n        return false;\n    }\n    const auto *chars = (const TblCharacter*)tblData;\n    for (uint16_t i = 0; i < tblHeader_.numChars; ++i) {\n        tblCharacters_[chars[i].code] = chars[i];\n    }\n\n    dc6Data_.assign((const uint8_t*)dc6, (const uint8_t*)dc6 + dc6Size);\n    dc6Header_ = (const DC6Header*)dc6Data_.data();\n    auto count = dc6Header_->numDir * dc6Header_->numFrame;\n    const auto *dc6Data = (const uint8_t*)dc6Data_.data() + sizeof(DC6Header);\n    dc6Size -= sizeof(DC6Header);\n    auto dc6OffsetTableSize = sizeof(uint32_t) * count;\n    if (dc6Size < dc6OffsetTableSize) {\n        return false;\n    }\n    dc6OffsetTable_ = (const uint32_t*)dc6Data;\n    return true;\n}\n\nbool D2Font::read(uint32_t index, DC6FrameHeader &hdr, std::vector<uint32_t> &data) {\n    const auto *ptr = dc6Data_.data() + dc6OffsetTable_[index];\n    memcpy(&hdr, ptr, sizeof(DC6FrameHeader));\n    ptr += sizeof(DC6FrameHeader);\n    size_t y = hdr.height - 1;\n    size_t x = 0;\n    data.resize(hdr.height * hdr.width);\n    auto *end = ptr + hdr.length;\n    while (ptr < end) {\n        auto b = *ptr++;\n        if (b & 0x80) {\n            if (b == 0x80) {\n                x = 0;\n                if (--y < 0) {\n                    break;\n                }\n            } else {\n                x += b & 0x7f;\n            }\n        } else {\n            for (; b && ptr < end; b--) {\n                if (x >= hdr.width) {\n                    ptr += b;\n                    break;\n                }\n                auto c = *ptr++;\n                data[y * hdr.width + x] = palette_[c];\n                x++;\n            }\n        }\n    }\n    return true;\n}\n\n}\n"
  },
  {
    "path": "src/render/d2font.h",
    "content": "#pragma once\n\n#include \"font.h\"\n\n#include <vector>\n#include <array>\n#include <string>\n#include <fstream>\n#include <cstdint>\n\nnamespace render {\n\n#pragma pack(push, 1)\n\nstruct TblHeader {\n    uint32_t sign;      // +00 - 0x216f6f57 (Woo!)\n    int16_t unk0;       // +04 - 0x0001\n    int16_t unk1;       // +06 - mostly 0x0000\n    uint16_t numChars;  // +08\n    uint8_t lnSpacing; // +0A\n    uint8_t capHeight; // +0B\n};\n\nstruct TblCharacter {\n    uint16_t code;           // +00\n    int8_t unk0;            // +02 - mostly 0x00\n    uint8_t width;          // +03\n    uint8_t height;         // +04\n    int8_t unk1;            // +05 - mostly 1, seldomly 0\n    int16_t unk2;            // +06 - mostly 0x0000\n    uint16_t dc6Index;       // +08\n    int32_t unk3;            // +0A\n};\n\nstruct DC6Header {\n    uint32_t version;   // +00 - 0x00000006\n    uint32_t unk0;      // +04 - 0x00000001\n    uint32_t unk1;      // +08 - 0x00000000\n    uint32_t term;      // +0c - 0xeeeeeeee or 0xcdcdcdcd\n    uint32_t numDir;    // +10 - #Direction\n    uint32_t numFrame;  // +14 - #Frame per Direction\n};\n\nstruct DC6FrameHeader {\n    uint32_t flip;      // +00 - 1 if Flipped, 0 else\n    uint32_t width;     // +04\n    uint32_t height;    // +08\n    uint32_t offsetX;   // +0c\n    uint32_t offsetY;   // +10\n    uint32_t unk0;      // +14 - 0x00000000\n    uint32_t nextBlock; // +18\n    uint32_t length;    // +1c\n};\n\n#pragma pack(pop)\n\nclass D2Font: public Font {\npublic:\n    using Font::Font;\n    bool add(const std::string &filename, int param) override;\n\nprotected:\n    bool makeCache(FontData *fd, uint32_t ch, int fontSize) override;\n    uint64_t makeFontKey(uint32_t ch, int fontSize) override {\n        return ch;\n    }\n\nprivate:\n    bool load(const std::string &dc6file, const std::string &tblfile, const std::string &palfile);\n    bool loadMem(const void *dc6, size_t dc6Size, const void *tbl, size_t tblSize, const void *pal, size_t palSize);\n    bool read(uint32_t index, DC6FrameHeader &hdr, std::vector<uint32_t> &data);\n\nprivate:\n    std::array<uint32_t, 256> palette_ = {};\n\n    TblHeader tblHeader_ = {};\n    std::array<TblCharacter, 65536> tblCharacters_ = {};\n\n    std::vector<uint8_t> dc6Data_;\n    const DC6Header *dc6Header_ = {};\n    const uint32_t *dc6OffsetTable_;\n\n    int originFontSize_ = 0;\n};\n\n}\n"
  },
  {
    "path": "src/render/font.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"font.h\"\n\n#define STB_RECT_PACK_IMPLEMENTATION\n#define STBRP_STATIC\n#include <stb_rect_pack.h>\n#include <cstring>\n\nnamespace render {\n\nenum {\n    RectPackWidthDefault = 1024,\n};\n\nstruct RectPackData {\n    explicit RectPackData(int nodeCount) : nodes(new stbrp_node[nodeCount]) {\n    }\n    ~RectPackData() {\n        delete[] nodes;\n    }\n    stbrp_context context = {};\n    stbrp_node *nodes;\n};\n\nclass RectPacker final {\npublic:\n    explicit RectPacker(int width = RectPackWidthDefault, int height = RectPackWidthDefault);\n    ~RectPacker();\n    int pack(uint16_t w, uint16_t h, int16_t &x, int16_t &y);\n\nprivate:\n    void newRectPack();\n\nprivate:\n    int width_, height_;\n    std::vector<RectPackData*> rectpackData_;\n};\n\nRectPacker::RectPacker(int width, int height)\n    : width_(width), height_(height) {}\nRectPacker::~RectPacker() {\n    for (auto *rpd: rectpackData_) {\n        delete rpd;\n    }\n    rectpackData_.clear();\n}\nint RectPacker::pack(uint16_t w, uint16_t h, int16_t &x, int16_t &y) {\n    if (rectpackData_.empty()) {\n        newRectPack();\n    }\n    auto sz = int(rectpackData_.size());\n    stbrp_rect rc = {0, w, h};\n    int rpidx = -1;\n    for (int i = 0; i < sz; ++i) {\n        auto &rpd = rectpackData_[i];\n        if (stbrp_pack_rects(&rpd->context, &rc, 1)) {\n            rpidx = i;\n            break;\n        }\n    }\n    if (rpidx < 0) {\n        /* No space to hold the bitmap,\n         * create a new bitmap */\n        newRectPack();\n        auto &rpd = rectpackData_.back();\n        if (stbrp_pack_rects(&rpd->context, &rc, 1)) {\n            rpidx = int(rectpackData_.size()) - 1;\n        }\n    }\n    x = rc.x;\n    y = rc.y;\n    return rpidx;\n}\nvoid RectPacker::newRectPack() {\n    rectpackData_.resize(rectpackData_.size() + 1);\n    auto *&rpd = rectpackData_.back();\n    rpd = new RectPackData(width_);\n    stbrp_init_target(&rpd->context, width_, height_, rpd->nodes, width_);\n}\n\nFont::Font(FontRenderImpl &renderImpl)\n    : renderImpl_(renderImpl), rectpacker_(new RectPacker(RectPackWidthDefault, RectPackWidthDefault)) {\n    memset(altColor_, 0xFF, sizeof(altColor_));\n}\n\nFont::~Font() {\n    fontCache_.clear();\n    for (auto &tex: textures_) {\n        renderImpl_.destroyTexture(tex);\n    }\n    textures_.clear();\n    delete rectpacker_;\n}\n\nvoid Font::init(int size, uint8_t width) {\n    fontSize_ = size;\n    monoWidth_ = width;\n}\n\nvoid Font::charDimension(uint32_t ch, uint8_t &width, int8_t &t, int8_t &b, int fontSize) {\n    const auto *fd = getOrMakeCache(ch, fontSize);\n    if (!fd || fd->advW == 0) {\n        width = t = b = 0;\n        return;\n    }\n    if (fontSize == fd->origW) {\n        if (monoWidth_)\n            width = std::max(fd->advW, monoWidth_);\n        else\n            width = fd->advW;\n        t = fd->iy0;\n        b = fd->iy0 + fd->h;\n        return;\n    }\n    if (monoWidth_)\n        width = std::max(fd->advW, monoWidth_) * fontSize / fd->origW;\n    else\n        width = fd->advW * fontSize / fd->origW;\n    t = fd->iy0 * fontSize / fd->origW;\n    b = (fd->iy0 + fd->h) * fontSize / fd->origW;\n}\n\nuint8_t Font::charWidth(uint32_t ch, int fontSize) {\n    const auto *fd = getOrMakeCache(ch, fontSize);\n    if (!fd || fd->advW == 0) {\n        return 0;\n    }\n    if (fontSize == fd->origW) {\n        if (monoWidth_)\n            return std::max(fd->advW, monoWidth_);\n        return fd->advW;\n    }\n    if (monoWidth_)\n        return std::max(fd->advW, monoWidth_) * fontSize / fd->origW;\n    return fd->advW * fontSize / fd->origW;\n}\n\n#define RGBA(r, g, b, a) (uint32_t(r) | (uint32_t(g) << 8) | (uint32_t(b) << 16) | (uint32_t(a) << 24))\nvoid Font::setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {\n    altColor_[0] = RGBA(r, g, b, a);\n}\n\nvoid Font::setAltColor(int index, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {\n    if (index > 0 && index < 16) {\n        altColor_[index] = RGBA(r, g, b, a);\n    }\n}\n#undef RGBA\n\nconst Font::FontData *Font::getOrMakeCache(uint32_t ch, int fontSize) {\n    if (fontSize < 0) fontSize = fontSize_;\n    uint64_t key = makeFontKey(ch, fontSize);\n    auto ite = fontCache_.find(key);\n    if (ite != fontCache_.end()) {\n        return &ite->second;\n    }\n\n    FontData *fd = &fontCache_[key];\n    if (!makeCache(fd, ch, fontSize)) {\n        return nullptr;\n    }\n    return fd;\n}\n\nbool Font::updateTexture(int &rpidx, int16_t &rpx, int16_t &rpy, int w, int h, const uint8_t *data) {\n    rpidx = rectpacker_->pack(w, h, rpx, rpy);\n    if (rpidx < 0) {\n        return false;\n    }\n\n    if (size_t(rpidx) >= textures_.size()) {\n        textures_.resize(rpidx + 1, nullptr);\n    }\n    auto *tex = textures_[rpidx];\n    if (tex == nullptr) {\n        tex = renderImpl_.createTexture(RectPackWidthDefault, RectPackWidthDefault);\n        if (!tex) { return false; }\n        textures_[rpidx] = tex;\n    }\n    renderImpl_.updateTexture(tex, rpx, rpy, w, h, data);\n    return true;\n}\n\n}\n"
  },
  {
    "path": "src/render/font.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"fontrenderimpl.h\"\n#include <unordered_map>\n#include <vector>\n#include <string>\n#include <cstdint>\n\nnamespace render {\n\nclass RectPacker;\n\nclass Font {\nprotected:\n    struct FontData {\n        int16_t rpx, rpy;\n        int rpidx;\n\n        int8_t ix0, iy0;\n        uint8_t w, h;\n        uint8_t advW;\n        uint8_t origW;\n    };\n\npublic:\n    explicit Font(FontRenderImpl &renderImpl);\n    virtual ~Font();\n    virtual bool add(const std::string &filename, int param) = 0;\n\n    void init(int size, uint8_t width = 0);\n    void charDimension(uint32_t ch, uint8_t &width, int8_t &t, int8_t &b, int fontSize = -1);\n    uint8_t charWidth(uint32_t ch, int fontSize = -1);\n    template<typename T>\n    int stringWidth(const T &str, int fontSize = -1) {\n        int res = 0;\n        for (auto &ch: str) {\n            if (ch < 32) { continue; }\n            res += int(uint32_t(charWidth(ch, fontSize)));\n        }\n        return res;\n    }\n\n    inline int fontSize() const { return fontSize_; }\n    void setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255);\n    void setAltColor(int index, uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255);\n\n    template<typename T>\n    void render(const T &str, float x, float y, bool shadow, int fontSize = -1, int preSelColorIndex = 0) {\n        if (fontSize < 0) fontSize = fontSize_;\n        int colorIndex = preSelColorIndex;\n        renderImpl_.renderBegin();\n        for (auto ch: str) {\n            if (ch < 32) {\n                colorIndex = ch & 0x0F;\n                continue;\n            }\n            const auto *fd = getOrMakeCache(ch, fontSize);\n            if (!fd || fd->advW == 0) {\n                continue;\n            }\n            float ratio = fontSize == fd->origW ? 1.0f : (float(fontSize) / fd->origW);\n            auto *tex = textures_[fd->rpidx];\n            if (shadow) {\n                auto x0 = x + 2.f + fd->ix0, y0 = y + 2.f + fd->iy0;\n                renderImpl_.render(tex, x0, y0, x0 + fd->w * ratio, y0 + fd->h * ratio, fd->rpx, fd->rpy, fd->rpx + fd->w, fd->rpy + fd->h, 0xFF000000u);\n            }\n            {\n                auto x0 = x + fd->ix0, y0 = y + fd->iy0;\n                renderImpl_.render(tex, x0, y0, x0 + fd->w * ratio, y0 + fd->h * ratio, fd->rpx, fd->rpy, fd->rpx + fd->w, fd->rpy + fd->h, altColor_[colorIndex]);\n            }\n            x += fd->advW * fontSize / fd->origW;\n        }\n        renderImpl_.renderEnd();\n    }\n\nprotected:\n    virtual bool makeCache(FontData *fd, uint32_t ch, int fontSize) = 0;\n    virtual uint64_t makeFontKey(uint32_t ch, int fontSize) {\n        return (uint64_t(fontSize) << 32) | uint64_t(ch);\n    }\n    const FontData *getOrMakeCache(uint32_t ch, int fontSize = -1);\n    bool updateTexture(int &rpidx, int16_t &rpx, int16_t &rpy, int w, int h, const uint8_t *data);\n\nprotected:\n    int fontSize_ = 16;\n    uint8_t monoWidth_ = 0;\n\nprivate:\n    RectPacker *rectpacker_;\n    std::unordered_map<uint64_t, FontData> fontCache_;\n    std::vector<void*> textures_;\n    FontRenderImpl &renderImpl_;\n    uint32_t altColor_[16] = {};\n};\n\n}\n"
  },
  {
    "path": "src/render/fontrenderimpl.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <cstdint>\n\nnamespace render {\n\nclass FontRenderImpl {\npublic:\n    virtual void *createTexture(int width, int height) = 0;\n    virtual void destroyTexture(void *tex) = 0;\n    virtual void updateTexture(void *tex, int x, int y, int w, int h, const uint8_t *data) = 0;\n    virtual void renderBegin() = 0;\n    virtual void render(void *tex, float x0, float y0, float x1, float y1, int u0, int v0, int u1, int v1, uint32_t color) = 0;\n    virtual void renderEnd() = 0;\n};\n\n}\n"
  },
  {
    "path": "src/render/renderer.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"renderer.h\"\n\n#include \"HandmadeMath.h\"\n#include \"ui/window.h\"\n\n#include \"util/util.h\"\n\n#include <glad/glad_wgl.h>\n#include <windows.h>\n#include <chrono>\n#include <thread>\n#include <stdexcept>\n\nnamespace render {\n\ntypedef HGLRC (WINAPI *PFNWGLCREATECONTEXTPROC)(HDC hDc);\ntypedef BOOL (WINAPI *PFNWGLDELETECONTEXTPROC)(HGLRC oldContext);\ntypedef BOOL (WINAPI *PFNWGLMAKECURRENTPROC)(HDC hDc, HGLRC newContext);\n\nstruct RendererCtx {\n    ui::Window *owner = nullptr;\n\n    /* WGL functions */\n    HMODULE lib = nullptr;\n    PFNWGLCREATECONTEXTPROC wglCreateContext = nullptr;\n    PFNWGLDELETECONTEXTPROC wglDeleteContext = nullptr;\n    PFNWGLMAKECURRENTPROC wglMakeCurrent = nullptr;\n\n    /* OpenGL-Context related */\n    HDC dc = nullptr;\n    HGLRC glCtx = nullptr;\n\n    std::chrono::steady_clock::time_point nextRenderTime;\n    std::chrono::steady_clock::duration renderInterval = {};\n    bool fpsLimit = false;\n\n    /* Render related */\n    int width = 0, height = 0;\n    Texture *background = nullptr;\n\n    float clearColor[4] = {.0, .0, .0, .0};\n};\n\nRenderer::Renderer(ui::Window *wnd) : ctx_(new RendererCtx) {\n    ctx_->owner = wnd;\n    ctx_->lib = LoadLibraryW(L\"opengl32.dll\");\n    if (!ctx_->lib) {\n        throw std::runtime_error(\"Unable to load opengl32.dll\");\n    }\n    ctx_->wglCreateContext = (PFNWGLCREATECONTEXTPROC)GetProcAddress(ctx_->lib, \"wglCreateContext\");\n    ctx_->wglDeleteContext = (PFNWGLDELETECONTEXTPROC)GetProcAddress(ctx_->lib, \"wglDeleteContext\");\n    ctx_->wglMakeCurrent = (PFNWGLMAKECURRENTPROC)GetProcAddress(ctx_->lib, \"wglMakeCurrent\");\n    PIXELFORMATDESCRIPTOR pfd = {\n        sizeof(PIXELFORMATDESCRIPTOR), 1,\n        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION,\n        PFD_TYPE_RGBA, 32, 8, 0, 8, 0, 8, 0,\n        8, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, PFD_MAIN_PLANE,\n        0, 0, 0, 0\n    };\n    ctx_->dc = GetDC((HWND)wnd->hwnd());\n    int choose = ChoosePixelFormat(ctx_->dc, &pfd);\n    SetPixelFormat(ctx_->dc, choose, &pfd);\n    ctx_->glCtx = ctx_->wglCreateContext(ctx_->dc);\n    ctx_->wglMakeCurrent(ctx_->dc, ctx_->glCtx);\n\n    gladLoadGL();\n    gladLoadWGL(ctx_->dc);\n    wnd->getDimension(ctx_->width, ctx_->height);\n    wnd->setSizeCallback([this](int w, int h) {\n        ctx_->width = w;\n        ctx_->height = h;\n    });\n}\n\nRenderer::~Renderer() {\n    if (ctx_->glCtx) {\n        ctx_->wglDeleteContext(ctx_->glCtx);\n    }\n    FreeLibrary(ctx_->lib);\n    delete ctx_;\n}\n\nui::Window *Renderer::owner() {\n    return ctx_->owner;\n}\n\nvoid Renderer::setSwapInterval(int interval) {\n    wglSwapIntervalEXT(interval);\n}\nvoid Renderer::setViewport(int x, int y, int w, int h) {\n    glViewport(x, y, w, h);\n}\nvoid Renderer::limitFPS(uint32_t fps) {\n    if (fps) {\n        ctx_->renderInterval = std::chrono::nanoseconds(1000 * 1000 * 1000) / fps;\n        ctx_->fpsLimit = true;\n    } else {\n        ctx_->fpsLimit = false;\n    }\n}\nvoid Renderer::setClearColor(float r, float g, float b, float a) {\n    auto *c = ctx_->clearColor;\n    c[0] = r;\n    c[1] = g;\n    c[2] = b;\n    c[3] = a;\n}\nvoid Renderer::prepare() {\n    if (ctx_->fpsLimit) {\n        do {\n            auto now = util::getCurrTime();\n            if (ctx_->nextRenderTime > now) {\n                std::this_thread::sleep_for(ctx_->nextRenderTime - now);\n                util::updateTime();\n                continue;\n            }\n            ctx_->nextRenderTime += ctx_->renderInterval;\n            if (ctx_->nextRenderTime < now) { ctx_->nextRenderTime = now + ctx_->renderInterval; }\n            break;\n        } while (true);\n        util::updateTime();\n    }\n}\nvoid Renderer::begin() {\n    glDisable(GL_BLEND);\n    auto *c = ctx_->clearColor;\n    glClearColor(c[0], c[1], c[2], c[3]);\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glEnable(GL_MULTISAMPLE);\n}\nvoid Renderer::end() {\n    SwapBuffers(ctx_->dc);\n}\nvoid Renderer::getDimension(int &width, int &height) const {\n    width = ctx_->width;\n    height = ctx_->height;\n}\n\nShader::Shader(Shader::Type type) : tp(type) {\n    uint32_t stp = 0;\n    switch (type) {\n    case VertexShader:stp = GL_VERTEX_SHADER;\n        break;\n    case FragmentShader:stp = GL_FRAGMENT_SHADER;\n        break;\n    }\n    uid = glCreateShader(stp);\n}\nShader::~Shader() {\n    if (uid) {\n        glDeleteShader(uid);\n    }\n}\nbool Shader::compile(const char *src) {\n    if (uid == 0) {\n        return false;\n    }\n    glShaderSource(uid, 1, &src, nullptr);\n    glCompileShader(uid);\n    GLint compiled = GL_FALSE;\n    glGetShaderiv(uid, GL_COMPILE_STATUS, &compiled);\n    if (compiled == GL_FALSE) {\n        glDeleteShader(uid);\n        uid = 0;\n        return false;\n    }\n    return true;\n}\n\nShaderProgram::~ShaderProgram() {\n    if (uid) {\n        glDeleteProgram(uid);\n    }\n}\nbool ShaderProgram::compileAndLink(const char *vsSrc, const char *fsSrc) {\n    Shader vShader(Shader::VertexShader), fShader(Shader::FragmentShader);\n    if (!vShader.compile(vsSrc)) { return false; }\n    if (!fShader.compile(fsSrc)) { return false; }\n    const Shader *shaders[] = {&vShader, &fShader, nullptr};\n    return link(shaders);\n}\nbool ShaderProgram::link(const Shader **shaders) {\n    if (uid == 0 && (uid = glCreateProgram()) == 0) {\n        return false;\n    }\n    for (const auto *s = shaders; *s != nullptr; ++s) {\n        glAttachShader(uid, (uint32_t)**s);\n    }\n    glLinkProgram(uid);\n    GLint linked = GL_FALSE;\n    glGetProgramiv(uid, GL_LINK_STATUS, &linked);\n    if (linked == GL_FALSE) {\n        glDeleteProgram(uid);\n        uid = 0;\n        return false;\n    }\n    return true;\n}\nvoid ShaderProgram::use() const {\n    glUseProgram(uid);\n}\nvoid ShaderProgram::unuse() {\n    glUseProgram(0);\n}\nint ShaderProgram::uniformIndex(const char *name) const {\n    return glGetUniformLocation(uid, name);\n}\nvoid ShaderProgram::setInt(int id, int value) {\n    glUniform1i(id, value);\n}\nvoid ShaderProgram::setInt(const char *name, int value) const {\n    glUseProgram(uid);\n    auto id = glGetUniformLocation(uid, name);\n    if (id >= 0) {\n        glUniform1i(id, value);\n    }\n}\nvoid ShaderProgram::setFloat(int id, float value) {\n    glUniform1f(id, value);\n}\nvoid ShaderProgram::setFloat(const char *name, float value) const {\n    glUseProgram(uid);\n    auto id = glGetUniformLocation(uid, name);\n    if (id >= 0) {\n        glUniform1f(id, value);\n    }\n}\nvoid ShaderProgram::setMat4(int id, const float *data) {\n    glUniformMatrix4fv(id, 1, GL_FALSE, data);\n}\nvoid ShaderProgram::setMat4(const char *name, const float *data) const {\n    glUseProgram(uid);\n    auto id = glGetUniformLocation(uid, name);\n    if (id >= 0) {\n        glUniformMatrix4fv(id, 1, GL_FALSE, data);\n    }\n}\n\nstatic int roundup(int v) {\n    auto vi = uint32_t(v > 1 ? v - 1 : 1);\n    for (uint32_t i = 0; i < 5; i++) {\n        vi |= (vi >> (1 << i));\n    }\n    return int(vi + 1);\n}\n\nTexture::Texture() {\n    glGenTextures(1, &uid_);\n}\nTexture::~Texture() {\n    if (uid_) {\n        glDeleteTextures(1, &uid_);\n    }\n}\nTexture::Texture(Texture &&other) noexcept {\n    uid_ = other.uid_;\n    width_ = other.width_;\n    height_ = other.height_;\n    widthReal_ = other.widthReal_;\n    heightReal_ = other.heightReal_;\n    other.uid_ = 0;\n}\nvoid Texture::create(int width, int height) {\n    width_ = roundup(width);\n    height_ = roundup(height);\n    widthReal_ = width;\n    heightReal_ = height;\n    glBindTexture(GL_TEXTURE_2D, uid_);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glBindTexture(GL_TEXTURE_2D, 0);\n}\nvoid Texture::setData(int width, int height, const uint32_t *data) {\n    width_ = roundup(width);\n    height_ = roundup(height);\n    widthReal_ = width;\n    heightReal_ = height;\n    glBindTexture(GL_TEXTURE_2D, uid_);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);\n    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glBindTexture(GL_TEXTURE_2D, 0);\n}\nvoid Texture::updateSubData(int x, int y, int width, int height, const uint32_t *data) const {\n    glBindTexture(GL_TEXTURE_2D, uid_);\n    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    int err = glGetError();\n    glBindTexture(GL_TEXTURE_2D, 0);\n}\nvoid Texture::bind() const {\n    glBindTexture(GL_TEXTURE_2D, uid_);\n}\nvoid Texture::unbind() {\n    glBindTexture(GL_TEXTURE_2D, 0);\n}\n\nstruct VertexAttribPointerLayout {\n    int size;\n    uint32_t type;\n    uint8_t normalized;\n    const void *pointer;\n};\n\nstruct PipelineCtx {\n    const void *host = nullptr;\n    bool renderToTarget = false;\n\n    uint32_t uidVAO = 0;\n    uint32_t uidVBO = 0;\n    uint32_t uidEBO = 0;\n    uint32_t uidFB = 0;\n    int viewport[4] = {};\n    int scissor[4] = {};\n\n    ShaderProgram *program = nullptr;\n    bool freeProgram = false;\n    int stride = 0;\n    std::vector<VertexAttribPointerLayout> vertexAttrPtrLayouts;\n\n    bool built = false;\n    std::vector<uint8_t> vertices;\n    std::vector<uint16_t> indices;\n\n    hmm_mat4 mvpBase = HMM_Orthographic(-1, 1, -1, 1, -1, 1);\n    hmm_mat4 transform = HMM_Mat4d(1);\n    hmm_mat4 mvp;\n    bool mvpDirty = false;\n};\n\nPipeline::Pipeline(const Texture &texture, ShaderProgram *prog, int stri, const VertexAttribPointer *vap)\n    : ctx_(new PipelineCtx) {\n    init(prog, stri, vap);\n    ctx_->renderToTarget = true;\n    ctx_->host = &texture;\n}\nPipeline::Pipeline(Renderer &renderer, ShaderProgram *prog, int stri, const VertexAttribPointer *vap)\n    : ctx_(new PipelineCtx) {\n    init(prog, stri, vap);\n    ctx_->renderToTarget = false;\n    ctx_->host = &renderer;\n}\nPipeline::~Pipeline() {\n    if (ctx_->freeProgram) {\n        delete ctx_->program;\n    }\n    if (ctx_->uidFB) {\n        glDeleteFramebuffers(1, &ctx_->uidFB);\n    }\n    glDeleteBuffers(1, &ctx_->uidEBO);\n    glDeleteBuffers(1, &ctx_->uidVBO);\n    glDeleteVertexArrays(1, &ctx_->uidVAO);\n}\nvoid Pipeline::setViewport(int x, int y, int w, int h) {\n    ctx_->viewport[0] = x;\n    ctx_->viewport[1] = y;\n    ctx_->viewport[2] = w;\n    ctx_->viewport[3] = h;\n}\nvoid Pipeline::setScissor(int x, int y, int w, int h) {\n    ctx_->scissor[0] = x;\n    ctx_->scissor[1] = y;\n    ctx_->scissor[2] = w;\n    ctx_->scissor[3] = h;\n}\nvoid Pipeline::setOrtho(float left, float right, float bottom, float top, float nearf, float farf) {\n    ctx_->mvpBase = HMM_Orthographic(left, right, bottom, top, nearf, farf);\n    ctx_->mvpDirty = true;\n}\nvoid Pipeline::resetTransform() {\n    ctx_->transform = HMM_Mat4d(1.0f);\n    ctx_->mvpDirty = true;\n}\nvoid Pipeline::setTransform(const float *mat) {\n    memcpy(&ctx_->transform.Elements[0][0], mat, sizeof(float) * 4 * 4);\n    ctx_->mvpDirty = true;\n}\nvoid Pipeline::translate(float x, float y, float z) {\n    ctx_->transform = HMM_Translate(HMM_Vec3(x, y, z)) * ctx_->transform;\n    ctx_->mvpDirty = true;\n}\nvoid Pipeline::scale(float x, float y, float z) {\n    ctx_->transform = HMM_Scale(HMM_Vec3(x, y, z)) * ctx_->transform;\n    ctx_->mvpDirty = true;\n}\nvoid Pipeline::rotate(float angle, float x, float y, float z) {\n    ctx_->transform = HMM_Rotate(angle, HMM_Vec3(x, y, z)) * ctx_->transform;\n    ctx_->mvpDirty = true;\n}\nvoid Pipeline::render() {\n    if (ctx_->indices.empty()) { return; }\n    if (!ctx_->built) {\n        ctx_->built = true;\n        if (ctx_->renderToTarget && ctx_->uidFB == 0) {\n            glGenFramebuffers(1, &ctx_->uidFB);\n            glBindFramebuffer(GL_FRAMEBUFFER, ctx_->uidFB);\n            glFramebufferTexture2D(GL_FRAMEBUFFER,\n                                   GL_COLOR_ATTACHMENT0,\n                                   GL_TEXTURE_2D,\n                                   (uint32_t)*(Texture *)ctx_->host,\n                                   0);\n            glBindFramebuffer(GL_FRAMEBUFFER, 0);\n        }\n\n        glBindVertexArray(ctx_->uidVAO);\n        glBindBuffer(GL_ARRAY_BUFFER, ctx_->uidVBO);\n        glBufferData(GL_ARRAY_BUFFER, ctx_->vertices.size(), &ctx_->vertices[0], GL_STATIC_DRAW);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx_->uidEBO);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER,\n                     sizeof(uint16_t) * ctx_->indices.size(),\n                     &ctx_->indices[0],\n                     GL_STATIC_DRAW);\n        int count = ctx_->vertexAttrPtrLayouts.size();\n        for (int i = 0; i < count; ++i) {\n            auto &vapp = ctx_->vertexAttrPtrLayouts[i];\n            glVertexAttribPointer(i, vapp.size, vapp.type, vapp.normalized, ctx_->stride, vapp.pointer);\n            glEnableVertexAttribArray(i);\n        }\n        glBindBuffer(GL_ARRAY_BUFFER, 0);\n        glBindVertexArray(0);\n    }\n    if (ctx_->renderToTarget) {\n        int vw, vh;\n        glBindFramebuffer(GL_FRAMEBUFFER, ctx_->uidFB);\n        const auto *tex = (const Texture *)ctx_->host;\n        vw = tex->width();\n        vh = tex->height();\n        glViewport(0, 0, vw, vh);\n    } else {\n        glViewport(ctx_->viewport[0], ctx_->viewport[1], ctx_->viewport[2], ctx_->viewport[3]);\n        if (ctx_->scissor[2]) {\n            glEnable(GL_SCISSOR_TEST);\n            glScissor(ctx_->scissor[0], ctx_->scissor[1], ctx_->scissor[2], ctx_->scissor[3]);\n        }\n    }\n    doRender();\n    if (ctx_->renderToTarget) {\n        glBindFramebuffer(GL_FRAMEBUFFER, 0);\n    }\n}\nvoid Pipeline::push(int vertexCountIn, const void *verticesIn, int indexCountIn, const uint16_t *indicesIn) {\n    auto delta = uint16_t(ctx_->vertices.size() / ctx_->stride);\n    ctx_->vertices.insert(ctx_->vertices.end(),\n                          (const uint8_t *)verticesIn,\n                          (const uint8_t *)verticesIn + vertexCountIn * ctx_->stride);\n    ctx_->indices.reserve(ctx_->indices.size() + indexCountIn);\n    for (int i = 0; i < indexCountIn; ++i) {\n        ctx_->indices.push_back(indicesIn[i] + delta);\n    }\n    ctx_->built = false;\n}\nvoid Pipeline::reset() {\n    ctx_->vertices.clear();\n    ctx_->indices.clear();\n    ctx_->built = false;\n}\nvoid Pipeline::init(ShaderProgram *prog, int stri, const VertexAttribPointer *vap) {\n    ctx_->program = prog ? prog : new ShaderProgram;\n    ctx_->freeProgram = !prog;\n    ctx_->stride = stri;\n    glGenVertexArrays(1, &ctx_->uidVAO);\n    glGenBuffers(1, &ctx_->uidVBO);\n    glGenBuffers(1, &ctx_->uidEBO);\n    int total = 0;\n    for (; vap->fmt != VERTEXFORMAT_NONE; ++vap) {\n        VertexAttribPointerLayout vapp;\n        switch (vap->fmt) {\n        case VERTEXFORMAT_FLOAT:vapp = {1, GL_FLOAT, GL_FALSE,\n                                        (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_FLOAT2:vapp = {2, GL_FLOAT, GL_FALSE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 8;\n            break;\n        case VERTEXFORMAT_FLOAT3:vapp = {3, GL_FLOAT, GL_FALSE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 12;\n            break;\n        case VERTEXFORMAT_FLOAT4:vapp = {4, GL_FLOAT, GL_FALSE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 16;\n            break;\n        case VERTEXFORMAT_BYTE4:vapp = {4, GL_BYTE, GL_FALSE,\n                                        (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_BYTE4N:vapp = {4, GL_BYTE, GL_TRUE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_UBYTE4:vapp = {4, GL_UNSIGNED_BYTE, GL_FALSE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_UBYTE4N:vapp = {4, GL_UNSIGNED_BYTE, GL_TRUE,\n                                          (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_SHORT2:vapp = {2, GL_SHORT, GL_FALSE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_SHORT2N:vapp = {2, GL_SHORT, GL_TRUE,\n                                          (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_USHORT2N:vapp = {2, GL_UNSIGNED_SHORT, GL_TRUE,\n                                           (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 4;\n            break;\n        case VERTEXFORMAT_SHORT4:vapp = {4, GL_SHORT, GL_FALSE,\n                                         (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 8;\n            break;\n        case VERTEXFORMAT_SHORT4N:vapp = {4, GL_SHORT, GL_TRUE,\n                                          (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 8;\n            break;\n        case VERTEXFORMAT_USHORT4N:vapp = {4, GL_UNSIGNED_SHORT, GL_TRUE,\n                                           (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            total += 8;\n            break;\n        case VERTEXFORMAT_UINT10_N2:vapp = {4, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE,\n                                            (const void *)(uintptr_t)(vap->offset == 0 ? total : vap->offset)};\n            break;\n        default:continue;\n        }\n        ctx_->vertexAttrPtrLayouts.emplace_back(vapp);\n    }\n    if (!ctx_->stride) { ctx_->stride = total; }\n}\nvoid Pipeline::doRender() {\n    if (ctx_->mvpDirty) {\n        ctx_->mvp = ctx_->mvpBase * ctx_->transform;\n        ctx_->mvpDirty = false;\n    }\n    ctx_->program->use();\n    setMVP(&ctx_->mvp.Elements[0][0]);\n    glBindVertexArray(ctx_->uidVAO);\n    glDrawElements(GL_TRIANGLES, ctx_->indices.size(), GL_UNSIGNED_SHORT, nullptr);\n    glBindVertexArray(0);\n    ShaderProgram::unuse();\n}\n\nstruct Texture2DVertexData {\n    float x, y;\n    float u, v;\n    uint32_t color;\n};\nstatic constexpr VertexAttribPointer texture2DVAP[] = {\n    {VERTEXFORMAT_FLOAT2, 0},\n    {VERTEXFORMAT_FLOAT2, 8},\n    {VERTEXFORMAT_UBYTE4N, 16},\n    {VERTEXFORMAT_NONE},\n};\n\nPipelineTexture2D::PipelineTexture2D(Renderer &renderer) : Pipeline(renderer, nullptr, 0, texture2DVAP) {\n    init();\n}\nPipelineTexture2D::PipelineTexture2D(const Texture &tex) : Pipeline(tex, nullptr, 0, texture2DVAP) {\n    init();\n}\nvoid PipelineTexture2D::setTexture(const Texture &tex) {\n    tex_ = &tex;\n}\nvoid PipelineTexture2D::pushQuad(float x0, float y0, float x1, float y1, uint32_t color) {\n    float u1 = float(tex_->widthReal()) / float(tex_->width());\n    float v1 = float(tex_->heightReal()) / float(tex_->height());\n    pushQuad(x0, y0, x1, y1, 0, 0, u1, v1, color);\n}\nvoid PipelineTexture2D::pushQuad(float x0,\n                                 float y0,\n                                 float x1,\n                                 float y1,\n                                 float u0,\n                                 float v0,\n                                 float u1,\n                                 float v1,\n                                 uint32_t color) {\n    Texture2DVertexData v[] = {\n        {x0, y0, u0, v0, color},\n        {x0, y1, u0, v1, color},\n        {x1, y1, u1, v1, color},\n        {x1, y0, u1, v0, color},\n    };\n    const uint16_t i[6] = {0, 1, 2, 0, 2, 3};\n    push(4, v, 6, i);\n}\nvoid PipelineTexture2D::setMVP(const float *mvp) {\n    ctx_->program->setMat4(uniformMVP_, mvp);\n}\nvoid PipelineTexture2D::doRender() {\n    glActiveTexture(GL_TEXTURE0);\n    tex_->bind();\n    Pipeline::doRender();\n}\nvoid PipelineTexture2D::init() {\n    if (ctx_->freeProgram) {\n        ctx_->program->compileAndLink(R\"(\n            #version 330\n            uniform mat4 mvp;\n            layout(location=0) in vec2 position;\n            layout(location=1) in vec2 texcoord0;\n            layout(location=2) in vec4 color;\n            out vec2 uv;\n            out vec4 pass_color;\n            void main() {\n              gl_Position = mvp * vec4(position.xy, 0, 1);\n              uv = texcoord0;\n              pass_color = color;\n            }\n        )\", R\"(\n            #version 330\n            uniform sampler2D tex;\n            in vec2 uv;\n            in vec4 pass_color;\n            out vec4 frag_color;\n            void main() {\n              frag_color = texture(tex, uv) * pass_color;\n            }\n        )\"\n        );\n        ctx_->program->setInt(\"tex\", 0);\n    }\n    uniformMVP_ = ctx_->program->uniformIndex(\"mvp\");\n}\n\nstruct Squad2DVertexData {\n    float x, y;\n    uint32_t color;\n};\nstatic constexpr VertexAttribPointer squad2DVAP[] = {\n    {VERTEXFORMAT_FLOAT2, 0},\n    {VERTEXFORMAT_UBYTE4N, 8},\n    {VERTEXFORMAT_NONE},\n};\n\nPipelineSquad2D::PipelineSquad2D(Renderer &renderer) : Pipeline(renderer, nullptr, 0, squad2DVAP) {\n    init();\n}\nPipelineSquad2D::PipelineSquad2D(const Texture &tex) : Pipeline(tex, nullptr, 0, squad2DVAP) {\n    init();\n}\nvoid PipelineSquad2D::pushQuad(float x0, float y0, float x1, float y1, uint32_t color) {\n    const Squad2DVertexData v[4] = {\n        {x0, y0, color},\n        {x0, y1, color},\n        {x1, y1, color},\n        {x1, y0, color},\n    };\n    const uint16_t i[6] = {0, 1, 2, 0, 2, 3};\n    push(4, v, 6, i);\n}\nvoid PipelineSquad2D::pushQuad(float x0, float y0, float x1, float y1,\n                               float x2, float y2, float x3, float y3,\n                               uint32_t color) {\n    const Squad2DVertexData v[4] = {\n        {x0, y0, color},\n        {x1, y1, color},\n        {x2, y2, color},\n        {x3, y3, color},\n    };\n    const uint16_t i[6] = {0, 1, 2, 0, 2, 3};\n    push(4, v, 6, i);\n}\nvoid PipelineSquad2D::drawLine(float x0, float y0, float x1, float y1, float width, uint32_t color) {\n    auto fromPt = HMM_Vec2(x0, y0);\n    auto toPt = HMM_Vec2(x1, y1);\n    auto delta = toPt - fromPt;\n    auto perp = HMM_Normalize(HMM_Vec2(-delta.Y, delta.X)) * width * .5f;\n    auto A = fromPt + perp;\n    auto B = fromPt - perp;\n    auto C = toPt - perp;\n    auto D = toPt + perp;\n    const Squad2DVertexData v[] = {\n        {A.X, A.Y, color},\n        {B.X, B.Y, color},\n        {C.X, C.Y, color},\n        {D.X, D.Y, color},\n    };\n    const uint16_t i[6] = {0, 1, 2, 0, 2, 3};\n    push(4, v, 6, i);\n}\nvoid PipelineSquad2D::setMVP(const float *mvp) {\n    ctx_->program->setMat4(uniformMVP_, mvp);\n}\nvoid PipelineSquad2D::init() {\n    if (ctx_->freeProgram) {\n        ctx_->program->compileAndLink(R\"(\n            #version 330\n            uniform mat4 mvp;\n            layout(location=0) in vec2 position;\n            layout(location=1) in vec4 color;\n            out vec4 outColor;\n            void main() {\n              gl_Position = mvp * vec4(position.xy, 0, 1);\n              outColor = color;\n            }\n        )\", R\"(\n            #version 330\n            in vec4 outColor;\n            out vec4 frag_color;\n            void main() {\n              frag_color = outColor;\n            }\n        )\");\n    }\n    uniformMVP_ = ctx_->program->uniformIndex(\"mvp\");\n}\n\n}\n"
  },
  {
    "path": "src/render/renderer.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <vector>\n#include <cstdint>\n\nnamespace ui {\nclass Window;\n}\n\nnamespace render {\n\nstruct RendererCtx;\n\nclass Pipeline;\n\nclass Renderer final {\npublic:\n    explicit Renderer(ui::Window*);\n    ~Renderer();\n\n    [[nodiscard]] ui::Window *owner();\n\n    static void setSwapInterval(int interval);\n    static void setViewport(int x, int y, int w, int h);\n    void limitFPS(uint32_t fps);\n    void setClearColor(float r, float g, float b, float a);\n    void prepare();\n    void begin();\n    void end();\n\n    void getDimension(int &width, int &height) const;\n\nprivate:\n    RendererCtx *ctx_;\n};\n\nstruct Shader final {\n    enum Type {\n        VertexShader,\n        FragmentShader,\n    };\n    explicit Shader(Type type);\n    ~Shader();\n    bool compile(const char *src);\n    [[nodiscard]] inline explicit operator uint32_t() const { return uid; }\n    [[nodiscard]] inline Type type() { return tp; }\n\nprivate:\n    uint32_t uid = 0;\n    Type tp = VertexShader;\n};\n\nstruct ShaderProgram final {\n    ~ShaderProgram();\n    bool link(const Shader **shaders);\n    bool compileAndLink(const char *vsSrc, const char *fsSrc);\n    void use() const;\n    static void unuse();\n    [[nodiscard]] int uniformIndex(const char *name) const;\n    static void setInt(int id, int value);\n    void setInt(const char *name, int value) const;\n    static void setFloat(int id, float value);\n    void setFloat(const char *name, float value) const;\n    static void setMat4(int id, const float *data);\n    void setMat4(const char *name, const float *data) const;\n    [[nodiscard]] inline explicit operator uint32_t() const { return uid; }\n\nprivate:\n    uint32_t uid = 0;\n};\n\nclass Texture final {\npublic:\n    Texture();\n    ~Texture();\n    Texture(const Texture &) = delete;\n    Texture(Texture &&) noexcept;\n    void create(int width, int height);\n    void setData(int width, int height, const uint32_t *data);\n    void updateSubData(int x, int y, int width, int height, const uint32_t *data) const;\n    void bind() const;\n    static void unbind();\n    [[nodiscard]] inline explicit operator uint32_t() const { return uid_; }\n    [[nodiscard]] int width() const { return width_; }\n    [[nodiscard]] int height() const { return height_; }\n    [[nodiscard]] int widthReal() const { return widthReal_; }\n    [[nodiscard]] int heightReal() const { return heightReal_; }\n\nprivate:\n    uint32_t uid_ = 0;\n    int width_ = 0, height_ = 0, widthReal_ = 0, heightReal_ = 0;\n};\n\nenum VertexFormat {\n    VERTEXFORMAT_NONE,\n    VERTEXFORMAT_FLOAT,\n    VERTEXFORMAT_FLOAT2,\n    VERTEXFORMAT_FLOAT3,\n    VERTEXFORMAT_FLOAT4,\n    VERTEXFORMAT_BYTE4,\n    VERTEXFORMAT_BYTE4N,\n    VERTEXFORMAT_UBYTE4,\n    VERTEXFORMAT_UBYTE4N,\n    VERTEXFORMAT_SHORT2,\n    VERTEXFORMAT_SHORT2N,\n    VERTEXFORMAT_USHORT2N,\n    VERTEXFORMAT_SHORT4,\n    VERTEXFORMAT_SHORT4N,\n    VERTEXFORMAT_USHORT4N,\n    VERTEXFORMAT_UINT10_N2,\n    VERTEXFORMAT_MAX,\n};\n\nstruct VertexAttribPointer {\n    VertexFormat fmt = VERTEXFORMAT_FLOAT;\n    int offset = 0;\n};\n\nstruct PipelineCtx;\n\nclass Pipeline {\npublic:\n    Pipeline(const Texture &texture, ShaderProgram *prog, int stri, const VertexAttribPointer *vap);\n    Pipeline(Renderer &renderer, ShaderProgram *prog, int stri, const VertexAttribPointer *vap);\n    virtual ~Pipeline();\n    void setViewport(int x, int y, int w, int h);\n    void setScissor(int x, int y, int w, int h);\n    void setOrtho(float left, float right, float bottom, float top, float nearf = -1, float far = 1);\n    void resetTransform();\n    void setTransform(const float *mat);\n    void translate(float x, float y, float z);\n    void scale(float x, float y, float z);\n    void rotate(float angle, float x, float y, float z);\n    void render();\n    void push(int vertexSizeIn, const void *verticesIn, int indexCountIn, const uint16_t *indicesIn);\n    void reset();\n\nprotected:\n    void init(ShaderProgram *prog, int stri, const VertexAttribPointer *vap);\n    virtual void setMVP(const float *mvp) {}\n    virtual void doRender();\n\nprotected:\n    PipelineCtx *ctx_;\n};\n\nclass PipelineTexture2D: public Pipeline {\npublic:\n    explicit PipelineTexture2D(Renderer &renderer);\n    explicit PipelineTexture2D(const Texture &tex);\n    void setTexture(const Texture &tex);\n    void pushQuad(float x0, float y0, float x1, float y1, uint32_t color = 0xFFFFFFFFu);\n    void pushQuad(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, uint32_t color = 0xFFFFFFFFu);\n\nprotected:\n    void setMVP(const float *mvp) override;\n    void doRender() override;\n    void init();\n\nprivate:\n    const Texture *tex_ = nullptr;\n    int uniformMVP_ = -1;\n};\n\nclass PipelineSquad2D: public Pipeline {\npublic:\n    explicit PipelineSquad2D(Renderer &renderer);\n    explicit PipelineSquad2D(const Texture &tex);\n    void pushQuad(float x0, float y0, float x1, float y1, uint32_t color);\n    void pushQuad(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, uint32_t color);\n    void drawLine(float x0, float y0, float x1, float y1, float width, uint32_t color);\n\nprotected:\n    void setMVP(const float *mvp) override;\n    void init();\n\nprivate:\n    int uniformMVP_ = -1;\n};\n\n}\n"
  },
  {
    "path": "src/render/ttf.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"ttf.h\"\n\n#include \"d2r/storage.h\"\n#include \"cfg.h\"\n\n#ifdef USE_FREETYPE\n#include <ft2build.h>\n#include FT_FREETYPE_H\n#else\n#define STB_TRUETYPE_IMPLEMENTATION\n#define STBTT_STATIC\n#include <stb_truetype.h>\n#endif\n\n#include <fstream>\n\nnamespace render {\n\nTTF::TTF(FontRenderImpl &renderImpl) : Font(renderImpl) {\n#ifdef USE_FREETYPE\n    FT_Init_FreeType(&ftLib_);\n#endif\n}\n\nTTF::~TTF() {\n    for (auto &p: fonts_) {\n#ifdef USE_FREETYPE\n        FT_Done_Face(p.face);\n#else\n        delete static_cast<stbtt_fontinfo *>(p.font);\n#endif\n        p.ttf_buffer.clear();\n    }\n    fonts_.clear();\n#ifdef USE_FREETYPE\n    FT_Done_FreeType(ftLib_);\n#endif\n}\n\nbool TTF::add(const std::string &filename, int param) {\n    FontInfo fi;\n    auto fullpath = filename;\n    if (fullpath.empty()) {\n        const char *fontfile = \"formal436bt.ttf\";\n        if (cfg->language == \"jaJP\") {\n            fontfile = \"bljap_v8_3.ttf\";\n        } else if (cfg->language == \"zhTW\") {\n            fontfile = \"blizzardglobaltcunicode.ttf\";\n        } else if (cfg->language == \"koKR\" || cfg->language == \"ruRU\" || cfg->language == \"zhCN\") {\n            fontfile = \"blizzardglobal-v5_81.ttf\";\n        }\n        fullpath = fontfile;\n    }\n    std::ifstream ifs(fullpath, std::ios::binary | std::ios::in);\n    if (ifs.is_open()) {\n        ifs.seekg(0, std::ios::end);\n        auto size = ifs.tellg();\n        ifs.seekg(0, std::ios::beg);\n        fi.ttf_buffer.resize(size_t(size));\n        ifs.read((char *)fi.ttf_buffer.data(), size);\n        ifs.close();\n    } else {\n        fullpath = \"data:data/hd/ui/fonts/\" + fullpath;\n        d2r::storage.readFile(fullpath.c_str(), fi.ttf_buffer);\n    }\n#ifdef USE_FREETYPE\n    if (FT_New_Memory_Face(ftLib_, (const FT_Byte*)fi.ttf_buffer.data(), fi.ttf_buffer.size(), param, &fi.face)) {\n        return false;\n    }\n    fonts_.emplace_back(std::move(fi));\n#else\n    auto *info = new stbtt_fontinfo;\n    stbtt_InitFont(info, &fi.ttf_buffer[0], stbtt_GetFontOffsetForIndex(&fi.ttf_buffer[0], param));\n    fi.font = info;\n    fonts_.emplace_back(std::move(fi));\n#endif\n    return true;\n}\n\nbool TTF::makeCache(TTF::FontData *fd, uint32_t ch, int fontSize) {\n    FontInfo *fi = nullptr;\n#ifndef USE_FREETYPE\n    stbtt_fontinfo *info;\n    uint32_t index = 0;\n#endif\n\n    for (auto &f: fonts_) {\n#ifdef USE_FREETYPE\n        auto index = FT_Get_Char_Index(f.face, ch);\n        if (index == 0) continue;\n        FT_Set_Pixel_Sizes(f.face, 0, fontSize);\n        auto err = FT_Load_Glyph(f.face, index, FT_LOAD_DEFAULT);\n        if (!err) { fi = &f; break; }\n#else\n        info = static_cast<stbtt_fontinfo *>(f.font);\n        index = stbtt_FindGlyphIndex(info, ch);\n        if (index != 0) {\n            fi = &f;\n            break;\n        }\n#endif\n    }\n    if (fi == nullptr) {\n        memset(fd, 0, sizeof(FontData));\n        return false;\n    }\n\n#ifdef USE_FREETYPE\n    unsigned char *srcPtr;\n    int bitmapPitch;\n    if (FT_Render_Glyph(fi->face->glyph, FT_RENDER_MODE_NORMAL)) {\n        return false;\n    }\n    FT_GlyphSlot slot = fi->face->glyph;\n    fd->ix0 = slot->bitmap_left;\n    fd->iy0 = fontSize * 7 / 8 - slot->bitmap_top;\n    fd->w = slot->bitmap.width;\n    fd->h = slot->bitmap.rows;\n    fd->advW = slot->advance.x >> 6;\n    srcPtr = slot->bitmap.buffer;\n    bitmapPitch = slot->bitmap.pitch;\n#else\n    /* Read font data to cache */\n    int advW, leftB;\n    float fontScale = stbtt_ScaleForMappingEmToPixels(info, static_cast<float>(fontSize));\n    stbtt_GetGlyphHMetrics(info, index, &advW, &leftB);\n    int ascent, descent;\n    stbtt_GetFontVMetrics(info, &ascent, &descent, nullptr);\n    fd->advW = uint8_t(std::lround(fontScale * float(advW)));\n    int w, h, x, y;\n    stbtt_GetGlyphBitmap(info, fontScale, fontScale, index, &w, &h, &x, &y);\n    fd->ix0 = x;\n    fd->iy0 = int(float(ascent + descent) * fontScale) + y;\n    fd->w = w;\n    fd->h = h;\n#endif\n    fd->origW = uint8_t(uint32_t(fontSize));\n\n    int dstPitch = int((fd->w + 1u) & ~1u);\n    std::vector<uint8_t> dst(dstPitch * fd->h);\n\n#ifdef USE_FREETYPE\n    auto *dstPtr = dst.data();\n    for (int k = 0; k < fd->h; ++k) {\n        memcpy(dstPtr, srcPtr, fd->w);\n        srcPtr += bitmapPitch;\n        dstPtr += dstPitch;\n    }\n#else\n    stbtt_MakeGlyphBitmapSubpixel(info, dst.data(), fd->w, fd->h, dstPitch, fontScale, fontScale, 0, 0, index);\n#endif\n\n    std::vector<uint32_t> dst2(dstPitch * fd->h);\n    uint8_t *ptr = dst.data();\n    uint32_t *ptr2 = dst2.data();\n    for (int j = fd->h; j; --j) {\n        for (int i = dstPitch; i; --i) {\n            *ptr2++ = (uint32_t(*ptr++) << 24) | 0xFFFFFFu;\n        }\n    }\n    if (!updateTexture(fd->rpidx, fd->rpx, fd->rpy, dstPitch, fd->h, (const uint8_t *)dst2.data())) {\n        memset(fd, 0, sizeof(FontData));\n        return false;\n    }\n    return true;\n}\n\n}\n"
  },
  {
    "path": "src/render/ttf.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"fontrenderimpl.h\"\n#include \"font.h\"\n\n#include <vector>\n#include <unordered_map>\n#include <string>\n#include <cstdint>\n\n#ifdef USE_FREETYPE\ntypedef struct FT_FaceRec_ *FT_Face;\ntypedef struct FT_LibraryRec_ *FT_Library;\n#endif\n\nnamespace render {\n\nclass TTF: public Font {\nprotected:\n    struct FontInfo {\n#ifdef USE_FREETYPE\n        FT_Face face = nullptr;\n#else\n        void *font = nullptr;\n#endif\n        std::vector<uint8_t> ttf_buffer;\n    };\npublic:\n    explicit TTF(FontRenderImpl &renderImpl);\n    ~TTF() override;\n\n    bool add(const std::string &filename, int param) override;\n\nprotected:\n    bool makeCache(FontData *fd, uint32_t ch, int fontSize) override;\n\nprotected:\n    std::vector<FontInfo> fonts_;\n\nprivate:\n#ifdef USE_FREETYPE\n    FT_Library ftLib_ = nullptr;\n#endif\n};\n\n}\n"
  },
  {
    "path": "src/render/ttfgl.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"ttfgl.h\"\n\n#include \"renderer.h\"\n\nnamespace render {\n\nTTFRenderGL::TTFRenderGL(Renderer &renderer): pipeline_(new PipelineTexture2D(renderer)) {\n}\nTTFRenderGL::TTFRenderGL(Texture &tex): pipeline_(new PipelineTexture2D(tex)) {\n}\nTTFRenderGL::~TTFRenderGL() {\n    delete pipeline_;\n}\nPipeline *TTFRenderGL::pipeline() {\n    return pipeline_;\n}\nvoid *TTFRenderGL::createTexture(int width, int height) {\n    auto *tex = new Texture;\n    tex->create(width, height);\n    return tex;\n}\nvoid TTFRenderGL::destroyTexture(void *tex) {\n    delete (Texture*)tex;\n}\nvoid TTFRenderGL::updateTexture(void *tex, int x, int y, int w, int h, const uint8_t *data) {\n    ((Texture*)tex)->updateSubData(x, y, w, h, (const uint32_t*)data);\n}\nvoid TTFRenderGL::renderBegin() {\n    pipeline_->reset();\n    lastTex_ = nullptr;\n}\nvoid TTFRenderGL::render(void *tex,\n                         float x0, float y0, float x1, float y1, int u0, int v0, int u1, int v1,\n                         uint32_t color) {\n    auto *texture = (Texture*)tex;\n    if (tex != lastTex_) {\n        if (lastTex_) {\n            pipeline_->setTexture(*texture);\n            pipeline_->render();\n            pipeline_->reset();\n        }\n        lastTex_ = tex;\n    }\n    auto width = float(texture->width());\n    auto height = float(texture->height());\n    pipeline_->pushQuad(x0, y0, x1, y1,\n                        float(u0) / width, float(v0) / height,\n                        float(u1) / width, float(v1) / height,\n                        color);\n}\nvoid TTFRenderGL::renderEnd() {\n    if (lastTex_) {\n        auto *texture = (Texture*)lastTex_;\n        pipeline_->setTexture(*texture);\n        pipeline_->render();\n    }\n}\n\n}\n"
  },
  {
    "path": "src/render/ttfgl.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"fontrenderimpl.h\"\n\nnamespace render {\n\nclass Pipeline;\nclass PipelineTexture2D;\nclass Renderer;\nclass Texture;\n\nclass TTFRenderGL final : public FontRenderImpl {\npublic:\n    explicit TTFRenderGL(Renderer &renderer);\n    explicit TTFRenderGL(Texture &tex);\n    ~TTFRenderGL();\n    Pipeline *pipeline();\n    void *createTexture(int width, int height) override;\n    void destroyTexture(void *tex) override;\n    void updateTexture(void *tex, int x, int y, int w, int h, const uint8_t *data) override;\n    void renderBegin() override;\n    void render(void *tex,\n                float x0, float y0, float x1, float y1, int u0, int v0, int u1, int v1,\n                uint32_t color) override;\n    void renderEnd() override;\n\nprivate:\n    PipelineTexture2D *pipeline_;\n    void *lastTex_ = nullptr;\n};\n\n}\n"
  },
  {
    "path": "src/res/D2RMH.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<dependency>\n<dependentAssembly>\n<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" />\n</dependentAssembly>\n</dependency>\n</assembly>\n"
  },
  {
    "path": "src/res/manifest.rc",
    "content": "1 24 \"D2RMH.manifest\"\n"
  },
  {
    "path": "src/res/res.rc",
    "content": "1 ICON \"D2RMH.ico\"\n\n#include \"winres.h\"\n\n101 DIALOG DISCARDABLE  0, 0, 240, 155\nSTYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"About D2RMH\"\nFONT 10, \"Arial Bold\"\nBEGIN\n    LTEXT           \"D2RMH\",1000,20,20,200,20,SS_CENTER\n    LTEXT           \"a map revealing tool for Diablo II Resurrected\",IDC_STATIC,20,45,200,10,SS_CENTER\n    LTEXT           \"by Soar Qin<soarchin@gmail.com>\",IDC_STATIC,20,60,200,10,SS_CENTER\n    DEFPUSHBUTTON   \"OK\",IDOK,100,128,40,12\n    CONTROL         \"Project page: <a href=\"\"https://github.com/soarqin/D2RMH\"\">https://github.com/soarqin/D2RMH</a>\",1001,\"SysLink\",WS_TABSTOP,20,90,200,10\n    CONTROL         \"New releases: <a href=\"\"https://github.com/soarqin/D2RMH/releases\"\">https://github.com/soarqin/D2RMH/releases</a>\",1002,\"SysLink\",WS_TABSTOP,20,105,200,10\nEND\n"
  },
  {
    "path": "src/ui/maprenderer.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"maprenderer.h\"\n\n#include \"window.h\"\n#include \"util/util.h\"\n#include \"cfg.h\"\n#include \"render/ttf.h\"\n#include \"render/d2font.h\"\n\n#include \"pathfinder.h\"\n\n#if defined(_MSC_VER)\n#define strcasecmp _stricmp\n#endif\n\nnamespace ui {\n\nstatic LNG lngFromString(const std::string &language) {\n#define CHECK_LNG(n) if (language == #n) { return LNG_##n; }\n    CHECK_LNG(enUS)\n    CHECK_LNG(zhTW)\n    CHECK_LNG(deDE)\n    CHECK_LNG(esES)\n    CHECK_LNG(frFR)\n    CHECK_LNG(itIT)\n    CHECK_LNG(koKR)\n    CHECK_LNG(plPL)\n    CHECK_LNG(esMX)\n    CHECK_LNG(jaJP)\n    CHECK_LNG(ptBR)\n    CHECK_LNG(ruRU)\n    CHECK_LNG(zhCN)\n    return LNG_enUS;\n#undef CHECK_LNG\n}\n\nMapRenderer::MapRenderer(render::Renderer &renderer, d2mapapi::PipedChildProcess &childProcess) :\n    renderer_(renderer),\n    mapPipeline_(renderer),\n    framePipeline_(renderer),\n    dynamicPipeline_(renderer),\n    messagePipeline_(renderer),\n    ttfgl_(renderer),\n    childProcess_(childProcess),\n    plugin_(&d2rProcess_, this) {\n    d2rProcess_.setWindowPosCallback([this](int left, int top, int right, int bottom) {\n        d2rRect = {left, top, right, bottom};\n        updateWindowPos();\n    });\n    d2rProcess_.setProcessCloseCallback([this](void *hwnd) {\n        auto ite = sessions_.find(hwnd);\n        if (ite == sessions_.end()) { return; }\n        if (currSession_ == ite->second.get()) {\n            currSession_ = nullptr;\n        }\n        sessions_.erase(ite);\n    });\n\n    loadFromCfg();\n}\n\nvoid MapRenderer::update() {\n    bool lastEnabled = enabled_;\n    doUpdate();\n    if (lastEnabled != enabled_) {\n        renderer_.owner()->show(enabled_);\n        SetForegroundWindow(HWND(d2rProcess_.hwnd()));\n    }\n}\n\nvoid MapRenderer::doUpdate() {\n    d2rProcess_.updateData();\n    if (!d2rProcess_.available()) {\n        renderer_.owner()->enableHotkeys(false);\n        enabled_ = false;\n        return;\n    }\n    plugin_.run();\n    const auto *currPlayer = d2rProcess_.currPlayer();\n    if (!currPlayer || !currPlayer->seed || !currPlayer->levelId) {\n        renderer_.owner()->enableHotkeys(false);\n        enabled_ = false;\n        return;\n    }\n    if (d2rProcess_.panelEnabled() & cfg->panelMask) {\n        enabled_ = false;\n    } else {\n        switch (cfg->show) {\n        case 0:enabled_ = !d2rProcess_.mapEnabled();\n            break;\n        case 1:enabled_ = d2rProcess_.mapEnabled();\n            break;\n        default:enabled_ = true;\n            break;\n        }\n    }\n    auto *hwnd = d2rProcess_.hwnd();\n    bool changed = false;\n    bool switched = false;\n    if (!currSession_ || currSession_->hwnd != hwnd) {\n        auto &session = sessions_[hwnd];\n        if (!session) {\n            session = std::make_unique<MapRenderSession>();\n            session->hwnd = hwnd;\n            changed = true;\n        }\n        currSession_ = session.get();\n        nextPanelUpdateTime_ = util::getCurrTime();\n        switched = true;\n    }\n    if (currSession_->currSeed != currPlayer->seed) {\n        plugin_.onEnterGame();\n        currSession_->currSeed = currPlayer->seed;\n        currSession_->mapStartTime = util::getCurrTime();\n        changed = true;\n    }\n    if (changed || currSession_->currDifficulty != currPlayer->difficulty) {\n        currSession_->maps.clear();\n        currSession_->currMap = nullptr;\n        currSession_->currDifficulty = currPlayer->difficulty;\n        changed = true;\n    }\n    if (!enabled_) {\n        return;\n    }\n    if (uint32_t levelId = currPlayer->levelId; levelId != currSession_->currLevelId) {\n        currSession_->currLevelId = levelId;\n        changed = true;\n    }\n    if (forceFlush_) {\n        forceFlush_ = false;\n        changed = true;\n    }\n    if (changed) {\n        currSession_->textStrings.clear();\n        currSession_->lines.clear();\n        auto *currMap = getMap(currSession_->currLevelId);\n        currSession_->currMap = currMap;\n        if (!currMap) {\n            enabled_ = false;\n            return;\n        }\n        auto originX = currMap->offset.x, originY = currMap->offset.y;\n        std::map<uint32_t, const d2mapapi::CollisionMap *> knownMaps;\n        int x0 = currMap->crop.x0, y0 = currMap->crop.y0,\n            x1 = currMap->crop.x1, y1 = currMap->crop.y1;\n        int totalX0 = originX + x0, totalY0 = originY + y0, totalX1 = originX + x1, totalY1 = originY + y1;\n        auto cx = currMap->offset.x + (x1 + x0) / 2;\n        auto cy = currMap->offset.y + (y1 + y0) / 2;\n        if (cfg->neighbourMapBounds != 0) {\n            auto bounds = cfg->neighbourMapBounds > 0 ? cfg->neighbourMapBounds : 2048;\n            auto steps = cfg->neighbourMapBounds < 0 ? -cfg->neighbourMapBounds : 32;\n            auto mx0 = std::max(0, cx - bounds);\n            auto my0 = std::max(0, cy - bounds);\n            auto mx1 = cx + bounds;\n            auto my1 = cy + bounds;\n            std::vector<std::pair<const d2mapapi::CollisionMap *, int>> mapsToProcess = {{currMap, 0}};\n            while (!mapsToProcess.empty()) {\n                const auto[map, step] = mapsToProcess.back();\n                mapsToProcess.pop_back();\n                knownMaps[map->id] = map;\n                if (step >= steps) { continue; }\n                for (auto &p: map->exits) {\n                    if (p.second.isPortal) { continue; }\n                    if (knownMaps.find(p.first) != knownMaps.end()) { continue; }\n                    auto *nearMap = getMap(p.first);\n                    if (nearMap) {\n                        mapsToProcess.emplace_back(nearMap, step + 1);\n                    }\n                }\n            }\n            knownMaps.erase(currMap->id);\n            for (auto ite = knownMaps.begin(); ite != knownMaps.end();) {\n                auto tx0 = ite->second->offset.x + ite->second->crop.x0;\n                auto ty0 = ite->second->offset.y + ite->second->crop.y0;\n                auto tx1 = ite->second->offset.x + ite->second->crop.x1;\n                auto ty1 = ite->second->offset.y + ite->second->crop.y1;\n                if (tx0 < mx0 || ty0 < my0 || tx1 > mx1 || ty1 > my1) {\n                    ite = knownMaps.erase(ite);\n                    continue;\n                } else {\n                    if (tx0 < totalX0) { totalX0 = tx0; }\n                    if (ty0 < totalY0) { totalY0 = ty0; }\n                    if (tx1 > totalX1) { totalX1 = tx1; }\n                    if (ty1 > totalY1) { totalY1 = ty1; }\n                    ++ite;\n                }\n            }\n        }\n        currSession_->x0 = totalX0;\n        currSession_->y0 = totalY0;\n        currSession_->x1 = totalX1;\n        currSession_->y1 = totalY1;\n        currSession_->cx = cx;\n        currSession_->cy = cy;\n        int width = totalX1 - totalX0;\n        int height = totalY1 - totalY0;\n        auto *pixels = new uint32_t[width * height];\n        memset(pixels, 0, sizeof(uint32_t) * width * height);\n        auto walkableColor = cfg->walkableColor;\n        if (walkableColor == 0) { walkableColor = 1; }\n        auto edgeColor = cfg->edgeColor;\n        auto &mapData = currSession_->mapData;\n        mapData.clear();\n        mapData.resize(width * height);\n        auto mapDataToPixels = [](uint32_t *pixels,\n                                  const uint8_t *data,\n                                  int pitch,\n                                  int ox,\n                                  int oy,\n                                  int w,\n                                  int h,\n                                  const uint32_t *colorTable) {\n            int x = ox, y = oy;\n            int skip = pitch - w;\n            auto *ptr = data + y * pitch + x;\n            auto *out = pixels + y * pitch + x;\n            for (; h; h--) {\n                for (int z = w; z; z--) {\n                    *out++ = colorTable[*ptr++];\n                }\n                ptr += skip;\n                out += skip;\n            }\n        };\n        int ox = currMap->offset.x - totalX0, oy = currMap->offset.y - totalY0;\n        currMap->extractCellData<uint8_t>(mapData.data(), width, height, ox, oy, 0, 1, 2);\n        const uint32_t colorTable[3] = {0u, walkableColor, edgeColor};\n        mapDataToPixels(pixels, mapData.data(), width, ox, oy,\n                        currMap->crop.x1 - currMap->crop.x0, currMap->crop.y1 - currMap->crop.y0, colorTable);\n        for (auto &p: knownMaps) {\n            ox = p.second->offset.x - totalX0, oy = p.second->offset.y - totalY0;\n            p.second->extractCellData<uint8_t>(mapData.data(), width, height, ox, oy, 0, 1, 2);\n            mapDataToPixels(pixels, mapData.data(), width, ox, oy,\n                            p.second->crop.x1 - p.second->crop.x0, p.second->crop.y1 - p.second->crop.y0, colorTable);\n        }\n        auto &mapTex = currSession_->mapTex;\n        mapTex.setData(width, height, pixels);\n        delete[] pixels;\n\n        const std::set<int> *guides;\n        {\n            auto gdite = data::gamedata->guides.find(currSession_->currLevelId);\n            if (gdite != data::gamedata->guides.end()) {\n                guides = &gdite->second;\n            } else {\n                guides = nullptr;\n            }\n        }\n\n        render::PipelineSquad2D squadPip(mapTex);\n        squadPip.setOrtho(0, float(mapTex.width()), 0, float(mapTex.height()));\n        auto widthf = float(x1 - x0) * .5f, heightf = float(y1 - y0) * .5f;\n        auto realTombLevelId = d2rProcess_.realTombLevelId();\n        auto superUniqueTombLevelId = d2rProcess_.superUniqueTombLevelId();\n        for (auto &p: currMap->exits) {\n            if (p.first >= data::gamedata->levels.size()) { continue; }\n            for (auto &e: p.second.offsets) {\n                auto px = float(e.x - totalX0);\n                auto py = float(e.y - totalY0);\n                const auto *lngarr = data::gamedata->levels[p.first].second;\n                std::wstring name = lngarr ? (*lngarr)[lng_] : L\"\";\n                auto rx = float(e.x - currSession_->cx), ry = float(e.y - currSession_->cy);\n                /* Check for TalTombs */\n                if (p.first == realTombLevelId) {\n                    name = L\">>> \" + name + L\" <<<\";\n                    currSession_->lines.emplace_back(rx, ry);\n                }\n                if (p.first == superUniqueTombLevelId) {\n                    name += L\" <== SuperUnique\";\n                }\n                squadPip.pushQuad(px - 4, py - 4, px + 4, py + 4, objColors_[data::TypePortal]);\n                currSession_->textStrings\n                    .emplace_back(rx, ry, name, float(ttf_->stringWidth(name, cfg->fontSize)) * .5f);\n                if (guides && (*guides).find(p.first) != (*guides).end()) {\n                    currSession_->lines.emplace_back(rx, ry);\n                }\n            }\n        }\n        const std::map<uint32_t, std::vector<d2mapapi::Point>> *objs[2] = {&currMap->objects, &currMap->npcs};\n        for (int i = 0; i < 2; ++i) {\n            for (const auto &[id, vec]: *objs[i]) {\n                auto ite = data::gamedata->objects[i].find(id);\n                if (ite == data::gamedata->objects[i].end()) { continue; }\n                for (auto &pt: vec) {\n                    auto ptx = float(pt.x - totalX0);\n                    auto pty = float(pt.y - totalY0);\n                    auto tp = std::get<0>(ite->second);\n                    switch (tp) {\n                    case data::TypeDoor: {\n                        float w = std::get<3>(ite->second) * .5f, h = std::get<4>(ite->second) * .5f;\n                        squadPip.pushQuad(ptx - w, pty - h, ptx + w, pty + h, objColors_[tp]);\n                        break;\n                    }\n                    case data::TypeWayPoint:\n                    case data::TypeQuest:\n                    case data::TypePortal:\n                    case data::TypeChest:\n                    case data::TypeShrine:\n                    case data::TypeWell: {\n                        auto sizeMinimal = cfg->objectSizeMinimal;\n                        float w = tp == data::TypePortal ? 4.f : (std::max(sizeMinimal, std::get<3>(ite->second)) * .5f);\n                        float h = tp == data::TypePortal ? 4.f : (std::max(sizeMinimal, std::get<4>(ite->second)) * .5f);\n                        squadPip.pushQuad(ptx - w, pty - h, ptx + w, pty + h, objColors_[tp]);\n                        if (tp != data::TypeShrine && tp != data::TypeWell) {\n                            const auto *lngarr = std::get<2>(ite->second);\n                            std::wstring name = lngarr ? (*lngarr)[lng_] : L\"\";\n                            currSession_->textStrings.emplace_back(float(pt.x - currSession_->cx),\n                                                                   float(pt.y - currSession_->cy),\n                                                                   name,\n                                                                   float(ttf_->stringWidth(name, cfg->fontSize)) * .5f);\n                        }\n                        if (guides && (*guides).find(id | (0x10000 * (i + 1))) != (*guides).end()) {\n                            currSession_->lines\n                                .emplace_back(float(pt.x - currSession_->cx), float(pt.y - currSession_->cy));\n                        }\n                        break;\n                    }\n                    default: break;\n                    }\n                }\n            }\n        }\n        squadPip.render();\n        renderer_.owner()->enableHotkeys(true);\n        enabled_ = true;\n    } else {\n        auto on = currSession_->currMap != nullptr;\n        renderer_.owner()->enableHotkeys(on);\n        enabled_ = on;\n    }\n    if (switched || changed) {\n        if (auto *currMap = currSession_->currMap) {\n            int x0 = currSession_->x0, y0 = currSession_->y0,\n                x1 = currSession_->x1, y1 = currSession_->y1,\n                cx = currSession_->cx, cy = currSession_->cy;\n            mapPipeline_.reset();\n            mapPipeline_.setTexture(currSession_->mapTex);\n            mapPipeline_.pushQuad(float(x0 - cx), float(y0 - cy), float(x1 - cx), float(y1 - cy));\n            updateWindowPos();\n        }\n    }\n}\n\nvoid MapRenderer::render() {\n    if (!enabled_) { return; }\n    dynamicTextStrings_.clear();\n    dynamicPipeline_.reset();\n    messagePipeline_.reset();\n    updatePlayerPos();\n    mapPipeline_.render();\n    framePipeline_.render();\n    drawObjects();\n    dynamicPipeline_.render();\n    messagePipeline_.render();\n    auto fontSize = cfg->fontSize;\n    for (const auto &[x, y, text, offX]: currSession_->textStrings) {\n        if (text.empty()) { continue; }\n        auto coord = transform_ * HMM_Vec4(x - 4.f, y - 4.f, 0, 1);\n        ttf_->render(text, coord.X - offX, coord.Y - fontSize, false, fontSize);\n    }\n    for (const auto &s: dynamicTextStrings_) {\n        auto coord = transform_ * HMM_Vec4(s.x - 4.f, s.y - 4.f, 0, 1);\n        ttf_->render(std::string_view(s.text), coord.X - s.offX, coord.Y - fontSize, false, fontSize);\n    }\n    for (auto[sv, x, y, fsize, color]: textToDraw_) {\n        ttf_->render(sv, x, y, false, fsize, color);\n    }\n    for (auto[sv, x, y, fsize, color]: msgToDraw_) {\n        ttf_->render(sv, x, y, false, fsize, color);\n    }\n    textToDraw_.clear();\n    msgToDraw_.clear();\n    updatePanelText();\n    if (!panelText_.empty() || !pluginTextMap_.empty()) {\n        int vw, vh;\n        renderer_.getDimension(vw, vh);\n        if (!panelText_.empty()) {\n            auto cx = float(vw) * cfg->panelPositionX;\n            auto cy = float(vh) * cfg->panelPositionY;\n            auto align = cfg->panelAlign;\n            auto fontSize2 = cfg->msgFontSize;\n            for (const auto &s: panelText_) {\n                float nx;\n                switch (align) {\n                case 1:nx = cx - float(ttf_->stringWidth(s, fontSize2)) * .5f;\n                    break;\n                case 2:nx = cx - float(ttf_->stringWidth(s, fontSize2));\n                    break;\n                default:nx = cx;\n                    break;\n                }\n                ttf_->render(s, nx, cy, false, fontSize2, 0);\n                cy = cy + fontSize2 + 2;\n            }\n        }\n        for (auto &[key, ptext]: pluginTextMap_) {\n            auto cx = float(vw) * (ptext.x - 0.5f);\n            auto cy = float(vh) * (ptext.y - 0.5f);\n            auto align = ptext.align;\n            auto valign = ptext.valign;\n            auto fontSize2 = cfg->msgFontSize;\n            auto now = util::getCurrTime();\n            for (auto ite = ptext.textList.begin(); ite != ptext.textList.end();) {\n                if (now >= ite->timeout) {\n                    ptext.textList.erase(ite);\n                    continue;\n                }\n                const auto &s = ite->text;\n                auto fsize = ite->fontSize;\n                if (!fsize) fsize = fontSize2;\n                float nx;\n                float sw;\n                switch (align) {\n                case 1:sw = float(ttf_->stringWidth(s, fsize));\n                    nx = cx - sw * .5f;\n                    break;\n                case 2:sw = float(ttf_->stringWidth(s, fsize));\n                    nx = cx - sw;\n                    break;\n                default:nx = cx;\n                    break;\n                }\n                if (valign) {\n                    cy = cy - fsize + 2;\n                }\n                ttf_->render(s, nx, cy, false, fsize, 0);\n                if (!valign) {\n                    cy = cy + fsize + 2;\n                }\n                ++ite;\n            }\n        }\n    }\n}\n\nplugin::PluginTextList &MapRenderer::getPluginText(const std::string &key) {\n    return pluginTextMap_[key];\n}\n\nvoid MapRenderer::removePluginText(const std::string &key) {\n    pluginTextMap_.erase(key);\n}\n\nvoid MapRenderer::updateWindowPos() {\n    if (!currSession_) { return; }\n    auto *currMap = currSession_->currMap;\n    if (!currMap) { return; }\n    auto width = d2rRect.right - d2rRect.left, height = d2rRect.bottom - d2rRect.top;\n    renderer_.owner()->move(d2rRect.left, d2rRect.top, width, height);\n\n    int x0 = currMap->crop.x0, y0 = currMap->crop.y0, x1 = currMap->crop.x1, y1 = currMap->crop.y1;\n    int w, h;\n    auto mw = float(x1 - x0) * .5f, mh = float(y1 - y0) * .5f;\n    if (cfg->mapAreaW > .0f) {\n        w = std::lround(float(width) * cfg->mapAreaW);\n        h = std::lround(float(height) * cfg->mapAreaH);\n    } else {\n        if (cfg->position == 2) {\n            w = std::lround(float(width));\n            h = std::lround(float(height));\n        } else {\n            w = (int)lroundf(cfg->scale * (mw + mh) * 1.42f /* sqrt(2) */) + cfg->fontSize;\n            h = w / 2;\n        }\n    }\n    auto widthf = float(w) * 0.5f, heightf = float(h) * 0.5f;\n\n    switch (cfg->position) {\n    case 0:\n        mapViewport_[0] = 0;\n        mapViewport_[1] = height - h;\n        break;\n    case 1:\n        mapViewport_[0] = width - w;\n        mapViewport_[1] = height - h;\n        break;\n    default:\n        mapViewport_[0] = (width - w) / 2;\n        mapViewport_[1] = (height - h) / 2;\n        break;\n    }\n    mapViewport_[2] = w;\n    mapViewport_[3] = h;\n    if (!cfg->drawOnGameBar && mapViewport_[1] < height / 5) {\n        for (int i = 0; i < 4; i++) {\n            scissor_[i] = mapViewport_[i];\n        }\n        auto delta = height / 5 - scissor_[1];\n        scissor_[1] += delta;\n        scissor_[3] -= delta;\n    } else {\n        scissor_[0] = scissor_[1] = scissor_[2] = scissor_[3] = 0;\n    }\n\n    mapPipeline_.setViewport(mapViewport_[0], mapViewport_[1], mapViewport_[2], mapViewport_[3]);\n    mapPipeline_.setScissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);\n    mapPipeline_.setOrtho(-widthf, widthf, heightf, -heightf);\n    framePipeline_.setViewport(mapViewport_[0], mapViewport_[1], mapViewport_[2], mapViewport_[3]);\n    framePipeline_.setScissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);\n    framePipeline_.reset();\n    framePipeline_.setOrtho(-widthf, widthf, heightf, -heightf);\n    dynamicPipeline_.setViewport(mapViewport_[0], mapViewport_[1], mapViewport_[2], mapViewport_[3]);\n    dynamicPipeline_.setScissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);\n    dynamicPipeline_.reset();\n    dynamicPipeline_.setOrtho(-widthf, widthf, heightf, -heightf);\n    auto *ttfPipeline = ttfgl_.pipeline();\n    ttfPipeline->setViewport(mapViewport_[0], mapViewport_[1], mapViewport_[2], mapViewport_[3]);\n    ttfPipeline->setScissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);\n    ttfPipeline->setOrtho(-widthf, widthf, heightf, -heightf);\n    widthf = float(width) * .5f;\n    heightf = float(height) * .5f;\n    messagePipeline_.setViewport(0, 0, width, height);\n    if (scissor_[2]) {\n        messagePipeline_.setScissor(0, height - height / 4, width, height);\n    }\n    messagePipeline_.reset();\n    messagePipeline_.setOrtho(-widthf, widthf, heightf, -heightf);\n}\n\nvoid MapRenderer::reloadConfig() {\n    loadFromCfg();\n    d2rProcess_.reloadConfig();\n}\n\nvoid MapRenderer::updatePlayerPos() {\n    auto cx = currSession_->cx, cy = currSession_->cy;\n    const auto *currPlayer = d2rProcess_.currPlayer();\n    bool showPlayerNames = cfg->showPlayerNames;\n    framePipeline_.reset();\n    auto currAct = currPlayer->act;\n    for (const auto &[id, plr]: d2rProcess_.players()) {\n        if (plr.act != currAct) { continue; }\n        auto posX = plr.posX;\n        auto posY = plr.posY;\n        auto oxf = float(posX - cx);\n        auto oyf = float(posY - cy);\n        if (showPlayerNames && plr.name[0]) {\n            dynamicTextStrings_.emplace_back(DynamicTextString{oxf, oyf, plr.name,\n                                                               float(ttf_->stringWidth(plr.name, cfg->fontSize))\n                                                                   * .5f});\n        }\n        if (&plr == currPlayer) {\n            if (currSession_->lastPosX != posX / 5 || currSession_->lastPosY != posY / 5) {\n                currSession_->lastPosX = posX / 5;\n                currSession_->lastPosY = posY / 5;\n                currSession_->path.clear();\n                if (!currSession_->lines.empty() && !currSession_->currMap->path.empty()) {\n                    auto *currMap = currSession_->currMap;\n                    auto [x0, y0, x1, y1] = currMap->crop;\n                    int mw = (x1 - x0) / 5;\n                    int mh = (y1 - y0) / 5;\n                    int offX = (currMap->offset.x + x0) / 5;\n                    int offY = (currMap->offset.y + y0) / 5;\n                    for (auto [rx, ry]: currSession_->lines) {\n                        int x = (std::lround(rx) + currSession_->cx) / 5 - offX;\n                        int y = (std::lround(ry) + currSession_->cy) / 5 - offY;\n                        int toX = currSession_->lastPosX - offX;\n                        int toY = currSession_->lastPosY - offY;\n                        auto &path = currMap->path;\n                        if (!path[y * mw + x]) {\n                            int deltaX[4], deltaY[4];\n                            if (x < toX) {\n                                if (y < toY) {\n                                    if (toX - x < toY - y) {\n                                        deltaX[0] = 0;\n                                        deltaY[0] = -1;\n                                        deltaX[1] = -1;\n                                        deltaY[1] = 0;\n                                    } else {\n                                        deltaX[0] = -1;\n                                        deltaY[0] = 0;\n                                        deltaX[1] = 0;\n                                        deltaY[1] = -1;\n                                    }\n                                } else {\n                                    if (toX - x < y - toY) {\n                                        deltaX[0] = 0;\n                                        deltaY[0] = 1;\n                                        deltaX[1] = -1;\n                                        deltaY[1] = 0;\n                                    } else {\n                                        deltaX[0] = -1;\n                                        deltaY[0] = 0;\n                                        deltaX[1] = 0;\n                                        deltaY[1] = 1;\n                                    }\n                                }\n                            } else {\n                                if (y < toY) {\n                                    if (x - toX < toY - y) {\n                                        deltaX[0] = 0;\n                                        deltaY[0] = -1;\n                                        deltaX[1] = 1;\n                                        deltaY[1] = 0;\n                                    } else {\n                                        deltaX[0] = 1;\n                                        deltaY[0] = 0;\n                                        deltaX[1] = 0;\n                                        deltaY[1] = -1;\n                                    }\n                                } else {\n                                    if (x - toX < y - toY) {\n                                        deltaX[0] = 0;\n                                        deltaY[0] = 1;\n                                        deltaX[1] = 1;\n                                        deltaY[1] = 0;\n                                    } else {\n                                        deltaX[0] = 1;\n                                        deltaY[0] = 0;\n                                        deltaX[1] = 0;\n                                        deltaY[1] = 1;\n                                    }\n                                }\n                            }\n                            deltaX[2] = -deltaX[0];\n                            deltaY[2] = -deltaY[0];\n                            deltaX[3] = -deltaX[1];\n                            deltaY[3] = -deltaY[1];\n                            bool found = false;\n                            for (int i = 0; i < 4; ++i) {\n                                auto nx = x + deltaX[i];\n                                auto ny = y + deltaY[i];\n                                if (nx >= 0 && nx < mw && ny >= 0 && ny < mh && path[ny * mw + nx]) {\n                                    x = nx; y = ny;\n                                    found = true;\n                                }\n                            }\n                            if (!found) { continue; }\n                        }\n                        auto res = d2mapapi::pathFindBFS(x, y, toX, toY, path.data(), mw, mh, true);\n                        if (!res.empty()) {\n                            currSession_->path.emplace_back(std::move(res));\n                        }\n                    }\n                }\n            }\n            framePipeline_.pushQuad(oxf - 4, oyf - 4, oxf - 2, oyf + 4, cfg->playerOuterColor);\n            framePipeline_.pushQuad(oxf + 2, oyf - 4, oxf + 4, oyf + 4, cfg->playerOuterColor);\n            framePipeline_.pushQuad(oxf - 2, oyf - 4, oxf + 2, oyf - 2, cfg->playerOuterColor);\n            framePipeline_.pushQuad(oxf - 2, oyf + 2, oxf + 2, oyf + 4, cfg->playerOuterColor);\n            framePipeline_.pushQuad(oxf - 2, oyf - 2, oxf + 2, oyf + 2, cfg->playerInnerColor);\n            auto c = cfg->lineColor;\n            auto lineStyle = cfg->lineStyle;\n            if (lineStyle == 2 && !currSession_->path.empty()) {\n                auto *currMap = currSession_->currMap;\n                auto [x0, y0, x1, y1] = currMap->crop;\n                auto [offX, offY] = currMap->offset;\n                for (auto &path: currSession_->path) {\n                    size_t psz = path.size();\n                    for (size_t i = 1; i < psz; ++i) {\n                        auto[x, y] = path[i - 1];\n                        auto sx = float(x * 5 + 2 + x0 + offX - cx);\n                        auto sy = float(y * 5 + 2 + y0 + offY - cy);\n                        x = path[i].first;\n                        y = path[i].second;\n                        auto ex = float(x * 5 + 2 + x0 + offX - cx);\n                        auto ey = float(y * 5 + 2 + y0 + offY - cy);\n                        framePipeline_.drawLine(sx, sy, ex, ey, 1.5f, c);\n                    }\n                }\n            } else {\n                for (auto [x, y]: currSession_->lines) {\n                    if (lineStyle) {\n                        auto line = HMM_Vec2(x, y) - HMM_Vec2(oxf, oyf);\n                        auto len = HMM_Length(line);\n                        auto sx = oxf + line.X / len * 8.f;\n                        auto sy = oyf + line.Y / len * 8.f;\n                        auto ex = x - line.X / len * 8.f;\n                        auto ey = y - line.Y / len * 8.f;\n                        if (len < 17.f) {\n                            ex = sx;\n                            ey = sy;\n                        }\n                        framePipeline_.drawLine(sx, sy, ex, ey, 1.5f, c);\n                    } else {\n                        const float mlen = 78.f;\n                        const float gap = 12.f;\n                        float sx, sy, ex, ey;\n                        auto line = HMM_Vec2(x, y) - HMM_Vec2(oxf, oyf);\n                        auto len = HMM_Length(line);\n                        sx = oxf + line.X / len * 8.f;\n                        sy = oyf + line.Y / len * 8.f;\n                        if (len > mlen) {\n                            ex = oxf + line.X / len * (mlen - gap);\n                            ey = oyf + line.Y / len * (mlen - gap);\n                        } else if (len > gap) {\n                            ex = x - line.X / len * gap;\n                            ey = y - line.Y / len * gap;\n                        } else {\n                            ex = sx;\n                            ey = sy;\n                        }\n\n                        /* Draw the line */\n                        framePipeline_.drawLine(sx, sy, ex, ey, 1.5f, c);\n\n                        /* Draw the dot */\n                        if (ex != sx) {\n                            ex += line.X / len * gap;\n                            ey += line.Y / len * gap;\n                            framePipeline_\n                                .pushQuad(ex - 3, ey - 3, ex + 1.5f, ey - 1.5f, ex + 3, ey + 3, ex - 1.5f, ey + 1.5f, c);\n                        }\n                    }\n                }\n            }\n\n            transform_ = HMM_Scale(HMM_Vec3(1, .5f, 1.f))\n                * HMM_Rotate(45.f, HMM_Vec3(0, 0, 1))\n                * HMM_Scale(HMM_Vec3(cfg->scale, cfg->scale, 1));\n            if (cfg->mapCentered) {\n                transform_ = transform_ * HMM_Translate(HMM_Vec3(-oxf, -oyf, 0));\n            }\n            mapPipeline_.setTransform(&transform_.Elements[0][0]);\n            framePipeline_.setTransform(&transform_.Elements[0][0]);\n            dynamicPipeline_.setTransform(&transform_.Elements[0][0]);\n        } else {\n            auto inParty = plr.party != uint16_t(-1) && plr.party == currPlayer->party;\n            auto outerColor = inParty ? cfg->playerOuterColor : cfg->nonPartyPlayerOuterColor;\n            auto innerColor = inParty ? cfg->playerInnerColor : cfg->nonPartyPlayerInnerColor;\n            framePipeline_.pushQuad(oxf - 4, oyf - 4, oxf - 2, oyf + 4, outerColor);\n            framePipeline_.pushQuad(oxf + 2, oyf - 4, oxf + 4, oyf + 4, outerColor);\n            framePipeline_.pushQuad(oxf - 2, oyf - 4, oxf + 2, oyf - 2, outerColor);\n            framePipeline_.pushQuad(oxf - 2, oyf + 2, oxf + 2, oyf + 4, outerColor);\n            framePipeline_.pushQuad(oxf - 2, oyf - 2, oxf + 2, oyf + 2, innerColor);\n        }\n    }\n}\nvoid MapRenderer::drawObjects() {\n    auto &mons = d2rProcess_.monsters();\n    auto &objs = d2rProcess_.objects();\n    auto &items = d2rProcess_.items();\n    auto fontSize = cfg->fontSize;\n    if (!mons.empty() || !objs.empty() || !items.empty()) {\n        auto *currMap = currSession_->currMap;\n        auto ctx = currSession_->cx, cty = currSession_->cy;\n        for (const auto &mon: mons) {\n            auto x = float(mon.x - ctx);\n            auto y = float(mon.y - cty);\n            dynamicPipeline_.pushQuad(x - 1.5f,\n                                      y - 1.5f,\n                                      x + 1.5f,\n                                      y + 1.5f,\n                                      objColors_[mon.isNpc ? data::TypeNpc : mon.isUnique ? data::TypeUniqueMonster\n                                                                                          : data::TypeMonster]);\n            if (mon.name) {\n                auto coord = transform_ * HMM_Vec4(x - 1.f, y - 1.f, 0, 1);\n                std::wstring_view sv = (*mon.name)[lng_];\n                textToDraw_.emplace_back(sv,\n                                         coord.X - float(ttf_->stringWidth(sv, fontSize)) * .5f,\n                                         coord.Y - fontSize,\n                                         fontSize,\n                                         0);\n                if (mon.enchants[0]) {\n                    std::wstring_view svenc = mon.enchants;\n                    textToDraw_.emplace_back(svenc,\n                                             coord.X - float(ttf_->stringWidth(svenc, fontSize)) * .5f,\n                                             coord.Y - fontSize * 2.f,\n                                             fontSize,\n                                             0);\n                }\n            } else {\n                if (mon.enchants[0]) {\n                    auto coord = transform_ * HMM_Vec4(x - 1.f, y - 1.f, 0, 1);\n                    std::wstring_view svenc = mon.enchants;\n                    textToDraw_.emplace_back(svenc,\n                                             coord.X - float(ttf_->stringWidth(svenc, fontSize)) * .5f,\n                                             coord.Y - fontSize,\n                                             fontSize,\n                                             0);\n                }\n            }\n        }\n        for (const auto &p: objs) {\n            const auto &obj = p.second;\n            auto x = float(obj.x - ctx);\n            auto y = float(obj.y - cty);\n            auto sizeMinimal = cfg->objectSizeMinimal * 0.5f;\n            auto dw = std::max(sizeMinimal, obj.w), dh = std::max(sizeMinimal, obj.h);\n            dynamicPipeline_.pushQuad(x - dw, y - dh, x + dw, y + dh, objColors_[obj.type]);\n            if (obj.name) {\n                auto coord = transform_ * HMM_Vec4(x - dw, y - dh, 0, 1);\n                std::wstring_view sv = (*obj.name)[lng_];\n                /* if type is Portal, the portal target level is stored in field `flag` */\n                if (obj.type == data::TypePortal && obj.flag < data::gamedata->levels.size()) {\n                    const auto *lngarr = data::gamedata->levels[obj.flag].second;\n                    if (lngarr) {\n                        sv = (*lngarr)[lng_];\n                    }\n                }\n                textToDraw_.emplace_back(sv,\n                                         coord.X - float(ttf_->stringWidth(sv, fontSize)) * .5f,\n                                         coord.Y - fontSize,\n                                         fontSize,\n                                         0);\n            }\n        }\n        if (!items.empty()) {\n            int vw, vh;\n            renderer_.getDimension(vw, vh);\n            auto cx = float(vw) * cfg->msgPositionX;\n            auto cy = float(vh) * cfg->msgPositionY;\n            auto align = cfg->msgAlign;\n            auto fontSize2 = cfg->msgFontSize;\n            for (const auto &item: items) {\n                std::wstring_view sv = (*item.name)[lng_];\n                if (item.flag & 1) {\n                    auto x = float(item.x - ctx);\n                    auto y = float(item.y - cty);\n                    dynamicPipeline_.pushQuad(x - 1.5f, y - 1.5f, x + 1.5f, y + 1.5f, 0xFFFFFFFF);\n                    if (item.name) {\n                        auto coord = transform_ * HMM_Vec4(x - 4.f, y - 4.f, 0, 1);\n                        textToDraw_.emplace_back(sv,\n                                                 coord.X - float(ttf_->stringWidth(sv, fontSize)) * .5f,\n                                                 coord.Y - fontSize,\n                                                 fontSize,\n                                                 item.color);\n                    }\n                }\n                if (item.flag & 2) {\n                    auto txtw = float(ttf_->stringWidth(sv, fontSize2));\n                    float nx;\n                    switch (align) {\n                    case 1:nx = cx - txtw * .5f;\n                        break;\n                    case 2:nx = cx - txtw;\n                        break;\n                    default:nx = cx;\n                        break;\n                    }\n                    messagePipeline_.pushQuad(nx - 1.f, cy - 1.f, nx + 1.f + txtw, cy + 1.f + fontSize2, cfg->msgBgColor);\n                    msgToDraw_.emplace_back(sv, nx, cy, fontSize2, item.color);\n                    cy = cy + fontSize2 + 2;\n                }\n            }\n        }\n    }\n}\n\nvoid MapRenderer::updatePanelText() {\n    auto now = util::getCurrTime();\n    if (now < nextPanelUpdateTime_) {\n        return;\n    }\n    nextPanelUpdateTime_ = now + std::chrono::seconds(1);\n    const auto &panels = cfg->panelPatterns;\n    auto size = panels.size();\n    panelText_.resize(size);\n    for (size_t i = 0; i < size; ++i) {\n        const auto &pat = panels[i];\n        auto &target = panelText_[i];\n        target.clear();\n        size_t len = pat.size();\n        size_t pos = 0;\n        while (pos < len) {\n            if (pat[pos] == '{') {\n                ++pos;\n                auto start = pos;\n                while (pos < len && pat[pos] != '}') ++pos;\n                if (pos >= len) { break; }\n                std::wstring_view sv(pat.data() + start, pos - start);\n                if (sv == L\"duration\") {\n                    wchar_t n[16];\n                    auto dur =\n                        uint32_t(std::chrono::duration_cast<std::chrono::seconds>(now - currSession_->mapStartTime)\n                                     .count());\n                    if (dur < 3600) {\n                        wsprintfW(n, L\"%02u:%02u\", dur / 60, dur % 60);\n                    } else {\n                        wsprintfW(n, L\"%u:%02u:%02u\", dur / 3600, (dur % 3600) / 60, dur % 60);\n                    }\n                    target += n;\n                } else if (sv == L\"time\") {\n                    wchar_t n[16];\n                    auto currUnixTime = time(nullptr);\n                    struct tm tm = {};\n                    localtime_s(&tm, &currUnixTime);\n                    wcsftime(n, 16, L\"%H:%M:%S\", &tm);\n                    target += n;\n                } else if (sv == L\"timea\") {\n                    wchar_t n[16];\n                    auto currUnixTime = time(nullptr);\n                    struct tm tm = {};\n                    localtime_s(&tm, &currUnixTime);\n                    wcsftime(n, 16, L\"%I:%M:%S %p\", &tm);\n                    target += n;\n                } else if (sv == L\"difficulty\") {\n                    const auto *cpl = d2rProcess_.currPlayer();\n                    if (cpl) {\n                        static const char *diffKey[] =\n                            {\"strCreateGameNormalText\", \"strCreateGameNightmareText\", \"strCreateGameHellText\"};\n                        auto ite = data::gamedata->strings.find(diffKey[std::min(uint8_t(2), cpl->difficulty)]);\n                        if (ite != data::gamedata->strings.end()) {\n                            target += ite->second[lng_];\n                        }\n                    }\n                } else if (sv == L\"act\") {\n                    const auto *cpl = d2rProcess_.currPlayer();\n                    if (cpl) {\n                        static const wchar_t *actNames[] = {L\"ACT I\", L\"ACT II\", L\"ACT III\", L\"ACT IV\", L\"ACT V\"};\n                        target += actNames[std::min(4u, cpl->act)];\n                    }\n                } else if (sv == L\"mapname\") {\n                    const auto *cpl = d2rProcess_.currPlayer();\n                    if (cpl) {\n                        if (cpl->levelId < data::gamedata->levels.size()) {\n                            target += (*data::gamedata->levels[cpl->levelId].second)[lng_];\n                        }\n                    }\n                } else if (sv == L\"gamename\") {\n                    target += d2rProcess_.gameName();\n                } else if (sv == L\"gamepass\") {\n                    target += d2rProcess_.gamePass();\n                } else if (sv == L\"region\") {\n                    target += d2rProcess_.region();\n                } else if (sv == L\"season\") {\n                    target += d2rProcess_.season();\n                }\n            } else {\n                target += pat[pos];\n            }\n            ++pos;\n        }\n    }\n}\n\nvoid MapRenderer::loadFromCfg() {\n    if (cfg->fontFilePath.empty()) {\n        ttf_ = std::make_unique<render::TTF>(ttfgl_);\n        if (!ttf_->add(cfg->fontFilePath, 0)) {\n            ttf_ = std::make_unique<render::D2Font>(ttfgl_);\n            ttf_->add(cfg->fontFilePath, cfg->msgFontSize);\n        }\n    } else {\n        auto pos = cfg->fontFilePath.find_last_of('.');\n        std::string ext;\n        if (pos != std::string::npos) {\n            ext = cfg->fontFilePath.substr(pos);\n        }\n        if (!strcasecmp(ext.c_str(), \".ttf\") || !strcasecmp(ext.c_str(), \".ttc\")\n            || !strcasecmp(ext.c_str(), \".otf\")) {\n            ttf_ = std::make_unique<render::TTF>(ttfgl_);\n            ttf_->add(cfg->fontFilePath, 0);\n        } else {\n            ttf_ = std::make_unique<render::D2Font>(ttfgl_);\n            std::string name = cfg->fontFilePath;\n            int sz = cfg->msgFontSize;\n            if (pos != std::string::npos) {\n                name.erase(pos);\n            }\n            pos = cfg->fontFilePath.find_last_of('|');\n            if (pos != std::string::npos) {\n                sz = int(strtol(cfg->fontFilePath.c_str() + pos + 1, nullptr, 0));\n                if (sz <= 0) {\n                    sz = cfg->msgFontSize;\n                }\n            }\n            /* Available D2 dc6 font sizes in px: 6, 8, 16, 24, 30 and 42 */\n            if (sz > 36) {\n                sz = 42;\n            } else if (sz > 27) {\n                sz = 30;\n            } else if (sz > 20) {\n                sz = 24;\n            } else if (sz > 12) {\n                sz = 16;\n            } else if (sz > 7) {\n                sz = 8;\n            } else {\n                sz = 6;\n            }\n            ttf_->add(name, sz);\n        }\n    }\n    lng_ = lngFromString(cfg->language);\n    objColors_[data::TypeWayPoint] = cfg->waypointColor;\n    objColors_[data::TypePortal] = cfg->portalColor;\n    objColors_[data::TypeChest] = cfg->chestColor;\n    objColors_[data::TypeQuest] = cfg->questColor;\n    objColors_[data::TypeShrine] = cfg->shrineColor;\n    objColors_[data::TypeWell] = cfg->wellColor;\n    objColors_[data::TypeMonster] = cfg->monsterColor;\n    objColors_[data::TypeUniqueMonster] = cfg->uniqueMonsterColor;\n    objColors_[data::TypeNpc] = cfg->npcColor;\n    objColors_[data::TypeDoor] = cfg->doorColor;\n    auto alpha = (cfg->textColor >> 24);\n    ttf_->setColor(cfg->textColor & 0xFF, (cfg->textColor >> 8) & 0xFF, (cfg->textColor >> 16) & 0xFF, alpha);\n    ttf_->setAltColor(1, 228, 88, 67, alpha);\n    ttf_->setAltColor(2, 31, 255, 0, alpha);\n    ttf_->setAltColor(3, 104, 104, 223, alpha);\n    ttf_->setAltColor(4, 192, 166, 130, alpha);\n    ttf_->setAltColor(5, 104, 104, 104, alpha);\n    ttf_->setAltColor(6, 0, 0, 0, alpha);\n    ttf_->setAltColor(7, 223, 202, 130, alpha);\n    ttf_->setAltColor(8, 255, 171, 41, alpha);\n    ttf_->setAltColor(9, 255, 239, 130, alpha);\n    ttf_->setAltColor(10, 31, 130, 10, alpha);\n    ttf_->setAltColor(11, 213, 41, 255, alpha);\n    ttf_->setAltColor(12, 52, 161, 26, alpha);\n    ttf_->setAltColor(13, 255, 255, 255, alpha);\n    ttf_->setAltColor(14, 255, 255, 255, alpha);\n    ttf_->setAltColor(15, 255, 255, 255, alpha);\n    plugin_.load();\n}\n\nd2mapapi::CollisionMap *MapRenderer::getMap(uint32_t levelId) {\n    if (!currSession_) { return nullptr; }\n    d2mapapi::CollisionMap *currMap;\n    auto &map = currSession_->maps[levelId];\n    if (!map) {\n        currMap = childProcess_.queryMap(currSession_->currSeed, currSession_->currDifficulty, levelId, cfg->lineStyle == 2);\n        map = std::unique_ptr<d2mapapi::CollisionMap>(currMap);\n    } else {\n        currMap = map.get();\n    }\n    return currMap->built ? currMap : nullptr;\n}\n\n}\n"
  },
  {
    "path": "src/ui/maprenderer.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include \"render/renderer.h\"\n#include \"render/font.h\"\n#include \"render/ttfgl.h\"\n#include \"render/HandmadeMath.h\"\n#include \"d2r/processmanager.h\"\n#include \"data/gamedata.h\"\n#include \"plugin/plugin.h\"\n\n#include \"collisionmap.h\"\n#include \"pipehost.h\"\n\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#include <windows.h>\n#include <vector>\n#include <map>\n#include <memory>\n#include <tuple>\n#include <string>\n#include <chrono>\n\nnamespace ui {\n\nenum LNG {\n    LNG_enUS,\n    LNG_zhTW,\n    LNG_deDE,\n    LNG_esES,\n    LNG_frFR,\n    LNG_itIT,\n    LNG_koKR,\n    LNG_plPL,\n    LNG_esMX,\n    LNG_jaJP,\n    LNG_ptBR,\n    LNG_ruRU,\n    LNG_zhCN,\n    LNG_MAX,\n};\n\nclass MapRenderer final {\n    struct MapRenderSession {\n        void *hwnd = nullptr;\n        render::Texture mapTex;\n        uint32_t currSeed = uint32_t(-1);\n        uint8_t currDifficulty = uint8_t(-1);\n        uint32_t currLevelId = 0;\n        std::map<uint32_t, std::unique_ptr<d2mapapi::CollisionMap>> maps;\n        std::vector<uint8_t> mapData;\n        int x0 = 0, y0 = 0, x1 = 0, y1 = 0, cx = 0, cy = 0;\n        int lastPosX = -1, lastPosY = -1;\n        const d2mapapi::CollisionMap *currMap = nullptr;\n        std::vector<std::tuple<float, float, std::wstring, float>> textStrings;\n        std::vector<std::tuple<float, float>> lines;\n        std::vector<std::vector<std::pair<int, int>>> path;\n        std::chrono::steady_clock::time_point mapStartTime;\n    };\npublic:\n    MapRenderer(render::Renderer &renderer, d2mapapi::PipedChildProcess &);\n    inline render::Renderer &getRenderer() { return renderer_; }\n    void update();\n    void render();\n    void reloadConfig();\n\n    void forceFlush() {\n        forceFlush_ = true;\n    }\n\n    plugin::PluginTextList &getPluginText(const std::string &key);\n    void removePluginText(const std::string &key);\n\nprivate:\n    void doUpdate();\n    void updateWindowPos();\n    void updatePlayerPos();\n    void drawObjects();\n    void updatePanelText();\n    void loadFromCfg();\n\n    d2mapapi::CollisionMap *getMap(uint32_t levelId);\n\nprivate:\n    render::Renderer &renderer_;\n    render::PipelineTexture2D mapPipeline_;\n    render::PipelineSquad2D framePipeline_;\n    render::PipelineSquad2D dynamicPipeline_;\n    render::PipelineSquad2D messagePipeline_;\n    d2r::ProcessManager d2rProcess_;\n    render::TTFRenderGL ttfgl_;\n    std::unique_ptr<render::Font> ttf_;\n    hmm_mat4 transform_ = {};\n    int mapViewport_[4] = {};\n    int scissor_[4] = {};\n\n    bool enabled_ = false;\n    RECT d2rRect = {};\n    LNG lng_ = LNG_enUS;\n\n    std::map<void*, std::unique_ptr<MapRenderSession>> sessions_;\n    MapRenderSession *currSession_ = nullptr;\n\n    struct DynamicTextString {\n        float x, y;\n        const char *text;\n        float offX;\n    };\n    std::vector<DynamicTextString> dynamicTextStrings_;\n    std::vector<std::tuple<std::wstring_view, float, float, int, uint8_t>> textToDraw_, msgToDraw_;\n\n    uint32_t objColors_[data::TypeMax] = {};\n\n    std::chrono::steady_clock::time_point nextPanelUpdateTime_;\n    std::vector<std::wstring> panelText_;\n\n    d2mapapi::PipedChildProcess &childProcess_;\n\n    bool forceFlush_ = false;\n    plugin::Plugin plugin_;\n    std::map<std::string, plugin::PluginTextList> pluginTextMap_;\n};\n\n}\n"
  },
  {
    "path": "src/ui/window.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#if defined(_MSC_VER)\n#pragma comment(linker,\"\\\"/manifestdependency:type='win32' \\\nname='Microsoft.Windows.Common-Controls' version='6.0.0.0' \\\nprocessorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#endif\n\n#include \"window.h\"\n\n#include \"util/util.h\"\n\n#include <windows.h>\n#include <versionhelpers.h>\n#include <dwmapi.h>\n#include <commctrl.h>\n#include <stdexcept>\n#include <map>\n#include <tuple>\n#include <string>\n\nEXTERN_C IMAGE_DOS_HEADER __ImageBase;\n#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)\n#define WM_TRAY_CALLBACK_MESSAGE (WM_USER + 1)\n\nnamespace ui {\n\nstruct MenuItem {\n    UINT id = 0;\n    HMENU submenu = nullptr;\n\n    std::wstring name;\n    int parent = 0;\n    unsigned flags = 0;\n    std::function<void()> cb;\n};\n\nstruct WindowCtx {\n    HWND hwnd = nullptr;\n    std::function<void(int, int)> sizeCB;\n    NOTIFYICONDATAW nid = {};\n    HMENU trayMenu = nullptr;\n    bool running = false;\n    UINT userMsg = WM_USER + 1;\n    std::map<UINT, MenuItem> trayMenuInfo;\n    struct {\n        bool enabled = false;\n        const wchar_t *icon = nullptr;\n        std::wstring tip, info, infoTitle;\n    } trayMenuBase;\n\n    std::map<int, std::tuple<UINT, UINT, std::function<void()>>> hotkeys;\n    bool hotkeysEnabled = false;\n};\n\nstatic bool updateFramebufferTransparency(HWND hwnd) {\n    BOOL composition, opaque;\n    DWORD color;\n\n    if (!IsWindowsVistaOrGreater())\n        return false;\n\n    if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)\n        return false;\n\n    if (IsWindows8OrGreater() ||\n        (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque)) {\n        HRGN region = CreateRectRgn(0, 0, -1, -1);\n        DWM_BLURBEHIND bb = {0};\n        bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;\n        bb.hRgnBlur = region;\n        bb.fEnable = TRUE;\n\n        DwmEnableBlurBehindWindow(hwnd, &bb);\n        MARGINS m = {-1};\n        DeleteObject(region);\n    } else {\n        DWM_BLURBEHIND bb = {0};\n        bb.dwFlags = DWM_BB_ENABLE;\n        DwmEnableBlurBehindWindow(hwnd, &bb);\n    }\n    return true;\n}\n\nstatic LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\n    static UINT taskbarRestartMsg;\n    switch (uMsg) {\n    case WM_CREATE: {\n        taskbarRestartMsg = RegisterWindowMessageW(L\"TaskbarCreated\");\n        break;\n    }\n    case WM_DESTROY: {\n        auto *ctx = ((Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA))->ctx();\n        if (ctx->nid.cbSize) {\n            Shell_NotifyIconW(NIM_DELETE, &ctx->nid);\n        }\n        ctx->running = false;\n        return 0;\n    }\n    case WM_CLOSE:\n        DestroyWindow(hwnd);\n        return 0;\n    case WM_SIZE: {\n        auto *wnd = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);\n        if (!wnd) { break; }\n        auto *ctx = wnd->ctx();\n        if (ctx->sizeCB) { ctx->sizeCB(LOWORD(lParam), HIWORD(lParam)); }\n        break;\n    }\n    case WM_TRAY_CALLBACK_MESSAGE:\n        if (lParam == WM_RBUTTONUP) {\n            POINT p;\n            GetCursorPos(&p);\n            SetForegroundWindow(hwnd);\n            auto *ctx = ((Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA))->ctx();\n            WORD cmd = TrackPopupMenu(ctx->trayMenu,\n                                      TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,\n                                      p.x, p.y, 0, hwnd, nullptr);\n            SendMessage(hwnd, WM_COMMAND, cmd, 0);\n            return 0;\n        }\n        break;\n    case WM_COMMAND: {\n        auto *ctx = ((Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA))->ctx();\n        auto ite = ctx->trayMenuInfo.find(wParam);\n        if (ite == ctx->trayMenuInfo.end()) {\n            break;\n        }\n        ite->second.cb();\n        return 0;\n    }\n    case WM_DWMCOMPOSITIONCHANGED:\n    case WM_DWMCOLORIZATIONCOLORCHANGED: {\n        auto *ctx = ((Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA))->ctx();\n        updateFramebufferTransparency(ctx->hwnd);\n        return 0;\n    }\n    case WM_HOTKEY: {\n        auto id = int(wParam);\n        if (id < 0) { break; }\n        auto *ctx = ((Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA))->ctx();\n        auto ite = ctx->hotkeys.find(id);\n        if (ite == ctx->hotkeys.end()) { break; }\n        const auto &func = std::get<2>(ite->second);\n        if (func) { func(); }\n        return 0;\n    }\n    default:\n        if (uMsg == taskbarRestartMsg) {\n            auto *win = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);\n            auto *ctx = win->ctx();\n            if (!ctx->trayMenuBase.enabled) {\n                break;\n            }\n            auto m = ctx->trayMenuInfo;\n            win->destroyTrayMenu();\n            win->enableTrayMenu(true, ctx->trayMenuBase.icon, ctx->trayMenuBase.tip.c_str(), ctx->trayMenuBase.info.c_str(), ctx->trayMenuBase.infoTitle.c_str());\n            for (auto &p: m) {\n                win->addTrayMenuItem(p.second.name.c_str(), p.second.parent, p.second.flags, p.second.cb);\n            }\n        }\n        break;\n    }\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\nWindow::Window(int x, int y, int width, int height): ctx_(new WindowCtx) {\n    INITCOMMONCONTROLSEX iccex = { sizeof(INITCOMMONCONTROLSEX) };\n    InitCommonControlsEx(&iccex);\n    auto inst = HINST_THISCOMPONENT;\n    auto icon = LoadIconW(inst, MAKEINTRESOURCEW(1));\n\n    WNDCLASSEXW wcx = {};\n\n    wcx.cbSize = sizeof(wcx);\n    wcx.style = CS_HREDRAW | CS_VREDRAW;\n    wcx.lpfnWndProc = wndProc;\n    wcx.hInstance = inst;\n    wcx.hIcon = icon;\n    wcx.hCursor = LoadCursor(nullptr, IDC_ARROW);\n    wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);\n    wcx.lpszClassName = L\"D2RMH\";\n    wcx.hIconSm = icon;\n    RegisterClassExW(&wcx);\n    DWORD exStyle = WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_LAYERED;\n    DWORD style = WS_POPUP;\n    RECT rc = {x, y, x + width, y + height};\n    AdjustWindowRectEx(&rc, style, FALSE, exStyle);\n\n    ctx_->hwnd = CreateWindowExW(exStyle, L\"D2RMH\", L\"D2RMH\",\n        style, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, inst, this);\n    if (ctx_->hwnd == nullptr) {\n        throw std::runtime_error(\"Unable to create window\");\n    }\n    SetWindowLongPtr(ctx_->hwnd, GWLP_USERDATA, (LONG_PTR)this);\n    SetLayeredWindowAttributes(ctx_->hwnd, 0, 0, 0);\n    updateFramebufferTransparency(ctx_->hwnd);\n    ctx_->running = true;\n}\n\nWindow::~Window() {\n    clearHotkeys();\n    if (IsWindow(ctx_->hwnd)) {\n        DestroyWindow(ctx_->hwnd);\n    }\n    delete ctx_;\n}\n\nINT_PTR CALLBACK dialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\n    switch (uMsg) {\n    case WM_CLOSE:\n        EndDialog(hWnd, TRUE);\n        break;\n    case WM_COMMAND:\n        switch (LOWORD(wParam)) {\n        case IDOK:\n            EndDialog(hWnd, TRUE);\n            break;\n        }\n        break;\n    case WM_NOTIFY: {\n        auto *nmhdr = LPNMHDR(lParam);\n        switch (nmhdr->code) {\n        case NM_CLICK:\n        case NM_RETURN: {\n            if (nmhdr->idFrom == 1001) {\n                auto pNMLink = PNMLINK(lParam);\n                auto item = pNMLink->item;\n                if (item.iLink == 0) {\n                    ShellExecuteW(nullptr, L\"open\", item.szUrl, nullptr, nullptr, SW_SHOW);\n                }\n            }\n            break;\n        }\n        }\n        break;\n    }\n    case WM_INITDIALOG: {\n        RECT rc, rc2;\n        GetWindowRect(GetDesktopWindow(), &rc);\n        GetWindowRect(hWnd, &rc2);\n        auto width = rc2.right - rc2.left;\n        auto height = rc2.bottom - rc2.top;\n        MoveWindow(hWnd, (rc.right + rc.left - width) / 2, (rc.top + rc.bottom - height) / 2, width, height, FALSE);\n        auto caption = GetDlgItem(hWnd, 1000);\n        SetWindowTextW(caption, L\"D2RMH \" VERSION_STRING_FULL);\n        auto font = HFONT(SendMessage(caption, WM_GETFONT, 0, 0));\n        LOGFONTW lf = {};\n        GetObjectW(font, sizeof(lf), &lf);\n        lf.lfHeight *= 2; lf.lfWidth *= 2;\n        auto font2 = CreateFontIndirectW(&lf);\n        SendMessage(caption, WM_SETFONT, (WPARAM)font2, TRUE);\n        break;\n    }\n    case WM_CTLCOLORSTATIC: {\n        if (GetDlgCtrlID((HWND)lParam) == 1000) {\n            SetTextColor((HDC)wParam, 0x881111);\n            SetBkMode((HDC)wParam, TRANSPARENT);\n            return (INT_PTR)::GetStockObject(NULL_BRUSH);\n        }\n        return FALSE;\n    }\n    default:\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nvoid Window::show(bool on) {\n    ShowWindow(ctx_->hwnd, on ? SW_SHOW : SW_HIDE);\n}\n\nvoid Window::enableTrayMenu(bool enable, const wchar_t *icon, const wchar_t *tip, const wchar_t *info, const wchar_t *infoTitle) {\n    ctx_->trayMenuBase = {enable, icon, tip ? tip : L\"\", info ? info : L\"\", infoTitle ? infoTitle : L\"\"};\n    if (!enable) {\n        if (ctx_->nid.cbSize) {\n            Shell_NotifyIconW(NIM_DELETE, &ctx_->nid);\n            memset(&ctx_->nid, 0, sizeof(ctx_->nid));\n        }\n        return;\n    }\n    HICON hicon;\n    if (IS_INTRESOURCE(icon)) {\n        hicon = LoadIconW(HINST_THISCOMPONENT, icon);\n    } else {\n        ExtractIconExW(icon, 0, nullptr, &hicon, 1);\n    }\n    memset(&ctx_->nid, 0, sizeof(ctx_->nid));\n    ctx_->nid.cbSize = NOTIFYICONDATAW_V3_SIZE;\n    ctx_->nid.uVersion = 3;\n    ctx_->nid.hWnd = ctx_->hwnd;\n    ctx_->nid.uID = 0;\n    ctx_->nid.uFlags = NIF_ICON | NIF_MESSAGE;\n    if (tip && tip[0]) {\n        ctx_->nid.uFlags |= NIF_TIP;\n        lstrcpyW(ctx_->nid.szTip, tip);\n    }\n    if (info && info[0] && infoTitle && infoTitle[0]) {\n        ctx_->nid.uFlags |= NIF_INFO;\n        lstrcpyW(ctx_->nid.szInfo, info);\n        lstrcpyW(ctx_->nid.szInfoTitle, infoTitle);\n        ctx_->nid.dwInfoFlags = NIIF_NONE | NIIF_NOSOUND\n#ifdef NIIF_RESPECT_QUIET_TIME\n            | NIIF_RESPECT_QUIET_TIME\n#endif\n            ;\n    }\n    ctx_->nid.hIcon = hicon;\n    ctx_->nid.uCallbackMessage = WM_TRAY_CALLBACK_MESSAGE;\n    Shell_NotifyIconW(NIM_ADD, &ctx_->nid);\n\n    ctx_->trayMenu = CreatePopupMenu();\n}\n\nvoid Window::addAboutMenu() {\n    addTrayMenuItem(L\"About\", -1, 0, [] {\n        DialogBox(HINST_THISCOMPONENT, MAKEINTRESOURCE(101), nullptr, dialogProc);\n    });\n}\n\nint Window::addTrayMenuItem(const wchar_t *name, int parent, unsigned flags, const std::function<void()> &cb) {\n    HMENU parentMenu;\n    if (parent < 0) {\n        parentMenu = ctx_->trayMenu;\n    } else {\n        auto ite = ctx_->trayMenuInfo.find(parent);\n        if (ite == ctx_->trayMenuInfo.end() || !ite->second.submenu) {\n            return -1;\n        }\n        parentMenu = ite->second.submenu;\n    }\n    auto &st = ctx_->trayMenuInfo[ctx_->userMsg];\n    if (lstrcmpW(name, L\"-\") == 0) {\n        InsertMenuW(parentMenu, ctx_->userMsg, MF_SEPARATOR, TRUE, L\"\");\n    } else {\n        MENUITEMINFOW item = {};\n        item.cbSize = sizeof(MENUITEMINFOW);\n        item.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;\n        item.fType = MFT_STRING;\n        item.fState = 0;\n        if (flags & TRAYMENU_SUBMENU) {\n            item.fMask |= MIIM_SUBMENU;\n            item.hSubMenu = CreatePopupMenu();\n            st.submenu = item.hSubMenu;\n        }\n        if (flags & TRAYMENU_DISABLED) {\n            item.fState |= MFS_DISABLED;\n        }\n        if (flags & TRAYMENU_CHECKED) {\n            item.fState |= MFS_CHECKED;\n        }\n        item.wID = ctx_->userMsg;\n        item.dwTypeData = (LPWSTR)name;\n        item.dwItemData = (ULONG_PTR)&st;\n        InsertMenuItemW(parentMenu, ctx_->userMsg, TRUE, &item);\n    }\n    st.id = ctx_->userMsg++;\n\n    st.name = name;\n    st.parent = parent;\n    st.flags = flags;\n    st.cb = cb;\n    return st.id;\n}\n\nvoid Window::destroyTrayMenu() {\n    if (ctx_->nid.cbSize) {\n        Shell_NotifyIconW(NIM_DELETE, &ctx_->nid);\n        memset(&ctx_->nid, 0, sizeof(ctx_->nid));\n    }\n    ctx_->trayMenuBase.enabled = false;\n    DestroyMenu(ctx_->trayMenu);\n    ctx_->trayMenu = nullptr;\n    ctx_->trayMenuInfo.clear();\n    ctx_->userMsg = WM_USER + 1;\n}\n\nbool Window::run() const {\n    if (!ctx_->running) {\n        return false;\n    }\n    MSG msg = { };\n    while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE) > 0) {\n        TranslateMessage(&msg);\n        DispatchMessage(&msg);\n    }\n    return true;\n}\n\nbool Window::running() const {\n    return ctx_->running;\n}\n\nvoid Window::quit() {\n    DestroyWindow(ctx_->hwnd);\n    PostQuitMessage(0);\n}\n\nvoid Window::getDimension(int &w, int &h) {\n    RECT rc;\n    GetClientRect(ctx_->hwnd, &rc);\n    w = rc.right - rc.left;\n    h = rc.bottom - rc.top;\n}\n\nvoid Window::move(int x, int y, int w, int h) {\n    auto exStyle = GetWindowLong(ctx_->hwnd, GWL_EXSTYLE);\n    auto style = GetWindowLong(ctx_->hwnd, GWL_STYLE);\n    RECT rc = {x, y, x + w, y + h};\n    AdjustWindowRectEx(&rc, style, FALSE, exStyle);\n    MoveWindow(ctx_->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);\n}\n\nvoid Window::reloadConfig() {\n    clearHotkeys();\n    SetLayeredWindowAttributes(ctx_->hwnd, 0, 0, 0);\n    updateFramebufferTransparency(ctx_->hwnd);\n}\n\nvoid Window::enableHotkeys(bool enable) {\n    if (enable == ctx_->hotkeysEnabled) { return; }\n    ctx_->hotkeysEnabled = enable;\n    if (enable) {\n        for (auto &p: ctx_->hotkeys) {\n            RegisterHotKey(ctx_->hwnd, p.first, std::get<0>(p.second) | MOD_NOREPEAT, std::get<1>(p.second));\n        }\n    } else {\n        for (auto &p: ctx_->hotkeys) {\n            UnregisterHotKey(ctx_->hwnd, p.first);\n        }\n    }\n}\n\nvoid Window::registerHotkey(const std::string &name, const std::function<void()> &cb) {\n    if (!cb) { return; }\n    UINT mods;\n    UINT vkey = util::mapStringToVKey(name, mods);\n    if (!vkey) { return; }\n    for (int nid = 1; nid < 0xC000; ++nid) {\n        if (ctx_->hotkeys.find(nid) != ctx_->hotkeys.end()) { continue; }\n        ctx_->hotkeys[nid] = std::make_tuple(mods, vkey, cb);\n        if (ctx_->hotkeysEnabled) {\n            RegisterHotKey(ctx_->hwnd, nid, mods | MOD_NOREPEAT, vkey);\n        }\n        break;\n    }\n}\n\nvoid Window::clearHotkeys() {\n    for (auto &p: ctx_->hotkeys) {\n        UnregisterHotKey(ctx_->hwnd, p.first);\n    }\n    ctx_->hotkeys.clear();\n}\n\nint Window::messageBox(const wchar_t *msg, const wchar_t *title, uint32_t type) {\n    return MessageBoxW(ctx_->hwnd, msg, title, type);\n}\n\nvoid Window::setSizeCallback(const std::function<void(int, int)> &cb) {\n    ctx_->sizeCB = cb;\n}\n\nvoid *Window::hwnd() {\n    return (void*)ctx_->hwnd;\n}\n\n}\n"
  },
  {
    "path": "src/ui/window.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <functional>\n#include <string>\n\nnamespace render {\nclass Renderer;\n}\n\nnamespace ui {\n\nstruct WindowCtx;\n\nclass Window final {\n    friend class ::render::Renderer;\npublic:\n    enum {\n        TRAYMENU_DISABLED = 1,\n        TRAYMENU_CHECKED = 2,\n        TRAYMENU_SUBMENU = 4,\n    };\n\n    Window(int x, int y, int width, int height);\n    ~Window();\n\n    void show(bool on);\n    void enableTrayMenu(bool enable,\n                        const wchar_t *icon,\n                        const wchar_t *tip = nullptr,\n                        const wchar_t *info = nullptr,\n                        const wchar_t *infoTitle = nullptr);\n    void addAboutMenu();\n    int addTrayMenuItem(const wchar_t *name, int parent, unsigned flags, const std::function<void()> &cb);\n    void destroyTrayMenu();\n\n    [[nodiscard]] bool run() const;\n    [[nodiscard]] bool running() const;\n    void quit();\n\n    [[nodiscard]] inline WindowCtx *ctx() { return ctx_; }\n    void getDimension(int &w, int &h);\n    void move(int x, int y, int w, int h);\n\n    void reloadConfig();\n\n    void enableHotkeys(bool enable);\n    void registerHotkey(const std::string &name, const std::function<void()> &cb);\n    void clearHotkeys();\n\n    int messageBox(const wchar_t *msg, const wchar_t *title, uint32_t type);\n\nprivate:\n    void setSizeCallback(const std::function<void(int, int)> &cb);\n    void *hwnd();\n\nprivate:\n    WindowCtx *ctx_;\n};\n\n}\n"
  },
  {
    "path": "src/util/ntprocess.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"ntprocess.h\"\n\n#include \"os_structs.h\"\n\n#include <vector>\n#include <cstdint>\n#include <stdexcept>\n\nnamespace util {\n\n#if defined(_M_IX86)\n\n#define IS_TRUE(clause, msg) if (!(clause)) { throw std::runtime_error(msg); }\n\nvoid checkIfProcessIsX64(HANDLE handle) {\n    BOOL is_wow64_process = TRUE;\n    IS_TRUE(::IsWow64Process(handle, &is_wow64_process), \"IsWow64Process failed\");\n    IS_TRUE(FALSE == is_wow64_process, \"Target process is not x64 one\");\n}\n\nuint32_t readMemory64(HANDLE handle, uint64_t address, uint32_t length, void *data) {\n    IS_TRUE(handle, \"No process handle obtained\");\n\n    NTSTATUS status = NtWow64ReadVirtualMemory64(handle, address, data, length, FALSE);\n\n    if(!NT_SUCCESS(status)) {\n        return 0;\n    }\n    return length;\n}\n\nvoid readPBI(HANDLE handle, PROCESS_BASIC_INFORMATION64 &pbi) {\n    IS_TRUE(handle, \"No process handle obtained\");\n\n    NTSTATUS status = NtWow64QueryInformationProcess64(handle, ProcessBasicInformation, &pbi, sizeof(pbi), nullptr);\n\n    IS_TRUE(NT_SUCCESS(status), \"NtQueryInformationProcess failed\");\n}\n\nuint32_t readPEBData(HANDLE handle, PEB64 *peb) {\n    PROCESS_BASIC_INFORMATION64 pbi = {0};\n    readPBI(handle, pbi);\n\n    return readMemory64(handle, pbi.PebBaseAddress, sizeof(PEB64), peb);\n}\n\nbool getModules(HANDLE handle, const std::function<bool(uint64_t, uint64_t, const wchar_t*)> &cb) {\n    PEB64 peb;\n    readPEBData(handle, &peb);\n\n    // ------------------------------------------------------------------------\n    // Read memory from pointer to loader data structures.\n    // ------------------------------------------------------------------------\n    std::vector<uint8_t> read_peb_ldr_data(sizeof(PEB_LDR_DATA64));\n    readMemory64(handle, (uint64_t)peb.LoaderData, sizeof(PEB_LDR_DATA64), read_peb_ldr_data.data());\n    auto *peb_ldr_data = (PEB_LDR_DATA64 *)read_peb_ldr_data.data();\n\n    ULONGLONG address = peb_ldr_data->InLoadOrderModuleList.Flink;\n\n    // ------------------------------------------------------------------------\n    // Traversing loader data structures.\n    // ------------------------------------------------------------------------\n    for (;;) {\n        std::vector<uint8_t> read_ldr_table_entry(sizeof(LDR_DATA_TABLE_ENTRY64));\n        readMemory64(handle, address, sizeof(LDR_DATA_TABLE_ENTRY64), read_ldr_table_entry.data());\n\n        auto *ldr_table_entry = (LDR_DATA_TABLE_ENTRY64 *)read_ldr_table_entry.data();\n        if (!ldr_table_entry->BaseAddress) {\n            break;\n        }\n\n        std::vector<uint8_t> unicode_name(ldr_table_entry->BaseDllName.MaximumLength);\n        readMemory64(handle,\n                     ldr_table_entry->BaseDllName.Buffer,\n                     ldr_table_entry->BaseDllName.MaximumLength,\n                     unicode_name.data());\n\n        if (!cb(ldr_table_entry->BaseAddress, ldr_table_entry->SizeOfImage, (const wchar_t*)unicode_name.data())) {\n            break;\n        }\n\n        ldr_table_entry = (LDR_DATA_TABLE_ENTRY64 *)read_ldr_table_entry.data();\n        address = (uint64_t)ldr_table_entry->InLoadOrderModuleList.Flink;\n    }\n\n    return true;\n}\n\n#elif defined(_M_X64)\n\n#include <tlhelp32.h>\n\nuint32_t readMemory64(HANDLE handle, uint64_t address, uint32_t length, void *data) {\n    SIZE_T bytesRead;\n    if (!ReadProcessMemory(handle, (LPCVOID)(UINT_PTR)(address), data, length, &bytesRead)) {\n        return 0;\n    }\n    return uint32_t(bytesRead);\n}\n\nbool getModules(HANDLE handle, const std::function<bool(uint64_t, uint64_t, const wchar_t*)> &cb) {\n    auto snap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, GetProcessId(handle) );\n    if (snap == INVALID_HANDLE_VALUE) {\n        return false;\n    }\n    MODULEENTRY32W me32 = {.dwSize = sizeof(me32)};\n    if(!Module32FirstW(snap, &me32)) {\n        CloseHandle( snap );\n        return false;\n    }\n    do {\n        if (!cb((uint64_t)(UINT_PTR)me32.modBaseAddr, me32.modBaseSize, me32.szModule)) {\n            break;\n        }\n    } while (Module32NextW(snap, &me32));\n    CloseHandle(snap);\n    return true;\n}\n\n#else\n\n#   error \"This application must be built as an x86 executable\"\n\n#endif\n\n}\n"
  },
  {
    "path": "src/util/ntprocess.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#include <windows.h>\n#include <functional>\n#include <cstdint>\n\nnamespace util {\n\nextern uint32_t readMemory64(HANDLE handle, uint64_t address, uint32_t length, void *data);\nextern bool getModules(HANDLE handle, const std::function<bool(uint64_t, uint64_t, const wchar_t *)> &cb);\n\n}\n"
  },
  {
    "path": "src/util/os_structs.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"os_structs.h\"\n\nextern \"C\" {\n\n#if defined(_M_IX86)\nNtWow64QueryInformationProcess64Proc NtWow64QueryInformationProcess64;\nNtWow64ReadVirtualMemory64Proc NtWow64ReadVirtualMemory64;\n\nstatic HMODULE getNtDllMod() {\n    static HMODULE ntdllMod = LoadLibraryA(\"ntdll.dll\");\n    return ntdllMod;\n}\n#endif\n\nvoid osInit() {\n#if defined(_M_IX86)\n    NtWow64QueryInformationProcess64 =\n        (NtWow64QueryInformationProcess64Proc)GetProcAddress(getNtDllMod(), \"NtWow64QueryInformationProcess64\");\n    NtWow64ReadVirtualMemory64 =\n        (NtWow64ReadVirtualMemory64Proc)GetProcAddress(getNtDllMod(), \"NtWow64ReadVirtualMemory64\");\n#endif\n}\n\n}\n"
  },
  {
    "path": "src/util/os_structs.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <windows.h>\n\n#if defined(_M_IX86)\n\n#define NT_SUCCESS(x) ((x) >= 0)\n\n// Namespace is present Not to collide with \"winbase.h\"\n// definition of PROCESS_INFORMATION_CLASS and others.\nnamespace util {\n\ntypedef enum _PROCESS_INFORMATION_CLASS {\n    ProcessBasicInformation,\n    ProcessQuotaLimits,\n    ProcessIoCounters,\n    ProcessVmCounters,\n    ProcessTimes,\n    ProcessBasePriority,\n    ProcessRaisePriority,\n    ProcessDebugPort,\n    ProcessExceptionPort,\n    ProcessAccessToken,\n    ProcessLdtInformation,\n    ProcessLdtSize,\n    ProcessDefaultHardErrorMode,\n    ProcessIoPortHandlers,\n    ProcessPooledUsageAndLimits,\n    ProcessWorkingSetWatch,\n    ProcessUserModeIOPL,\n    ProcessEnableAlignmentFaultFixup,\n    ProcessPriorityClass,\n    ProcessWx86Information,\n    ProcessHandleCount,\n    ProcessAffinityMask,\n    ProcessPriorityBoost,\n    MaxProcessInfoClass\n} PROCESS_INFORMATION_CLASS, *PPROCESS_INFORMATION_CLASS;\n\n// ------------------------------------------------------------------------\n// Structs.\n// ------------------------------------------------------------------------\n\ntypedef struct _PROCESS_BASIC_INFORMATION64 {\n    ULONGLONG Reserved1;\n    ULONGLONG PebBaseAddress;\n    ULONGLONG Reserved2[2];\n    ULONGLONG UniqueProcessId;\n    ULONGLONG Reserved3;\n} PROCESS_BASIC_INFORMATION64;\n\ntypedef struct _PEB_LDR_DATA64 {\n    ULONG Length;\n    BOOLEAN Initialized;\n    ULONGLONG SsHandle;\n    LIST_ENTRY64 InLoadOrderModuleList;\n    LIST_ENTRY64 InMemoryOrderModuleList;\n    LIST_ENTRY64 InInitializationOrderModuleList;\n} PEB_LDR_DATA64, *PPEB_LDR_DATA64;\n\n// Structure is cut down to ProcessHeap.\ntypedef struct _PEB64 {\n    BOOLEAN InheritedAddressSpace;\n    BOOLEAN ReadImageFileExecOptions;\n    BOOLEAN BeingDebugged;\n    BOOLEAN Spare;\n    ULONGLONG Mutant;\n    ULONGLONG ImageBaseAddress;\n    ULONGLONG LoaderData;\n    ULONGLONG ProcessParameters;\n    ULONGLONG SubSystemData;\n    ULONGLONG ProcessHeap;\n} PEB64;\n\ntypedef struct _UNICODE_STRING64 {\n    USHORT Length;\n    USHORT MaximumLength;\n    ULONGLONG Buffer;\n} UNICODE_STRING64;\n\ntypedef struct _LDR_DATA_TABLE_ENTRY64 {\n    LIST_ENTRY64 InLoadOrderModuleList;\n    LIST_ENTRY64 InMemoryOrderModuleList;\n    LIST_ENTRY64 InInitializationOrderModuleList;\n    ULONGLONG BaseAddress;\n    ULONGLONG EntryPoint;\n    DWORD64 SizeOfImage;\n    UNICODE_STRING64 FullDllName;\n    UNICODE_STRING64 BaseDllName;\n    ULONG Flags;\n    SHORT LoadCount;\n    SHORT TlsIndex;\n    LIST_ENTRY64 HashTableEntry;\n    ULONGLONG TimeDateStamp;\n} LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;\n\n}\n\n#endif\n\n// ------------------------------------------------------------------------\n// Function prototypes.\n// ------------------------------------------------------------------------\nextern \"C\" {\n\n#if defined(_M_IX86)\n\ntypedef NTSTATUS (NTAPI *NtWow64QueryInformationProcess64Proc)(\n    IN HANDLE ProcessHandle,\n    ULONG ProcessInformationClass,\n    OUT PVOID ProcessInformation,\n    IN ULONG ProcessInformationLength,\n    OUT PULONG ReturnLength OPTIONAL);\n\ntypedef NTSTATUS (NTAPI *NtWow64ReadVirtualMemory64Proc)(\n    IN HANDLE ProcessHandle,\n    IN DWORD64 BaseAddress,\n    OUT PVOID Buffer,\n    IN ULONG64 Size,\n    OUT PDWORD64 NumberOfBytesRead);\n\nextern NtWow64QueryInformationProcess64Proc NtWow64QueryInformationProcess64;\nextern NtWow64ReadVirtualMemory64Proc NtWow64ReadVirtualMemory64;\n\n#endif\n\nextern void osInit();\n\n}\n"
  },
  {
    "path": "src/util/util.cpp",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#include \"util.h\"\n\n#include <windows.h>\n#include <map>\n\nnamespace util {\n\nstd::wstring utf8toucs4(const std::string &s) {\n    std::wstring ws;\n    wchar_t wc;\n    size_t sz = s.length();\n    for (size_t i = 0; i < sz;) {\n        char c = s[i];\n        if ((c & 0x80) == 0) {\n            wc = c;\n            ++i;\n        } else if ((c & 0xE0) == 0xC0) {\n            wc = (s[i] & 0x1F) << 6;\n            wc |= (s[i + 1] & 0x3F);\n            i += 2;\n        } else if ((c & 0xF0) == 0xE0) {\n            wc = (s[i] & 0xF) << 12;\n            wc |= (s[i + 1] & 0x3F) << 6;\n            wc |= (s[i + 2] & 0x3F);\n            i += 3;\n        } else if ((c & 0xF8) == 0xF0) {\n            wc = (s[i] & 0x7) << 18;\n            wc |= (s[i + 1] & 0x3F) << 12;\n            wc |= (s[i + 2] & 0x3F) << 6;\n            wc |= (s[i + 3] & 0x3F);\n            i += 4;\n        } else if ((c & 0xFC) == 0xF8) {\n            wc = (s[i] & 0x3) << 24;\n            wc |= (s[i] & 0x3F) << 18;\n            wc |= (s[i] & 0x3F) << 12;\n            wc |= (s[i] & 0x3F) << 6;\n            wc |= (s[i] & 0x3F);\n            i += 5;\n        } else if ((c & 0xFE) == 0xFC) {\n            wc = (s[i] & 0x1) << 30;\n            wc |= (s[i] & 0x3F) << 24;\n            wc |= (s[i] & 0x3F) << 18;\n            wc |= (s[i] & 0x3F) << 12;\n            wc |= (s[i] & 0x3F) << 6;\n            wc |= (s[i] & 0x3F);\n            i += 6;\n        }\n        ws += wc;\n    }\n    return ws;\n}\n\nstd::vector<std::string> splitString(const std::string &str, char c) {\n    typename std::string::size_type pos = 0;\n    std::vector<std::string> result;\n    while (true) {\n        auto epos = str.find(c, pos);\n        result.emplace_back(str.substr(pos, epos - pos));\n        if (epos == std::string::npos) {\n            break;\n        }\n        pos = epos + 1;\n    }\n    return result;\n}\n\nstatic std::chrono::steady_clock::time_point sCurrTime;\nvoid updateTime() {\n    sCurrTime = std::chrono::steady_clock::now();\n}\n\nstd::chrono::steady_clock::time_point getCurrTime() {\n    return sCurrTime;\n}\n\nuint32_t mapStringToVKey(const std::string &name, uint32_t &mods) {\n    static const std::map<std::string, UINT> sModMap = {\n        {\"SHIFT\", MOD_SHIFT},\n        {\"CONTROL\", MOD_CONTROL},\n        {\"CTRL\", MOD_CONTROL},\n        {\"ALT\", MOD_ALT},\n        {\"WIN\", MOD_WIN},\n    };\n\n    static const std::map<std::string, UINT> sVKeyMap = {\n        {\"LBUTTON\", VK_LBUTTON},\n        {\"RBUTTON\", VK_RBUTTON},\n        {\"CANCEL\", VK_CANCEL},\n        {\"MBUTTON\", VK_MBUTTON},\n        {\"XBUTTON1\", VK_XBUTTON1},\n        {\"XBUTTON2\", VK_XBUTTON2},\n        {\"BACK\", VK_BACK},\n        {\"BACKSPACE\", VK_BACK},\n        {\"TAB\", VK_TAB},\n        {\"CLEAR\", VK_CLEAR},\n        {\"RETURN\", VK_RETURN},\n        {\"ENTER\", VK_RETURN},\n        {\"PAUSE\", VK_PAUSE},\n        {\"CAPITAL\", VK_CAPITAL},\n        {\"CAPSLOCK\", VK_CAPITAL},\n        {\"KANA\", VK_KANA},\n        {\"HANGUL\", VK_HANGUL},\n        {\"JUNJA\", VK_JUNJA},\n        {\"FINAL\", VK_FINAL},\n        {\"HANJA\", VK_HANJA},\n        {\"KANJI\", VK_KANJI},\n        {\"ESCAPE\", VK_ESCAPE},\n        {\"ESC\", VK_ESCAPE},\n        {\"CONVERT\", VK_CONVERT},\n        {\"NONCONVERT\", VK_NONCONVERT},\n        {\"ACCEPT\", VK_ACCEPT},\n        {\"MODECHANGE\", VK_MODECHANGE},\n        {\"SPACE\", VK_SPACE},\n        {\"PRIOR\", VK_PRIOR},\n        {\"NEXT\", VK_NEXT},\n        {\"END\", VK_END},\n        {\"HOME\", VK_HOME},\n        {\"LEFT\", VK_LEFT},\n        {\"UP\", VK_UP},\n        {\"RIGHT\", VK_RIGHT},\n        {\"DOWN\", VK_DOWN},\n        {\"SELECT\", VK_SELECT},\n        {\"PRINT\", VK_PRINT},\n        {\"EXECUTE\", VK_EXECUTE},\n        {\"SNAPSHOT\", VK_SNAPSHOT},\n        {\"INSERT\", VK_INSERT},\n        {\"DELETE\", VK_DELETE},\n        {\"HELP\", VK_HELP},\n        {\"0\", 0x30},\n        {\"1\", 0x31},\n        {\"2\", 0x32},\n        {\"3\", 0x33},\n        {\"4\", 0x34},\n        {\"5\", 0x35},\n        {\"6\", 0x36},\n        {\"7\", 0x37},\n        {\"8\", 0x38},\n        {\"9\", 0x39},\n        {\"A\", 0x41},\n        {\"B\", 0x42},\n        {\"C\", 0x43},\n        {\"D\", 0x44},\n        {\"E\", 0x45},\n        {\"F\", 0x46},\n        {\"G\", 0x47},\n        {\"H\", 0x48},\n        {\"I\", 0x49},\n        {\"J\", 0x4A},\n        {\"K\", 0x4B},\n        {\"L\", 0x4C},\n        {\"M\", 0x4D},\n        {\"N\", 0x4E},\n        {\"O\", 0x4F},\n        {\"P\", 0x50},\n        {\"Q\", 0x51},\n        {\"R\", 0x52},\n        {\"S\", 0x53},\n        {\"T\", 0x54},\n        {\"U\", 0x55},\n        {\"V\", 0x56},\n        {\"W\", 0x57},\n        {\"X\", 0x58},\n        {\"Y\", 0x59},\n        {\"Z\", 0x5A},\n        {\"APPS\", VK_APPS},\n        {\"SLEEP\", VK_SLEEP},\n        {\"NUMPAD0\", VK_NUMPAD0},\n        {\"NUMPAD1\", VK_NUMPAD1},\n        {\"NUMPAD2\", VK_NUMPAD2},\n        {\"NUMPAD3\", VK_NUMPAD3},\n        {\"NUMPAD4\", VK_NUMPAD4},\n        {\"NUMPAD5\", VK_NUMPAD5},\n        {\"NUMPAD6\", VK_NUMPAD6},\n        {\"NUMPAD7\", VK_NUMPAD7},\n        {\"NUMPAD8\", VK_NUMPAD8},\n        {\"NUMPAD9\", VK_NUMPAD9},\n        {\"NUM0\", VK_NUMPAD0},\n        {\"NUM1\", VK_NUMPAD1},\n        {\"NUM2\", VK_NUMPAD2},\n        {\"NUM3\", VK_NUMPAD3},\n        {\"NUM4\", VK_NUMPAD4},\n        {\"NUM5\", VK_NUMPAD5},\n        {\"NUM6\", VK_NUMPAD6},\n        {\"NUM7\", VK_NUMPAD7},\n        {\"NUM8\", VK_NUMPAD8},\n        {\"NUM9\", VK_NUMPAD9},\n        {\"MULTIPLY\", VK_MULTIPLY},\n        {\"ADD\", VK_ADD},\n        {\"SUBTRACT\", VK_SUBTRACT},\n        {\"MINUS\", VK_SUBTRACT},\n        {\"DECIMAL\", VK_DECIMAL},\n        {\"DIVIDE\", VK_DIVIDE},\n        {\"F1\", VK_F1},\n        {\"F2\", VK_F2},\n        {\"F3\", VK_F3},\n        {\"F4\", VK_F4},\n        {\"F5\", VK_F5},\n        {\"F6\", VK_F6},\n        {\"F7\", VK_F7},\n        {\"F8\", VK_F8},\n        {\"F9\", VK_F9},\n        {\"F10\", VK_F10},\n        {\"F11\", VK_F11},\n        {\"F12\", VK_F12},\n        {\"F13\", VK_F13},\n        {\"F14\", VK_F14},\n        {\"F15\", VK_F15},\n        {\"F16\", VK_F16},\n        {\"F17\", VK_F17},\n        {\"F18\", VK_F18},\n        {\"F19\", VK_F19},\n        {\"F20\", VK_F20},\n        {\"F21\", VK_F21},\n        {\"F22\", VK_F22},\n        {\"F23\", VK_F23},\n        {\"F24\", VK_F24},\n        {\"NUMLOCK\", VK_NUMLOCK},\n        {\"SCROLL\", VK_SCROLL},\n        {\"LSHIFT\", VK_LSHIFT},\n        {\"RSHIFT\", VK_RSHIFT},\n        {\"LCONTROL\", VK_LCONTROL},\n        {\"RCONTROL\", VK_RCONTROL},\n        {\"LMENU\", VK_LMENU},\n        {\"RMENU\", VK_RMENU},\n        {\"BROWSER_BACK\", VK_BROWSER_BACK},\n        {\"BROWSER_FORWARD\", VK_BROWSER_FORWARD},\n        {\"BROWSER_REFRESH\", VK_BROWSER_REFRESH},\n        {\"BROWSER_STOP\", VK_BROWSER_STOP},\n        {\"BROWSER_SEARCH\", VK_BROWSER_SEARCH},\n        {\"BROWSER_FAVORITES\", VK_BROWSER_FAVORITES},\n        {\"BROWSER_HOME\", VK_BROWSER_HOME},\n        {\"VOLUME_MUTE\", VK_VOLUME_MUTE},\n        {\"VOLUME_DOWN\", VK_VOLUME_DOWN},\n        {\"VOLUME_UP\", VK_VOLUME_UP},\n        {\"MEDIA_NEXT_TRACK\", VK_MEDIA_NEXT_TRACK},\n        {\"MEDIA_PREV_TRACK\", VK_MEDIA_PREV_TRACK},\n        {\"MEDIA_STOP\", VK_MEDIA_STOP},\n        {\"MEDIA_PLAY_PAUSE\", VK_MEDIA_PLAY_PAUSE},\n        {\"LAUNCH_MAIL\", VK_LAUNCH_MAIL},\n        {\"LAUNCH_MEDIA_SELECT\", VK_LAUNCH_MEDIA_SELECT},\n        {\"LAUNCH_APP1\", VK_LAUNCH_APP1},\n        {\"LAUNCH_APP2\", VK_LAUNCH_APP2},\n        {\"OEM_PLUS\", VK_OEM_PLUS},\n        {\"OEM_COMMA\", VK_OEM_COMMA},\n        {\"OEM_MINUS\", VK_OEM_MINUS},\n        {\"OEM_PERIOD\", VK_OEM_PERIOD},\n        {\";\", VK_OEM_1},\n        {\"/\", VK_OEM_2},\n        {\"~\", VK_OEM_3},\n        {\"[\", VK_OEM_4},\n        {\"\\\\\", VK_OEM_5},\n        {\"]\", VK_OEM_6},\n        {\"'\", VK_OEM_7},\n        {\"PROCESSKEY\", VK_PROCESSKEY},\n        {\"ATTN\", VK_ATTN},\n        {\"CRSEL\", VK_CRSEL},\n        {\"EXSEL\", VK_EXSEL},\n        {\"EREOF\", VK_EREOF},\n        {\"PLAY\", VK_PLAY},\n        {\"ZOOM\", VK_ZOOM},\n        {\"PA1\", VK_PA1},\n        {\"OEM_CLEAR\", VK_OEM_CLEAR},\n    };\n\n    mods = 0;\n    std::string str = name;\n    for (auto &c: str) { c = std::toupper(c); }\n    auto sl = splitString(str, '+');\n    if (sl.empty()) {\n        return 0;\n    }\n    auto ite = sVKeyMap.find(sl.back());\n    if (ite == sVKeyMap.end()) {\n        return 0;\n    }\n    sl.pop_back();\n    for (const auto &s: sl) {\n        auto ite2 = sModMap.find(s);\n        if (ite2 == sModMap.end()) {\n            return 0;\n        }\n        mods |= ite2->second;\n    }\n    return ite->second;\n}\n\n}\n"
  },
  {
    "path": "src/util/util.h",
    "content": "/*\n * Copyright (c) 2021 Soar Qin<soarchin@gmail.com>\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://opensource.org/licenses/MIT.\n */\n\n#pragma once\n\n#include <string>\n#include <vector>\n#include <chrono>\n\nnamespace util {\n\n/* String functions */\nstd::wstring utf8toucs4(const std::string &s);\nstd::vector<std::string> splitString(const std::string &str, char c);\n\n/* Time series functions */\nvoid updateTime();\nstd::chrono::steady_clock::time_point getCurrTime();\n\n/* Hotkey functions */\nuint32_t mapStringToVKey(const std::string &name, uint32_t &mods);\n\n}\n"
  }
]